From df7eb058cd93245a19b85c69a6337e22cd815de5 Mon Sep 17 00:00:00 2001 From: Sergey Linev <S.Linev@gsi.de> Date: Fri, 1 Mar 2019 12:26:47 +0100 Subject: [PATCH] jsroot: rename location of JSROOT into $ROOTSYS/js --- js/LICENSE | 21 + js/changes.md | 959 +++ js/files/canvas.htm | 74 + js/files/canvas6.htm | 73 + js/files/draw.htm | 23 + js/files/online.htm | 21 + js/files/panel.htm | 75 + js/files/web.config | 17 + js/img/RootIcon.ico | Bin 0 -> 32038 bytes js/index.htm | 53 + js/openui5/ColorButton.js | 70 + js/openui5/Component.js | 23 + js/openui5/GuiPanelController.js | 55 + js/openui5/SVGSample.js | 92 + js/openui5/controller/Canvas.controller.js | 461 ++ .../controller/CanvasPanel.controller.js | 85 + js/openui5/controller/FitPanel.controller.js | 55 + js/openui5/controller/Ged.controller.js | 196 + js/openui5/controller/Inspector.controller.js | 35 + js/openui5/controller/Panel.controller.js | 134 + js/openui5/view/Canvas.view.xml | 98 + js/openui5/view/CanvasPanel.view.xml | 5 + js/openui5/view/FitPanel.view.xml | 25 + js/openui5/view/Ged.view.xml | 20 + js/openui5/view/Hist.fragment.xml | 98 + js/openui5/view/Inspector.fragment.xml | 10 + js/openui5/view/Inspector.view.xml | 6 + js/openui5/view/Panel.view.xml | 5 + js/openui5/view/TAttFill.fragment.xml | 45 + js/openui5/view/TAttLine.fragment.xml | 50 + js/openui5/view/TAttMarker.fragment.xml | 57 + js/openui5/view/TNamed.fragment.xml | 19 + js/scripts/JSRoot3DPainter.js | 990 +++ js/scripts/JSRootCore.js | 2332 ++++++ js/scripts/JSRootGeoBase.js | 3392 ++++++++ js/scripts/JSRootGeoPainter.js | 4125 ++++++++++ js/scripts/JSRootGeoWorker.js | 108 + js/scripts/JSRootIOEvolution.js | 3058 ++++++++ js/scripts/JSRootMath.js | 721 ++ js/scripts/JSRootPainter.hierarchy.js | 2865 +++++++ js/scripts/JSRootPainter.hist.js | 6882 +++++++++++++++++ js/scripts/JSRootPainter.hist3d.js | 3511 +++++++++ js/scripts/JSRootPainter.jquery.js | 2220 ++++++ js/scripts/JSRootPainter.js | 6536 ++++++++++++++++ js/scripts/JSRootPainter.more.js | 3702 +++++++++ js/scripts/JSRootPainter.openui5.js | 525 ++ js/scripts/JSRootPainter.v6.js | 4903 ++++++++++++ js/scripts/JSRootPainter.v7.js | 4316 +++++++++++ js/scripts/JSRootPainter.v7hist.js | 3622 +++++++++ js/scripts/JSRootPainter.v7more.js | 158 + js/scripts/JSRootTree.js | 2588 +++++++ js/scripts/ThreeCSG.js | 905 +++ js/scripts/d3.LICENSE | 27 + js/scripts/d3.min.js | 2 + js/scripts/dat.gui.min.js | 2 + js/scripts/jquery-ui.min.js | 13 + js/scripts/jquery.min.js | 4 + js/scripts/jquery.mousewheel.min.js | 8 + js/scripts/rawinflate.min.js | 1 + js/scripts/three.LICENSE | 21 + js/scripts/three.extra.min.js | 1 + js/scripts/three.min.js | 966 +++ js/scripts/touch-punch.min.js | 11 + js/style/JSRootGeoPainter.css | 295 + js/style/JSRootPainter.css | 707 ++ js/style/images/ui-icons_444444_256x240.png | Bin 0 -> 7006 bytes js/style/images/ui-icons_555555_256x240.png | Bin 0 -> 7074 bytes js/style/images/ui-icons_777620_256x240.png | Bin 0 -> 4676 bytes js/style/images/ui-icons_777777_256x240.png | Bin 0 -> 7013 bytes js/style/images/ui-icons_cc0000_256x240.png | Bin 0 -> 4632 bytes js/style/images/ui-icons_ffffff_256x240.png | Bin 0 -> 6313 bytes js/style/jquery-ui.css | 1312 ++++ 72 files changed, 63789 insertions(+) create mode 100644 js/LICENSE create mode 100644 js/changes.md create mode 100644 js/files/canvas.htm create mode 100644 js/files/canvas6.htm create mode 100644 js/files/draw.htm create mode 100644 js/files/online.htm create mode 100644 js/files/panel.htm create mode 100644 js/files/web.config create mode 100644 js/img/RootIcon.ico create mode 100644 js/index.htm create mode 100644 js/openui5/ColorButton.js create mode 100644 js/openui5/Component.js create mode 100644 js/openui5/GuiPanelController.js create mode 100644 js/openui5/SVGSample.js create mode 100644 js/openui5/controller/Canvas.controller.js create mode 100644 js/openui5/controller/CanvasPanel.controller.js create mode 100644 js/openui5/controller/FitPanel.controller.js create mode 100644 js/openui5/controller/Ged.controller.js create mode 100644 js/openui5/controller/Inspector.controller.js create mode 100644 js/openui5/controller/Panel.controller.js create mode 100644 js/openui5/view/Canvas.view.xml create mode 100644 js/openui5/view/CanvasPanel.view.xml create mode 100644 js/openui5/view/FitPanel.view.xml create mode 100644 js/openui5/view/Ged.view.xml create mode 100644 js/openui5/view/Hist.fragment.xml create mode 100644 js/openui5/view/Inspector.fragment.xml create mode 100644 js/openui5/view/Inspector.view.xml create mode 100644 js/openui5/view/Panel.view.xml create mode 100644 js/openui5/view/TAttFill.fragment.xml create mode 100644 js/openui5/view/TAttLine.fragment.xml create mode 100644 js/openui5/view/TAttMarker.fragment.xml create mode 100644 js/openui5/view/TNamed.fragment.xml create mode 100644 js/scripts/JSRoot3DPainter.js create mode 100644 js/scripts/JSRootCore.js create mode 100644 js/scripts/JSRootGeoBase.js create mode 100644 js/scripts/JSRootGeoPainter.js create mode 100644 js/scripts/JSRootGeoWorker.js create mode 100644 js/scripts/JSRootIOEvolution.js create mode 100644 js/scripts/JSRootMath.js create mode 100644 js/scripts/JSRootPainter.hierarchy.js create mode 100644 js/scripts/JSRootPainter.hist.js create mode 100644 js/scripts/JSRootPainter.hist3d.js create mode 100644 js/scripts/JSRootPainter.jquery.js create mode 100644 js/scripts/JSRootPainter.js create mode 100644 js/scripts/JSRootPainter.more.js create mode 100644 js/scripts/JSRootPainter.openui5.js create mode 100644 js/scripts/JSRootPainter.v6.js create mode 100644 js/scripts/JSRootPainter.v7.js create mode 100644 js/scripts/JSRootPainter.v7hist.js create mode 100644 js/scripts/JSRootPainter.v7more.js create mode 100644 js/scripts/JSRootTree.js create mode 100644 js/scripts/ThreeCSG.js create mode 100644 js/scripts/d3.LICENSE create mode 100644 js/scripts/d3.min.js create mode 100644 js/scripts/dat.gui.min.js create mode 100644 js/scripts/jquery-ui.min.js create mode 100644 js/scripts/jquery.min.js create mode 100644 js/scripts/jquery.mousewheel.min.js create mode 100644 js/scripts/rawinflate.min.js create mode 100644 js/scripts/three.LICENSE create mode 100644 js/scripts/three.extra.min.js create mode 100644 js/scripts/three.min.js create mode 100644 js/scripts/touch-punch.min.js create mode 100644 js/style/JSRootGeoPainter.css create mode 100644 js/style/JSRootPainter.css create mode 100644 js/style/images/ui-icons_444444_256x240.png create mode 100644 js/style/images/ui-icons_555555_256x240.png create mode 100644 js/style/images/ui-icons_777620_256x240.png create mode 100644 js/style/images/ui-icons_777777_256x240.png create mode 100644 js/style/images/ui-icons_cc0000_256x240.png create mode 100644 js/style/images/ui-icons_ffffff_256x240.png create mode 100644 js/style/jquery-ui.css diff --git a/js/LICENSE b/js/LICENSE new file mode 100644 index 00000000000..e18084be504 --- /dev/null +++ b/js/LICENSE @@ -0,0 +1,21 @@ +The MIT License + +Copyright © 2013-2015 JavaScript ROOT authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/js/changes.md b/js/changes.md new file mode 100644 index 00000000000..713b6314e38 --- /dev/null +++ b/js/changes.md @@ -0,0 +1,959 @@ +# JSROOT changelog + +## Changes in dev +1. Upgrade three.js 86 -> 97 +2. Upgrade d3.js 4.4.4 -> 5.7.0 +3. Many adjustment with new TWebCanvas +4. Implement update of TF2 drawings, see tutorials/graphics/anim.C +5. Use gStyle attributes to draw histogram title +6. Add support of TProfile2Poly class +7. Support eve7 geometry viewer - render data generated in ROOT itself +8. Provide initial WebVR support (#176), thanks to Diego Marcos (@dmarcos) +9. Improve windows handling in flex(ible) layout +10. Fix - support clipping for tracks and points in geo painter +11. Fix - drawing of TGeoNode with finder +12. Fix - key press events processed only in actvie pad (ROOT-9128) + + +## Changes in 5.6.2 +1. Fix - correctly handle negative parameter values in TF1/TF2 + + +## Changes in 5.6.1 +1. Add TMath.BreitWigner function +2. Support custom streamers for TMaterial and TMixture (very old examples) +3. Fix Y-scale drawing of THStack (https://root-forum.cern.ch/t/31266) +4. Fix - select palette from colz element +5. Fix - LZ4 uncompression of large buffers + + +## Changes in 5.6.0 +1. By drawing outline speed up (factor 10) canvas with many small sub-pads +2. Let configure user click and double-click handlers, extend tooltip.htm example +3. Implement workaround for standard THREE.SVGRenderer - no need for patched version +4. When producing 3D graphical images in batch, use normal THREE.CanvasRenderer +5. Use WebGL renderer in Chrome headless mode for 3D images generation +6. Provide possibility to create SVG files for canvas or frame (#172) +7. Support text drawing with TH1 bar option +8. Fix - when drawing text, reserve extra y range to show it correctly +9. Migrate to Node.js 8, do not support older versions + + +## Changes in 5.5.2 +1. Fix - draw TH2Poly bins outline when no content specified +2. Fix - always set axis interactive handlers (#170) +3. Fix - take into account zaxis properties when drawing color palette (#171) + + +## Changes in 5.5.1 +1. Fix - adjust v7 part to new class naming convention, started with R +2. Fix - show RCanvas title +3. New - implement 'nocache' option for JSROOT scripts loading. When specified in URL with + JSRootCore.js script, tries to avoid scripts caching problem by adding stamp parameter to all URLs +4. New - provide simple drawing for TObjString (#164) + + +## Changes in 5.5.0 +1. Introduce JSROOT.StoreJSON() function. It creates JSON code for the + TCanvas with all drawn objects inside. Allows to store current canvas state +2. Support "item=img:file.png" parameter to insert images in existing layout (#151) +3. Support TTree drawing into TGraph (#153), thanks @cozzyd +4. Let configure "&toolbar=right" in URL to change position of tool buttons +5. Let configure "&divsize=500x400" in URL of size of main div element (default - full browser) +6. Implement "optstat1001" and "optfit101" draw options for histograms +7. Remove "autocol" options - standard "plc" should be used instead +8. Provide drawing of artificial "$legend" item - it creates TLegend for all primitives in pad + Can be used when several histograms or several graphs superimposed +9. Let configure "&toolbar=vert" in URL to change orientation of tool buttons +10. Improve markers and error bars drawing for TH1/TProfile + + +## Changes in 5.4.3 +1. Fix - draw functions also when histogram "same" option used (#159) +2. Fix - when draw histogram as markers improve optimization algorithm +3. Fix - correct histogram Y-axis range selection in logarithmic scale +4. Fix - for TH2 draw options allow combination "colztext" (#162) +5. Fix - PNG file generation with 3D drawings inside + + +## Changes in 5.4.2 +1. Fix - take into account extra quotes in multipart http reply (#157) +2. Fix - display of labels on X axis with TProfile +3. Fix - support time display in TMultiGraph +4. Fix - correctly parse "optstat" and "optfit" in URL +5. Fix - correctly update TGraph drawing when X range is changing +6. Fix - return only TF1/TF2 object when searching function (#158) + + +## Changes in 5.4.1 +1. Fix - monitoring mode in draw.htm page +2. Fix - zooming in colz palette +3. Fix - support both 9.x and 10.x jsdom version in Node.js (#149) +4. Fix - draw axis main line with appropriate attributes (#150) +5. Fix - use axis color when drawing grids lines (#150) +6. Fix - when set pad logx/logy, reset existing user ranges in pad +7. Fix - avoid too deep calling stack when drawing many graphs or histos (#154) +8. Fix - correctly (re)draw tooltips on canvas with many subpads + + +## Changes in 5.4.0 +1. New supported classes: + - TDiamond + - TArc + - TCurlyLine + - TCurlyArc + - TCrown +2. New draw options: + - "RX" and "RY" for TGraph to reverse axis + - "noopt" for TGraph to disable drawing optimization + - "CPN" for TCanvas to create color palette from N last colors + - "line" for TGraph2D +3. New features: + - support LZ4 compression + - tooltips and zooming in TGraphPolar drawings + - TPavesText with multiple underlying paves + - implement all fill styles + - draw borders for TWbox + - draw all objects from TList/TObjArray as they appear in list of primitives + - let enable/disable highlight of extra objects in geometry viewer + - draw axis labels on both sides when pad.fTick[x/y] > 1 + - make drawing of TCanvas with many primitives smoother + - add fOptTitle, fOptLogx/y/z fields in JSROOT.gStyle +4. Behavior changes: + - disable automatic frame adjustment, can be enabled with "&adjframe" parameter in URL + - when drawing TH2/TH3 scatter plots, always generate same "random" pattern + - use barwidth/baroffset parameters in lego plots +5. Bug fixes: + - use same number of points to draw lines and markers on the TGraph + - correctly draw filled TArrow endings + - let combine "L" or "C" TGraph draw option with others + - correct positioning of custom axis labels + - correctly toggle lin/log axes in lego plot + - let correctly change marker attributes interactively + + +## Changes in 5.3.5 +1. Fix - correctly show histogram with negative bins and fill attributes (#143) +2. Fix - correct animation for status line (when visible) +3. Fix - correctly set lin/log settings back top TPad object +4. Fix - correctly use preloaded d3.js in notebooks/require.js environment +5. Cached Latex regex to improve drawing speed (#145) + + +## Changes in 5.3.4 +1. Fix - several problem in TLatex preprocessing for MathJax.js +2. Fix - use "E" draw options for THStack only when no any other specified + + +## Changes in 5.3.3 +1. Use latest jsdom and mathjax-node packages (Node.js only) + + +## Changes in 5.3.2 +1. Fix - use FontSize when draw TLegend entries +2. Fix - correctly show TH2 overflow stats +3. Fix - tooltips handling for TH1 hbar drawings +4. Implement JSROOT.toJSON() function to produce ROOT JSON string + + +## Changes in 5.3.1 +1. Fix - show TH2 projections also when tooltip is disabled +2. Fix - use z_handle to format Z-axis labels +3. Fix - support labels on TH3 Z axis +4. Fix - TH1 zooming in 3D mode +5. Fix - suppress empty {} in TLatex +6. Add several math symbols for TLatex +7. Fix - font kind 1 is italic times roman +8. Fix - do not let expand parent item in hierarchy +9. Fix - use correct painter to check range +10. Fix - change proper axis attributes in context menu +11. Fix - correctly show axis labels on 3D plot +12. Fix - correctly handle circle (marker style 24) as marker kind +13. Fix - correct circle drawing with coordinates rounding +14. Fix - TLatex #frac and #splitline, adjust vertical position +15. Fix - workaround for y range when fMinimum==fMaximum!=-1111 +16. Fix - correct tooltips for graph with marker drawing + + +## Changes in 5.3.0 +1. New supported classes: + - TGraphPolar + - TGraphTime + - TSpline3 + - TSpline5 + - TPolyLine3D + - TPolyMarker + - TEfficiency + - TH1K +2. New supported options: + "PFC" - auto fill color (histograms and graphs) + "PLC" - auto line color + "PMC" - auto marker color + "A" - fully disables axes drawing for histograms painters + "TEXT" - for TH2Poly + "SAMES" - draw stat box for superimposed histograms + "NOCOL" - ignore stored in the TCanvas colors list + "NOPAL" - ignore stored in the TCanvas color palette +3. Improvements in existing painters: + - use color palette stored in the TCanvas + - draw stats box when really required + - let resize frames and paves in all eight directions + - support lines, boxes and arbitrary text positions in TPaveText + - automatic title positioning of vertical axis when fTitleOffset==0 + - when pad.fTickx/y==2 draw axes labels on opposite side + - editing of TGraph objects - moving of the graph bins + - draw X/Y/Z axis titles in lego plots + - use canvas Theta/Phi angles to set initial camera position in 3D plots +4. New TLatex processor supports most ROOT features, still MathJax can be used +5. New X/Y projections display for TH2 histograms (aka TH2::SetShowProjectionX/Y) +6. New in geometry viewer: + - provide shape parameters in TGeo tooltips + - let inspect selected TGeoNode + - provide text info when geometry drawing takes too long +7. Change in JSROOT.draw functionality. Now valid painter instance can be only + obtained via call-back - forth argument of JSROOT.draw() function. +8. Use latest three.js r86 with improved Projector and CanvasRenderer + Still use own SVGRenderer which supported direct SVG text dump +9. Introduce openui5 components for webgui functionality +10. In all sources specify "use strict" directive + + +## Changes in 5.2.4 +1. Fix - support pow(x,n) function in formula +2. Fix - use pad.fFillColor for frame when fFrameFillColor==0 +3. Fix - correctly identify horizontal TGaxis with reverse scale +4. Fix - correctly handle negative line width in exclusion +5. Fix - tooltips handling for TF1 + + +## Changes in 5.2.3 +1. Fix - potential mix-up in marker attributes handling +2. Fix - unzomming of log scale https://root-forum.cern.ch/t/25889 +3. Fix - ignore not-supported options in TMultiGraph https://root-forum.cern.ch/t/25888 +4. Fix - correctly use fGridColor from TStyle +5. Fix - prevent error when TPaveText includes TLine or TBox in list of lines +6. Fix - bin errors calculations in TProfile + + +## Changes in 5.2.2 +1. Fix several problems, discovered with "use strict" directive + + +## Changes in 5.2.1 +1. Fix - correctly handle new TF1 parameter coding convention (#132) +2. Fix - Check if pad name can be used as element id (#133) +3. Fix - adjust title position for vertical axis with fTitleOffset==0 + + +## Changes in 5.2.0 +1. Basic JSROOT functionality can be used in Node.js: + var jsroot = require("path/to/JSRootCore.js"); + One could parse ROOT JSON, read binary ROOT files (local and remote) and produce SVG. +2. Implement dropping of TTree object on the geometry drawing. + This automatically invokes extract_geo_tracks() function, which + should extract TGeoTracks from provided TTree. + Example can be found in demo/alice_esd.js and in api.htm. +3. Implement projection of geometry on given plane. + One could reuse drawing of geometry in other div (should be drawn with main option). + In control GUI one could change position of the projection plane +4. One of the TGeo drawing can be assigned as main. When same object drawn next time, + its drawing will be derived from the main. Useful for geometry projections. + Also all tracks and hits will be imported from main drawing. +5. Let change background color of geo drawing. +6. One can change web browser title, providing &title="any string" in URL. +7. Introduce event status line, which is similar to ROOT TCanvas. + Shown information similar to output in tooltip. + One can enable both tooltips and status line at the same time. +8. Introduce JSROOT.GEO.build function to create three.js model for + any supported TGeo class. Such model can be inserted in any three.js scene + independent from normal JSROOT drawings. +9. Improve rendering of geometries with transparency. Use EVE approach, when transparent + objects rendered after opaque and without writing depth buffer. Provide different + methods to produce render order for transparent objects. +10. Let specify initial zoom factor for geometry like opt=zoom50. +11. Support also TPolyMarker3D class in geo painter. +12. Implement TGeoScaledShape. +13. Limit complexity of composite shape. If it has too many components, only most left is used. +14. When produce canvas or pad screenshot, render 3D objects with SVGRenderer. + Allows to combine 2D and 3D objects in same PNG image +15. Improve MathJax.js output. It scales correctly in Firefox, makes correct alignment + and works significantly faster. +16. When creating image in SVG format, correctly convert url("#id") references +17. Use latest three.js r85 +18. Fix 'transpXY' URL parameter handling - it was used as opacity, but opacity=1-transparency + + +## Changes in 5.1.2 +1. Fix - support newest TFormula in TF1 (#127) +2. Fix - ignore NaN value in saved TF1 buffer +3. Fix - correctly treat transparency in geo painter +4. Fix - disable useFontCache for SVG mathjax output +5. Fix - produce PNG image for objects with special symbols in names + + +## Changes in 5.1.1 +1. Fix - invoke callback in JSROOT.draw() at proper time +2. Fix - support TGeoHMatrix, produced after GDML conversion +3. Fix - support also TGeoScale and TGeoGenTrans matrices +4. Fix - update histograms with all provided functions (#125) + + +## Changes in 5.1.0 +1. New 'float' browser kind overlays with objects drawing +2. Browser can be enabled after drawing with 'nobrowser' mode +3. One can hide browser or switch browser kind at any time +4. New 'horizontal' and 'vertical' layouts for object display. + One could configure several frames, each divided on sub-frames. + Like display=horiz231 will create three horizontal frames, + divided on 2,3 and 1 sub-frames. +5. One could enable status line where current tooltip info will be shown +6. Improve enlarge functionality - now works with all layouts +7. Do not display all canvas tool buttons by default - provide toggle button instead +8. Let move TAxis title, its position now similar to ROOT graphics +9. Support 'col0' option for TH2Poly class to suppress empty bins +10. Implement for TH3 'box2', 'box3', 'glbox2', 'glcol' draw options +11. Support more superscript/subscript letters in normal text output +12. Correctly handle unzoom with logx/logy scales +13. Let disable stamp parameter in file url with "-" sign at the end of file name +14. Let use quotes in the URL parameters to protect complex arguments with special symbols +15. Introduce direct streamers - like TBasket or TRef + Benefit - one can add custom streamers of such kind or reuse existing +16. Handle TMatrixTSym classes in I/O +17. Correctly count TH3 statistic in TTree::Draw +18. Recognize bower installation when "bower_components/jsroot/scripts" string + appears in the script path (#120) + + +## Changes in 5.0.3 +1. Fix - prevent exception when discover HTML element position (#121) +2. Fix - prevent I/O failure when server automatically gzip response (#119) +3. Fix - lego drawing for stacked TH1 histograms +4. Fix - when change global tooltips settings, also change for each sub-pad + + +## Changes in 5.0.2 +1. Fix - read branch entries as arrays +2. Fix - command submission to THttpServer +3. Fix - let refill statbox also for empty histogram +4. Fix - problem with online TTree::Draw and ROOT6 + + +## Changes in 5.0.1 +1. Support older ROOT files, created before 2010 +2. Support TBranchObject - appears in old files +3. Correctly set TBasket buffer position for the entry +4. Fix - problem with empty STL containers +5. Fix - empty baskets at the end of branch store +6. Fix - problem with zooming in THStack + + +## Changes in 5.0.0 +1. Reading TTree data + - all kinds of branches, including split STL containers + - branches with several elementary leaves + - branches from different ROOT files + - JSROOT.TSelector class to access TTree data + - simple access to branch data with "dump" draw option +2. TTree::Draw support + - simple 1D/2D/3D histograms + - simple cut conditions + - configurable histogram like "px:py>>hist(50,-5,5,50,-5,5)" + - strings support + - iterate over arrays indexes, let use another branch as index values + - support "Entry$" and "Entries$" variables in expressions + - bits histogram like "event.fTracks.fBits>>bits(16)" + - special handling of TBits + - arbitrary math function from JavaScript Math class, some TMath:: function from ROOT + - if branch is object, one could use methods "TMath::Abs(lep1_p4.X()+lep1_p4.Y())" + - interactive player to configure and execute draw expression +3. Full support of Float16_t and Double32_t types in I/O +4. Drawing of RooPlot objects, I/O support for RooFit classes +5. Many improvements in object inspector + - support of large lists; only first part is shown + - support of large arrays; values group in decades + - allow to call draw function for sub-elements in inspector +6. Canvas or selected sub-pad can be enlarged when double-clicked outside frame (#116) + Complete drawing will be expanded to the visible space. + Not available for flex, tabs and collapsible layouts. +7. Support reading of local ROOT files with HTML5 FileReader. + Files can be selected only with interactive dialog. +8. Combine "Ctrl" and "Shift" keys with mouse click on the items: + - with Shift key typically object inspector will be activated + - with Ctrl key alternative draw options will be used (like colz for TH2) +9. Update libraries + - d3.js - 4.4.4 + - three.js - 84 + - jquery - 3.3.1 + - jquery-ui - 1.12.1 + + +## Changes in 4.8.2 +1. Support compressed array, produced with newest TBufferJSON + - $arr field identify such array and contains data type + - native arrays are used when decoding such array + - zero values are not stored + - many similar values stored as one with repetition factor + - position stored only when differ from produced with previous block + - array [3,3,3,3,3,3,1,2,2,2,2,2,2,2] compressed as {$arr:"Int",len:14,v:3,n:6,v1:1,v2:2,n2:7} + + +## Changes in 4.8.1 +1. Support new JSON format, produced with newest TBufferJSON + - object references stored as {"$ref":12} + - pair objects for std::map marked with "$pair" : "pair<type1,type2>" data member + - old JSON format will be recognized automatically and supported as well +2. Fix - better selection of Y range for log scale +3. Provide JSROOT.parse_multi function to correctly parse response of multi.json request, + support it in the JSROOT.NewHttpRequest method as well. +4. Fix - correctly calculate integral for TH1 +5. Partially support new TFormula with complex C code inside + + +## Changes in 4.8.0 +1. Many improvements in the I/O part + - support most of STL containers + - support TMap and TClonesArray containers + - all kind of multidimensional arrays + - correct treatment of foreign classes + - supports different versions of class in the same file + - support members like ClassName* fField; //[fCnt] + - support const char* + - support fixed-size array of TString, TObject and TNamed +2. Many new draw options for different classes are supported: + - TGraph - 'z', 'x', '||', '[]', '>', '|>', '5', 'X+', 'Y+' + - TH1 - '*', 'L', 'LF2', 'B', 'B1', 'TEXT', 'E0', 'E3', 'E4', 'EX0', 'X+', 'Y+' + - TH2 - 'E', 'col1', 'box', 'box1', 'surf3', 'surf7', 'base0' + - TH2 - 'same' with 'box', 'col', 'cont', 'lego', 'surf' + - TH3 - 'scat', use by default + - TF1/TF2 - 'nosave' to ignore saved buffer + - TCanvas - logx/y/z, gridx/y, tickx/y + - THStack - 'lego' and other 3D draw options +3. Implement drawing of TProfile2D, TF2, TGraph2D, TGraph2DErrors and TMarker +4. Fix - correctly place TGAxis relative to frame (when exists) +5. When superimpose items, one can specify individual options + ...&item=histo1+histo2&opt=hist+e1 + ...&item=[histo1,histo2]&opt=[hist,e1] +6. Support loading of TStyle object, providing in URL + ...&style=item_name or ...&style=json_file_name + All values are copied directly to JSROOT.gStyle object. +7. Add callback argument into JSROOT.draw() function. + Function will be called after drawing of object is completed. + Painter for drawn object will be provided as first argument (or null in case of error). +8. Improve cleanup of JSROOT objects + + +## Changes in 4.7.1 +1. Workaround for MathJax output - scaling not always works in Firefox +2. Fix - bin scaling for box draw option for TH2 and TH3 histograms +3. Fix - increase points limits for contour plots +4. Fix - position of 3D canvas in WebKit browsers +5. Fix - use abs bin content in RMS calculations +6. Fix - support char star* and object arrays in I/O +7. Fix - correct decoding of TAxis time offset +8. Fix - checksum reading for foreign classes + + +## Changes in 4.7.0 +1. Implement simple TTree::Draw over single leaf (#80) + Support basic types, fixed-size arrays and several vector types +2. Display of TEveTrack(s) and TEvePointSet(s) over drawn geometry (drag and drop) + Also browsing, toggling, highlight of tracks and hits are done. +3. Let set default geo colors as TGeoManager::DefaultColors() does +4. Let use original ROOT macros to configure visibility of geometry volumes. Like: + &file=files/alice2.root&item=Geometry;1&opt=macro:macros/geomAlice.C + One can set default colors or colors/transparency for selected volumes. + Also volume, selected for drawing in the macro, will be used in the JSROOT +5. Support drawing of TH2Poly class with 'col' and 'lego' options +6. Implement 'CONT', 'ARR' and 'SURF' draw options for TH2 class +7. Support basic drawing of TPolyLine class +8. Interactive axis zooming in 3D with mouse, very much like to 2D +9. Zooming and tool buttons via keyboards + + +## Changes in 4.6.0 +1. Improvements in TGeo drawings + - support of large (~10M volumes) models, only most significant volumes are shown + - one could activate several clip planes (only with WebGL) + - interaction with object browser to change visibility flags or focus on selected volume + - support of floating browser for TGeo objects + - intensive use of HTML Worker to offload computation tasks and keep interactivity + - enable more details when changing camera position/zoom + - better and faster build of composite shapes +2. Improvements in histograms 3D drawing + - all lego options: lego1..lego4, combined with 'fb', 'bb', '0' or 'z' + - support axis labels on lego plots + - support lego plots for TH1 +3. Improvements in all 3D graphics + - upgrade three.js to r79 + - use of THREE.BufferGeometry for all components + - significant (up to factor 10) performance improvement +4. Implement box and hbox draw options for TH1 class +5. Implement drawing of axes ticks on opposite side (when fTickx/y specified) +6. Preliminary support of candle plot (many options to be implemented) +7. Update draw attributes (fill/line/position) when monitor objects + + +## Changes in 4.5.3 +1. Fix - position of TFrame in canvas/pad +2. Fix - use histogram fMinimum/fMaximum when creating color palette +3. Fix - correctly draw empty th2 bins when zmin<0 is specified +4. Fix - limit th2 text output size +5. Fix - use histogram fMinimum/fMaximum when drawing z axis in lego plot +6. Fix - error in TGeoCtub shape creation +7. Fix - error in pcon/pgon shapes when Rmin===0 + + +## Changes in 4.5.1 +1. Fix - correctly handle ^2..^9 in TFormula equations +2. Fix - support TMath::Gaus in TFormula +3. Fix - correctly display ^2 and ^3 in SVG text output +4. Fix - do not show tooltips for empty TProfile bins +5. Fix - statbox toggling was not working on subpads +6. Fix - positioning of 3D objects in Webkit browsers in complex layouts +7. Fix - difference in TF1 between ROOT5/6 (#54) + + +## Changes in 4.5.0 +1. Zooming with mouse wheel +2. Context menus for many different objects attributes are provided +3. Context menu for every drawn object can be activated via toolbar button +4. Support browsing of TTask and derived classes (#40) +5. Apply user range for drawing TH1/TH2 histograms, also when superimposed (#44) +6. Implement scaling factor like x10^3 on the vertical axes +7. Provide shortcut buttons for each subpad +8. Implement simple drawing for TBox, TWbox, TSliderBox classes + + +## Changes in 4.4.4 +1. Fix - toggling of statbox was not working in all situations +2. Fix - for mouse rect zooming use only left mouse button +3. Fix - correctly draw TH2 with lego option, when histogram has negative bin content +4. Fix - log axis drawing with no visible ticks + + +## Changes in 4.4.3 +1. Fix - wrong selection of TH1 Y axis range when errors are displayed (#44) +2. Fix - apply user range for TH1 X-axis zooming (#44) +3. Fix - protect against pathological case of 1-bin histogram +4. Fix - use error plot by default in TH1 only when positive sumw2 entry exists +5. Fix - for TH2 box draw option draw at least 1px rect for non-empty bin +6. Fix - support transparency (alpha) in TColor (#45) +7. Fix - correct tooltip handling for graphs with lines and markers +8. Fix - interactive zooming in TH2 when doing histogram update + + +## Changes in 4.4.2 +1. Fix - statistic collection for TH2 +2. Fix - correct handling of empty TList in browser/inspector +3. Fix - support TFolder in browser/inspector (#40) + + +## Changes in 4.4.1 +1. Fix - colz palette resize when drawing histogram second time +2. Fix - use embedded in TCanvas color for background color of canvas itself +3. Fix - rotate too long X axis text labels +4. Fix - draw histogram bins on frame boundary +5. Fix - use alternative color for shapes with default black color +6. Fix - correctly handle pcon/pgon shape with rmin==rmax on top or bottom side + + +## Changes in 4.4 +1. Fix faces orientation for all TGeo shapes. +2. Improve TGeoTorus creation - handle all parameters combinations +3. Implement TGeoCompositeShape, using ThreeCSG.js +4. Fix problem with color palette when switch to 3D mode (#28) +5. Use nested CSS classes to avoid conflicts with other libraries (#29) +6. Let move and resize TFrame +7. Improve TH1/TH2 drawings + - draw all histograms points in the range (no any skipped bins) + - minimize SVG code for drawing (up to factor 100) + - gives significant speedup in drawings +8. SVG code improvement for TGraph, TF1, TAxis drawings +9. Provide new tooltip kind + - created only when needed (minimizing SVG code) + - tooltip can be drawn for every object in the frame + - touch devices are supported +10. Fix - let draw same object on the canvas with different options +11. Create cached list of known class methods. It can be extended by users. +12. Use of cached methods improves binary I/O performance by 20% +13. Support TGaxis +14. Project now can be obtained via 'bower install jsroot' +15. Support 'scat' and 'text' draw options for TH2 +16. Support in binary I/O zipped buffer bigger than 16M +17. Correctly handle in binary I/O pointer on TArray object (like in THnSparseArrayChunk) + + +## Changes in 4.3 +1. Implement TGeoCtub, TGeoParaboloid and TGeoHype shapes +2. Support TGeoTube with Rmin==0 +3. Exclude empty faces in TGeoArb8 +4. Improve TGeoSphere creation - handle all parameters combinations +5. Introduce JSROOT.cleanup() function to safely clear all drawn objects +6. Fix wrong resize method in 'tabs' and 'collapsible' layouts +7. Fix canvas resize problem (issue #27) +8. Fix zero-height canvas when draw TGeo in collapsible layout +9. Fix problem of simultaneous move TGeo drawings and canvas in flexible layout + + +## Changes in 4.2 +1. Significant performance improvements in 3D drawings - TGeo/TH2/TH3 +2. Implement TGeoPara, TGeoGtra, TGeoXtru and TGeoEltu shapes +3. Optimize (reduce vertices number) for others TGeo shapes +4. Correct rotation/translation/scaling of TGeo nodes +5. Workaround for axis reflection (not directly supported in three.js) +6. Support array of objects in I/O (like in TAxis3D) +7. Correct reading of multi-dim arrays like Double_t fXY[8][2]; +8. Provide canvas toolbar for actions like savepng or unzoom +9. Implement JSROOT.resize() function to let resize drawing after changes in page layout +10. Fix error with title display/update + + +## Changes in 4.1 +1. Introduce object inspector - one could browse object members of any class +2. Let draw sub-items from TCanvas list of primitives like sub-pad or TLatex +3. Provide possibility to save drawn SVG canvas as PNG +4. TGraph drawing optimization - limit number of drawn points +5. Implement painter for TPolyMarker3D +6. Improve drawing and update of TMultiGraph +7. Reorganize 3D drawing of TH2/TH3 histograms, allow to mix 2D and 3D display together +8. Support overlay of 3D graphic over SVG canvas (used for IE) +9. Fix problems and improve flex(ible) layout + + +## Changes in 4.0 +1. New TGeo classes support: + - browsing through volumes hierarchy + - changing visibility flags + - drawing of selected volumes +2. New 'flex' layout: + - create frames like in Multi Document Interface + - one could move/resize/minimize/maximize such frames +3. Significant (factor 4) I/O performance improvement: + - use ArrayBuffer class in HTTP requests instead of String + - use native arrays (like Int32Array) for array data members + - highly optimize streamer infos handling +4. TH2 drawing optimization: + - if there are too many non-empty bins, combine them together + - when zoom-in, all original bins will be displayed separately + - let draw big TH2 histogram faster than in 1 sec + - optimization can be disabled by providing '&optimize=0' in URL +5. TF1 drawing optimization: + - function 'compiled' only once +6. Reorganize scripts structure: + - move all math functions to JSRootMath.js + - TH2, TF1, THStack and TMultiGraph painters moved into JSRootPainter.more.js script + - reduce size of scripts required for default functionality +7. Update all basic libraries: + - d3.js - v3.5.9, + - jquery.js - v2.1.4, + - jquery-ui.js - v1.11.4, + - three.js - r73 +8. Implement ROOT6-like color palettes: + - all palettes in range 51...112 are implemented + - by default palette 57 is used + - one could change default palette with '&palette=111' in URL + - or palette can be specified in draw option like '&opt=colz,pal77' + + +## Changes in 3.9 +1. Support non-equidistant bins for TH1/TH2 objects. +2. Display entries count from histo.fEntries member, only when not set use computed value +3. Support italic and bold text when used with MathJax +4. Improve TF1 drawing - support exp function in TFormula, fix errors with logx scale, enable zoom-in, (re)calculate function points when zooming +5. Support several columns in TLegend +6. Introduce context menus for x/y axis, add some items similar to native ROOT menus +7. Introduce context menu for TPaveStats, let switch single elements in the box +8. Enable usage of all context menus on touch devices +9. Implement JSROOT.Math.Prob function, provides probability value in stat box +10. Introduce context menu for color palette (z axis) +11. Implement col0 and col0z draw option for TH2 histograms, similar to ROOT6 + + +## Changes in 3.8 +1. Let use HTML element pointer in JSROOT.draw function like: + JSROOT.draw(document.getElementsByTagName("div")[0], obj, "hist"); + Normally unique identifier was used before, which is not required any longer. + Of course, old functionality with element identifier will work as well. +2. TreePlayer can also be used for trees, which not yet read from the file. + Requires appropriate changes in TRootSniffer class. +3. Fix error in I/O with members like: `Double_t *fArr; //[fN]` +4. Introduce JSROOT.OpenFile function. It loads I/O functionality automatically, + therefore can be used directly after loading JSRootCore.js script +5. Same is done with JSROOT.draw function. It is defined in the JSRootCore.js + and can be used directly. Makes usage of JSROOT easier +6. Introduce JSRootPainter.more.js script, where painters for auxiliary classes + will be implemented. +7. Implement painter for TEllipse, TLine, TArrow classes +8. Fix several problems with markers drawing; implement plus, asterisk, mult symbols. +9. Implement custom layout, which allows to configure user-defined layout for displayed objects +10. Fix errors with scaling of axis labels. +11. Support also Y axis with custom labels like: http://jsroot.gsi.de/dev/?nobrowser&file=../files/atlas.root&item=LEDShapeHeightCorr_Gain0;1&opt=col + + +## Changes in 3.7 +1. Support of X axis with custom labels like: http://jsroot.gsi.de/dev/?nobrowser&json=../files/hist_xlabels.json +2. Extend functionality of JSROOT.addDrawFunc() function. One could register type-specific + `make_request` and `after_request` functions; `icon`, `prereq`, `script`, `monitor` properties. + This let add more custom elements to the generic gui, implemented with JSROOT.HierarchyPainter +3. Provide full support of require.js. One could load now JSRootCore.js script like: + + <script type="text/javascript" src="require.js" data-main="scripts/JSRootCore.js"></script> + + After this several modules are defined and can be used with syntax like: + + require(['JSRootPainter'], function(jsroot) { /*any user code*/}); + + Also inside JSROOT require.js used to load all dependencies. + + +## Changes in 3.6 +1. Try to provide workaround for websites where require.js already loaded. + This makes problem by direct loading of jquery and jquery-ui +2. Provide workaround for older version of jquery-ui +3. Prompt for input of command arguments +4. After command execution one could automatically reload hierarchy (_hreload property) or + update view of displayed object (_update_item property) +5. Use HiearchyPainter for implementing draw.htm. This let us handle + all different kinds of extra attributes in central place +6. Fix problem in tabs layout - new tab should be add to direct child +7. When drawing several tabs, activate frame before drawing - only then + real frame size will be set +8. Fix problem with GetBBox - it only can be used for visible elements in mozilla. +9. Support drawing of fit parameters in stat box, use (as far as possible) stat and + fit format for statistic display +10. Implement 'g' formatting kind for stat box output - one need to checks + significant digits when producing output. +11. Support new draw options for TGraph: 'C', 'B1', '0', '2', '3', '4', '[]' +12. Primary support for STL containers in IO part. Allows to read ROOT6 TF1. +13. Full support of TGraphBentErrors +14. Support objects drawing from JSON files in default user interface, including + monitoring. One could open file from link like: https://root.cern.ch/js/dev/?json=demo/canvas_tf1.json +15. Introduce JSROOT.FFormat function to convert numeric values into string according + format like 6.4g or 5.7e. Used for statistic display. + + +## Changes in 3.5 +1. Fix error in vertical text alignment +2. Many improvements in TPaletteAxis drawing - draw label, avoid too large ticks. +3. Fix error with col drawing - bin with maximum value got wrong color +4. Test for existing jquery.js, jquery-ui.js and d3.js libraries, reuse when provided +5. Fix several I/O problems; now one could read files, produced in Geant4 +6. Implement 'e2' drawing option for TH1 class, + use by default 'e' option when TH1 has non-empty fSumw2 +7. Reuse statistic from histogram itself, when no axis selection done +8. Support log/lin z scale for color drawing +9. Implement interactive z-scale selection on TPaletteAxis +10. Allow to redraw item with other draw options (before one should clear drawings) +11. Several improvements in THttpServer user interface - repair hierarchy reload, + hide unsupported context menu entries, status line update + + +## Changes in 3.4 +1. Support usage of minimized versions of .js and .css files. + Minimized scripts used by default on web servers. +2. Implement JSROOT.extend instead of jQuery.extend, reduce + usage of jquery.js in core JSROOT classes +3. Implement main graphics without jquery at all, + such mode used in `nobrowser` mode. +4. Provide optional latex drawing with MathJax SVG. + TMathText always drawn with MathJax, + other classes require `mathjax` option in URL +5. Improve drawing of different text classes, correctly handle + their alignment and scaling, special handling for IE +6. Fix error with time axes - time offset was not correctly interpreted + + +## Changes in 3.3 +1. Use d3.time.scale for display of time scales +2. Within JSRootCore.js script URL one could specify JSROOT + functionality to be loaded: '2d', '3d', 'io', 'load', 'onload'. + Old method with JSROOT.AssertPrerequisites will also work. +3. With THttpServer JSROOT now provides simple control functionality. + One could publish commands and execute them from the browser +4. One could open several ROOT files simultaneously +5. Add 'simple' layout - drawing uses full space on the right side +6. Allow to open ROOT files in online session (via url parameter) +7. One could monitor simultaneously objects from server and root files +8. Implement 'autocol' draw option - when superimposing histograms, + their line colors will be automatically assigned +9. Implement 'nostat' draw option - disabled stat drawing +10. Using '_same_' identifier in item name, one can easily draw or superimpose + similar items from different files. Could be used in URL like: + `...&files=[file1.root,file2.root]&items=[file1.root/hpx, file2.root/_same_]` + `...&files=[file1.root,file2.root]&item=file1.root/hpx+file2.root/_same_` + Main limitation - file names should have similar length. +11. When 'autozoom' specified in draw options, histogram zoomed into + non-empty content. Same command available via context menu. +12. Item of 'Text' kind can be created. It is displayed as + plain text in the browser. If property 'mathjax' specified, + MathJax.js library will be loaded and used for rendering. + See httpcontrol.C macro for example. +13. When using foreignObject, provide workaround for absolute positioning + problem in Chrome/Safari, see <http://bit.ly/1wjqCQ9> + + +## Changes in 3.2 +1. Support JSON objects embedding in html pages, produced by THttpServer +2. For small resize of canvas use autoscale functionality of SVG. Only when + relative changes too large, redraw complete canvas again. +3. Use touch-punch.min.js to process touch events with jquery-ui +4. Even when several TH1/TGraph/TF1 objects with fill attribute overlap each other, + one able to get tooltip for underlying objects +5. Use jquery-ui menu for context menu +6. From context menu one could select several options for drawing +7. Provide user interface for executing TTree::Draw on THttpServer +8. 3D graphic (three.js) works only with IE11 + + +## Changes in 3.1 +1. Correctly show tooltips in case of overlapped objects +2. Implement JSROOT.Create() method to create supported + in JavaScript ROOT classes like TH1 or TGraph +3. Fix problem with JSROOT.draw in HTML element with zero width (display:none) +4. Provide possibility to load user scripts with JSROOT.BuildSimpleGUI + and JSROOT.AssertPrerequisites, also with main index.htm +5. Support of TCutG drawing +6. Implement hierarchy display (former dtree) with jQuery +7. Fix several problems in drawing optimization +8. Implement dragging objects from hierarchy browser into existing canvas + to superimpose several objects +9. Implement col2 and col3 draw options, using html5 canvas +10. Support 'p' and 'p0' draw options for TH1 class + + +## Development of version 3.0 + +### November 2014 +1. Better font size and position in pave stats +2. Resize/move of element only inside correspondent pad +3. Adjust of frame size when Y-axis exceed pad limits +4. Correct values in tooltip for THStack +5. Exclude drawing of markers from TGraph outside visible range +6. Drawing of canvas without TFrame object +7. Many other small bug fixes and improvements, thanks to Maximilian Dietrich + +### October 2014 +1. Add "shortcut icon" +2. Add demo of online THttpServer - shell script copies data from + running httpserver.C macro on Apache webserver +3. Evaluate 'monitoring' parameter for online server like: + <http://localhost:8080/?monitoring=1000> + Parameter defines how often displayed objects should be updated. +4. Implement 'opt' and 'opts' URL parameters for main page. +5. Show progress with scripts loading in the browser window +6. When one appends "+" to the filename, its content read completely with first I/O operation. +7. Implement JS custom streamer for TCanvas, restore aspect ratio when drawing +8. Major redesign of drawing classes. Resize and update of TCanvas are implemented. + All major draw functions working with HTML element id as first argument. +9. Extract 3D drawings into separate JSRoot3DPainter.js script +10. Use newest three.min.js (r68) for 3D drawings, solves problem with Firefox. +11. Introduce generic list of draw functions for all supported classes. +12. Add possibility to 'expand' normal objects in the hierarchy browser. + For instance, this gives access to single elements of canvas, + when whole canvas cannot be drawn. +13. Correct usage of colors map, provided with TCanvas. +14. Introduce JSROOT.redraw() function which is capable to create or update object drawing. +15. In main index.htm page browser can be disabled (nobrowser parameter) and + page can be used to display only specified items from the file +16. Add support of TPolyMarker3D in binary I/O + +### September 2014 +1. First try to handle resize of the browser, + for the moment works only with collapsible layout +2. Also first try to interactively move separation line between + browser and drawing field. +3. Small fix of minor ticks drawing on the axis +4. Introduce display class for MDI drawing. Provide two implementations - + 'collapsible' for old kind and 'tabs' for new kinds. +5. Adjust size of color palette drawing when labels would take more place as provided. +6. Add correct filling of statistic for TProfile, + fix small problem with underflow/overflow bins. +7. Provide way to select display kind ('collapsible', 'tabs') in the simple GUI. +8. Implement 'grid' display, one could specify any number of division like + 'grid 3x3' or 'grid 4x2'. +9. MDI display object created at the moment when first draw is performed. +10. Introduce painter class for TCanvas, support resize and update of canvas drawing +11. Resize almost works for all layouts and all objects kinds. +12. Implement JSROOT.GetUrlOption to extract options from document URL. +13. Provide example fileitem.htm how read and display item from ROOT file. +14. In default index.htm page one could specify 'file', 'layout', + 'item' and 'items' parameters like: + <http://root.cern.ch/js/3.0/index.htm?file=../files/hsimple.root&layout=grid3x2&item=hpx;1> +15. Support direct reading of objects from sub-sub-directories. +16. Introduce demo.htm, which demonstrates online usage of JSROOT. +17. One could use demo.htm directly with THttpServer providing address like: + <http://localhost:8080/jsrootsys/demo/demo.htm?addr=../../Files/job1.root/hpx/root.json.gz&layout=3x3> +18. Also for online server process url options like 'item', 'items', 'layout' +19. Possibility to generate URL, which reproduces opened page with layout and drawn items + +### August 2014 +1. All communication between server and browser done with JSON format. +2. Fix small error in dtree.js - one should always set + last sibling (_ls) property while tree can be dynamically changed. +3. In JSRootCore.js provide central function, which handles different kinds + of XMLHttpRequest. Use only async requests, also when getting file header. +4. Fully reorganize data management in file/tree/directory/collection hierarchical + display. Now complete description collected in HPainter class and decoupled from + visualization, performed with dTree.js. +5. Remove all global variables from the code. +6. Automatic scripts/style loading handled via JSROOT.loadScript() function. + One can specify arbitrary scripts list, which asynchronously loaded by browser. +7. Method to build simple GUI changed and more simplified :). The example in index.htm. + While loadScript and AssertPrerequisites functions moved to JSROOT, one + can easily build many different kinds of GUIs, reusing provided JSRootCore.js functions. +8. In example.htm also use AssertPrerequisites to load necessary scripts. + This helps to keep code up-to-date even by big changes in JavaScript code. +9. Provide monitoring of online THttpServer with similar interface as for ROOT files. +10. Fix several errors in TKey Streamer, use member names as in ROOT itself. +11. Keep the only version identifier JSROOT.version for JS code +12. One can specify in JSROOT.AssertPrerequisites functionality which is required. + One could specify '2d', 'io' (default) or '3d'. +13. Use new AssertPrerequisites functionality to load only required functionality. +14. When displaying single element, one could specify draw options and monitor property like: + <http://localhost:8080/Files/job1.root/hpxpy/draw.htm?opt=col&monitor=2000> + Such link is best possibility to integrate display into different HTML pages, + using `<iframe/>` tag like: + `<iframe src="http://localhost:8080/Files/job1.root/hpx/draw.htm"` + `style="width: 800px; height:600px"></iframe>` +15. Remove 'JSROOTIO.' prefix from _typename. Now real class name is used. +16. Use in all scripts JSROOT as central 'namespace' +17. Introduce context menu in 3D, use it for switch between 2D/3D modes +18. Use own code to generate hierarchical structure in HTML, replace dtree.js which is + extremely slow for complex hierarchies. Dramatically improve performance for + structures with large (~1000) number of items. +19. Deliver to the server title of the objects, display it as hint in the browser. +20. Better handling of special characters in the hierarchies - allows to display + symbols like ' or " in the file structure. + +### July 2014 +1. Migration to d3.v3.js and jQuery v2.1.1 +2. Fix errors in filling of histogram statbox +3. Possibility of move and resize of statbox, title, color palete +4. Remove many (not all) global variables +5. Example with direct usage of JSRootIO graphics +6. Example of inserting ROOT graphics from THttpServer into `<iframe></iframe>` + +### May 2014 +1. This JSRootIO code together with THttpServer class included + in ROOT repository + +### March 2014 +1. Introduce TBuffer class, which plays similar role + as TBuffer in native ROOT I/O. Simplifies I/O logic, + reduce duplication of code in many places, fix errors. + Main advantage - one could try to keep code synchronous with C++. +2. Avoid objects cloning when object referenced several times. +3. Treat special cases (collection, arrays) in one place. + This is major advantage, while any new classes need to be implemented only once. +4. Object representation, produced by JSRootIO is similar to + objects, produced by TBufferJSON class. By this one can exchange + I/O engine and use same JavaSctript graphic for display. +5. More clear functions to display different elements of the file. + In the future functions should be fully separated from I/O part + and organized in similar way as online part. +6. Eliminate usage of gFile pointer in the I/O part. +7. Provide TBufferJSON::JsonWriteMember method. It allows to stream any + selected data member of the class. Supported are: + basic data types, arrays of basic data types, TString, TArray classes. + Also any object as data member can be streamed. +8. TRootSniffer do not creates sublevels for base classes diff --git a/js/files/canvas.htm b/js/files/canvas.htm new file mode 100644 index 00000000000..d8728a0bcc9 --- /dev/null +++ b/js/files/canvas.htm @@ -0,0 +1,74 @@ +<!-- this file used for ROOT7 Canvas display --> +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="UTF-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + <title>ROOT7 TCanvas</title> + <script type="text/javascript" src="jsrootsys/scripts/JSRootCore.js"></script> + </head> + + <style> + html { height: 100%; } + body { min-height: 100%; margin: 0; overflow: hidden } + #CanvasDiv { + position: absolute; + left: 0; + top: 0; + bottom: 0; + right: 0; + padding: 1 + } + </style> + + <body> + <div id="CanvasDiv"> + loading scripts... + </div> + </body> + + <script type='text/javascript'> + + function InitV7Canvas(handle, args) { + var use_openui = true; + + var painter = new JSROOT.v7.TCanvasPainter(null); + painter.batch_mode = JSROOT.GetUrlOption("batch_mode") !== null; + if (painter.batch_mode) JSROOT.BatchMode = true; + + if (window) { + window.onbeforeunload = painter.WindowBeforeUnloadHanlder.bind(painter); + if (JSROOT.browser.qt5) window.onqt5unload = window.onbeforeunload; + } + + if (use_openui && !painter.batch_mode) { + + painter._window_handle = handle; + painter.use_openui = true; + + return JSROOT.AssertPrerequisites('openui5', function() { + + new JSROOT.sap.ui.xmlview({ + id: "TopCanvasId", + viewName: "sap.ui.jsroot.view.Canvas", + viewData: { canvas_painter: painter } + }).placeAt("CanvasDiv"); + }); + } + + painter.SetDivId("CanvasDiv", -1); // just assign id, nothing else is happens + + painter.UseWebsocket(handle); // when connection activated, ROOT must send new instance of the canvas + + if (!painter.batch_mode) JSROOT.RegisterForResize(painter); + } + + JSROOT.ConnectWebWindow({ + prereq: "2d;v6;v7;", + prereq_logdiv: "CanvasDiv", + callback: InitV7Canvas + }); + + </script> + +</html> diff --git a/js/files/canvas6.htm b/js/files/canvas6.htm new file mode 100644 index 00000000000..d6e08f7c912 --- /dev/null +++ b/js/files/canvas6.htm @@ -0,0 +1,73 @@ +<!-- this file used for ROOT6 Canvas display with TWebWindow --> +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="UTF-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + <title>ROOT6 TCanvas</title> + <script type="text/javascript" src="jsrootsys/scripts/JSRootCore.js"></script> + </head> + + <style> + html { height: 100%; } + body { min-height: 100%; margin: 0; overflow: hidden } + #CanvasDiv { + position: absolute; + left: 0; + top: 0; + bottom: 0; + right: 0; + padding: 1 + } + </style> + + <body> + <div id="CanvasDiv"> + loading scripts... + </div> + </body> + + <script type='text/javascript'> + + function InitV6Canvas(handle, args) { + + var painter = new JSROOT.TCanvasPainter(null); + + painter.online_canvas = true; + painter.use_openui = (JSROOT.GetUrlOption("noopenui") === null); + painter.batch_mode = JSROOT.GetUrlOption("batch_mode") !== null; + if (painter.batch_mode) JSROOT.BatchMode = true; + + if (window) { + window.onbeforeunload = painter.WindowBeforeUnloadHanlder.bind(painter); + if (JSROOT.browser.qt5) window.onqt5unload = window.onbeforeunload; + } + + if (painter.use_openui && !painter.batch_mode) { + + painter._window_handle = handle; + + return JSROOT.AssertPrerequisites('openui5', function() { + + new JSROOT.sap.ui.xmlview({ + id: "TopCanvasId", + viewName: "sap.ui.jsroot.view.Canvas", + viewData: { canvas_painter: painter } + }).placeAt("CanvasDiv"); + }); + } + + painter.SetDivId("CanvasDiv", -1); // just assign id, nothing else happens + + painter.UseWebsocket(handle); // when connection activated, ROOT must send new instance of the canvas + } + + JSROOT.ConnectWebWindow({ + prereq: "jq2d;v6;", + prereq_logdiv: "CanvasDiv", + callback: InitV6Canvas + }); + + </script> + +</html> diff --git a/js/files/draw.htm b/js/files/draw.htm new file mode 100644 index 00000000000..b1646d85b3c --- /dev/null +++ b/js/files/draw.htm @@ -0,0 +1,23 @@ +<!-- this file used by THttpServer to display single element --> +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="UTF-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + <title>Draw of single element</title> + <script type="text/javascript" src="jsrootsys/scripts/JSRootCore.js?gui"></script> + + <script type='text/javascript'> + function GetCachedHierarchy() { return "$$$h.json$$$"; } + function GetCachedObject() { return "$$$root.json$$$"; } + </script> + + </head> + + <body> + <div id="drawGUI"> + loading scripts... + </div> + </body> + +</html> diff --git a/js/files/online.htm b/js/files/online.htm new file mode 100644 index 00000000000..0b59cb82aba --- /dev/null +++ b/js/files/online.htm @@ -0,0 +1,21 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <!-- this file used by THttpServer to display objects hierarchy --> + <meta charset="UTF-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + <title>Online server</title> + <link rel="shortcut icon" href="jsrootsys/img/RootIcon.ico"/> + <script type="text/javascript" src="jsrootsys/scripts/JSRootCore.js?gui"></script> + <script type="text/javascript"> + function GetCachedHierarchy() { return "$$$h.json$$$"; } + </script> + </head> + + <body> + <div id="onlineGUI"> + loading scripts... + </div> + </body> + +</html> diff --git a/js/files/panel.htm b/js/files/panel.htm new file mode 100644 index 00000000000..7a64da0b3b2 --- /dev/null +++ b/js/files/panel.htm @@ -0,0 +1,75 @@ +<!-- this file used for display different panels in ROOT7 --> +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="UTF-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + <title>ROOT7 web panel</title> + <script type="text/javascript" src="jsrootsys/scripts/JSRootCore.js"></script> + </head> + + <style> + html { height: 100%; } + body { min-height: 100%; margin: 0; overflow: hidden } + #PanelDiv { + position: absolute; + left: 0; + top: 0; + bottom: 0; + right: 0; + padding: 1 + } + </style> + + <body> + <div id="PanelDiv"> + loading scripts... + </div> + </body> + + <script type='text/javascript'> + + function ShowOpenui5Panel(panel_handle, arg) { + + if (!panel_handle || !arg.first_msg || !JSROOT.sap) return false; + + var panelid = "TopPanelId"; + + var oModel = new JSROOT.sap.ui.model.json.JSONModel({ + handle: panel_handle + }); + + sap.ui.getCore().setModel(oModel, panelid); + + var viewName, p = arg.first_msg.indexOf("."); + + if (p>=0) { + console.log('Register module path', arg.first_msg.substr(0,p)); + viewName = arg.first_msg; + jQuery.sap.registerModulePath(arg.first_msg.substr(0,p), "/currentdir/"); + } else { + viewName = "sap.ui.jsroot.view." + arg.first_msg; + } + + JSROOT.sap.ui.xmlview({ + id: panelid, + viewName : viewName, + // layoutData: oLd, + // height: "100%" + }).placeAt("PanelDiv"); + } + + JSROOT.ConnectWebWindow({ + + prereq_logdiv: "PanelDiv", + + first_recv: "SHOWPANEL:", + + prereq2: "openui5", + + callback: ShowOpenui5Panel + }); + + </script> + +</html> diff --git a/js/files/web.config b/js/files/web.config new file mode 100644 index 00000000000..0607c2957bf --- /dev/null +++ b/js/files/web.config @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<configuration> + <system.webServer> + <handlers accessPolicy="Read, Script" /> + <directoryBrowse enabled="false" /> + <security> + <ipSecurity allowUnlisted="true"> + <clear /> + </ipSecurity> + </security> + <staticContent> + <remove fileExtension=".root" /> + <mimeMap fileExtension=".root" mimeType="application/root+root.exe" /> + </staticContent> + <httpErrors errorMode="Detailed" /> + </system.webServer> +</configuration> diff --git a/js/img/RootIcon.ico b/js/img/RootIcon.ico new file mode 100644 index 0000000000000000000000000000000000000000..8bce131f7c53c24170558efd29304a5ebb0a2f9e GIT binary patch literal 32038 zcmd6w37BM6b;sW@1LF#!85S9)8yto~7Dq@>h-OB%geW9Lc2Hyqf_^H31PmZ8Ae$0{ z0xB5+6%!B`LXcgcB?g0_1g3lT>FJs2ec$)4m*4-qcZ=%ks;+ufuc|rU_wW1OtGh4f zo_p@Ow>@u;H_xlA^l&S^2j1s-$9bOjK3u(DG|%(8cwV+F{Cz*qJ9UBQtymGfFFnfh z5=VO8Qo<00$7c(NLnQV$(jVXVJunCC4bB92gI7Q!=nc_?`zlxoJ_jnm4j@umsh$-U zDBT0Vji3gMfLtU$YrrkwAP^}Z_*c5ZuHXt#4>C|9!?$Ulw)5p`@Mpl{O)X>kv-5+y z6#N&M0MlrEw9Xguq)Gfe1ymPV^Wc8NJrukKvQWbBZNA<g?0zK6?^!?pAHRGIOv{7& zhO2U`A7!QSk@bGdx<B{(TK^@hpBa8o9u5Xm@({kOy&nTJQg6%6e#7cL{H}&e@RwH~ zNRRJnJ}dy%{BlF6uVrj+z8k5{TQ>ZqrQcrnSwAs3=zfagD$~~jjV;nnc!|m319{#8 zW~9Eh@B584m45TugUH7x{E0CQ`+}%}P|JYVSi6VU-SCZ@2D=~jCnq|yMm90J&2QcC zNxyB=@qSO!HGb2Y5Bp<7YR-a59Y}RhF*aON)6@KIzoY*1{y@i1!*We++y3@DDf`~` z`*815epBs-{Gr}o7o0c&*Mr4CJayPljQb-4|KoRVy}-)Y*Ls^jKC+3Q5|*FVjYm=b zzq04C;ni0D{`Ncgy<i$8<oQ7SJW1+PLp`hfw#}dMTh@Qv?`f`LykAGz7bVBs#CVJK z!|sO5lHm$`xSw#EOQzA}c)Q=<eiwN-(r;Y77w!?%$7b_KfA!nzPBG}Y2zryS>Wf(@ zVQtXUbd}%N_OJMPt50+{ULK5r@zyM1^ZML@FU_GdQi8sbUe5mZA2SXQ^y#}ZhRyM# z=E|JuXNqIE?-}~w5?^i+r1T|6M5eLfTH{0g9aFk*)Of^j{tz{g{7;Uz*?8=3yt0ts zF3f5kR=SrcZXz+_cWgNwoZ%-D8p;LHF9~%vP&-7X?#6FY2P>!xb>ql1Mu-bRC8&)Y zng9bGE9nCt@yABi6%u?SftCQxzmgRr({SH!7y}3R!~HKr4oiUBK{yASOtLL%Br3Pc zKhSw^)S#NU4+Bp2kb5<dte7{c-CH+)iuw3kd4~x--hgXmmk`9W@B#27$eR+0F`KhB zPl+G*H2pL4)wRr5H~76Rw=iGb2H*Yx^T>~E-X7@ux%kx!jF&woC;F1&Hwn5tNJf4= z?+oBkbM`>z&-{U|`~AVL|3EH&i23tT@VGzR`y}Z-3!e8!`d{Mx>DumwuOB+p{eZXb z#bomKkdg<<$VCY@S@N$j_6e8H)YOAF_ZzP2;b{=5Kj1$TDURoX$$Pk&l1_fp?;*5i zx(3WJKlAI%)XdM<f!%<`n@lLjL+D>?$3wtvK=N8Xj8=S2yhQ@TM?s|ZXL_~>uY4<x zeZhI)=im*{4kY{tV!)DR#Lq7Pi@{uw9^JHeziJLE0Porf&s#p?c@;gLw@ba}&9C;n zxnNFJ052*L&I1;{nz-tTQ*kQ|rKL2Lw)7NIOH=~sH;mA6WFwUc><CtXd%z~3h0qY# z4DJI*0r^QrqvsInSK{}oKjf-`OzSAs=Xb#Z;KIpO*atvT5FG4!z#kp>J)fqL{5%9) z9P@Zqy2-GTaoaY38or@s%S!5dJHl5!H9oSTRqF&t;y2>IIo84|=drBS?$LThbLQyK zpIApU`<>gqXuPYZ3D%zyuZus$RiC3zOCH`}JhgM{7vQ&76HkK=Ph;)Ylj42aV?AHg zMgfu5=-?|RTT6}+@6MsmkbLr1co$FT_O^TnKKydp*D0?GuYQt|20HG6Z$F&zxA3F# ze{VJq;_>}$Kg{;CzTXejC)@OrPLkoZ&dRd<S6@61sQ;)>P9yarwSnfFk%9lFKmITE z`$yIWtJTimCxDFwT=m6Yfn*=#nYRgBM~n`>YHMocXMAK`f;d(&f9~Gj@e}oZ2gUI{ zpnPQ`$<<1CcVOY%Kn&k^!aW+OU)2M(kDzDO)v-W+TrjVGzUNiXg{RC(e#-eEzY3$U z;xo&@7eJEFEaoL9QeH!-u0I4$1~-Anf%x@yps^@4fYsm$a4R?s><6sOxH07_cQi^X z#2&b3fL{WQ74g%2Npnygco2LZ>;;nYUG7{&_d)zF-wS!Z9H@>p_ZCZHu(jZ7PzfxZ z=sC<B!o`RCZg4J8z9l2YO&a5Cz(rtZP;@z59JouszXOfg8A)r?#AKANG%Y%{=_+s# zD7XwREbcKtb)FZE^uLJg{$gH!b9h?I@1FsY#|2?jZiPD)h<D^g(iwGbJ&(ERj=cQm z;i(lr=YSnR<_@0rRsKRK?+Twcjr9K(J?nnR2mh3Jm^?go;pZHXvmNl`@~%FUcfI4+ zbTVDrzl5%S_fSV878x6<9!~^W$AkL~cYhFhJt>)1`bFtpC1Xn86*H|PzC%F9GKAm7 zBQ+mIBjiiTL(02!_RVV#LB0`7kDdOL7<U0vdcEF5h`;CLk@%THql2$mo|Si@sdis< z2+vLN6Vr?4y03sKZ9wnkeR6NUNA5S0CA%B12<pCeAHR{jH`Xk)bw^BjPLD?YXfd!h zXslUmWf>b@b7hV-O?o``J~s5G-@NWn^8Z1`?V0Sw{H^V`*%~Qhh*&;eM=X|ac!t-t z?czP#HvP>TJ?K}pR+FA9KT4P`PW|5L=DQm%4R{cHTSe%Jb0sg`NG0&l39_Hqe>VEA zaqXuyuRF{a9~|kg&a}>+67SgXTK0DTg8c4@Uhi!D53|<1-QHU_9$ToMc}f~tUL=2A z2-F7ifbksZ2DHyjTTq`%El)!|kFnP6#>;f-ZMnhvz3mO+PbB}1H5JsuM_E&;no34W z@Et&FkBzCROt42K8K7nT$H+^i-@f_pY~3#%fTQt|jkd?8y4T*aThFWiX|GjfQX7_# zv_3i*Xx)@SU<`B*((x)k;wh~gkGB3H-9c~bt@cgjlU~Hp#8{*4(`igd|64-RAQivY znlC#sH%V6^xvWwA5k8}KX<mD<Jxd>?^}HkP$7-)ra)kC_OH6kWzwAzOQm{|_DEg}t zsCVWmn`<jf&ptJ9g1PuI%YWzA^O;&S<&=zmOU#kxEXg&&KJyXQpVVK{N&D;?7qUIb zHulrQ6!<Rv<+kWyH8$3n?uQDV7JR7p3EHT_>}K2^`ZQ1Re2{GYR_Bc;PIOYt$=IA| zEuj6D64GEP@-KUd)(y*zKc(`f5|l&v7axt4G!JX9*?3UP%<Qemgw=oEC^C+W!6lP6 ztlrJ<+J-s=8MQ<t9oVl+5x49;j0eGQ*}E)75{mOBAbn))Bs&q!&6?{bMz_Wue;DCU zaHUI)b+N6u1ACK0kUjRdy$gMdnIu140QLi#2Vy0&S79Bmxw-(`&3y7A{m4hajzD{4 zv69)luqKf0rS|npKpMC20$Kw|haEeUkR6%vpzT_6YsnECY101^P~L^Tfc6(+CD}#> z>w}Y6n+?Pn_a-9S7r6Y(y(-QG6qoEUBy-EAQ2UlK(#^zWd6yC*e6GZ;i7^ecbCSJ} zY>u=pi-}bCOF>eHrRNY#ma*)q5Dh)v?1hej2Q6Y<oYykL!p-nUWArkRtb138@Y{QF z9|p0I^f21@77vnr(d0xI=nUN+#zdcu3$2YLGl^%}{)g5)24z>{Uc(h6CY}NB2QJ%5 z7Z0utwC}M7#6q&wYIt)u>qD}qZr!-T);(>Tjx$}C)^qK3CxMeq=93;qWtLqsdMR`{ zUtv9WDf`vm-i$ur@WJi}J@l2ye5XE;VONGv^V||g0kkI|y_jsk1KZ^5X^Wef6TWM9 z5P`kdoj!Zkq0QHQ(`>V_rReI~e#z;|-{#-XyrCSHVGi!+Kqr`O>LmjggSjBJy0bpZ zAJ_qCUW>E`ga0^5_4h>}9b4A?X8J+?f!aZPXxd9FH%TTt8K@pJWijVBg$r>o?xP@I z#V%e8CMjH=1cw1jKW9c~@ZjRW-5E&ckp5i^trVoW=~A#OC_3+{#d7iCO75rvDu)<! zu_OkseBTJPPp&?jnsltsiaShWZ(I~?)~~kVj)Hti{ZInY<3Mx%KA@!ePOk*gv-ZV( z2ly~J2iyT(02@IEkkBcJkEo8T!H<B-tuggZVDY5KpYOYx${<5UJ!7;uUv4!<jB=~6 zAHv0c5er7ovzdE&=vH_h!3gMi1jE`9+atNyA33*L@7N?cw@U9!LC)3dY*LjHPsvYp z_-?Ljsq~&w9#>9RZs)psarNZtEm@C5WcBLm*$?Vnc3LYy6-e4?=|dUF^&MQTVHbhp zz}LaQf#-m9Q*}UNMbPt`;CXNlxEvf0G=6phMfJrp6xs3@=2Q7S5QwKg2*eMiXc9lm zm*lq}Yyhjk*MM{a8q;s9x^VfyeLpw_JOr9S0>nj%s|`E`&H@X-tk#1|A6Ikgxj+i_ z5m0K<9P=u;7|cpNkgn=p{aiBS3qW})H;t3v%RsWEjf+x`bJB6+d=bxg0*&k0ra>}r zFOa^oWMd+XTe8g2;13`&Nq0Ivx+QYBJOix8-w7b^^<2LFg*a8On#(Q(;%x<y^nL}L zF^iIx<he^hY~z8rRCdXOR|Cn61(BW6*!0)v8?GuSe1t&Sv$zGk2jttt8T~0dP}y$) zMe%l>P0^l#bU^vrA(3ifB;I&CcrVCUwp<?-4yezo-HR%_^n2}fe{VW(>BnZepMbRD zBGtjIAo5rsjLI%(yh{!%igcFI+3(3FPG^70L~6HhfV_1r_;qDJhUbEL9bt_oCwl$% zEvJNbEsFx%19XpNB<+Qt1gu<n_WKI_zXFOT>E~thC0%_0?!MrRYniEr^p=7d>mdAH zWBv|MG-1Dpt>0P6wzu+Q-=uTJvp~NfP4V)KT|nPMNT%%tMHA<gt-qUHmur9Q)H=8Q zBda5^r?Qf40nY>(`#|_zYZ<M<izb~_>D+qm)V5b0(EhRoc6O0PCloCL$*p^WDSd#p z2--d|aRI-@(l8_3Wgr`epzSM||31t6Qr;JuZElWpn$b#?zi+LhB_B@d1Kfw>u^;*Y z=BbzCn47g<r!%pEEhFV!|8e$=pT<4H%CCCKan3aV5=Hm<20`{x9f&yN={40Z_S)<I z;Z*ElM`brE89lIHRCPtCk%8aQ*0QY)>^ZepsQ%u*`NZUSV81VV#PNifAQ~7@&<9wP zdF-vu$6X~kr41Qfd|LaNx~EF^%u!TVl5MrO8MM95j4VsuFV(gE%Y6T!{ic22S)^x4 z``v(XpfehYgLpPsM>dACm2X*pxaC!LR%*Y|q1W@0+jSn>Y>>mYx4WG}Uf<XHy`WyG z1KILNsaHJ5N!>(t1PJ(EpsP%YKY^XrI?kV5Y5iFH^s<-e+Wu9$e<SNTM9Rq>WI-7z zzidrY&-BY)O7^qr8yXAR=buHoDlEU`os5G~eOc$gwPut2u6hs;@2o$^?j=c|!_-IA z-`%*^K7Z<25uFQ{&56wc@I>9kHjDHOX=@BrfEo9JCCBMpzvgX~O}0ytX=UFq(D@5r zV@6wkI#b}rz3NGGU@A?FZBLm4u)U!^W|36+2ZG~3Uh<yGsrw0R9+REEcp3d!Yg+LL zozZb^Z|i*QS5ir~UaGU8jw<LwQti(gNl$VbkUS7!Z$dWm>&<pV<J-!jx~K`x2x{(N zKIKloCo&W)0T20FP;Z3M{4&dQBkA8=NFH>TTyW3exxxC*>L8GBJGPw0e4m-O>HfQ* z&X@xlw5?N^j8RCQGlWqG)Ld9FsZS4e2lpHX>s!tZ&2R@uaE`0e>Y#|bHw(^hTEN$M zk95u@EqwA-XTxMOCA;{U?s0SHz|;qVyFVL~am>O)J!x)^FWt#-PS4(_Q_qn#tvS%- zs`%269Fz3r4Ut0?5x|{83+8}*;FFIR5nItgrQ0lP`Ni)f69;qWLe7lEqG~F%B2@mm zLIW2XPGy!1s5<CwlzMj7NV-w2hs#QKjxId2sku@%zOzJIN%y&Or#&|GhOLdn19YA( zke|z)3rp{h{9Re@lvQ3k$4B|KR@VJmvqZXg;&Ko{{w+SI?i`@;K)aJdOR-rYDPfKW z;)7+S;BE`8pO^!RyL-6Md~0t^`tW_ghC(ALG@Q;Mx;a4W=2;-k`-gy?z$4{O-_9}W zP7~%pyQ2b~ahd5iq-Qn)xL+-E+R1Z}HV1J3Lh4-wWy(tx={Wu0GM-z@l&&QcoTEI- z)`6xY=FXBblJq^F1g`w^dDdJ|Hge}M)&HeS)0w(5(u<^JwjsE#4$k6v43v#z3uJR3 zI>i#(MWvQWi_<RyE4TK5!si9JuYj_V?7@<AK=ZZbN>^v#76BFANY5cI!qxszSx9}} zY$F&0+AA)DU6ji8O^|H+v^r29_?<kJgMxeK*)O2{+IN$kREbGzy(w*<R({pX$zY(w z`LO7NbF9Z&`K3D#_8Lo;@+dK%52m$!S{=w<?58EmMM}i#@3yyOa{za;aJPNwDDg0H zo4n)7o9^<v;{%I%jzuq;t33KY1Hl}y$j+haZY-Tm)gHR`4z))lovGH$x=&emo5_Ao z|I<gd#M(pC8Fc**CFx)#M@^3FEO9sJH9b5!>N@tY4h31;-ql4)9h|^(N3Q%A`};uW zeL?wc{{Wp(4f~_q@1gxh@kZ^XG}SI)-*A81JJem0S~E*#k}aYBhnM!MwI?NgvewnQ z&nq~Ge7yFX`dD9_{nFi@$NfL9m@~Rz9mr<z5>Qg*jM_K&|0}1Nt(fk*(_El)(w*qi zWiy~XBb}AD|4os4W|@29^nb+c%rbjP!I|Z|Y(1&F$iX=GS6*N9ls9kNpWZWLnbUs^ z>p*hhO`wEwk#y!mrUMJkxs#Oa1?+AeO~q18NMwmj1Wf#xeX5-^or_N|Z>D!r)OZok z&_-Pe>wwtfB~{u=uq((^w7kD5JWw6n3`#l{h(8WeJKYJ2F1xEF;!+)GUesQ3CwRM( z)^*<kvTJbJkHuAdU@kZj)PT1eZ6rfyfO#O6GN(tPctb3~{TUbpvrSSQJp>L0mcR6T z$Ne6r^G@8;f!2&=TQiZCBk?%NXy*cx>u}>PYS#FaR*2nkWytV4VB#t{sjh3m6<{GK zOPgn_2$w$Y9^gFi6ez_)PQ2}Ta4}H1=YVY4D*JckCB(aM4+mEQ-IuWyXx@w}#AsY^ z2hW0Qz>%Qr{k)KhB%iJ>#3K#>T2o&Keg(uY>Oec_0czI{um!vd9s%D0;w=XOo6B$u z$x6;JG>iU&6vPb#yU4B91r3mb;sh5EZ~{#475rxzxroKpa`9Ltm#!#>0CrD7@PDxM zzC65<X}JX_0=wscl$={HUqo2XA83BHIrcxZ^fb3Bc-Q~G5+&W>_3iVwD#%JQf9}0H z_&(RU^}+jm=el}uuB#_kZ_ah~>gqXJ@70QscCZL(7mI*)a_#2YF}OH_1|=nHXJTCL G`~MFEQ*4z0 literal 0 HcmV?d00001 diff --git a/js/index.htm b/js/index.htm new file mode 100644 index 00000000000..71e281c120d --- /dev/null +++ b/js/index.htm @@ -0,0 +1,53 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="UTF-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + <title>Read a ROOT file</title> + <link rel="shortcut icon" href="img/RootIcon.ico"/> + <!-- To make use of RequireJS, replace following line with commented one --> + <script type="text/javascript" src="scripts/JSRootCore.js?gui"></script> + <!--script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/require.js/2.2.0/require.min.js" data-main="scripts/JSRootCore.js"></script--> + </head> + <body> + <div id="simpleGUI" path="../files/" files="ct.root;exclusion.root;fillrandom.root;glbox.root;graph.root;hsimple.root;legends.root;rf107.root;stacks.root;zdemo.root"> + loading scripts ... + </div> + </body> +</html> + +<!-- + +This is JSROOT main page, which aims to display content of ROOT files. +Several URL parameters could be specified when opening page: + file - name of the file(s), which will be automatically open with page loading + json - name of JSON file(s) with ROOT object, stored by TBufferJSON::ConvertToJSON method + item - object name in the file to display + items - object names in the file to display + opt - draw option for the item + opts - draw options for the items + layout - can be 'simple', 'flex', 'collapsible', 'tabs' or gridNxM where N and M are integer values + nobrowser - only file item(s) will be displayed, browser will be disabled + load - name of JavaScript(s), automatically loaded at the beginning + mathjax - use MathJax for Latex output (automatically loaded for TMathText objects) + palette - id of default color palette, 51..123 - new ROOT6 palette (default 57) + style - TStyle object itemname or JSON file name + toolbar - configure position and orientation of pad toolbar, combine 'right','vert','off' + +Example: + https://root.cern/js/latest/?file=../files/hsimple.root&layout=grid2x2&item=[hpx;1,hpxpy;1]&opts=[,colz] + +Page can be used to open files from other web servers like: + https://root.cern/js/latest/?file=https://jsroot.gsi.de/files/hsimple.root + +But one should be aware about Cross-Origin Request blocking. +Read https://developer.mozilla.org/en/http_access_control for more details. + +To avoid problem at all, one can copy only index.htm on the web server where data files are located. +And specify full path to the JSRootCore.js script like + <script type="text/javascript" src="https://root.cern/js/latest/scripts/JSRootCore.min.js?gui"></script> + +If necessary, complete JSROOT can be installed on the web server. +Project repository: https://github.com/root-project/jsroot. + +--> diff --git a/js/openui5/ColorButton.js b/js/openui5/ColorButton.js new file mode 100644 index 00000000000..b5c39a74287 --- /dev/null +++ b/js/openui5/ColorButton.js @@ -0,0 +1,70 @@ +sap.ui.define([ + 'sap/ui/core/mvc/Controller', + 'sap/m/Button', + 'sap/m/ButtonRenderer', + 'sap/m/Dialog', + 'sap/ui/commons/ColorPicker' +], function (Controller, Button, ButtonRenderer, Dialog, ColorPicker) { + + "use strict"; + + var ColorButton = Button.extend("sap.ui.jsroot.ColorButton", { + metadata: { + properties: { + attrcolor : { type : "string", group : "Misc", defaultValue : null } + } + }, + renderer: ButtonRenderer.render, + init: function() { + // svg images are always loaded without @2 + this.addEventDelegate({ + onAfterRendering: function() { this._setColor(); } + }, this); + } + }); + + ColorButton.prototype._setColor = function() { + this.$().children().css('background-color', this.getProperty("attrcolor")); + } + + ColorButton.prototype.firePress = function(args) { + // if (Button.prototype.firePress) + // Button.prototype.firePress.call(this, args); + + var that = this; + + if (!this.colorPicker) + this.colorPicker = new ColorPicker(); + + if (!this.colorDialog) { + this.colorDialog = new Dialog({ + title: 'Select color', + content: this.colorPicker, + beginButton: new Button({ + text: 'Apply', + press: function () { + if (that.colorPicker) { + var col = that.colorPicker.getColorString(); + that.setProperty("attrcolor", col); + } + that.colorDialog.close(); + } + }), + endButton: new Button({ + text: 'Cancel', + press: function () { + that.colorDialog.close(); + } + }) + }); + } + + var col = this.getProperty("attrcolor"); + + this.colorPicker.setColorString(col); + this.colorDialog.open(); + } + + return ColorButton; + +}); diff --git a/js/openui5/Component.js b/js/openui5/Component.js new file mode 100644 index 00000000000..736f87b8ee8 --- /dev/null +++ b/js/openui5/Component.js @@ -0,0 +1,23 @@ +sap.ui.define([ + "sap/ui/core/UIComponent" +], function (UIComponent, JSONModel, ResourceModel) { + "use strict"; + return UIComponent.extend("sap.ui.jsroot.Component", { + metadata : { + rootView: "sap.ui.jsroot.view.Canvas", + dependencies : { + libs : [ "sap.m" ] + }, + config : { + sample : { + stretch: true, + files : [ "Canvas.view.xml", "Canvas.controller.js" ] + } + } + }, + init : function () { + // call the init function of the parent + UIComponent.prototype.init.apply(this, arguments); + } + }); +}); \ No newline at end of file diff --git a/js/openui5/GuiPanelController.js b/js/openui5/GuiPanelController.js new file mode 100644 index 00000000000..b6c30f76411 --- /dev/null +++ b/js/openui5/GuiPanelController.js @@ -0,0 +1,55 @@ +sap.ui.define([ + 'sap/ui/core/mvc/Controller', + 'sap/ui/model/json/JSONModel' +], function (Controller, JSONModel) { + "use strict"; + + return Controller.extend("sap.ui.jsroot.GuiPanelController", { + + onInit : function() { + var id = this.getView().getId(); + console.log("Initialization GuiPanel id = " + id); + + var oModel = sap.ui.getCore().getModel(id); + + if (oModel) { + this.websocket = oModel.getData().handle; + this.websocket.SetReceiver(this); // redirect websocket handling on controller itself + this.websocket.Send("PANEL_READY"); // confirm panel creation, only then GUI can send commands + } + + if (this.onPanelInit) this.onPanelInit(); + }, + + OnWebsocketOpened: function(handle) { + console.log('Connection established - should never happen'); + }, + + OnWebsocketMsg: function(handle, msg) { + console.log('GuiPanel Get message ' + msg); + }, + + OnWebsocketClosed: function(handle) { + console.log('GuiPanel closed'); + if (window) window.open('','_self').close(); // window.close(); + delete this.websocket; // remove reference on websocket + }, + + onExit : function() { + if (this.onPanelExit) this.onPanelExit(); + console.log("Closing GuiPanel id = " + this.getView().getId()); + if (this.websocket) { + this.websocket.Close(); + delete this.websocket; + } + }, + + closePanel : function() { + var main = sap.ui.getCore().byId("TopCanvasId"); + if (main) main.getController().showLeftArea(""); + else if (window) window.open('','_self').close(); // window.close(); + } + + }); + +}); diff --git a/js/openui5/SVGSample.js b/js/openui5/SVGSample.js new file mode 100644 index 00000000000..188e1d66d55 --- /dev/null +++ b/js/openui5/SVGSample.js @@ -0,0 +1,92 @@ +sap.ui.define([ + 'sap/ui/core/Control', + 'sap/ui/core/ResizeHandler' +], function (Control, ResizeHandler) { + "use strict"; + + return Control.extend("sap.ui.jsroot.SVGSample", { + metadata: { + properties: { + svgsample : { type: "object", group: "Misc", defaultValue: null } + }, + defaultAggregation: null + }, + + init: function() { + this.attachModelContextChange({}, this.modelChanged, this); + + this.resize_id = ResizeHandler.register(this, this.onResize.bind(this)); + }, + + exit: function() { + console.log('destroy SVGSample'); + }, + + onAfterRendering: function() { + this._setSVG(); + }, + + renderer: function(oRm, oControl){ + //first up, render a div for the ShadowBox + oRm.write("<div"); + + //next, render the control information, this handles your sId (you must do this for your control to be properly tracked by ui5). + oRm.writeControlData(oControl); + + oRm.addClass("sapUiSizeCompact"); + oRm.addClass("sapMSlt"); + + oRm.writeClasses(); + + oRm.addStyle("width","50%"); + // oRm.addStyle("height","100%"); + + oRm.writeStyles(); + + oRm.write(">"); + + //next, iterate over the content aggregation, and call the renderer for each control + //$(oControl.getContent()).each(function(){ + // oRm.renderControl(this); + //}); + + //and obviously, close off our div + oRm.write("</div>") + }, + + _setSVG: function() { + var dom = this.$(); + if (!dom) return; + + var w = dom.innerWidth(), h = dom.innerHeight(); + dom.empty(); + + var svg = d3.select(dom.get(0)).append("svg").attr("width", w).attr("height",h).attr("viewBox","0 0 " + w + " " + h); + + var attr = this.getProperty("svgsample"); + if (attr && (typeof attr == "object") && (typeof attr.CreateSample == "function")) + attr.CreateSample(svg,w,h); + else + svg.append("text").text("none"); + }, + + onResize: function() { + this._setSVG(); + }, + + modelPropertyChanged: function() { + this._setSVG(); + }, + + modelChanged: function() { + if (this._lastModel !== this.getModel()) { + this._lastModel = this.getModel(); + this.getModel().attachPropertyChange({}, this.modelPropertyChanged, this); + } + } + + }); + + return SVGSample; + +}); diff --git a/js/openui5/controller/Canvas.controller.js b/js/openui5/controller/Canvas.controller.js new file mode 100644 index 00000000000..61e2f593594 --- /dev/null +++ b/js/openui5/controller/Canvas.controller.js @@ -0,0 +1,461 @@ +sap.ui.define([ + 'jquery.sap.global', + 'sap/ui/core/mvc/Controller', + 'sap/ui/model/json/JSONModel', + 'sap/m/MessageToast', + 'sap/m/Dialog', + 'sap/m/List', + 'sap/m/InputListItem', + 'sap/m/Input', + 'sap/m/Button', + 'sap/m/Label', + 'sap/ui/layout/Splitter', + 'sap/ui/layout/SplitterLayoutData', + 'sap/ui/unified/Menu', + 'sap/ui/unified/MenuItem' + +], function (jQuery, Controller, JSONModel, MessageToast, Dialog, List, InputListItem, Input, Button, Label, Splitter, SplitterLayoutData, Menu, MenuItem) { + "use strict"; + + var CController = Controller.extend("sap.ui.jsroot.controller.Canvas", { + onInit : function() { + this._Page = this.getView().byId("CanvasMainPage"); + this.bottomVisible = false; + + var model = new JSONModel({ GedIcon: "", StatusIcon: "", ToolbarIcon: "", TooltipIcon: "sap-icon://accept", + StatusLbl1:"", StatusLbl2:"", StatusLbl3:"", StatusLbl4:"" }); + this.getView().setModel(model); + + var data = this.getView().getViewData(); + + if (data) { + this.getView().byId("MainPanel").getController().setPainter(data.canvas_painter); + delete data.canvas_painter; + } + + // this.toggleGedEditor(); + }, + + getCanvasPainter : function(also_without_websocket) { + var elem = this.getView().byId("MainPanel"); + + var p = elem ? elem.getController().getPainter() : null; + + return (p && (p._websocket || also_without_websocket)) ? p : null; + }, + + closeMethodDialog : function(method, call_back) { + + var args = ""; + + if (method) { + var cont = this.methodDialog.getContent(); + + var items = cont[0].getItems(); + + if (method.fArgs.length !== items.length) + alert('Mismatch between method description' + method.fArgs.length + ' and args list in dialog ' + items.length); + + // console.log('ITEMS', method.fArgs.length, items.length); + + for (var k=0;k<method.fArgs.length;++k) { + var arg = method.fArgs[k]; + var value = items[k].getContent()[0].getValue(); + + if (value==="") value = arg.fDefault; + + if ((arg.fTitle=="Option_t*") || (arg.fTitle=="const char*")) { + // check quotes, + // TODO: need to make more precise checking of escape characters + if (!value) value = '""'; + if (value[0]!='"') value = '"' + value; + if (value[value.length-1] != '"') value += '"'; + } + + args += (k>0 ? "," : "") + value; + } + } + + this.methodDialog.close(); + this.methodDialog.destroy(); + JSROOT.CallBack(call_back, args); + }, + + showMethodsDialog : function(method, call_back) { + var items = []; + + for (var n=0;n<method.fArgs.length;++n) { + var arg = method.fArgs[n]; + arg.fValue = arg.fDefault; + if (arg.fValue == '\"\"') arg.fValue = ""; + var item = new InputListItem({ + label: arg.fName + " (" +arg.fTitle + ")", + content: new Input({ placeholder: arg.fName, value: arg.fValue }) + }); + items.push(item); + } + + this.methodDialog = new Dialog({ + title: method.fClassName + '::' + method.fName, + content: new List({ + items: items +// items: { +// path: '/Method/fArgs', +// template: new InputListItem({ +// label: "{fName} ({fTitle})", +// content: new Input({placeholder: "{fName}", value: "{fValue}" }) +// }) +// } + }), + beginButton: new Button({ + text: 'Cancel', + press: this.closeMethodDialog.bind(this, null, null) + }), + endButton: new Button({ + text: 'Ok', + press: this.closeMethodDialog.bind(this, method, call_back) + }) + }); + + // this.getView().getModel().setProperty("/Method", method); + //to get access to the global model + // this.getView().addDependent(this.methodDialog); + + this.methodDialog.addStyleClass("sapUiSizeCompact"); + + this.methodDialog.open(); + }, + + onFileMenuAction : function (oEvent) { + //var oItem = oEvent.getParameter("item"), + // sItemPath = ""; + //while (oItem instanceof sap.m.MenuItem) { + // sItemPath = oItem.getText() + " > " + sItemPath; + // oItem = oItem.getParent(); + //} + //sItemPath = sItemPath.substr(0, sItemPath.lastIndexOf(" > ")); + + var p = this.getCanvasPainter(); + if (!p) return; + + var name = oEvent.getParameter("item").getText(); + + switch (name) { + case "Close canvas": p.OnWebsocketClosed(); p.CloseWebsocket(true); break; + case "Interrupt": p.SendWebsocket("INTERRUPT"); break; + case "Quit ROOT": p.SendWebsocket("QUIT"); break; + case "Canvas.png": + case "Canvas.jpeg": + case "Canvas.svg": + p.SaveCanvasAsFile(name); + break; + case "Canvas.root": + case "Canvas.pdf": + case "Canvas.ps": + case "Canvas.C": + p.SendSaveCommand(name); + break; + } + + MessageToast.show("Action triggered on item: " + name); + }, + + onCloseCanvasPress : function() { + var p = this.getCanvasPainter(); + if (p) { + p.OnWebsocketClosed(); + p.CloseWebsocket(true); + } + }, + + onInterruptPress : function() { + var p = this.getCanvasPainter(); + if (p) p.SendWebsocket("INTERRUPT"); + }, + + onQuitRootPress : function() { + var p = this.getCanvasPainter(); + if (p) p.SendWebsocket("QUIT"); + }, + + onReloadPress : function() { + var p = this.getCanvasPainter(); + if (p) p.SendWebsocket("RELOAD"); + }, + + isGedEditor : function() { + return this.getView().getModel().getProperty("/LeftArea") == "Ged"; + }, + + showGeEditor : function(new_state) { + this.showLeftArea(new_state ? "Ged" : ""); + this.getView().getModel().setProperty("/GedIcon", new_state ? "sap-icon://accept" : ""); + + }, + + cleanupIfGed : function() { + var ged = this.getLeftController("Ged"), + p = this.getCanvasPainter(); + if (ged) ged.cleanupGed(); + if (p) p.RegisterForPadEvents(null); + }, + + getLeftController : function(name) { + if (this.getView().getModel().getProperty("/LeftArea") != name) return null; + var split = this.getView().byId("MainAreaSplitter"); + return split ? split.getContentAreas()[0].getController() : null; + }, + + toggleGedEditor : function() { + this.showGeEditor(!this.isGedEditor()); + }, + + showPanelInLeftArea : function(panel_name, panel_handle, call_back) { + + var split = this.getView().byId("MainAreaSplitter"); + var curr = this.getView().getModel().getProperty("/LeftArea"); + if (!split || (curr === panel_name)) return JSROOT.CallBack(call_back, false); + + // first need to remove existing + if (curr) { + this.cleanupIfGed(); + split.removeContentArea(split.getContentAreas()[0]); + } + + this.getView().getModel().setProperty("/LeftArea", panel_name); + this.getView().getModel().setProperty("/GedIcon", (panel_name=="Ged") ? "sap-icon://accept" : ""); + + if (!panel_handle || !panel_name) return JSROOT.CallBack(call_back, false); + + var oLd = new SplitterLayoutData({ + resizable : true, + size : "250px", + maxSize : "500px" + }); + + var panelid = "LeftPanelId"; + + var oModel = new JSROOT.sap.ui.model.json.JSONModel({ + handle: panel_handle + }); + sap.ui.getCore().setModel(oModel, panelid); + + var oContent = sap.ui.xmlview({ + id: panelid, + viewName : "sap.ui.jsroot.view." + panel_name, + layoutData: oLd, + height: panel_name=="Panel" ? "100%" : undefined + }); + + split.insertContentArea(oContent, 0); + + JSROOT.CallBack(call_back, true); + }, + + showLeftArea : function(panel_name, call_back) { + var split = this.getView().byId("MainAreaSplitter"); + var curr = this.getView().getModel().getProperty("/LeftArea"); + if (!split || (curr === panel_name)) return JSROOT.CallBack(call_back, false); + + // first need to remove existing + if (curr) { + this.cleanupIfGed(); + split.removeContentArea(split.getContentAreas()[0]); + } + + this.getView().getModel().setProperty("/LeftArea", panel_name); + this.getView().getModel().setProperty("/GedIcon", (panel_name=="Ged") ? "sap-icon://accept" : ""); + + if (!panel_name) return JSROOT.CallBack(call_back, false); + + var oLd = new SplitterLayoutData({ + resizable : true, + size : "250px", + maxSize : "500px" + }); + + var oContent = sap.ui.xmlview({ + viewName : "sap.ui.jsroot.view." + panel_name, + layoutData: oLd, + height: panel_name=="Panel" ? "100%" : undefined + }); + + split.insertContentArea(oContent, 0); + + if (panel_name === "Ged") { + var ged = oContent.getController(), p = this.getCanvasPainter(); + if (p && ged && (typeof p.RegisterForPadEvents == "function")) { + p.RegisterForPadEvents(ged.padEventsReceiver.bind(ged)); + p.SelectObjectPainter(p); + } + } + + JSROOT.CallBack(call_back, true); + + return oContent.getController(); // return controller of new panel + }, + + getBottomController : function(can, call_back) { + if (!this.bottomVisible) return null; + var split = this.getView().byId("MainAreaSplitter"); + var cont = split.getContentAreas(); + var vsplit = cont[cont.length-1]; + var vcont = vsplit.getContentAreas(); + var bottom = vcont[vcont.length-1]; + return bottom ? bottom.getController() : null; + }, + + drawInProjectionArea : function(can, opt, call_back) { + var ctrl = this.getBottomController(); + if (!ctrl) ctrl = this.getLeftController("Panel"); + + if (ctrl && ctrl.drawObject) + ctrl.drawObject(can, opt, call_back); + else + JSROOT.CallBack(call_back, null); + }, + + showProjectionArea : function(kind, call_back) { + var bottom = this.showBottomArea(kind == "X"); + var left = this.showLeftArea(kind == "Y" ? "Panel" : ""); + + var ctrl = bottom || left; + + if (!ctrl || ctrl.getView().getDomRef()) + return JSROOT.CallBack(call_back, !!ctrl); + + if (ctrl.rendering_perfromed) console.log('Rendering already done'); + + // FIXME: one should have much easier way to get callback when rendering done + ctrl.after_render_callback = call_back; + }, + + showBottomArea : function(is_on) { + + if (this.bottomVisible == is_on) return this.getBottomController(); + + var split = this.getView().byId("MainAreaSplitter"); + + if (!split) return null; + + var cont = split.getContentAreas(); + + this.bottomVisible = !this.bottomVisible; + + if (this.bottomVisible == false) { + // vertical splitter exists - toggle it + + var vsplit = cont[cont.length-1]; + var main = vsplit.removeContentArea(0); + vsplit.destroyContentAreas(); + split.removeContentArea(vsplit); + split.addContentArea(main); + return null; + } + + // remove panel with normal drawing + split.removeContentArea(cont[cont.length-1]); + var vsplit = new Splitter({orientation: "Vertical"}); + + split.addContentArea(vsplit); + + vsplit.addContentArea(cont[cont.length-1]); + + var oLd = new SplitterLayoutData({ + resizable : true, + size : "200px", + maxSize : "500px" + }); + + var oContent = sap.ui.xmlview({ + viewName : "sap.ui.jsroot.view.Panel", + layoutData: oLd, + height: "100%" + }); + + vsplit.addContentArea(oContent); + + return oContent.getController(); + }, + + ShowCanvasStatus : function (text1,text2,text3,text4) { + var model = this.getView().getModel(); + model.setProperty("/StatusLbl1", text1); + model.setProperty("/StatusLbl2", text2); + model.setProperty("/StatusLbl3", text3); + model.setProperty("/StatusLbl4", text4); + }, + + isStatusShown : function() { + return this._Page.getShowFooter(); + }, + + toggleShowStatus : function(new_state) { + if (new_state === undefined) new_state = !this.isStatusShown(); + + this._Page.setShowFooter(new_state); + this.getView().getModel().setProperty("/StatusIcon", new_state ? "sap-icon://accept" : ""); + }, + + toggleToolBar : function(new_state) { + if (new_state === undefined) new_state = !this.getView().getModel().getProperty("/ToolbarIcon"); + + this._Page.setShowSubHeader(new_state); + + this.getView().getModel().setProperty("/ToolbarIcon", new_state ? "sap-icon://accept" : ""); + }, + + toggleToolTip : function(new_state) { + if (new_state === undefined) new_state = !this.getView().getModel().getProperty("/TooltipIcon"); + + this.getView().getModel().setProperty("/TooltipIcon", new_state ? "sap-icon://accept" : ""); + + var p = this.getCanvasPainter(true); + if (p) p.SetTooltipAllowed(new_state); + }, + + setShowMenu : function(new_state) { + this._Page.setShowHeader(new_state); + }, + + onViewMenuAction : function (oEvent) { + + var item = oEvent.getParameter("item"); + + switch (item.getText()) { + case "Editor": this.toggleGedEditor(); break; + case "Event statusbar": this.toggleShowStatus(); break; + case "Toolbar": this.toggleToolBar(); break; + case "Tooltip info": this.toggleToolTip(); break; + } + }, + + onToolsMenuAction : function(oEvent) { + var item = oEvent.getParameter("item"), + name = item.getText(); + + if (name != "Fit panel") return; + + var curr = this.getView().getModel().getProperty("/LeftArea"); + + this.showLeftArea(curr == "FitPanel" ? "" : "FitPanel"); + }, + + showMessage : function(msg) { + MessageToast.show(msg); + }, + + showSection : function(that, on) { + // this function call when section state changed from server side + switch(that) { + case "Menu": this.setShowMenu(on); break; + case "StatusBar": this.toggleShowStatus(on); break; + case "Editor": this.showGeEditor(on); break; + case "ToolBar": this.toggleToolBar(on); break; + case "ToolTips": this.toggleToolTip(on); break; + } + } + }); + return CController; + +}); diff --git a/js/openui5/controller/CanvasPanel.controller.js b/js/openui5/controller/CanvasPanel.controller.js new file mode 100644 index 00000000000..9eb3b78e30d --- /dev/null +++ b/js/openui5/controller/CanvasPanel.controller.js @@ -0,0 +1,85 @@ +sap.ui.define([ + 'sap/ui/core/mvc/Controller', + 'sap/ui/core/ResizeHandler' +], function (Controller, ResizeHandler) { + "use strict"; + + return Controller.extend("sap.ui.jsroot.controller.CanvasPanel", { + + onBeforeRendering: function() { + }, + + setPainter: function(painter) { + this.canvas_painter = painter; + }, + + getPainter: function() { + return this.canvas_painter; + }, + + onAfterRendering: function() { + if (this.canvas_painter && this.canvas_painter._window_handle) { + this.canvas_painter.SetDivId(this.getView().getDomRef(), -1); + this.canvas_painter.UseWebsocket(this.canvas_painter._window_handle); + delete this.canvas_painter._window_handle; + } + }, + + onResize: function(event) { + // use timeout + if (this.resize_tmout) clearTimeout(this.resize_tmout); + this.resize_tmout = setTimeout(this.onResizeTimeout.bind(this), 300); // minimal latency + }, + + drawCanvas : function(can, opt, call_back) { + if (this.canvas_painter) { + this.canvas_painter.Cleanup(); + delete this.canvas_painter; + } + + if (!this.getView().getDomRef()) return JSROOT.CallBack(call_back, null); + + var oController = this; + JSROOT.draw(this.getView().getDomRef(), can, opt, function(painter) { + oController.canvas_painter = painter; + JSROOT.CallBack(call_back, painter); + }); + }, + + onResizeTimeout: function() { + delete this.resize_tmout; + if (this.canvas_painter) + this.canvas_painter.CheckCanvasResize(); + }, + + onInit: function() { + // this.canvas_painter = JSROOT.openui5_canvas_painter; + // delete JSROOT.openui5_canvas_painter; + + console.log("INIT CANVAS PANEL"); + +/* + console.log(sap.ui.getCore().byId("TopCanvasId").getViewData()); + + var oModel = sap.ui.getCore().getModel(this.getView().getId()); + if (oModel) { + var oData = oModel.getData(); + + if (oData.canvas_painter) { + this.canvas_painter = oData.canvas_painter; + delete oData.canvas_painter; + } + }*/ + + ResizeHandler.register(this.getView(), this.onResize.bind(this)); + }, + + onExit: function() { + if (this.canvas_painter) { + this.canvas_painter.Cleanup(); + delete this.canvas_painter; + } + } + }); + +}); diff --git a/js/openui5/controller/FitPanel.controller.js b/js/openui5/controller/FitPanel.controller.js new file mode 100644 index 00000000000..0b0a63a67f1 --- /dev/null +++ b/js/openui5/controller/FitPanel.controller.js @@ -0,0 +1,55 @@ +sap.ui.define([ + 'sap/ui/jsroot/GuiPanelController', + 'sap/ui/model/json/JSONModel' +], function (GuiPanelController, JSONModel) { + "use strict"; + + return GuiPanelController.extend("sap.ui.jsroot.controller.FitPanel", { + + // function called from GuiPanelController + onPanelInit : function() { + var id = this.getView().getId(); + console.log("Initialization FitPanel id = " + id); + // such data will be produced on server from TFitPanelModel + var model = new JSONModel({ + fDataNames:[ { fId:"1", fName: "----" } ], + fSelectDataId: "0", + fModelNames: [ { fId:"1", fName: "----" } ], + fSelectModelId: "0" + }); + this.getView().setModel(model); + }, + + // function called from GuiPanelController + onPanelExit : function() { + }, + + OnWebsocketMsg: function(handle, msg) { + if (msg.indexOf("MODEL:")==0) { + var json = msg.substr(6); + var data = JSROOT.parse(json); + + if (data) { + this.getView().setModel(new JSONModel(data)); + console.log('FitPanel set new model'); + } + + } else { + console.log('FitPanel Get message ' + msg); + } + }, + + handleFitPress : function() { + console.log('Press fit'); + // To now with very simple logic + // One can bind some parameters direct to the model and use values from model + var v1 = this.getView().byId("FitData"), + v2 = this.getView().byId("FitModel"); + + if (this.websocket && v1 && v2) + this.websocket.Send('DOFIT:"' + v1.getValue() + '","' + v2.getValue() + '"'); + } + + }); + +}); diff --git a/js/openui5/controller/Ged.controller.js b/js/openui5/controller/Ged.controller.js new file mode 100644 index 00000000000..ff39f82255f --- /dev/null +++ b/js/openui5/controller/Ged.controller.js @@ -0,0 +1,196 @@ +sap.ui.define([ + 'sap/ui/core/mvc/Controller', + 'sap/ui/model/json/JSONModel', + 'sap/m/Dialog', + 'sap/m/Button', + 'sap/ui/core/HTML' +], function (Controller, JSONModel, Dialog, Button, HTML) { + "use strict"; + + return Controller.extend("sap.ui.jsroot.controller.Ged", { + + currentPainter: null, + + gedFragments : [], + + onInit : function() { + console.log('init GED editor'); + var model = new JSONModel({ SelectedClass: "none" }); + this.getView().setModel(model); + }, + + onExit : function() { + console.log('exit GED editor'); + this.cleanupGed(); + + }, + + cleanupGed : function() { + console.log('Clenup GED editor'); + + // empty fragments + this.getView().byId("ged_page").removeAllContent(); + + // set dummy model + this.getView().setModel(new JSONModel({ SelectedClass: "none" })); + + // remove references + this.currentPainter = null; + this.currentPadPainter = null; + + // TODO: deregsiter for all events + + }, + + addFragment : function(page, kind, model) { + var fragm = this.gedFragments[kind]; + + if (!fragm) + fragm = this.gedFragments[kind] = sap.ui.xmlfragment(this.getView().getId(), "sap.ui.jsroot.view." + kind, this); + + if (!fragm) return; + + fragm.ged_fragment = true; // mark as ged fragment + + var html = new HTML(); + html.setContent("<hr>"); + html.setTooltip(kind); + page.addContent(html); + + fragm.setModel(model); + page.addContent(fragm); + }, + + /// function called when user changes model property + /// data object includes _kind, _painter and _handle (optionally) + modelPropertyChange : function(evnt, data) { + var pars = evnt.getParameters(); + console.log('Model property changes', pars.path, pars.value, data._kind); + + if (data._handle) { + //var subname = pars.path.substr(1); + //if (subname in data._handle) data._handle[subname] = pars.value; + + if (typeof data._handle.verifyDirectChange === 'function') + data._handle.verifyDirectChange(data._painter); + data._handle.changed = true; + } + + if (data._painter && (typeof data._painter.AttributeChange === 'function')) + data._painter.AttributeChange(data._kind, pars.path.substr(1), pars.value); + + if (this.currentPadPainter) + this.currentPadPainter.Redraw(); + }, + + processHistModelChange : function(evnt, data) { + var pars = evnt.getParameters(), opts = data.options; + console.log('Hist model changes', pars.path, pars.value); + + opts.Mode3D = opts.Mode3Dindx > 0; + opts.Lego = parseInt(opts.Lego); + opts.Contor = parseInt(opts.Contor); + opts.ErrorKind = parseInt(opts.ErrorKind); + + if (this.currentPadPainter) + this.currentPadPainter.InteractiveRedraw("object","drawopt"); + + }, + + onObjectSelect : function(padpainter, painter, place) { + + if (this.currentPainter === painter) return; + + this.currentPadPainter = padpainter; + this.currentPainter = painter; + + var obj = painter.GetObject(); + + this.getView().getModel().setProperty("/SelectedClass", obj ? obj._typename : painter.GetTipName()); + + var oPage = this.getView().byId("ged_page"); + oPage.removeAllContent(); + + if (painter.lineatt && painter.lineatt.used) { + var model = new JSONModel( { attline: painter.lineatt } ); + model.attachPropertyChange({ _kind: "TAttLine", _painter: painter, _handle: painter.lineatt }, this.modelPropertyChange, this); + + this.addFragment(oPage, "TAttLine", model); + } + + if (painter.fillatt && painter.fillatt.used) { + var model = new JSONModel( { attfill: painter.fillatt } ); + model.attachPropertyChange({ _kind: "TAttFill", _painter: painter, _handle: painter.fillatt }, this.modelPropertyChange, this); + + this.addFragment(oPage, "TAttFill", model); + } + + if (painter.markeratt && painter.markeratt.used) { + var model = new JSONModel( { attmark: painter.markeratt } ); + model.attachPropertyChange({ _kind: "TAttMarker", _painter: painter, _handle: painter.markeratt }, this.modelPropertyChange, this); + + this.addFragment(oPage, "TAttMarker", model); + } + + if (typeof painter.processTitleChange == 'function') { + var obj = painter.processTitleChange("check"); + if (obj) { + var model = new JSONModel( { tnamed: obj } ); + model.attachPropertyChange( {}, painter.processTitleChange, painter ); + this.addFragment(oPage, "TNamed", model); + } + + if (typeof painter.GetHisto == 'function') { + + // this object used to copy ged setting from options and back, + // do not (yet) allow to change options directly + +/* if (painter.ged === undefined) + painter.ged = { ndim: painter.Dimension(), Errors: 0, Style: 0, Contor: 1, Lego: 2 }; + + painter.ged.mode3d = painter.mode3d ? 1 : 0; + painter.ged.markers = painter.options.Mark; + painter.ged.bar = painter.options.Bar; + painter.ged.Lego = painter.options.Lego; +*/ + + painter.options.Mode3Dindx = painter.options.Mode3D ? 1 : 0; + + var model = new JSONModel( { opts : painter.options } ); + + // model.attachPropertyChange({}, painter.processTitleChange, painter); + this.addFragment(oPage, "Hist", model); + + model.attachPropertyChange({ options: painter.options }, this.processHistModelChange, this); + } + } + }, + + onObjectRedraw : function(padpainter, painter) { + if ((this.currentPadPainter !== padpainter) || (this.currentPainter !== painter)) return; + + console.log('GED sees selected object redraw'); + + var page = this.getView().byId("ged_page"); + var cont = page.getContent(); + + for (var n=0;n<cont.length;++n) + if (cont[n] && cont[n].ged_fragment) { + var model = cont[n].getModel(); + + model.refresh(); + } + }, + + padEventsReceiver : function(evnt) { + if (!evnt) return; + + if (evnt.what == "select") + this.onObjectSelect(evnt.padpainter, evnt.painter); + else if (evnt.what == "redraw") + this.onObjectRedraw(evnt.padpainter, evnt.painter); + } + + }); + +}); diff --git a/js/openui5/controller/Inspector.controller.js b/js/openui5/controller/Inspector.controller.js new file mode 100644 index 00000000000..ce6fb3b486f --- /dev/null +++ b/js/openui5/controller/Inspector.controller.js @@ -0,0 +1,35 @@ +sap.ui.define([ + 'sap/ui/core/mvc/Controller' +], function (Controller) { + "use strict"; + + return Controller.extend("sap.ui.jsroot.controller.Inspector", { + + renderObj: null, + + setObject: function(obj) { + this.renderObj = obj; + }, + + onAfterRendering: function() { + if (!this.renderObj) return; + + if (this.ipainter) this.ipainter.Cleanup(); + delete this.ipainter; + + var pthis = this; + JSROOT.draw(this.getView().getDomRef(), this.renderObj, 'inspect', function(ipainter) { + pthis.ipainter = ipainter; + }); + }, + + onInit : function() { + }, + + onExit : function() { + if (this.ipainter) this.ipainter.Cleanup(); + delete this.ipainter; + } + }); + +}); diff --git a/js/openui5/controller/Panel.controller.js b/js/openui5/controller/Panel.controller.js new file mode 100644 index 00000000000..0f13e38e217 --- /dev/null +++ b/js/openui5/controller/Panel.controller.js @@ -0,0 +1,134 @@ +sap.ui.define([ + 'sap/ui/core/mvc/Controller', + 'sap/ui/core/ResizeHandler' +], function (Controller, ResizeHandler) { + "use strict"; + + return Controller.extend("sap.ui.jsroot.controller.Panel", { + + onBeforeRendering: function() { + console.log("Cleanup Panel", this.getView().getId()); + if (this.object_painter) { + this.object_painter.Cleanup(); + delete this.object_painter; + } + this.rendering_perfromed = false; + }, + + drawObject: function(obj, options, call_back) { + + if (call_back) this.get_callbacks.push(call_back); + + if (!this.rendering_perfromed) { + this.panel_data = { object: obj, opt: opt }; + return; + } + + var oController = this; + oController.object = obj; + d3.select(oController.getView().getDomRef()).style('overflow','hidden'); + + JSROOT.draw(oController.getView().getDomRef(), oController.object, options, function(painter) { + console.log("object painting finished"); + oController.object_painter = painter; + oController.get_callbacks.forEach(function(cb) { JSROOT.CallBack(cb,painter); }); + oController.get_callbacks = []; + }); + }, + + drawModel: function(model) { + if (!model) return; + if (!this.rendering_perfromed) { + this.panel_data = model; + return; + } + + var oController = this; + if (model.object) { + oController.drawObject(model.object, model.opt); + } else if (model.jsonfilename) { + JSROOT.NewHttpRequest(model.jsonfilename, 'object', function(obj) { + oController.drawObject(obj, model.opt); + }).send(); + } else if (model.filename) { + JSROOT.OpenFile(model.filename, function(file) { + file.ReadObject(model.itemname, function(obj) { + oController.drawObject(obj, model.opt); + }); + }); + } + }, + + /** method to access object painter + if object already painted and exists, it will be returned as result + but it may take time to complete object drawing, therefore callback function should be used like + var panel = sap.ui.getCore().byId("YourPanelId"); + var object_painter = null; + panel.getController().getPainter(funciton(painter) { + object_painter = painter; + }); + */ + getPainter: function(call_back) { + + if (this.object_painter) { + JSROOT.CallBack(call_back, this.object_painter); + } else if (call_back) { + this.get_callbacks.push(call_back); + } + return this.object_painter; + }, + + onAfterRendering: function() { + console.log('Panel On after rendering', this.getView().getId(), typeof this.after_render_callback); + + if (this.after_render_callback) { + JSROOT.CallBack(this.after_render_callback); + delete this.after_render_callback; + } + + this.rendering_perfromed = true; + if (this.panel_data) this.drawModel(this.panel_data); + }, + + onResize: function(event) { + // use timeout + if (this.resize_tmout) clearTimeout(this.resize_tmout); + this.resize_tmout = setTimeout(this.onResizeTimeout.bind(this), 300); // minimal latency + }, + + onResizeTimeout: function() { + delete this.resize_tmout; + if (this.object_painter) + this.object_painter.CheckResize(); + }, + + onInit: function() { + + this.get_callbacks = []; // list of callbacks + + this.rendering_perfromed = false; + + var id = this.getView().getId(); + + console.log("Initialization of JSROOT Panel", id); + + var oModel = sap.ui.getCore().getModel(id); + if (!oModel && (id.indexOf("__xmlview0--")==0)) oModel = sap.ui.getCore().getModel(id.substr(12)); + + if (oModel) + this.panel_data = oModel.getData(); + + ResizeHandler.register(this.getView(), this.onResize.bind(this)); + }, + + onExit: function() { + console.log("Exit from JSROOT Panel", this.getView().getId()); + + if (this.object_painter) { + this.object_painter.Cleanup(); + delete this.object_painter; + } + } + }); + +}); diff --git a/js/openui5/view/Canvas.view.xml b/js/openui5/view/Canvas.view.xml new file mode 100644 index 00000000000..d3a623ff406 --- /dev/null +++ b/js/openui5/view/Canvas.view.xml @@ -0,0 +1,98 @@ +<mvc:View height="100%" class="sapUiSizeCompact" controllerName="sap.ui.jsroot.controller.Canvas" + xmlns:mvc="sap.ui.core.mvc" xmlns:l="sap.ui.layout" xmlns="sap.m"> + <Page title="" showNavButton="false" showFooter="false" + showSubHeader="false" id="CanvasMainPage"> + <customHeader> + <OverflowToolbar id="otb1"> + <Button icon="sap-icon://log" type="Transparent" + tooltip="Quit ROOT session" press="onQuitRootPress" /> + <!-- Button icon="sap-icon://refresh" type="Transparent" + tooltip="Reload canvas from server" press="onReloadPress" /--> + <!-- Button icon="sap-icon://user-edit" type="Transparent" + tooltip="Toggle GED editor" press="toggleGedEditor" /--> + <MenuButton text="File"> + <menu> + <Menu itemSelected="onFileMenuAction"> + <items> + <MenuItem text="Open" icon="sap-icon://open-folder" enabled="false"/> + <MenuItem text="Close canvas" icon="sap-icon://decline" tooltip="Close browser window"/> + <MenuItem text="Save" startsSection="true" icon="sap-icon://save"> + <items> + <MenuItem text="Canvas.png" tooltip="Creates PNG snapshot of browser window"/> + <MenuItem text="Canvas.svg" tooltip="Creates SVG snapshot of browser window"/> + <MenuItem text="Canvas.jpeg" tooltip="Creates JPEG snapshot of browser window"/> + <MenuItem text="Canvas.root" startsSection="true" tooltip="Produces ROOT output on C++ side"/> + <MenuItem text="Canvas.pdf" tooltip="Produces PDF output on C++ side"/> + <MenuItem text="Canvas.ps" tooltip="Produces PS output on C++ side"/> + <MenuItem text="Canvas.C" tooltip="Produces C output on server side"/> + </items> + </MenuItem> + <MenuItem text="Save as ..." icon="sap-icon://save" enabled="false"/> + <MenuItem text="Interrupt" startsSection="true" icon="sap-icon://stop" tooltip="Interrupts current event loop"/> + <MenuItem text="Quit ROOT" icon="sap-icon://log" tooltip="Quit ROOT session"/> + + </items> + </Menu> + </menu> + </MenuButton> + <Button text="Edit" type="Transparent"></Button> + <MenuButton text="View" type="Transparent"> + <menu> + <Menu itemSelected="onViewMenuAction"> + <items> + <MenuItem text="Editor" icon="{/GedIcon}" tooltip="Toggle graphics attribute editor"/> + <MenuItem text="Toolbar" icon="{/ToolbarIcon}" tooltip="Toolbar with several shortcuts"/> + <MenuItem text="Event statusbar" icon="{/StatusIcon}" /> + <MenuItem text="Tooltip info" icon="{/TooltipIcon}" /> + <MenuItem text="Colors" startsSection="true" enabled="false"/> + <MenuItem text="Fonts" enabled="false"/> + <MenuItem text="Markers" enabled="false"/> + </items> + </Menu> + </menu> + </MenuButton> + <Button text="Options" type="Transparent"></Button> + <MenuButton text="Tools" type="Transparent"> + <menu> + <Menu itemSelected="onToolsMenuAction"> + <items> + <MenuItem text="Fit panel" enabled="false" /> + <MenuItem text="Browser" enabled="false" /> + </items> + </Menu> + </menu> + </MenuButton> + <ToolbarSpacer /> + <Button text="Help" type="Transparent"/> + </OverflowToolbar> + </customHeader> + <subHeader> + <OverflowToolbar> + <Button icon="sap-icon://user-edit" type="Transparent" + press="toggleGedEditor" tooltip="Toggle graphics attribute editor"/> + <Button icon="sap-icon://decline" type="Transparent" + press="onCloseCanvasPress" tooltip="Close browser window"/> + <Button icon="sap-icon://stop" type="Transparent" + press="onInterruptPress" tooltip="Interrupts current event loop"/> + <Button icon="sap-icon://log" type="Transparent" + press="onQuitRootPress" tooltip="Quit ROOT session"/> + </OverflowToolbar> + </subHeader> + <content> + <l:Splitter orientation="Horizontal" id="MainAreaSplitter"> + <mvc:XMLView id="MainPanel" width="100%" + height="100%" viewName="sap.ui.jsroot.view.CanvasPanel"> + </mvc:XMLView> + </l:Splitter> + </content> + <footer> + <OverflowToolbar> + <Label text="{/StatusLbl1}" id="FooterLbl1" /> + <Label text="{/StatusLbl2}" id="FooterLbl2" /> + <Label text="{/StatusLbl3}" id="FooterLbl3" /> + <Label text="{/StatusLbl4}" id="FooterLbl4" /> + </OverflowToolbar> + </footer> + </Page> +</mvc:View> + diff --git a/js/openui5/view/CanvasPanel.view.xml b/js/openui5/view/CanvasPanel.view.xml new file mode 100644 index 00000000000..02e7c9fc632 --- /dev/null +++ b/js/openui5/view/CanvasPanel.view.xml @@ -0,0 +1,5 @@ +<core:View + xmlns="sap.m" + xmlns:core="sap.ui.core" + controllerName="sap.ui.jsroot.controller.CanvasPanel"> +</core:View> \ No newline at end of file diff --git a/js/openui5/view/FitPanel.view.xml b/js/openui5/view/FitPanel.view.xml new file mode 100644 index 00000000000..e3ba01e08d0 --- /dev/null +++ b/js/openui5/view/FitPanel.view.xml @@ -0,0 +1,25 @@ +<mvc:View class="sapUiSizeCompact" height="100%" controllerName="sap.ui.jsroot.controller.FitPanel" + xmlns:mvc="sap.ui.core.mvc" xmlns:core="sap.ui.core" xmlns="sap.m"> + <Page id="fitpanel_page" title="Fit Panel" showHeader="true"> + <content> + <VBox> + <Text text="Data"/> + <ComboBox id="FitData" selectedKey="{/fSelectDataId}" items="{ path: '/fDataNames', sorter: { path: 'fName' } }"> + <core:Item key="{fId}" text="{fName}" /> + </ComboBox> + <Text text="Models"/> + <ComboBox id="FitModel" selectedKey="{/fSelectModelId}" items="{ path: '/fModelNames', sorter: { path: 'fName' } }"> + <core:Item key="{fId}" text="{fName}" /> + </ComboBox> + </VBox> + </content> + <footer> + <Bar> + <contentRight> + <Button id="fitpanel_Fit" text="Fit" press="handleFitPress" /> + <Button id="fitpanel_Close" text="Close" press="closePanel" /> + </contentRight> + </Bar> + </footer> + </Page> +</mvc:View> \ No newline at end of file diff --git a/js/openui5/view/Ged.view.xml b/js/openui5/view/Ged.view.xml new file mode 100644 index 00000000000..8231dc79954 --- /dev/null +++ b/js/openui5/view/Ged.view.xml @@ -0,0 +1,20 @@ +<mvc:View + class="sapUiSizeCompact" + height="100%" + controllerName="sap.ui.jsroot.controller.Ged" + xmlns:mvc="sap.ui.core.mvc" + xmlns="sap.m"> + <Page id="ged_page" title="class: {/SelectedClass}" showHeader="true"> +<!-- + <footer> + <Bar> + <contentRight> + <Button id="edit" text="Edit" press="handleEditPress" /> + <Button id="save" text="Save" type="Emphasized" visible="false" press="handleSavePress" /> + <Button id="cancel" text="Cancel" visible="false" press="handleCancelPress" /> + </contentRight> + </Bar> + </footer> + --> + </Page> +</mvc:View> \ No newline at end of file diff --git a/js/openui5/view/Hist.fragment.xml b/js/openui5/view/Hist.fragment.xml new file mode 100644 index 00000000000..3a870ed73ab --- /dev/null +++ b/js/openui5/view/Hist.fragment.xml @@ -0,0 +1,98 @@ +<core:FragmentDefinition + xmlns="sap.m" + xmlns:l="sap.ui.layout" + xmlns:core="sap.ui.core"> + <VBox> + <RadioButtonGroup selectedIndex="{/opts/Mode3Dindx}" columns="2" + width="100%"> + <buttons> + <RadioButton text="2-D" /> + <RadioButton text="3-D" /> + </buttons> + </RadioButtonGroup> + <Panel visible="{= ${/opts/Mode3Dindx} === 0 && ${/opts/ndim} === 1}"> + <Label text="Error:" class="sapUiSmallMarginEnd" labelFor="ErrorsSelectTh1" /> + <Select selectedKey="{/opts/ErrorKind}" enabled="{/opts/Error}" tooltip="Error kinds" id="ErrorsSelectTh1"> + <items> + <core:Item text="Simple" key="-1" /> + <core:Item text="E0" key="0"/> + <core:Item text="E1" key="1"/> + <core:Item text="E2" key="2"/> + <core:Item text="E3" key="3"/> + <core:Item text="E4" key="4"/> + </items> + </Select> + <Label text="Style:" class="sapUiSmallMarginEnd" labelFor="StyleSelectTh1" /> + <Select selectedKey="{/opts/Style}" tooltip="Contor" id="StyleSelectTh1"> + <items> + <core:Item text="No" key="0" /> + <core:Item text="Simple" key="1" /> + <core:Item text="Strooth" key="2" /> + <core:Item text="Fill" key="3" /> + </items> + </Select> + + <CheckBox text="Simple drawing" selected="true" enabled="false" /> + <CheckBox text="Show errors" selected="{/opts/Error}" /> + <CheckBox text="Show lines" selected="{/opts/Line}" /> + <CheckBox text="Show markers" selected="{/opts/Mark}" /> + <CheckBox text="Draw bar chart" selected="{/opts/Bar}" /> + <CheckBox text="Bar option" selected="false" enabled="false"/> + </Panel> + + <Panel visible="{= ${/opts/Mode3Dindx} === 1 && ${/opts/ndim} === 1}"> + <Label text="Type" labelFor="LegoSelectTh1" /> + <Select selectedKey="{/opts/Lego}" tooltip="Contor" id="LegoSelectTh1"> + <items> + <core:Item text="NoLego" key="0" /> + <core:Item text="Lego" key="1" /> + <core:Item text="Lego1" key="11" /> + <core:Item text="Lego2" key="12" /> + <core:Item text="Lego3" key="13" /> + <core:Item text="Lego4" key="14" /> + </items> + </Select> + </Panel> + + <Panel visible="{= ${/opts/Mode3Dindx} === 0 && ${/opts/ndim} === 2}"> + <Label text="Contor" labelFor="ContorSelectTh2" /> + <Select selectedKey="{/opts/Contor}" tooltip="Contor" id="ContorSelectTh2"> + <items> + <core:Item text="none" key="0"/> + <core:Item text="Cont" key="1"/> + <core:Item text="Cont1" key="11"/> + <core:Item text="Cont2" key="12"/> + <core:Item text="Cont3" key="13"/> + <core:Item text="Cont4" key="14"/> + </items> + </Select> + + <CheckBox text="Scat" selected="{/opts/Scat}" /> + <CheckBox text="Col" selected="{/opts/Color}" /> + <CheckBox text="Arrow" selected="{/opts/Arrow}" /> + <CheckBox text="Box" selected="{/opts/Box}" /> + <CheckBox text="Text" selected="{/opts/Text}" /> + <CheckBox text="Zero" selected="{/opts/Zero}" /> + <CheckBox text="Palette" selected="{/opts/Zscale}" /> + </Panel> + + <Panel visible="{= ${/opts/Mode3Dindx} === 1 && ${/opts/ndim} === 2}"> + <Label text="Type" labelFor="LegoSelectTh2" /> + <Select selectedKey="{/opts/Lego}" tooltip="Contor" id="LegoSelectTh2"> + <items> + <core:Item text="NoLego" key="0" /> + <core:Item text="Lego" key="1" /> + <core:Item text="Lego1" key="11" /> + <core:Item text="Lego2" key="12" /> + <core:Item text="Lego3" key="13" /> + <core:Item text="Lego4" key="14" /> + </items> + </Select> + + <CheckBox text="Front" selected="{/opts/FrontBox}" /> + <CheckBox text="Back" selected="{/opts/BackBox}" /> + <CheckBox text="Errors" selected="{/opts/Error}" /> + <CheckBox text="Palette" selected="{/opts/Zscale}" /> + </Panel> + </VBox> +</core:FragmentDefinition> diff --git a/js/openui5/view/Inspector.fragment.xml b/js/openui5/view/Inspector.fragment.xml new file mode 100644 index 00000000000..de3ce364d8f --- /dev/null +++ b/js/openui5/view/Inspector.fragment.xml @@ -0,0 +1,10 @@ +<core:FragmentDefinition xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc"> + <Dialog title="Inspect" contentWidth="75%"> + <content> + <mvc:XMLView id="object_inspector" padding="5px" viewName="sap.ui.jsroot.view.Inspector"></mvc:XMLView> + </content> + <endButton> + <Button text="Close It" press="closeObjectInspector" /> + </endButton> + </Dialog> +</core:FragmentDefinition> diff --git a/js/openui5/view/Inspector.view.xml b/js/openui5/view/Inspector.view.xml new file mode 100644 index 00000000000..5a0cb98b4ce --- /dev/null +++ b/js/openui5/view/Inspector.view.xml @@ -0,0 +1,6 @@ +<core:View + class="sapUiSizeCompact" + xmlns="sap.m" + xmlns:core="sap.ui.core" + controllerName="sap.ui.jsroot.controller.Inspector"> +</core:View> \ No newline at end of file diff --git a/js/openui5/view/Panel.view.xml b/js/openui5/view/Panel.view.xml new file mode 100644 index 00000000000..36439002e62 --- /dev/null +++ b/js/openui5/view/Panel.view.xml @@ -0,0 +1,5 @@ +<core:View + xmlns="sap.m" + xmlns:core="sap.ui.core" + controllerName="sap.ui.jsroot.controller.Panel"> +</core:View> \ No newline at end of file diff --git a/js/openui5/view/TAttFill.fragment.xml b/js/openui5/view/TAttFill.fragment.xml new file mode 100644 index 00000000000..05d2c1b5c5e --- /dev/null +++ b/js/openui5/view/TAttFill.fragment.xml @@ -0,0 +1,45 @@ +<core:FragmentDefinition + xmlns="sap.m" + xmlns:l="sap.ui.layout" + xmlns:jsroot="sap.ui.jsroot" + xmlns:core="sap.ui.core"> + <FlexBox renderType="Bare" width="100%"> + <items> + <jsroot:ColorButton text="fill" attrcolor="{/attfill/color}" tooltip="Fill color"/> + <Select selectedKey="{/attfill/pattern}" tooltip="Fill pattern"> + <layoutData> + <FlexItemData growFactor="2"/> + </layoutData> + <items> + <core:Item text="none" key="0"/> + <core:Item text="solid" key="1001"/> + <core:Item text="3001" key="3001"/> + <core:Item text="3002" key="3002"/> + <core:Item text="3003" key="3003"/> + <core:Item text="3004" key="3004"/> + <core:Item text="3005" key="3005"/> + <core:Item text="3006" key="3006"/> + <core:Item text="3007" key="3007"/> + <core:Item text="3008" key="3008"/> + <core:Item text="3009" key="3009"/> + <core:Item text="3010" key="3010"/> + <core:Item text="3011" key="3011"/> + <core:Item text="3012" key="3012"/> + <core:Item text="3013" key="3013"/> + <core:Item text="3014" key="3014"/> + <core:Item text="3015" key="3015"/> + <core:Item text="3016" key="3016"/> + <core:Item text="3017" key="3017"/> + <core:Item text="3018" key="3018"/> + <core:Item text="3019" key="3019"/> + <core:Item text="3020" key="3020"/> + </items> + </Select> + <jsroot:SVGSample svgsample="{/attfill}" tooltip="Fill pattern sample"> + <jsroot:layoutData> + <FlexItemData growFactor="2"/> + </jsroot:layoutData> + </jsroot:SVGSample> + </items> + </FlexBox> +</core:FragmentDefinition> \ No newline at end of file diff --git a/js/openui5/view/TAttLine.fragment.xml b/js/openui5/view/TAttLine.fragment.xml new file mode 100644 index 00000000000..27a40834443 --- /dev/null +++ b/js/openui5/view/TAttLine.fragment.xml @@ -0,0 +1,50 @@ +<core:FragmentDefinition + xmlns="sap.m" + xmlns:l="sap.ui.layout" + xmlns:jsroot="sap.ui.jsroot" + xmlns:core="sap.ui.core"> + <FlexBox renderType="Bare" width="100%"> + <items> + <jsroot:ColorButton text="line" attrcolor="{/attline/color}" tooltip="Line color"/> + <Select selectedKey="{/attline/style}" tooltip="Line style"> + <layoutData> + <FlexItemData growFactor="2"/> + </layoutData> + <items> + <core:Item text="none" key="0"/> + <core:Item text="solid" key="1"/> + <core:Item text="2" key="2"/> + <core:Item text="3" key="3"/> + <core:Item text="4" key="4"/> + <core:Item text="5" key="5"/> + <core:Item text="6" key="6"/> + <core:Item text="7" key="7"/> + <core:Item text="8" key="8"/> + <core:Item text="9" key="9"/> + <core:Item text="10" key="10"/> + <core:Item text="11" key="11"/> + </items> + </Select> + <Select selectedKey="{/attline/width}" tooltip="Line width"> + <layoutData> + <FlexItemData growFactor="2"/> + </layoutData> + <items> + <core:Item text="1" key="1"/> + <core:Item text="2" key="2"/> + <core:Item text="3" key="3"/> + <core:Item text="4" key="4"/> + <core:Item text="5" key="5"/> + <core:Item text="6" key="6"/> + <core:Item text="7" key="7"/> + <core:Item text="8" key="8"/> + </items> + </Select> + <jsroot:SVGSample svgsample="{/attline}" tooltip="Line pattern sample"> + <jsroot:layoutData> + <FlexItemData growFactor="2"/> + </jsroot:layoutData> + </jsroot:SVGSample> + </items> + </FlexBox> +</core:FragmentDefinition> diff --git a/js/openui5/view/TAttMarker.fragment.xml b/js/openui5/view/TAttMarker.fragment.xml new file mode 100644 index 00000000000..511751b8285 --- /dev/null +++ b/js/openui5/view/TAttMarker.fragment.xml @@ -0,0 +1,57 @@ +<core:FragmentDefinition + xmlns="sap.m" + xmlns:l="sap.ui.layout" + xmlns:jsroot="sap.ui.jsroot" + xmlns:core="sap.ui.core"> + <FlexBox renderType="Bare" width="100%"> + <items> + <jsroot:ColorButton text="marker" attrcolor="{/attmark/color}" tooltip="Marker color"/> + <Select selectedKey="{/attmark/style}" tooltip="Marker style"> + <items> + <core:Item text="none" key="0"/> + <core:Item text="1" key="1"/> + <core:Item text="2" key="2"/> + <core:Item text="3" key="3"/> + <core:Item text="4" key="4"/> + <core:Item text="5" key="5"/> + <core:Item text="6" key="6"/> + <core:Item text="7" key="7"/> + <core:Item text="8" key="8"/> + <core:Item text="21" key="21"/> + <core:Item text="22" key="22"/> + <core:Item text="23" key="23"/> + <core:Item text="24" key="24"/> + <core:Item text="25" key="25"/> + <core:Item text="26" key="26"/> + <core:Item text="27" key="27"/> + <core:Item text="28" key="28"/> + <core:Item text="29" key="29"/> + <core:Item text="30" key="30"/> + <core:Item text="31" key="31"/> + <core:Item text="32" key="32"/> + <core:Item text="33" key="33"/> + <core:Item text="34" key="34"/> + </items> + </Select> + <Select selectedKey="{/attmark/size}" tooltip="Marker size"> + <items> + <core:Item text="1" key="1"/> + <core:Item text="1.5" key="1.5"/> + <core:Item text="2" key="2"/> + <core:Item text="2.5" key="2.5"/> + <core:Item text="3" key="3"/> + <core:Item text="4" key="4"/> + <core:Item text="5" key="5"/> + <core:Item text="6" key="6"/> + <core:Item text="7" key="7"/> + <core:Item text="8" key="8"/> + </items> + </Select> + <jsroot:SVGSample svgsample="{/attmark}" tooltip="Marker sample"> + <jsroot:layoutData> + <FlexItemData growFactor="2"/> + </jsroot:layoutData> + </jsroot:SVGSample> + </items> + </FlexBox> +</core:FragmentDefinition> diff --git a/js/openui5/view/TNamed.fragment.xml b/js/openui5/view/TNamed.fragment.xml new file mode 100644 index 00000000000..ebb4d1e6d17 --- /dev/null +++ b/js/openui5/view/TNamed.fragment.xml @@ -0,0 +1,19 @@ +<core:FragmentDefinition + xmlns="sap.m" + xmlns:l="sap.ui.layout" + xmlns:core="sap.ui.core"> + <FlexBox renderType="Bare" width="100%"> + <items> + <Input + id="titleInput" + type="Text" + placeholder="Enter title ..." + valueStateText="Edit object title." + valueLiveUpdate="true" + value="{ + path : '/tnamed/fTitle', + type : 'sap.ui.model.type.String' + }"/> + </items> + </FlexBox> +</core:FragmentDefinition> diff --git a/js/scripts/JSRoot3DPainter.js b/js/scripts/JSRoot3DPainter.js new file mode 100644 index 00000000000..7a5faf4c6b4 --- /dev/null +++ b/js/scripts/JSRoot3DPainter.js @@ -0,0 +1,990 @@ +/// @file JSRoot3DPainter.js +/// JavaScript ROOT 3D graphics + +(function( factory ) { + if ( typeof define === "function" && define.amd ) { + define( ['JSRootPainter', 'd3', 'threejs', 'threejs_all'], factory ); + } else + if (typeof exports === 'object' && typeof module !== 'undefined') { + var jsroot = require("./JSRootCore.js"); + factory(jsroot, require("./d3.min.js"), require("./three.min.js"), require("./three.extra.min.js"), + jsroot.nodejs || (typeof document=='undefined') ? jsroot.nodejs_document : document); + } else { + + if (typeof JSROOT == 'undefined') + throw new Error('JSROOT is not defined', 'JSRoot3DPainter.js'); + + if (typeof d3 != 'object') + throw new Error('This extension requires d3.js', 'JSRoot3DPainter.js'); + + if (typeof THREE == 'undefined') + throw new Error('THREE is not defined', 'JSRoot3DPainter.js'); + + factory(JSROOT, d3, THREE); + } +} (function(JSROOT, d3, THREE, THREE_MORE, document) { + + "use strict"; + + JSROOT.sources.push("3d"); + + if ((typeof document=='undefined') && (typeof window=='object')) document = window.document; + + if (typeof JSROOT.Painter != 'object') + throw new Error('JSROOT.Painter is not defined', 'JSRoot3DPainter.js'); + + /** Returns true if WebGL can be used + * + * This can be situation of Node.js without "canvas" module + * @author alteredq / http://alteredqualia.com/ + * @author mr.doob / http://mrdoob.com/ + * @private + */ + + JSROOT.Painter.TestWebGL = function() { + + if (JSROOT.gStyle.NoWebGL || JSROOT.nodejs) return false; + + if ('_Detect_WebGL' in this) return this._Detect_WebGL; + + try { + var canvas = document.createElement( 'canvas' ); + this._Detect_WebGL = !! ( window.WebGLRenderingContext && ( canvas.getContext( 'webgl' ) || canvas.getContext( 'experimental-webgl' ) ) ); + //res = !!window.WebGLRenderingContext && !!document.createElement('canvas').getContext('experimental-webgl'); + } catch (e) { + this._Detect_WebGL = false; + } + + return this._Detect_WebGL; + } + + /** Returns true if SVGRenderer must be used. + * + * This can be situation of Node.js without "canvas" module + * + * @private + */ + + JSROOT.Painter.UseSVGFor3D = function() { + if (!JSROOT.nodejs) return false; + + if (this._Detect_UseSVGFor3D !== undefined) + return this._Detect_UseSVGFor3D; + + var nodejs_canvas = null; + + try { + nodejs_canvas = require('canvas'); + } catch (er) { + nodejs_canvas = null; + } + + this._Detect_UseSVGFor3D = !nodejs_canvas; + return this._Detect_UseSVGFor3D; + } + + /** Creates renderer for the 3D frawngs + * + * width and height - dimension of canvas for rendering + * usesvg - if SVGRenderer should be used + * makeimage - if normal renderer used, one can convert canvas into <image>, but without interactivity + * usewebgl - if WebGL should be used + * args - parameters for WebGLRenderer (if used) + * @private + */ + + JSROOT.Painter.Create3DRenderer = function(width, height, usesvg, makeimage, usewebgl, args) { + var res = { + renderer: null, + dom: null, + usesvg: usesvg, + usesvgimg: usesvg && JSROOT.gStyle.ImageSVG + } + + if (!args) args = { antialias: true, alpha: true }; + + if (JSROOT.nodejs) { + res.usewebgl = false; + } else if (usewebgl !== undefined) { + res.usewebgl = usewebgl; + } else { + res.usewebgl = JSROOT.Painter.TestWebGL(); + } + + // solves problem with toDataUrl in headless mode of chrome + // found https://stackoverflow.com/questions/48011613 + if (JSROOT.BatchMode && JSROOT.browser.isChromeHeadless && res.usewebgl) + args.premultipliedAlpha = false; + + if (usesvg) { + + var nodejs_canvas = null; + + if (JSROOT.nodejs && res.usesvgimg) { + try { + nodejs_canvas = require('canvas'); + } catch (er) { + nodejs_canvas = null; + res.usesvgimg = false; + JSROOT.gStyle.ImageSVG = false; // no need to try once again + } + } + + if (res.usesvgimg) { + + if (nodejs_canvas) { + args.canvas = new nodejs_canvas(width, height); + args.canvas.style = {}; + } + + res.renderer = res.usewebgl ? new THREE.WebGLRenderer(args) : new THREE.CanvasRenderer(args); + } else { + // this.renderer = new THREE.SVGRenderer({ precision: 0, astext: true }); + res.renderer = THREE.CreateSVGRenderer(false, 0, document); + } + + if (res.usesvgimg || (res.renderer.makeOuterHTML !== undefined)) { + // this is indication of new three.js functionality + if (!JSROOT.svg_workaround) JSROOT.svg_workaround = []; + res.renderer.workaround_id = JSROOT.svg_workaround.length; + JSROOT.svg_workaround[res.renderer.workaround_id] = "<svg></svg>"; // dummy, need to be replaced + + // replace DOM element in renderer + res.dom = document.createElementNS( 'http://www.w3.org/2000/svg', 'path'); + res.dom.setAttribute('jsroot_svg_workaround', res.renderer.workaround_id); + } + } else { + res.renderer = res.usewebgl ? new THREE.WebGLRenderer(args) : new THREE.CanvasRenderer(args); + } + + //renderer.setClearColor(0xffffff, 1); + // renderer.setClearColor(0x0, 0); + res.renderer.setSize(width, height); + + if (!res.dom) { + res.dom = res.renderer.domElement; + if (!usesvg && makeimage) { + res.dom = res.renderer.svgImage = document.createElementNS('http://www.w3.org/2000/svg','image'); + d3.select(res.dom).attr("width", width) + .attr("height", height); + } + } + + return res; + } + + JSROOT.Painter.AfterRender3D = function(renderer) { + if (renderer.svgImage) { + var dataUrl = renderer.domElement.toDataURL("image/png"); + var attrname = JSROOT.nodejs ? "xlink_href_nodejs" : "xlink:href"; + d3.select(renderer.svgImage).attr(attrname, dataUrl); + } + + // when using SVGrenderer producing text output, provide result + if (renderer.workaround_id !== undefined) { + if (typeof renderer.makeOuterHTML == 'function') { + JSROOT.svg_workaround[renderer.workaround_id] = renderer.makeOuterHTML(); + } else { + var canvas = renderer.domElement; + var dataUrl = canvas.toDataURL("image/png"); + var svg = '<image width="' + canvas.width + '" height="' + canvas.height + '" xlink:href="' + dataUrl + '"></image>'; + JSROOT.svg_workaround[renderer.workaround_id] = svg; + } + } + } + + JSROOT.Painter.ProcessSVGWorkarounds = function(svg) { + if (!JSROOT.svg_workaround) return svg; + for (var k=0;k<JSROOT.svg_workaround.length;++k) + svg = svg.replace('<path jsroot_svg_workaround="' + k + '"></path>', JSROOT.svg_workaround[k]); + JSROOT.svg_workaround = undefined; + return svg; + } + + + JSROOT.Painter.TooltipFor3D = function(prnt, canvas) { + this.tt = null; + this.cont = null; + this.lastlbl = ''; + this.parent = prnt ? prnt : document.body; + this.canvas = canvas; // we need canvas to recalculate mouse events + this.abspos = !prnt; + + this.check_parent = function(prnt) { + if (prnt && (this.parent !== prnt)) { + this.hide(); + this.parent = prnt; + } + } + + this.pos = function(e) { + // method used to define position of next tooltip + // event is delivered from canvas, + // but position should be calculated relative to the element where tooltip is placed + + if (this.tt === null) return; + var u,l; + if (this.abspos) { + l = JSROOT.browser.isIE ? (e.clientX + document.documentElement.scrollLeft) : e.pageX; + u = JSROOT.browser.isIE ? (e.clientY + document.documentElement.scrollTop) : e.pageY; + } else { + + l = e.offsetX; + u = e.offsetY; + + var rect1 = this.parent.getBoundingClientRect(), + rect2 = this.canvas.getBoundingClientRect(); + + if ((rect1.left !== undefined) && (rect2.left!== undefined)) l += (rect2.left-rect1.left); + + if ((rect1.top !== undefined) && (rect2.top!== undefined)) u += rect2.top-rect1.top; + + if (l + this.tt.offsetWidth + 3 >= this.parent.offsetWidth) + l = this.parent.offsetWidth - this.tt.offsetWidth - 3; + + if (u + this.tt.offsetHeight + 15 >= this.parent.offsetHeight) + u = this.parent.offsetHeight - this.tt.offsetHeight - 15; + + // one should find parent with non-static position, + // all absolute coordinates calculated relative to such node + var abs_parent = this.parent; + while (abs_parent) { + var style = getComputedStyle(abs_parent); + if (!style || (style.position !== 'static')) break; + if (!abs_parent.parentNode || (abs_parent.parentNode.nodeType != 1)) break; + abs_parent = abs_parent.parentNode; + } + + if (abs_parent && (abs_parent !== this.parent)) { + var rect0 = abs_parent.getBoundingClientRect(); + l+=(rect1.left - rect0.left); + u+=(rect1.top - rect0.top); + } + + } + + this.tt.style.top = (u + 15) + 'px'; + this.tt.style.left = (l + 3) + 'px'; + }; + + this.show = function(v, mouse_pos, status_func) { + // if (JSROOT.gStyle.Tooltip <= 0) return; + if (!v || (v==="")) return this.hide(); + + if (v && (typeof v =='object') && (v.lines || v.line)) { + if (v.only_status) return this.hide(); + + if (v.line) { + v = v.line; + } else { + var res = v.lines[0]; + for (var n=1;n<v.lines.length;++n) res+= "<br/>" + v.lines[n]; + v = res; + } + } + + if (this.tt === null) { + this.tt = document.createElement('div'); + this.tt.setAttribute('class', 'jsroot_tt3d_main'); + this.cont = document.createElement('div'); + this.cont.setAttribute('class', 'jsroot_tt3d_cont'); + this.tt.appendChild(this.cont); + this.parent.appendChild(this.tt); + } + + if (this.lastlbl !== v) { + this.cont.innerHTML = v; + this.lastlbl = v; + this.tt.style.width = 'auto'; // let it be automatically resizing... + if (JSROOT.browser.isIE) + this.tt.style.width = this.tt.offsetWidth; + } + }; + + this.hide = function() { + if (this.tt !== null) + this.parent.removeChild(this.tt); + + this.tt = null; + this.lastlbl = ""; + } + + return this; + } + + + JSROOT.Painter.CreateOrbitControl = function(painter, camera, scene, renderer, lookat) { + + if (JSROOT.gStyle.Zooming && JSROOT.gStyle.ZoomWheel) + renderer.domElement.addEventListener( 'wheel', control_mousewheel); + + var enable_zoom = JSROOT.gStyle.Zooming && JSROOT.gStyle.ZoomMouse, + enable_select = typeof painter.ProcessMouseClick == "function"; + + if (enable_zoom || enable_select) { + renderer.domElement.addEventListener( 'mousedown', control_mousedown); + renderer.domElement.addEventListener( 'mouseup', control_mouseup); + } + + var control = new THREE.OrbitControls(camera, renderer.domElement); + + control.enableDamping = false; + control.dampingFactor = 1.0; + control.enableZoom = true; + if (lookat) { + control.target.copy(lookat); + control.target0.copy(lookat); + control.update(); + } + + control.tooltip = new JSROOT.Painter.TooltipFor3D(painter.select_main().node(), renderer.domElement); + + control.painter = painter; + control.camera = camera; + control.scene = scene; + control.renderer = renderer; + control.raycaster = new THREE.Raycaster(); + control.raycaster.linePrecision = 10; + control.mouse_zoom_mesh = null; // zoom mesh, currently used in the zooming + control.block_ctxt = false; // require to block context menu command appearing after control ends, required in chrome which inject contextmenu when key released + control.block_mousemove = false; // when true, tooltip or cursor will not react on mouse move + control.cursor_changed = false; + control.control_changed = false; + control.control_active = false; + control.mouse_ctxt = { x:0, y: 0, on: false }; + control.enable_zoom = enable_zoom; + control.enable_select = enable_select; + + control.Cleanup = function() { + if (JSROOT.gStyle.Zooming && JSROOT.gStyle.ZoomWheel) + this.domElement.removeEventListener( 'wheel', control_mousewheel); + if (this.enable_zoom || this.enable_select) { + this.domElement.removeEventListener( 'mousedown', control_mousedown); + this.domElement.removeEventListener( 'mouseup', control_mouseup); + } + + this.domElement.removeEventListener('dblclick', this.lstn_dblclick); + this.domElement.removeEventListener('contextmenu', this.lstn_contextmenu); + this.domElement.removeEventListener('mousemove', this.lstn_mousemove); + this.domElement.removeEventListener('mouseleave', this.lstn_mouseleave); + + this.dispose(); // this is from OrbitControl itself + + this.tooltip.hide(); + delete this.tooltip; + delete this.painter; + delete this.camera; + delete this.scene; + delete this.renderer; + delete this.raycaster; + delete this.mouse_zoom_mesh; + } + + control.HideTooltip = function() { + this.tooltip.hide(); + } + + control.GetMousePos = function(evnt, mouse) { + mouse.x = ('offsetX' in evnt) ? evnt.offsetX : evnt.layerX; + mouse.y = ('offsetY' in evnt) ? evnt.offsetY : evnt.layerY; + mouse.clientX = evnt.clientX; + mouse.clientY = evnt.clientY; + return mouse; + } + + control.GetOriginDirectionIntersects = function(origin, direction) { + this.raycaster.set(origin, direction); + var intersects = this.raycaster.intersectObjects(this.scene.children, true); + // painter may want to filter intersects + if (typeof this.painter.FilterIntersects == 'function') + intersects = this.painter.FilterIntersects(intersects); + return intersects; + } + + control.GetMouseIntersects = function(mouse) { + // domElement gives correct coordinate with canvas render, but isn't always right for webgl renderer + var sz = (this.renderer instanceof THREE.WebGLRenderer) ? this.renderer.getSize() : this.renderer.domElement; + var pnt = { x: mouse.x / sz.width * 2 - 1, y: -mouse.y / sz.height * 2 + 1 }; + + this.camera.updateMatrix(); + this.camera.updateMatrixWorld(); + this.raycaster.setFromCamera( pnt, this.camera ); + var intersects = this.raycaster.intersectObjects(this.scene.children, true); + + // painter may want to filter intersects + if (typeof this.painter.FilterIntersects == 'function') + intersects = this.painter.FilterIntersects(intersects); + + return intersects; + } + + control.DetectZoomMesh = function(evnt) { + var mouse = this.GetMousePos(evnt, {}); + var intersects = this.GetMouseIntersects(mouse); + if (intersects) + for (var n=0;n<intersects.length;++n) + if (intersects[n].object.zoom) + return intersects[n]; + + return null; + } + + control.ProcessDblClick = function(evnt) { + var intersect = this.DetectZoomMesh(evnt); + if (intersect && this.painter) { + this.painter.Unzoom(intersect.object.use_y_for_z ? "y" : intersect.object.zoom); + } else { + this.reset(); + } + // this.painter.Render3D(); + } + + control.ChangeEvent = function() { + this.mouse_ctxt.on = false; // disable context menu if any changes where done by orbit control + this.painter.zoom_changed_interactive = 1; + this.painter.Render3D(0); + this.control_changed = true; + } + + control.StartEvent = function() { + this.control_active = true; + this.block_ctxt = false; + this.mouse_ctxt.on = false; + + this.tooltip.hide(); + + // do not reset here, problem of events sequence in orbitcontrol + // it issue change/start/stop event when do zooming + // control.control_changed = false; + } + + control.EndEvent = function() { + this.control_active = false; + if (this.mouse_ctxt.on) { + this.mouse_ctxt.on = false; + this.ContextMenu(this.mouse_ctxt, this.GetMouseIntersects(this.mouse_ctxt)); + } else + if (this.control_changed) { + // react on camera change when required + } + this.control_changed = false; + } + + control.MainProcessContextMenu = function(evnt) { + evnt.preventDefault(); + this.GetMousePos(evnt, this.mouse_ctxt); + if (this.control_active) + this.mouse_ctxt.on = true; + else + if (this.block_ctxt) + this.block_ctxt = false; + else + this.ContextMenu(this.mouse_ctxt, this.GetMouseIntersects(this.mouse_ctxt)); + } + + control.ContextMenu = function(pos, intersects) { + // do nothing, function called when context menu want to be activated + } + + control.SwitchTooltip = function(on) { + this.block_mousemove = !on; + if (on===false) { + this.tooltip.hide(); + this.RemoveZoomMesh(); + } + } + + control.RemoveZoomMesh = function() { + if (this.mouse_zoom_mesh && this.mouse_zoom_mesh.object.ShowSelection()) + this.painter.Render3D(); + this.mouse_zoom_mesh = null; // in any case clear mesh, enable orbit control again + } + + control.MainProcessMouseMove = function(evnt) { + if (this.control_active && evnt.buttons && (evnt.buttons & 2)) + this.block_ctxt = true; // if right button in control was active, block next context menu + + if (this.control_active || this.block_mousemove || !this.ProcessMouseMove) return; + + if (this.mouse_zoom_mesh) { + // when working with zoom mesh, need special handling + + var zoom2 = this.DetectZoomMesh(evnt), pnt2 = null; + + if (zoom2 && (zoom2.object === this.mouse_zoom_mesh.object)) { + pnt2 = zoom2.point; + } else { + pnt2 = this.mouse_zoom_mesh.object.GlobalIntersect(this.raycaster); + } + + if (pnt2) this.mouse_zoom_mesh.point2 = pnt2; + + if (pnt2 && this.painter.enable_highlight) + if (this.mouse_zoom_mesh.object.ShowSelection(this.mouse_zoom_mesh.point, pnt2)) + this.painter.Render3D(0); + + this.tooltip.hide(); + return; + } + + evnt.preventDefault(); + + var mouse = this.GetMousePos(evnt, {}), + intersects = this.GetMouseIntersects(mouse), + tip = this.ProcessMouseMove(intersects), + status_func = this.painter.GetShowStatusFunc(); + + if (tip && status_func) { + var name = "", title = "", coord = "", info = ""; + if (mouse) coord = mouse.x.toFixed(0)+ "," + mouse.y.toFixed(0); + if (typeof tip == "string") { + info = tip; + } else { + name = tip.name; title = tip.title; + if (tip.line) info = tip.line; else + if (tip.lines) { info = tip.lines.slice(1).join(' '); name = tip.lines[0]; } + } + status_func(name, title, info, coord); + } + + this.cursor_changed = false; + if (tip && this.painter && this.painter.IsTooltipAllowed()) { + this.tooltip.check_parent(this.painter.select_main().node()); + + this.tooltip.show(tip, mouse); + this.tooltip.pos(evnt); + } else { + this.tooltip.hide(); + if (intersects) + for (var n=0;n<intersects.length;++n) + if (intersects[n].object.zoom) this.cursor_changed = true; + } + + document.body.style.cursor = this.cursor_changed ? 'pointer' : 'auto'; + }; + + control.MainProcessMouseLeave = function() { + this.tooltip.hide(); + if (typeof this.ProcessMouseLeave === 'function') this.ProcessMouseLeave(); + if (this.cursor_changed) { + document.body.style.cursor = 'auto'; + this.cursor_changed = false; + } + }; + + function control_mousewheel(evnt) { + // try to handle zoom extra + + if (JSROOT.Painter.IsRender3DFired(control.painter) || control.mouse_zoom_mesh) { + evnt.preventDefault(); + evnt.stopPropagation(); + evnt.stopImmediatePropagation(); + return; // already fired redraw, do not react on the mouse wheel + } + + var intersect = control.DetectZoomMesh(evnt); + if (!intersect) return; + + evnt.preventDefault(); + evnt.stopPropagation(); + evnt.stopImmediatePropagation(); + + if (control.painter && (typeof control.painter.AnalyzeMouseWheelEvent == 'function')) { + var kind = intersect.object.zoom, + position = intersect.point[kind], + item = { name: kind, ignore: false }; + + // z changes from 0..2*size_z3d, others -size_xy3d..+size_xy3d + if (kind!=="z") position = (position + control.painter.size_xy3d)/2/control.painter.size_xy3d; + else position = position/2/control.painter.size_z3d; + + control.painter.AnalyzeMouseWheelEvent(evnt, item, position, false); + + if ((kind==="z") && intersect.object.use_y_for_z) kind="y"; + + control.painter.Zoom(kind, item.min, item.max); + } + } + + function control_mousedown(evnt) { + + // function used to hide some events from orbit control and redirect them to zooming rect + + if (control.mouse_zoom_mesh) { + evnt.stopImmediatePropagation(); + evnt.stopPropagation(); + return; + } + + // only left-button is considered + if ((evnt.button!==undefined) && (evnt.button !==0)) return; + if ((evnt.buttons!==undefined) && (evnt.buttons !== 1)) return; + + if (control.enable_zoom) { + control.mouse_zoom_mesh = control.DetectZoomMesh(evnt); + if (control.mouse_zoom_mesh) { + // just block orbit control + evnt.stopImmediatePropagation(); + evnt.stopPropagation(); + return; + } + } + + if (control.enable_select) { + control.mouse_select_pnt = control.GetMousePos(evnt, {}); + } + } + + function control_mouseup(evnt) { + + if (control.mouse_zoom_mesh && control.mouse_zoom_mesh.point2 && control.painter.Get3DZoomCoord) { + + var kind = control.mouse_zoom_mesh.object.zoom, + pos1 = control.painter.Get3DZoomCoord(control.mouse_zoom_mesh.point, kind), + pos2 = control.painter.Get3DZoomCoord(control.mouse_zoom_mesh.point2, kind); + + if (pos1>pos2) { var v = pos1; pos1 = pos2; pos2 = v; } + + if ((kind==="z") && control.mouse_zoom_mesh.object.use_y_for_z) kind="y"; + + if ((kind==="z") && control.mouse_zoom_mesh.object.use_y_for_z) kind="y"; + + // try to zoom + if (pos1 < pos2) + if (control.painter.Zoom(kind, pos1, pos2)) + control.mouse_zoom_mesh = null; + } + + // if selection was drawn, it should be removed and picture rendered again + if (control.enable_zoom) + control.RemoveZoomMesh(); + + // only left-button is considered + //if ((evnt.button!==undefined) && (evnt.button !==0)) return; + //if ((evnt.buttons!==undefined) && (evnt.buttons !== 1)) return; + + if (control.enable_select && control.mouse_select_pnt) { + + var pnt = control.GetMousePos(evnt, {}); + + var same_pnt = (pnt.x == control.mouse_select_pnt.x) && (pnt.y == control.mouse_select_pnt.y); + delete control.mouse_select_pnt; + + if (same_pnt) { + var intersects = control.GetMouseIntersects(pnt); + control.painter.ProcessMouseClick(pnt, intersects, evnt); + } + } + } + + control.MainProcessDblClick = function(evnt) { + this.ProcessDblClick(evnt); + } + + control.addEventListener( 'change', control.ChangeEvent.bind(control)); + control.addEventListener( 'start', control.StartEvent.bind(control)); + control.addEventListener( 'end', control.EndEvent.bind(control)); + + control.lstn_contextmenu = control.MainProcessContextMenu.bind(control); + control.lstn_dblclick = control.MainProcessDblClick.bind(control); + control.lstn_mousemove = control.MainProcessMouseMove.bind(control); + control.lstn_mouseleave = control.MainProcessMouseLeave.bind(control); + + renderer.domElement.addEventListener('dblclick', control.lstn_dblclick); + renderer.domElement.addEventListener('contextmenu', control.lstn_contextmenu); + renderer.domElement.addEventListener('mousemove', control.lstn_mousemove); + renderer.domElement.addEventListener('mouseleave', control.lstn_mouseleave); + + return control; + } + + /** Method cleanup three.js object as much as possible. + * Simplify JS engine to remove it from memory + * @private */ + + JSROOT.Painter.DisposeThreejsObject = function(obj, only_childs) { + if (!obj) return; + + if (obj.children) { + for (var i = 0; i < obj.children.length; i++) + JSROOT.Painter.DisposeThreejsObject(obj.children[i]); + } + + if (only_childs) { + obj.children = []; + return; + } + + obj.children = undefined; + + if (obj.geometry) { + obj.geometry.dispose(); + obj.geometry = undefined; + } + if (obj.material) { + if (obj.material.map) { + obj.material.map.dispose(); + obj.material.map = undefined; + } + obj.material.dispose(); + obj.material = undefined; + } + + // cleanup jsroot fields to simplify browser cleanup job + delete obj.painter; + delete obj.bins_index; + delete obj.tooltip; + delete obj.stack; // used in geom painter + delete obj.drawn_highlight; // special highlight object + + obj = undefined; + } + + JSROOT.Painter.createLineSegments = function(arr, material, index, only_geometry) { + // prepare geometry for THREE.LineSegments + // If required, calculate lineDistance attribute for dashed geometries + + var geom = new THREE.BufferGeometry(); + + geom.addAttribute( 'position', arr instanceof Float32Array ? new THREE.BufferAttribute( arr, 3 ) : new THREE.Float32BufferAttribute( arr, 3 ) ); + if (index) geom.setIndex( new THREE.BufferAttribute(index, 1) ); + + if (material.isLineDashedMaterial) { + + var v1 = new THREE.Vector3(), + v2 = new THREE.Vector3(), + d = 0, distances = null; + + if (index) { + distances = new Float32Array(index.length); + for (var n=0; n<index.length; n+=2) { + var i1 = index[n], i2 = index[n+1]; + v1.set(arr[i1],arr[i1+1],arr[i1+2]); + v2.set(arr[i2],arr[i2+1],arr[i2+2]); + distances[n] = d; + d += v2.distanceTo( v1 ); + distances[n+1] = d; + } + } else { + distances = new Float32Array(arr.length/3); + for (var n=0; n<arr.length; n+=6) { + v1.set(arr[n],arr[n+1],arr[n+2]); + v2.set(arr[n+3],arr[n+4],arr[n+5]); + distances[n/3] = d; + d += v2.distanceTo( v1 ); + distances[n/3+1] = d; + } + } + geom.addAttribute( 'lineDistance', new THREE.BufferAttribute(distances, 1) ); + } + + return only_geometry ? geom : new THREE.LineSegments(geom, material); + } + + JSROOT.Painter.Box3D = { + Vertices: [ new THREE.Vector3(1, 1, 1), new THREE.Vector3(1, 1, 0), + new THREE.Vector3(1, 0, 1), new THREE.Vector3(1, 0, 0), + new THREE.Vector3(0, 1, 0), new THREE.Vector3(0, 1, 1), + new THREE.Vector3(0, 0, 0), new THREE.Vector3(0, 0, 1) ], + Indexes: [ 0,2,1, 2,3,1, 4,6,5, 6,7,5, 4,5,1, 5,0,1, 7,6,2, 6,3,2, 5,7,0, 7,2,0, 1,3,4, 3,6,4 ], + Normals: [ 1,0,0, -1,0,0, 0,1,0, 0,-1,0, 0,0,1, 0,0,-1 ], + Segments: [0, 2, 2, 7, 7, 5, 5, 0, 1, 3, 3, 6, 6, 4, 4, 1, 1, 0, 3, 2, 6, 7, 4, 5] // segments addresses Vertices + }; + + // these segments address vertices from the mesh, we can use positions from box mesh + JSROOT.Painter.Box3D.MeshSegments = (function() { + var box3d = JSROOT.Painter.Box3D, + arr = new Int32Array(box3d.Segments.length); + + for (var n=0;n<arr.length;++n) { + for (var k=0;k<box3d.Indexes.length;++k) + if (box3d.Segments[n] === box3d.Indexes[k]) { + arr[n] = k; break; + } + } + return arr; + })(); + + JSROOT.Painter.IsRender3DFired = function(painter) { + if (!painter || painter.renderer === undefined) return false; + + return painter.render_tmout !== undefined; // when timeout configured, object is prepared for rendering + } + + // ============================================================================== + + function InteractiveControl() {} + + InteractiveControl.prototype.cleanup = function() {} + + InteractiveControl.prototype.extractIndex = function(intersect) { return undefined; } + + InteractiveControl.prototype.setSelected = function(col, indx) {} + + InteractiveControl.prototype.setHighlight = function(col, indx) {} + + InteractiveControl.prototype.checkHighlightIndex = function(indx) { return undefined; } + + // ============================================================================== + + /** Special class to control highliht and selection of single points, used in geo painter + * @private */ + function PointsControl(mesh) { + InteractiveControl.call(this); + this.mesh = mesh; + } + + PointsControl.prototype = Object.create(InteractiveControl.prototype); + + PointsControl.prototype.cleanup = function() { + if (!this.mesh) return; + delete this.mesh.is_selected; + this.createSpecial(null); + delete this.mesh; + } + + PointsControl.prototype.extractIndex = function(intersect) { + return intersect && intersect.index!==undefined ? intersect.index : undefined; + } + + PointsControl.prototype.setSelected = function(col, indx) { + var m = this.mesh; + if ((m.select_col == col) && (m.select_indx == indx)) { + console.log("Reset selection"); + col = null; indx = undefined; + } + m.select_col = col; + m.select_indx = indx; + this.createSpecial(col, indx); + return true; + } + + PointsControl.prototype.setHighlight = function(col, indx) { + var m = this.mesh; + m.h_index = indx; + if (col) + this.createSpecial(col, indx); + else + this.createSpecial(m.select_col, m.select_indx); + return true; + } + + PointsControl.prototype.createSpecial = function(color, index) { + var m = this.mesh; + if (!color) { + if (m.js_special) { + m.remove(m.js_special); + JSROOT.Painter.DisposeThreejsObject(m.js_special); + delete m.js_special; + } + return; + } + + if (!m.js_special) { + var geom = new THREE.BufferGeometry(); + geom.addAttribute( 'position', m.geometry.getAttribute("position")); + var material = new THREE.PointsMaterial( { size: m.material.size*2, color: color } ); + material.sizeAttenuation = m.material.sizeAttenuation; + + m.js_special = new THREE.Points(geom, material); + m.js_special.jsroot_special = true; // special object, exclude from intersections + m.add(m.js_special); + } + + if (color) m.js_special.material.color = new THREE.Color(color); + if (index !== undefined) m.js_special.geometry.setDrawRange(index, 1); + } + + + function PointsCreator(size, iswebgl, scale) { + this.webgl = (iswebgl === undefined) ? true : iswebgl; + this.scale = scale || 1.; + + this.pos = new Float32Array(size*3); + this.geom = new THREE.BufferGeometry(); + this.geom.addAttribute( 'position', new THREE.BufferAttribute( this.pos, 3 ) ); + this.indx = 0; + } + + PointsCreator.prototype.AddPoint = function(x,y,z) { + this.pos[this.indx] = x; + this.pos[this.indx+1] = y; + this.pos[this.indx+2] = z; + this.indx+=3; + } + + PointsCreator.prototype.CreatePoints = function(mcolor) { + // only plain geometry and sprite material is supported by CanvasRenderer, but it cannot be scaled + + var material = new THREE.PointsMaterial( { size: (this.webgl ? 3 : 1) * this.scale, color: mcolor || 'black' } ); + var pnts = new THREE.Points(this.geom, material); + pnts.nvertex = 1; + return pnts; + } + + // ============================================================================== + + function Create3DLineMaterial(painter, obj) { + if (!painter || !obj) return null; + + var lcolor = painter.get_color(obj.fLineColor), + material = null, + style = obj.fLineStyle ? JSROOT.Painter.root_line_styles[obj.fLineStyle] : "", + dash = style ? style.split(",") : []; + + if (dash && dash.length>=2) + material = new THREE.LineDashedMaterial( { color: lcolor, dashSize: parseInt(dash[0]), gapSize: parseInt(dash[1]) } ); + else + material = new THREE.LineBasicMaterial({ color: lcolor }); + + if (obj.fLineWidth && (obj.fLineWidth>1) && !JSROOT.browser.isIE) material.linewidth = obj.fLineWidth; + + return material; + } + + // ============================================================================================================ + + function drawPolyLine3D() { + var line = this.GetObject(), + main = this.frame_painter(); + + if (!main || !main.mode3d || !main.toplevel || !line) return; + + var fN, fP, fOption, pnts = []; + + if (line._blob && (line._blob.length==4)) { + // workaround for custom streamer for JSON, should be resolved + fN = line._blob[1]; + fP = line._blob[2]; + fOption = line._blob[3]; + } else { + fN = line.fN; + fP = line.fP; + fOption = line.fOption; + } + + for (var n=3;n<3*fN;n+=3) + pnts.push(main.grx(fP[n-3]), main.gry(fP[n-2]), main.grz(fP[n-1]), + main.grx(fP[n]), main.gry(fP[n+1]), main.grz(fP[n+2])); + + var lines = JSROOT.Painter.createLineSegments(pnts, Create3DLineMaterial(this, line)); + + main.toplevel.add(lines); + } + + // ============================================================================================== + + + JSROOT.Painter.PointsCreator = PointsCreator; + JSROOT.Painter.InteractiveControl = InteractiveControl; + JSROOT.Painter.PointsControl = PointsControl; + + JSROOT.Painter.drawPolyLine3D = drawPolyLine3D; + + JSROOT.Painter.Create3DLineMaterial = Create3DLineMaterial; + + + return JSROOT; + +})); + diff --git a/js/scripts/JSRootCore.js b/js/scripts/JSRootCore.js new file mode 100644 index 00000000000..8eec1fa0094 --- /dev/null +++ b/js/scripts/JSRootCore.js @@ -0,0 +1,2332 @@ +/** @fileoverview Core methods of JavaScript ROOT + * @namespace JSROOT */ + +(function( factory ) { + if ( typeof define === "function" && define.amd ) { + + var jsroot = factory({}), + dir = jsroot.source_dir + "scripts/", + ext = jsroot.source_min ? ".min" : "", + norjs = (typeof requirejs=='undefined'), + paths = { + 'd3' : dir+'d3.min', + 'jquery' : dir+'jquery.min', + 'jquery-ui' : dir+'jquery-ui.min', + 'jqueryui-mousewheel' : dir+'jquery.mousewheel.min', + 'jqueryui-touch-punch' : dir+'touch-punch.min', + 'rawinflate' : dir+'rawinflate.min', + 'MathJax' : 'https://root.cern/js/mathjax/latest/MathJax.js?config=TeX-AMS-MML_SVG&delayStartupUntil=configured', + 'dat.gui' : dir+'dat.gui.min', + 'threejs' : dir+'three.min', + 'threejs_all' : dir+'three.extra.min', + 'JSRootCore' : dir+'JSRootCore'+ext, + 'JSRootMath' : dir+'JSRootMath'+ext, + 'JSRootIOEvolution' : dir+'JSRootIOEvolution'+ext, + 'JSRootTree' : dir+'JSRootTree'+ext, + 'JSRootPainter' : dir+'JSRootPainter'+ext, + 'JSRootPainter.v6' : dir+'JSRootPainter.v6'+ext, + 'JSRootPainter.hist' : dir+'JSRootPainter.hist'+ext, + 'JSRootPainter.hist3d' : dir+'JSRootPainter.hist3d'+ext, + 'JSRootPainter.more' : dir+'JSRootPainter.more'+ext, + 'JSRootPainter.hierarchy' : dir+'JSRootPainter.hierarchy'+ext, + 'JSRootPainter.jquery' : dir+'JSRootPainter.jquery'+ext, + 'JSRootPainter.openui5': dir+'JSRootPainter.openui5'+ext, + 'JSRootPainter.v7' : dir+'JSRootPainter.v7'+ext, + 'JSRootPainter.v7hist' : dir+'JSRootPainter.v7hist'+ext, + 'JSRootPainter.v7more' : dir+'JSRootPainter.v7more'+ext, + 'JSRoot3DPainter' : dir+'JSRoot3DPainter'+ext, + 'ThreeCSG' : dir+'ThreeCSG'+ext, + 'JSRootGeoBase' : dir+'JSRootGeoBase'+ext, + 'JSRootGeoPainter' : dir+'JSRootGeoPainter'+ext + }; + + if (norjs) { + // just define locations + paths['MathJax'] = 'https://root.cern/js/mathjax/latest/MathJax.js?config=TeX-AMS-MML_SVG&delayStartupUntil=configured'; + + require({ paths: paths }); + } else { + var cfg_paths; + if ((requirejs.s!==undefined) && (requirejs.s.contexts !== undefined) && ((requirejs.s.contexts._!==undefined) && + requirejs.s.contexts._.config!==undefined)) cfg_paths = requirejs.s.contexts._.config.paths; + else console.warn("Require.js paths changed - please contact JSROOT developers"); + + // check if modules are already loaded + for (var module in paths) + if (requirejs.defined(module) || (cfg_paths && (module in cfg_paths))) + delete paths[module]; + + // configure all dependencies + requirejs.config({ + paths: paths, + shim: { + 'jqueryui-mousewheel': { deps: ['jquery-ui'] }, + 'jqueryui-touch-punch': { deps: ['jquery-ui'] } + } + }); + } + + define( jsroot ); + + if (norjs || !require.specified("JSRootCore")) + define('JSRootCore', [], jsroot); + + if (norjs || !require.specified("jsroot")) + define('jsroot', [], jsroot); + + } else + if (typeof exports === 'object' /*&& typeof module !== 'undefined'*/) { + // processing with Node.js or CommonJS + + // mark JSROOT as used with Node.js + exports.BatchMode = exports.nodejs = (typeof global==='object') && global.process && (Object.prototype.toString.call(global.process) === '[object process]'); + + factory(exports); + + } else { + + if (typeof JSROOT != 'undefined') + throw new Error("JSROOT is already defined", "JSRootCore.js"); + + JSROOT = {}; + + factory(JSROOT); + } +} (function(JSROOT) { + + "use strict"; + + JSROOT.version = "dev 26/02/2019"; + + JSROOT.source_dir = ""; + JSROOT.source_min = false; + JSROOT.source_fullpath = ""; // full name of source script + JSROOT.bower_dir = null; // when specified, use standard libs from bower location + JSROOT.nocache = false; + JSROOT.sources = ['core']; // indicates which major sources were loaded + + JSROOT.id_counter = 0; + if (JSROOT.BatchMode === undefined) + JSROOT.BatchMode = false; // when true, disables all kind of interactive features + + //openuicfg // DO NOT DELETE, used to configure openui5 usage like JSROOT.openui5src = "nojsroot"; + + // JSROOT.use_full_libs = true; + + JSROOT.touches = false; + JSROOT.browser = { isOpera: false, isFirefox: true, isSafari: false, isChrome: false, isIE: false, isWin: false }; + + if ((typeof document !== "undefined") && (typeof window !== "undefined")) { + var scripts = document.getElementsByTagName('script'); + for (var n = 0; n < scripts.length; ++n) { + if (!scripts[n].src || (typeof scripts[n].src !== 'string')) continue; + + var pos = scripts[n].src.indexOf("scripts/JSRootCore."); + if (pos<0) continue; + + JSROOT.source_dir = scripts[n].src.substr(0, pos); + JSROOT.source_min = scripts[n].src.indexOf("scripts/JSRootCore.min.js") >= 0; + JSROOT.source_fullpath = scripts[n].src; + + if ((console!==undefined) && (typeof console.log == 'function')) + console.log("Set JSROOT.source_dir to " + JSROOT.source_dir + ", " + JSROOT.version); + break; + } + + JSROOT.touches = ('ontouchend' in document); // identify if touch events are supported + JSROOT.browser.isOpera = !!window.opera || navigator.userAgent.indexOf(' OPR/') >= 0; + JSROOT.browser.isFirefox = typeof InstallTrigger !== 'undefined'; + JSROOT.browser.isSafari = Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0; + JSROOT.browser.isChrome = !!window.chrome && !JSROOT.browser.isOpera; + JSROOT.browser.isIE = false || !!document.documentMode; + JSROOT.browser.isWin = navigator.platform.indexOf('Win') >= 0; + JSROOT.browser.isChromeHeadless = navigator.userAgent.indexOf('HeadlessChrome') >= 0; + } + + JSROOT.browser.isWebKit = JSROOT.browser.isChrome || JSROOT.browser.isSafari || JSROOT.browser.isOpera; + + // default draw styles, can be changed after loading of JSRootCore.js + // this style also can be changed providing style=itemname in the URL + JSROOT.gStyle = { + Tooltip: 1, // 0 - off, 1 - on + TooltipAnimation: 500, // time in msec for appearance of tooltips, 0 - no animation + ContextMenu: true, + Zooming: true, // global zooming flag, enable/disable any kind of interactive zooming + ZoomMouse: true, // Zooming with the mouse events + ZoomWheel: true, // Zooming with mouse wheel + ZoomTouch: true, // Zooming with the touch devices + MoveResize: true, // enable move and resize of elements like statbox, title, pave, colz + DragAndDrop: true, // enables drag and drop functionality + ToolBar: 'popup', // show additional tool buttons on the canvas, false - disabled, true - enabled, 'popup' - only toggle button + ToolBarSide: 'left', // 'left' left-bottom corner on canvas, 'right' - right-bottom corner on canvas, opposite on sub-pads + ToolBarVert: false, // display tool bar vertical (default false) + CanEnlarge: true, // if drawing inside particular div can be enlarged on full window + CanAdjustFrame: false, // if frame position can be adjusted to let show axis or colz labels + ApproxTextSize: false, // calculation of text size consumes time and can be skipped to improve performance (but with side effects on text adjustments) + OptimizeDraw: 1, // drawing optimization: 0 - disabled, 1 - only for large (>5000 1d bins, >50 2d bins) histograms, 2 - always + AutoStat: true, + FrameNDC: { fX1NDC: 0.07, fY1NDC: 0.12, fX2NDC: 0.95, fY2NDC: 0.88 }, + Palette: 57, + Latex: 2, // 0 - never, 1 - only latex symbols, 2 - normal TLatex processing (default), 3 - use MathJax for complex case, 4 - use MathJax always + // MathJax : 0, // depricated, will be supported till JSROOT 6.0, use Latex variable 0 - never, 1 - only for complex cases, 2 - always + ProgressBox: true, // show progress box + Embed3DinSVG: 2, // 0 - no embed, only 3D plot, 1 - overlay over SVG (IE/WebKit), 2 - embed into SVG (only Firefox) + ImageSVG: !JSROOT.nodejs, // when producing SVG images, use <image> elements to insert 3D drawings from three.js, + // To enable on nodejs, one should call "npm install canvas" + NoWebGL: false, // if true, WebGL will be disabled + GeoGradPerSegm: 6, // amount of grads per segment in TGeo spherical shapes like tube + GeoCompressComp: true, // if one should compress faces after creation of composite shape, + IgnoreUrlOptions: false, // if true, ignore all kind of URL options in the browser URL + HierarchyLimit: 250, // how many items shown on one level of hierarchy + SmallPad: { width: 150, height: 100 }, // size of pad, where many features will be deactivated like text draw or zooming + + // XValuesFormat : "6.4g", // custom format for all X values + // YValuesFormat : "6.4g", // custom format for all Y values + // ZValuesFormat : "6.4g", // custom format for all Z values + + // these are TStyle attributes, which can be changed via URL 'style' parameter or delivered by TWebCanvas + + fOptLogx: 0, + fOptLogy: 0, + fOptLogz: 0, + fOptDate: 0, + fOptFile: 0, + fOptTitle: 1, + fPadBottomMargin: 0.1, + fPadTopMargin: 0.1, + fPadLeftMargin: 0.1, + fPadRightMargin: 0.1, + fPadGridX: false, + fPadGridY: false, + fPadTickX: 0, + fPadTickY: 0, + fStatColor: 0, + fStatTextColor: 1, + fStatBorderSize: 1, + fStatFont: 42, + fStatFontSize: 0, + fStatStyle: 1001, + fStatFormat: "6.4g", + fStatX: 0.98, + fStatY: 0.935, + fStatW: 0.2, + fStatH: 0.16, + fTitleAlign: 23, + fTitleColor: 0, + fTitleTextColor: 1, + fTitleBorderSize: 0, + fTitleFont: 42, + fTitleFontSize: 0.05, + fTitleStyle: 0, + fTitleX: 0.5, + fTitleY: 0.995, + fTitleW: 0, + fTitleH: 0, + fFitFormat: "5.4g", + fOptStat: 1111, + fOptFit: 0, + fNumberContours: 20, + fGridColor: 0, + fGridStyle: 3, + fGridWidth: 1, + fFrameFillColor: 0, + fFrameFillStyle: 1001, + fFrameLineColor: 1, + fFrameLineWidth: 1, + fFrameLineStyle: 1, + fFrameBorderSize: 1, + fFrameBorderMode: 0, + fEndErrorSize: 2, // size in pixels of end error for E1 draw options + fErrorX: 0.5, // X size of the error marks for the histogram drawings + fHistMinimumZero: false, // when true, BAR and LEGO drawing using base = 0 + fPaintTextFormat : "g", + fTimeOffset : 788918400 // UTC time at 01/01/95 + }; + + /** Generate mask for given bit + * + * @param {number} n bit number + * @returns {Number} produced make + * @private */ + JSROOT.BIT = function(n) { return 1 << (n); } + + /** TH1 status bits + * @private */ + JSROOT.TH1StatusBits = { + kNoStats : JSROOT.BIT(9), // don't draw stats box + kUserContour : JSROOT.BIT(10), // user specified contour levels + kCanRebin : JSROOT.BIT(11), // can rebin axis + kLogX : JSROOT.BIT(15), // X-axis in log scale + kIsZoomed : JSROOT.BIT(16), // bit set when zooming on Y axis + kNoTitle : JSROOT.BIT(17), // don't draw the histogram title + kIsAverage : JSROOT.BIT(18) // Bin contents are average (used by Add) + }; + + /** Wrapper for console.log, let redirect output to specified div element + * @private */ + JSROOT.console = function(value, divid) { + if ((typeof divid == 'string') && document.getElementById(divid)) + document.getElementById(divid).innerHTML = value; + else + if ((typeof console != 'undefined') && (typeof console.log == 'function')) + console.log(value); + } + + /** @summary Wrapper for alert, throws Error in Node.js + * @private */ + JSROOT.alert = function(msg) { + if (this.nodeis) throw new Error(msg); + if (typeof alert === 'function') alert(msg); + else JSROOT.console('ALERT: ' + msg); + } + + /** + * @summary Seed simple random generator + * + * @private + * @param {number} i seed value + */ + JSROOT.seed = function(i) { + i = Math.abs(i); + if (i > 1e8) i = Math.abs(1e8 * Math.sin(i)); else + if (i < 1) i*=1e8; + this.m_w = Math.round(i); + this.m_z = 987654321; + } + + /** + * @summary Simple random generator + * + * @desc Works like Math.random(), but with configurable seed - see {@link JSROOT.seed} + * @private + * @returns {number} random value between 0 (inclusive) and 1.0 (exclusive) + */ + JSROOT.random = function() { + if (this.m_z===undefined) return Math.random(); + this.m_z = (36969 * (this.m_z & 65535) + (this.m_z >> 16)) & 0xffffffff; + this.m_w = (18000 * (this.m_w & 65535) + (this.m_w >> 16)) & 0xffffffff; + var result = ((this.m_z << 16) + this.m_w) & 0xffffffff; + result /= 4294967296; + return result + 0.5; + } + + /** @summary Should be used to reintroduce objects references, produced by TBufferJSON. + * + * @desc Replace all references inside object, object should not be null + * Idea of the code taken from JSON-R code, found on + * https://github.com/graniteds/jsonr + * Only unref part was used, arrays are not accounted as objects + * @param {object} obj object where references will be replaced + * @returns {object} same object with replaced references + * @private */ + JSROOT.JSONR_unref = function(obj) { + + var map = [], newfmt = undefined; + + function unref_value(value) { + if ((value===null) || (value===undefined)) return; + + if (typeof value === 'string') { + if (newfmt || (value.length < 6) || (value.indexOf("$ref:") !== 0)) return; + var ref = parseInt(value.substr(5)); + if (isNaN(ref) || (ref < 0) || (ref >= map.length)) return; + newfmt = false; + return map[ref]; + } + + if (typeof value !== 'object') return; + + var i, k, res, proto = Object.prototype.toString.apply(value); + + // scan array - it can contain other objects + if ((proto.indexOf('[object')==0) && (proto.indexOf('Array]')>0)) { + for (i = 0; i < value.length; ++i) { + res = unref_value(value[i]); + if (res!==undefined) value[i] = res; + } + return; + } + + var ks = Object.keys(value), len = ks.length; + + if ((newfmt!==false) && (len===1) && (ks[0]==='$ref')) { + var ref = parseInt(value['$ref']); + if (isNaN(ref) || (ref < 0) || (ref >= map.length)) return; + newfmt = true; + return map[ref]; + } + + if ((newfmt!==false) && (len>1) && (ks[0]==='$arr') && (ks[1]==='len')) { + // this is ROOT-coded array + var arr = null, dflt = (value.$arr==="Bool") ? false : 0; + switch (value.$arr) { + case "Int8" : arr = new Int8Array(value.len); break; + case "Uint8" : arr = new Uint8Array(value.len); break; + case "Int16" : arr = new Int16Array(value.len); break; + case "Uint16" : arr = new Uint16Array(value.len); break; + case "Int32" : arr = new Int32Array(value.len); break; + case "Uint32" : arr = new Uint32Array(value.len); break; + case "Float32" : arr = new Float32Array(value.len); break; + case "Int64" : + case "Uint64" : + case "Float64" : arr = new Float64Array(value.len); break; + default : arr = new Array(value.len); break; + } + for (var k=0;k<value.len;++k) arr[k] = dflt; + + var nkey = 2, p = 0; + while (nkey<len) { + if (ks[nkey][0]=="p") p = value[ks[nkey++]]; // position + if (ks[nkey][0]!=='v') throw new Error('Unexpected member ' + ks[nkey] + ' in array decoding'); + var v = value[ks[nkey++]]; // value + if (typeof v === 'object') { + for (var k=0;k<v.length;++k) arr[p++] = v[k]; + } else { + arr[p++] = v; + if ((nkey<len) && (ks[nkey][0]=='n')) { + var cnt = value[ks[nkey++]]; // counter + while (--cnt) arr[p++] = v; + } + } + } + + return arr; + } + + if ((newfmt!==false) && (len===3) && (ks[0]==='$pair') && (ks[1]==='first') && (ks[2]==='second')) { + newfmt = true; + var f1 = unref_value(value.first), + s1 = unref_value(value.second); + if (f1!==undefined) value.first = f1; + if (s1!==undefined) value.second = s1; + value._typename = value['$pair']; + delete value['$pair']; + return; // pair object is not counted in the objects map + } + + // debug code, can be commented out later + if (map.indexOf(value) >= 0) { + JSROOT.console('should never happen - object already in the map'); + return; + } + + // add object to object map + map.push(value); + + // add methods to all objects, where _typename is specified + if ('_typename' in value) JSROOT.addMethods(value); + + for (k = 0; k < len; ++k) { + i = ks[k]; + res = unref_value(value[i]); + if (res!==undefined) value[i] = res; + } + } + + unref_value(obj); + + return obj; + } + + JSROOT.debug = 0; + + /** @summary Just copies (not clone) all fields from source to the target object + * @desc This is simple replacement of jQuery.extend method + * @private */ + JSROOT.extend = function(tgt, src) { + if ((src === null) || (typeof src !== 'object')) return tgt; + if ((tgt === null) || (typeof tgt !== 'object')) tgt = {}; + + for (var k in src) + tgt[k] = src[k]; + + return tgt; + } + + /** @summary Make deep clone of the object, including all sub-objects + * @private */ + JSROOT.clone = function(src, map, nofunc) { + if (src === null) return null; + + if (!map) { + map = { obj:[], clones:[], nofunc: nofunc }; + } else { + var i = map.obj.indexOf(src); + if (i>=0) return map.clones[i]; + } + + var proto = Object.prototype.toString.apply(src); + + // process normal array + if (proto === '[object Array]') { + var tgt = []; + map.obj.push(src); + map.clones.push(tgt); + for (var i = 0; i < src.length; ++i) + if (typeof src[i] === 'object') + tgt.push(JSROOT.clone(src[i], map)); + else + tgt.push(src[i]); + + return tgt; + } + + // process typed array + if ((proto.indexOf('[object ') == 0) && (proto.indexOf('Array]') == proto.length-6)) { + var tgt = []; + map.obj.push(src); + map.clones.push(tgt); + for (var i = 0; i < src.length; ++i) + tgt.push(src[i]); + + return tgt; + } + + var tgt = {}; + map.obj.push(src); + map.clones.push(tgt); + + for (var k in src) { + if (typeof src[k] === 'object') + tgt[k] = JSROOT.clone(src[k], map); + else + if (!map.nofunc || (typeof src[k]!=='function')) + tgt[k] = src[k]; + } + + return tgt; + } + + /** + * @summary Clear all functions from the contained objects + * + * Only such objects can be cloned when transfer to Worker or converted into JSON + * @param {object} src object where functions will be removed + * @returns {object} same object after all functions are removed + * @private + */ + JSROOT.clear_func = function(src, map) { + if (src === null) return src; + + var proto = Object.prototype.toString.apply(src); + + if (proto === '[object Array]') { + for (var n=0;n<src.length;n++) + if (typeof src[n] === 'object') + JSROOT.clear_func(src[n], map); + return src; + } + + if ((proto.indexOf('[object ') == 0) && (proto.indexOf('Array]') == proto.length-6)) return src; + + if (!map) map = []; + var nomap = (map.length == 0); + if ('__clean_func__' in src) return src; + + map.push(src); + src['__clean_func__'] = true; + + for (var k in src) { + if (typeof src[k] === 'object') + JSROOT.clear_func(src[k], map); + else + if (typeof src[k] === 'function') delete src[k]; + } + + if (nomap) + for (var n=0;n<map.length;++n) + delete map[n]['__clean_func__']; + + return src; + } + + /** + * @summary Parse JSON code produced with TBufferJSON. + * + * @param {string} json string to parse + * @return {object|null} returns parsed object + */ + JSROOT.parse = function(json) { + if (!json) return null; + var obj = JSON.parse(json); + if (obj) obj = this.JSONR_unref(obj); + return obj; + } + + /** + * @summary Parse multi.json request results + * @desc Method should be used to parse JSON code, produced by multi.json request of THttpServer + * + * @param {string} json string to parse + * @return {Array|null} returns array of parsed elements + */ + JSROOT.parse_multi = function(json) { + if (!json) return null; + var arr = JSON.parse(json); + if (arr && arr.length) + for (var i=0;i<arr.length;++i) + arr[i] = this.JSONR_unref(arr[i]); + return arr; + } + + /** + * @summary Method converts JavaScript object into ROOT-like JSON + * + * @desc Produced JSON can be used in JSROOT.parse() again + * When performed properly, JSON can be used in TBufferJSON to read data back with C++ + */ + JSROOT.toJSON = function(obj) { + if (!obj || typeof obj !== 'object') return ""; + + var map = []; // map of stored objects + + function copy_value(value) { + if (typeof value === "function") return undefined; + + if ((value===undefined) || (value===null) || (typeof value !== 'object')) return value; + + var proto = Object.prototype.toString.apply(value); + + // typed array need to be converted into normal array, otherwise looks strange + if ((proto.indexOf('[object ') == 0) && (proto.indexOf('Array]') == proto.length-6)) { + var arr = new Array(value.length) + for (var i = 0; i < value.length; ++i) + arr[i] = copy_value(value[i]); + return arr; + } + + // this is how reference is code + var refid = map.indexOf(value); + if (refid >= 0) return { $ref: refid }; + + var ks = Object.keys(value), len = ks.length, tgt = {}; + + if ((len == 3) && (ks[0]==='$pair') && (ks[1]==='first') && (ks[2]==='second')) { + // special handling of pair objects which does not included into objects map + tgt.$pair = value.$pair; + tgt.first = copy_value(value.first); + tgt.second = copy_value(value.second); + return tgt; + } + + map.push(value); + + for (var k = 0; k < len; ++k) { + var name = ks[k]; + tgt[name] = copy_value(value[name]); + } + + return tgt; + } + + var tgt = copy_value(obj); + + return JSON.stringify(tgt); + } + + /** + * @summary Analyzes document.URL and extracts options after '?' mark + * + * @desc Following options supported ?opt1&opt2=3 + * In case of opt1 empty string will be returned, in case of opt2 '3' + * If option not found, null is returned (or default value value is provided) + * + * @param {string} opt option to search + * @param {string} full URL with options, document.URL will be used when not specified + * @returns {string|null} found value + * @private + */ + JSROOT.GetUrlOption = function(opt, url, dflt) { + + if (dflt === undefined) dflt = null; + if ((opt===null) || (typeof opt != 'string') || (opt.length==0)) return dflt; + + if (!url) { + if (JSROOT.gStyle.IgnoreUrlOptions || (typeof document === 'undefined')) return dflt; + url = document.URL; + } + + var pos = url.indexOf("?"), nquotes; + if (pos<0) return dflt; + url = decodeURI(url.slice(pos+1)); + + while (url.length>0) { + + if (url==opt) return ""; + + // try to correctly handle quotes in the URL + pos = 0; nquotes = 0; + while ((pos < url.length) && ((nquotes!==0) || (url[pos]!=="&"))) { + switch (url[pos]) { + case "'": if (nquotes>=0) nquotes = (nquotes+1)%2; break; + case '"': if (nquotes<=0) nquotes = (nquotes-1)%2; break; + } + pos++; + } + + if (url.indexOf(opt) == 0) { + if (url[opt.length]=="&") return ""; + + if (url[opt.length]==="=") { + url = url.slice(opt.length+1, pos); + if (((url[0]==="'") || (url[0]==='"')) && (url[0]===url[url.length-1])) url = url.substr(1, url.length-2); + return url; + } + } + + url = url.substr(pos+1); + } + return dflt; + } + + /** + * @summary Parse string value as array. + * + * @desc It could be just simple string: "value" or + * array with or without string quotes: [element], ['elem1',elem2] + * + * @private + */ + JSROOT.ParseAsArray = function(val) { + + var res = []; + + if (typeof val != 'string') return res; + + val = val.trim(); + if (val=="") return res; + + // return as array with single element + if ((val.length<2) || (val[0]!='[') || (val[val.length-1]!=']')) { + res.push(val); return res; + } + + // try to split ourself, checking quotes and brackets + var nbr = 0, nquotes = 0, ndouble = 0, last = 1; + + for (var indx = 1; indx < val.length; ++indx) { + if (nquotes > 0) { + if (val[indx]==="'") nquotes--; + continue; + } + if (ndouble > 0) { + if (val[indx]==='"') ndouble--; + continue; + } + switch (val[indx]) { + case "'": nquotes++; break; + case '"': ndouble++; break; + case "[": nbr++; break; + case "]": if (indx < val.length - 1) { nbr--; break; } + case ",": + if (nbr === 0) { + var sub = val.substring(last, indx).trim(); + if ((sub.length>1) && (sub[0]==sub[sub.length-1]) && ((sub[0]=='"') || (sub[0]=="'"))) + sub = sub.substr(1, sub.length-2); + res.push(sub); + last = indx+1; + } + break; + } + } + + if (res.length === 0) + res.push(val.substr(1, val.length-2).trim()); + + return res; + } + + /** + * @summary Special handling of URL options to produce array. + * + * @desc If normal option is specified ...?opt=abc, than array with single element will be created + * one could specify normal JSON array ...?opts=['item1','item2'] + * but also one could skip quotes ...?opts=[item1,item2] + * @private + */ + JSROOT.GetUrlOptionAsArray = function(opt, url) { + + var res = []; + + while (opt.length>0) { + var separ = opt.indexOf(";"); + var part = (separ>0) ? opt.substr(0, separ) : opt; + + if (separ>0) opt = opt.substr(separ+1); else opt = ""; + + var canarray = true; + if (part[0]=='#') { part = part.substr(1); canarray = false; } + + var val = this.GetUrlOption(part, url, null); + + if (canarray) res = res.concat(JSROOT.ParseAsArray(val)); + else if (val!==null) res.push(val); + } + return res; + } + + /** + * @summary Find function with given name. + * + * @desc Function name may include several namespaces like 'JSROOT.Painter.drawFrame' + * + * @private + */ + JSROOT.findFunction = function(name) { + if (typeof name === 'function') return name; + if (typeof name !== 'string') return null; + var names = name.split('.'), elem = null; + if (typeof window === 'object') elem = window; + if (names[0]==='JSROOT') { elem = this; names.shift(); } + + for (var n=0;elem && (n<names.length);++n) + elem = elem[names[n]]; + + return (typeof elem == 'function') ? elem : null; + } + + /** + * @summary Generic method to invoke callback function. + * + * @param {object|function} func either normal function or container like + * { obj: object_pointer, func: name of method to call } + * @param arg1 first optional argument of callback + * @param arg2 second optional argument of callback + * + * @private + */ + JSROOT.CallBack = function(func, arg1, arg2) { + + if (typeof func == 'string') func = JSROOT.findFunction(func); + + if (!func) return; + + if (typeof func == 'function') return func(arg1,arg2); + + if (typeof func != 'object') return; + + if (('obj' in func) && ('func' in func) && + (typeof func.obj == 'object') && (typeof func.func == 'string') && + (typeof func.obj[func.func] == 'function')) { + return func.obj[func.func](arg1, arg2); + } + } + + /** + * @summary Create asynchronous XMLHttpRequest object. + * + * @desc One should call req.send() to submit request + * kind of the request can be: + * + * - "bin" - abstract binary data, result as string + * - "buf" - abstract binary data, result as ArrayBuffer (default) + * - "text" - returns req.responseText + * - "object" - returns JSROOT.parse(req.responseText) + * - "multi" - returns correctly parsed multi.json request + * - "xml" - returns req.responseXML + * - "head" - returns request itself, uses "HEAD" method + * + * Result will be returned to the callback function. + * Request will be set as this pointer in the callback. + * If failed, request returns null + * + * @param {string} url - URL for the request + * @param {string} kind - kind of requested data + * @param {function} user_call_back - called when request is completed + * @returns {object} XMLHttpRequest object + * + * @example + * JSROOT.NewHttpRequest("https://root.cern/js/files/thstack.json.gz", "object", + * function(res) { + * if (res) console.log('Retrieve object', res._typename); + * else console.error('Fail to get object'); + * }).send(); + */ + + JSROOT.NewHttpRequest = function(url, kind, user_call_back) { + + var xhr = null; + if (JSROOT.nodejs) { + var nodejs_class = require("xhr2"); + xhr = new nodejs_class(); + } else { + xhr = new XMLHttpRequest(); + } + + function callback(res) { + // we set pointer on request when calling callback + if (typeof user_call_back == 'function') user_call_back.call(xhr, res); + } + + if (!kind) kind = "buf"; + + var pthis = this, method = "GET", async = true, p = kind.indexOf(";sync"); + if (p>0) { kind.substr(0,p); async = false; } + if (kind === "head") method = "HEAD"; else + if ((kind === "post") || (kind === "multi") || (kind === "posttext")) method = "POST"; + + xhr.onreadystatechange = function() { + + if (xhr.did_abort) return; + + if ((xhr.readyState === 2) && xhr.expected_size) { + var len = parseInt(xhr.getResponseHeader("Content-Length")); + if (!isNaN(len) && (len>xhr.expected_size)) { + xhr.did_abort = true; + xhr.abort(); + console.warn('Server response size ' + len + ' larger than expected ' + xhr.expected_size + ' Abort I/O operation'); + return callback(null); + } + } + + if (xhr.readyState != 4) return; + + if ((xhr.status != 200) && (xhr.status != 206) && !JSROOT.browser.qt5 && + // in these special cases browsers not always set status + !((xhr.status == 0) && ((url.indexOf("file://")==0) || (url.indexOf("blob:")==0)))) { + return callback(null); + } + + if (JSROOT.nodejs && (method == "GET") && (kind === "object") && + (xhr.responseType == "arraybuffer") && (xhr.getResponseHeader("content-encoding") == "gzip")) { + // special handling of gzipped JSON objects in Node.js + var zlib = require('zlib'), + str = zlib.unzipSync(Buffer.from(xhr.response)); + return callback(pthis.parse(str)); + } + + switch(kind) { + case "xml": return callback(xhr.responseXML); + case "posttext": + case "text": return callback(xhr.responseText); + case "object": return callback(pthis.parse(xhr.responseText)); + case "multi": return callback(pthis.parse_multi(xhr.responseText)); + case "head": return callback(xhr); + } + + // if no response type is supported, return as text (most probably, will fail) + if (! ('responseType' in xhr)) + return callback(xhr.responseText); + + if ((kind=="bin") && ('byteLength' in xhr.response)) { + // if string representation in requested - provide it + + var filecontent = "", u8Arr = new Uint8Array(xhr.response); + for (var i = 0; i < u8Arr.length; ++i) + filecontent += String.fromCharCode(u8Arr[i]); + + return callback(filecontent); + } + + callback(xhr.response); + } + + xhr.open(method, url, async); + + if ((kind == "bin") || (kind == "buf")) xhr.responseType = 'arraybuffer'; + + if (JSROOT.nodejs && (method == "GET") && (kind === "object") && (url.indexOf('.json.gz')>0)) + xhr.responseType = 'arraybuffer'; + + return xhr; + } + + /** + * @summary Dynamic script loader + * + * @desc One could specify list of scripts or style files, separated by semicolon ';' + * one can prepend file name with '$$$' - than file will be loaded from JSROOT location + * This location can be set by JSROOT.source_dir or it will be detected automatically + * by the position of JSRootCore.js file, which must be loaded by normal methods: + * <script type="text/javascript" src="scripts/JSRootCore.js"></script> + * When all scripts are loaded, callback function will be called + * + * @private + */ + JSROOT.loadScript = function(urllist, callback, debugout, from_previous) { + + delete JSROOT.complete_script_load; + + if (from_previous) { + if (debugout) + document.getElementById(debugout).innerHTML = ""; + else + JSROOT.progress(); + + if (!urllist) return JSROOT.CallBack(callback); + } + + if (!urllist) return JSROOT.CallBack(callback); + + var filename = urllist, separ = filename.indexOf(";"), + isrootjs = false, isbower = false; + + if (separ>0) { + filename = filename.substr(0, separ); + urllist = urllist.substr(separ+1); + } else { + urllist = ""; + } + + var completeLoad = JSROOT.loadScript.bind(JSROOT, urllist, callback, debugout, true); + + if (filename.indexOf('&&&scripts/')===0) { + isrootjs = true; + filename = filename.slice(3); + if (JSROOT.use_full_libs) filename = "libs/" + filename.slice(8, filename.length-7) + ".js"; + } else if (filename.indexOf("$$$")===0) { + isrootjs = true; + filename = filename.slice(3); + if ((filename.indexOf("style/")==0) && JSROOT.source_min && + (filename.lastIndexOf('.css')==filename.length-4) && + (filename.indexOf('.min.css')<0)) + filename = filename.slice(0, filename.length-4) + '.min.css'; + } else if (filename.indexOf("###")===0) { + isbower = true; + filename = filename.slice(3); + } + + if (JSROOT.nodejs) { + if ((filename.indexOf("scripts/")===0) && (filename.indexOf(".js")>0)) { + console.log('load', filename); + require("." + filename.substr(7)); + } + return completeLoad(); + } + + var isstyle = filename.indexOf('.css') > 0; + + if (isstyle) { + var styles = document.getElementsByTagName('link'); + for (var n = 0; n < styles.length; ++n) { + if (!styles[n].href || (styles[n].type !== 'text/css') || (styles[n].rel !== 'stylesheet')) continue; + + if (styles[n].href.indexOf(filename)>=0) return completeLoad(); + } + + } else { + var scripts = document.getElementsByTagName('script'); + + for (var n = 0; n < scripts.length; ++n) { + var src = scripts[n].src; + if (!src) continue; + + if ((src.indexOf(filename)>=0) && (src.indexOf("load=")<0)) + // avoid wrong decision when script name is specified as more argument + return completeLoad(); + } + } + + if (isrootjs && JSROOT.source_dir) filename = JSROOT.source_dir + filename; else + if (isbower && (JSROOT.bower_dir!==null)) filename = JSROOT.bower_dir + filename; + + var element = null; + + if (debugout) + document.getElementById(debugout).innerHTML = "loading " + filename + " ..."; + else + JSROOT.progress("loading " + filename + " ..."); + + if (JSROOT.nocache && isrootjs && (filename.indexOf("?")<0)) + filename += "?stamp=" + JSROOT.nocache; + + if (isstyle) { + element = document.createElement("link"); + element.setAttribute("rel", "stylesheet"); + element.setAttribute("type", "text/css"); + element.setAttribute("href", filename); + } else { + element = document.createElement("script"); + element.setAttribute('type', "text/javascript"); + element.setAttribute('src', filename); + } + + JSROOT.complete_script_load = completeLoad; + + if (element.readyState) { // Internet Explorer specific + element.onreadystatechange = function() { + if (element.readyState == "loaded" || element.readyState == "complete") { + element.onreadystatechange = null; + if (JSROOT.complete_script_load) JSROOT.complete_script_load(); + } + } + } else { // Other browsers + element.onload = function() { + element.onload = null; + if (JSROOT.complete_script_load) JSROOT.complete_script_load(); + } + } + + document.getElementsByTagName("head")[0].appendChild(element); + } + + /** @summary Load JSROOT functionality. + * + * @desc As first argument, required components should be specifed: + * + * - 'io' TFile functionality + * - 'tree' TTree support + * - '2d' basic 2d graphic (TCanvas/TPad/TFrame) + * - '3d' basic 3d graphic (three.js) + * - 'hist' histograms 2d graphic + * - 'hist3d' histograms 3d graphic + * - 'more2d' extra 2d graphic (TGraph, TF1) + * - 'v7' ROOT v7 graphics + * - 'v7hist' ROOT v7 histograms + * - 'v7more' ROOT v7 special classes + * - 'math' some methods from TMath class + * - 'jq' jQuery and jQuery-ui + * - 'hierarchy' hierarchy browser + * - 'jq2d' jQuery-dependent part of hierarchy + * - 'openui5' OpenUI5 and related functionality + * - 'geom' TGeo support + * - 'simple' for basic user interface + * - 'load:<path/script.js>' list of user-specific scripts at the end of kind string + * + * One could combine several compopnents, separating them by semicolon. + * Depending of available components, either require.js or plain script loading will be used + * + * @param {string} kind - modules to load + * @param {function} callback - called when all specified modules are loaded + * + * @example + * JSROOT.AssertPrerequisites("io;tree", function() { + * var selector = new JSROOT.TSelector; + * }); + */ + + JSROOT.AssertPrerequisites = function(kind, callback, debugout) { + // one could specify kind of requirements + + var jsroot = JSROOT; + + if (jsroot.doing_assert === undefined) jsroot.doing_assert = []; + if (jsroot.ready_modules === undefined) jsroot.ready_modules = []; + + if (!kind || (typeof kind !== 'string')) + return jsroot.CallBack(callback); + + if (kind === '__next__') { + if (jsroot.doing_assert.length==0) return; + var req = jsroot.doing_assert[0]; + if (req.running) return; + kind = req._kind; + callback = req._callback; + debugout = req._debug; + } else { + jsroot.doing_assert.push({_kind:kind, _callback:callback, _debug: debugout}); + if (jsroot.doing_assert.length > 1) return; + } + + function normal_callback() { + var req = jsroot.doing_assert.shift(); + for (var n=0;n<req.modules.length;++n) + jsroot.ready_modules.push(req.modules[n]); + jsroot.CallBack(req._callback); + jsroot.AssertPrerequisites('__next__'); + } + + jsroot.doing_assert[0].running = true; + + if (kind[kind.length-1]!=";") kind+=";"; + + var ext = jsroot.source_min ? ".min" : "", + need_jquery = false, + use_require = (typeof define === "function") && define.amd, + use_bower = jsroot.bower_dir!==null, + mainfiles = "", + extrafiles = "", // scripts for direct loading + modules = [], // modules used for require.js + load_callback = normal_callback; + + if ((kind.indexOf('io;')>=0) || (kind.indexOf('tree;')>=0)) + if (jsroot.sources.indexOf("io")<0) { + mainfiles += "&&&scripts/rawinflate.min.js;" + + "$$$scripts/JSRootIOEvolution" + ext + ".js;"; + modules.push('rawinflate', 'JSRootIOEvolution'); + } + + if ((kind.indexOf('math;')>=0) || (kind.indexOf('tree;')>=0) || (kind.indexOf('more2d;')>=0)) + if (jsroot.sources.indexOf("math")<0) { + mainfiles += '$$$scripts/JSRootMath' + ext + ".js;"; + modules.push('JSRootMath'); + } + + if (kind.indexOf('tree;')>=0) + if (jsroot.sources.indexOf("tree")<0) { + mainfiles += "$$$scripts/JSRootTree" + ext + ".js;"; + modules.push('JSRootTree'); + } + + if ((kind.indexOf('2d;')>=0) || (kind.indexOf('v6;')>=0) || (kind.indexOf('v7;')>=0) || + (kind.indexOf("3d;")>=0) || (kind.indexOf("geom;")>=0) || (kind.indexOf("openui5;")>=0)) { + if (!use_require && (typeof d3 != 'object') && (jsroot._test_d3_ === undefined)) { + mainfiles += use_bower ? '###d3/d3.min.js;' : '&&&scripts/d3.min.js;'; + jsroot._test_d3_ = null; + } + if (jsroot.sources.indexOf("2d") < 0) { + modules.push('JSRootPainter'); + mainfiles += '$$$scripts/JSRootPainter' + ext + ".js;"; + extrafiles += '$$$style/JSRootPainter' + ext + '.css;'; + } + if ((jsroot.sources.indexOf("v6") < 0) && (kind.indexOf('v7;') < 0)) { + mainfiles += '$$$scripts/JSRootPainter.v6' + ext + ".js;"; + modules.push('JSRootPainter.v6'); + } + } + + if (kind.indexOf('jq;')>=0) need_jquery = true; + + if (((kind.indexOf('hist;')>=0) || (kind.indexOf('hist3d;')>=0)) && (jsroot.sources.indexOf("hist")<0)) { + mainfiles += '$$$scripts/JSRootPainter.hist' + ext + ".js;"; + modules.push('JSRootPainter.hist'); + } + + if ((kind.indexOf('v6;')>=0) && (jsroot.sources.indexOf("v6")<0)) { + mainfiles += '$$$scripts/JSRootPainter.v6' + ext + ".js;"; + modules.push('JSRootPainter.v6'); + } + + if ((kind.indexOf('v7;')>=0) && (jsroot.sources.indexOf("v7")<0)) { + mainfiles += '$$$scripts/JSRootPainter.v7' + ext + ".js;"; + modules.push('JSRootPainter.v7'); + } + + if ((kind.indexOf('v7hist;')>=0) && (jsroot.sources.indexOf("v7hist")<0)) { + mainfiles += '$$$scripts/JSRootPainter.v7hist' + ext + ".js;"; + modules.push('JSRootPainter.v7hist'); + } + + if ((kind.indexOf('v7more;')>=0) && (jsroot.sources.indexOf("v7more")<0)) { + mainfiles += '$$$scripts/JSRootPainter.v7more' + ext + ".js;"; + modules.push('JSRootPainter.v7more'); + } + + if ((kind.indexOf('more2d;')>=0) && (jsroot.sources.indexOf("more2d")<0)) { + mainfiles += '$$$scripts/JSRootPainter.more' + ext + ".js;"; + modules.push('JSRootPainter.more'); + } + + if (((kind.indexOf('hierarchy;')>=0) || (kind.indexOf('jq2d;')>=0) || (kind.indexOf('openui5;')>=0)) && (jsroot.sources.indexOf("hierarchy")<0)) { + mainfiles += '$$$scripts/JSRootPainter.hierarchy' + ext + ".js;"; + modules.push('JSRootPainter.hierarchy'); + } + + if (((kind.indexOf('jq2d;')>=0) || (kind.indexOf('openui5;')>=0)) && (jsroot.sources.indexOf("jq2d")<0)) { + mainfiles += '$$$scripts/JSRootPainter.jquery' + ext + ".js;"; + modules.push('JSRootPainter.jquery'); + need_jquery = true; + } + + if ((kind.indexOf('openui5;')>=0) && (jsroot.sources.indexOf("openui5")<0)) { + mainfiles += '$$$scripts/JSRootPainter.openui5' + ext + ".js;"; + modules.push('JSRootPainter.openui5'); + } + + if (((kind.indexOf("3d;")>=0) || (kind.indexOf("geom;")>=0)) && (jsroot.sources.indexOf("3d")<0)) { + mainfiles += (use_bower ? "###threejs/build/" : "&&&scripts/") + "three.min.js;" + + "&&&scripts/three.extra.min.js;"; + modules.push("threejs", "threejs_all"); + mainfiles += "$$$scripts/JSRoot3DPainter" + ext + ".js;"; + modules.push('JSRoot3DPainter'); + } + + if ((kind.indexOf('hist3d;')>=0) && (jsroot.sources.indexOf("hist3d")<0)) { + mainfiles += '$$$scripts/JSRootPainter.hist3d' + ext + ".js;"; + modules.push('JSRootPainter.hist3d'); + } + + if ((kind.indexOf("geom;")>=0) && (jsroot.sources.indexOf("geom")<0)) { + if (!JSROOT.nodjs && (typeof window !='undefined')) + mainfiles += (use_bower ? "###dat.gui" : "&&&scripts") + "/dat.gui.min.js;"; + mainfiles += "$$$scripts/ThreeCSG" + ext + ".js;" + + "$$$scripts/JSRootGeoBase" + ext + ".js;" + + "$$$scripts/JSRootGeoPainter" + ext + ".js;"; + extrafiles += "$$$style/JSRootGeoPainter" + ext + ".css;"; + modules.push('dat.gui', 'ThreeCSG', 'JSRootGeoBase', 'JSRootGeoPainter'); + } + + if (kind.indexOf("mathjax;")>=0) { + + if (typeof MathJax == 'undefined') { + mainfiles += (use_bower ? "###MathJax/MathJax.js" : "https://root.cern/js/mathjax/latest/MathJax.js") + + "?config=TeX-AMS-MML_SVG&delayStartupUntil=configured"; + modules.push('MathJax'); + + load_callback = function() { + MathJax.Hub.Config({ jax: ["input/TeX", "output/SVG"], + TeX: { extensions: ["color.js"] }, + SVG: { mtextFontInherit: true, minScaleAdjust: 100, matchFontHeight: true, useFontCache: false } }); + + MathJax.Hub.Register.StartupHook("SVG Jax Ready",function () { + var VARIANT = MathJax.OutputJax.SVG.FONTDATA.VARIANT; + VARIANT["normal"].fonts.unshift("MathJax_SansSerif"); + VARIANT["bold"].fonts.unshift("MathJax_SansSerif-bold"); + VARIANT["italic"].fonts.unshift("MathJax_SansSerif"); + VARIANT["-tex-mathit"].fonts.unshift("MathJax_SansSerif"); + }); + + MathJax.Hub.Configured(); + + normal_callback(); + } + } + } + + if (kind.indexOf("simple;")>=0) { + need_jquery = true; + } + + if (need_jquery && !jsroot.load_jquery) { + var has_jq = (typeof jQuery != 'undefined'), lst_jq = ""; + + if (has_jq) + jsroot.console('Reuse existing jQuery ' + jQuery.fn.jquery + ", required 3.1.1", debugout); + else + lst_jq += (use_bower ? "###jquery/dist" : "&&&scripts") + "/jquery.min.js;"; + if (has_jq && typeof $.ui != 'undefined') + jsroot.console('Reuse existing jQuery-ui ' + $.ui.version + ", required 1.12.1", debugout); + else { + lst_jq += (use_bower ? "###jquery-ui" : "&&&scripts") + '/jquery-ui.min.js;'; + extrafiles += '$$$style/jquery-ui' + ext + '.css;'; + } + + if (jsroot.touches) { + lst_jq += use_bower ? '###jqueryui-touch-punch/jquery.ui.touch-punch.min.js;' : '$$$scripts/touch-punch.min.js;'; + modules.push('jqueryui-touch-punch'); + } + + modules.splice(0, 0, 'jquery', 'jquery-ui', 'jqueryui-mousewheel'); + mainfiles = lst_jq + mainfiles; + + jsroot.load_jquery = true; + } + + var pos = kind.indexOf("user:"); + if (pos<0) pos = kind.indexOf("load:"); + if (pos>=0) extrafiles += kind.slice(pos+5); + + // check if modules already loaded + for (var n=modules.length-1;n>=0;--n) + if (jsroot.ready_modules.indexOf(modules[n])>=0) + modules.splice(n,1); + + // no modules means no main files + if (modules.length===0) mainfiles = ""; + + jsroot.doing_assert[0].modules = modules; + + if ((modules.length>0) && (typeof define === "function") && define.amd) { + jsroot.console("loading " + JSON.stringify(modules) + " with require.js", debugout); + require(modules, function() { + jsroot.loadScript(extrafiles, load_callback, debugout); + }); + } else { + jsroot.loadScript(mainfiles + extrafiles, load_callback, debugout); + } + } + + // function can be used to open ROOT file, I/O functionality will be loaded when missing + JSROOT.OpenFile = function(filename, callback) { + JSROOT.AssertPrerequisites("io", function() { + JSROOT.OpenFile(filename, callback); + }); + } + + // function can be used to draw supported ROOT classes, + // required functionality will be loaded automatically + // if painter pointer required, one should load '2d' functionality itself + // or use callback function which provides painter pointer as first argument + // defined in JSRootPainter.js + JSROOT.draw = function(divid, obj, opt, callback) { + JSROOT.AssertPrerequisites("2d", function() { + JSROOT.draw(divid, obj, opt, callback); + }); + } + + // redraw object on given element + // defined in JSRootPainter.js + JSROOT.redraw = function(divid, obj, opt, callback) { + JSROOT.AssertPrerequisites("2d", function() { + JSROOT.redraw(divid, obj, opt, callback); + }); + } + + // Create SVG, defined in JSRootPainter.js + JSROOT.MakeSVG = function(args, callback) { + JSROOT.AssertPrerequisites("2d", function() { + JSROOT.MakeSVG(args, callback); + }); + } + + /** @summary Method to build JSROOT GUI with browser + * @private + */ + JSROOT.BuildSimpleGUI = function(user_scripts, andThen) { + if (typeof user_scripts == 'function') { + andThen = user_scripts; + user_scripts = null; + } + + var debugout = null, + nobrowser = JSROOT.GetUrlOption('nobrowser')!=null, + requirements = "2d;hierarchy;", + simplegui = document.getElementById('simpleGUI'); + + if (JSROOT.GetUrlOption('libs')!==null) JSROOT.use_full_libs = true; + + if (simplegui) { + debugout = 'simpleGUI'; + if (JSROOT.GetUrlOption('file') || JSROOT.GetUrlOption('files')) requirements += "io;"; + if (simplegui.getAttribute('nobrowser') && (simplegui.getAttribute('nobrowser')!="false")) nobrowser = true; + } else if (document.getElementById('onlineGUI')) { debugout = 'onlineGUI'; + } else if (document.getElementById('drawGUI')) { debugout = 'drawGUI'; nobrowser = true; + } else requirements += "io;"; + + if (user_scripts == 'check_existing_elements') { + user_scripts = null; + if (debugout == null) return; + } + + if (!nobrowser) requirements += 'jq2d;'; + + if (!user_scripts) user_scripts = JSROOT.GetUrlOption("autoload") || JSROOT.GetUrlOption("load"); + + if (user_scripts) requirements += "load:" + user_scripts + ";"; + + JSROOT.AssertPrerequisites(requirements, function() { + JSROOT.CallBack(JSROOT.findFunction(nobrowser ? 'JSROOT.BuildNobrowserGUI' : 'JSROOT.BuildGUI')); + JSROOT.CallBack(andThen); + }, debugout); + } + + /** @summary Create some ROOT classes + * + * @param {string} typename - ROOT class name + * @example + * var obj = JSROOT.Create("TNamed"); + * obj.fName = "name"; + * obj.fTitle = "title"; + */ + JSROOT.Create = function(typename, target) { + var obj = target || {}; + + switch (typename) { + case 'TObject': + JSROOT.extend(obj, { fUniqueID: 0, fBits: 0x3000008 }); + break; + case 'TNamed': + JSROOT.extend(obj, { fUniqueID: 0, fBits: 0x3000008, fName: "", fTitle: "" }); + break; + case 'TList': + case 'THashList': + JSROOT.extend(obj, { name: typename, arr : [], opt : [] }); + break; + case 'TAttAxis': + JSROOT.extend(obj, { fNdivisions: 510, fAxisColor: 1, + fLabelColor: 1, fLabelFont: 42, fLabelOffset: 0.005, fLabelSize: 0.035, fTickLength: 0.03, + fTitleOffset: 1, fTitleSize: 0.035, fTitleColor: 1, fTitleFont : 42 }); + break; + case 'TAxis': + JSROOT.Create("TNamed", obj); + JSROOT.Create("TAttAxis", obj); + JSROOT.extend(obj, { fNbins: 0, fXmin: 0, fXmax: 0, fXbins : [], fFirst: 0, fLast: 0, + fBits2: 0, fTimeDisplay: false, fTimeFormat: "", fLabels: null, fModLabs: null }); + break; + case 'TAttLine': + JSROOT.extend(obj, { fLineColor: 1, fLineStyle: 1, fLineWidth: 1 }); + break; + case 'TAttFill': + JSROOT.extend(obj, { fFillColor: 0, fFillStyle: 0 } ); + break; + case 'TAttMarker': + JSROOT.extend(obj, { fMarkerColor: 1, fMarkerStyle: 1, fMarkerSize: 1. }); + break; + case 'TLine': + JSROOT.Create("TObject", obj); + JSROOT.Create("TAttLine", obj); + JSROOT.extend(obj, { fX1: 0, fX2: 1, fY1: 0, fY2: 1 }); + break; + case 'TBox': + JSROOT.Create("TObject", obj); + JSROOT.Create("TAttLine", obj); + JSROOT.Create("TAttFill", obj); + JSROOT.extend(obj, { fX1: 0, fX2: 1, fY1: 0, fY2: 1 }); + break; + case 'TPave': + JSROOT.Create("TBox", obj); + JSROOT.extend(obj, { fX1NDC : 0., fY1NDC: 0, fX2NDC: 1, fY2NDC: 1, + fBorderSize: 0, fInit: 1, fShadowColor: 1, + fCornerRadius: 0, fOption: "blNDC", fName: "title" }); + break; + case 'TAttText': + JSROOT.extend(obj, { fTextAngle: 0, fTextSize: 0, fTextAlign: 22, fTextColor: 1, fTextFont: 42}); + break; + case 'TPaveText': + JSROOT.Create("TPave", obj); + JSROOT.Create("TAttText", obj); + JSROOT.extend(obj, { fLabel: "", fLongest: 27, fMargin: 0.05, fLines: JSROOT.Create("TList") }); + break; + case 'TPaveStats': + JSROOT.Create("TPaveText", obj); + JSROOT.extend(obj, { fOptFit: 0, fOptStat: 0, fFitFormat: "", fStatFormat: "", fParent: null }); + break; + case 'TLegend': + JSROOT.Create("TPave", obj); + JSROOT.Create("TAttText", obj); + JSROOT.extend(obj, { fColumnSeparation: 0, fEntrySeparation: 0.1, fMargin: 0.25, fNColumns: 1, fPrimitives: JSROOT.Create("TList") }); + break; + case 'TLegendEntry': + JSROOT.Create("TObject", obj); + JSROOT.Create("TAttText", obj); + JSROOT.Create("TAttLine", obj); + JSROOT.Create("TAttFill", obj); + JSROOT.Create("TAttMarker", obj); + JSROOT.extend(obj, { fLabel: "", fObject: null, fOption: "" }); + break; + case 'TText': + JSROOT.Create("TNamed", obj); + JSROOT.Create("TAttText", obj); + JSROOT.extend(obj, { fLimitFactorSize: 3, fOriginSize: 0.04 }); + break; + case 'TLatex': + JSROOT.Create("TText", obj); + JSROOT.Create("TAttLine", obj); + JSROOT.extend(obj, { fX: 0, fY: 0 }); + break; + case 'TObjString': + JSROOT.Create("TObject", obj); + JSROOT.extend(obj, { fString: "" }); + break; + case 'TH1': + JSROOT.Create("TNamed", obj); + JSROOT.Create("TAttLine", obj); + JSROOT.Create("TAttFill", obj); + JSROOT.Create("TAttMarker", obj); + + JSROOT.extend(obj, { + fNcells : 0, + fXaxis: JSROOT.Create("TAxis"), + fYaxis: JSROOT.Create("TAxis"), + fZaxis: JSROOT.Create("TAxis"), + fBarOffset: 0, fBarWidth: 1000, fEntries: 0., + fTsumw: 0., fTsumw2: 0., fTsumwx: 0., fTsumwx2: 0., + fMaximum: -1111., fMinimum: -1111, fNormFactor: 0., fContour: [], + fSumw2: [], fOption: "", + fFunctions: JSROOT.Create("TList"), + fBufferSize: 0, fBuffer: [], fBinStatErrOpt: 0, fStatOverflows: 2 }); + break; + case 'TH1I': + case 'TH1F': + case 'TH1D': + case 'TH1S': + case 'TH1C': + JSROOT.Create("TH1", obj); + obj.fArray = []; + break; + case 'TH2': + JSROOT.Create("TH1", obj); + JSROOT.extend(obj, { fScalefactor: 1., fTsumwy: 0., fTsumwy2: 0, fTsumwxy: 0}); + break; + case 'TH2I': + case 'TH2F': + case 'TH2D': + case 'TH2S': + case 'TH2C': + JSROOT.Create("TH2", obj); + obj.fArray = []; + break; + case 'TH3': + JSROOT.Create("TH1", obj); + JSROOT.extend(obj, { fTsumwy: 0., fTsumwy2: 0, fTsumwz: 0., fTsumwz2: 0, fTsumwxy: 0, fTsumwxz: 0, fTsumwyz: 0 }); + break; + case 'TH3I': + case 'TH3F': + case 'TH3D': + case 'TH3S': + case 'TH3C': + JSROOT.Create("TH3", obj); + obj.fArray = []; + break; + case 'THStack': + JSROOT.Create("TNamed", obj); + JSROOT.extend(obj, { fHists: JSROOT.Create("TList"), fHistogram: null, fMaximum: -1111, fMinimum: -1111 }); + break; + case 'TGraph': + JSROOT.Create("TNamed", obj); + JSROOT.Create("TAttLine", obj); + JSROOT.Create("TAttFill", obj); + JSROOT.Create("TAttMarker", obj); + JSROOT.extend(obj, { fFunctions: JSROOT.Create("TList"), fHistogram: null, + fMaxSize: 0, fMaximum: -1111, fMinimum: -1111, fNpoints: 0, fX: [], fY: [] }); + break; + case 'TGraphAsymmErrors': + JSROOT.Create("TGraph", obj); + JSROOT.extend(obj, { fEXlow: [], fEXhigh: [], fEYlow: [], fEYhigh: []}); + break; + case 'TMultiGraph': + JSROOT.Create("TNamed", obj); + JSROOT.extend(obj, { fFunctions: JSROOT.Create("TList"), fGraphs: JSROOT.Create("TList"), + fHistogram: null, fMaximum: -1111, fMinimum: -1111 }); + break; + case 'TGraphPolargram': + JSROOT.Create("TNamed", obj); + JSROOT.Create("TAttText", obj); + JSROOT.Create("TAttLine", obj); + JSROOT.extend(obj, { fRadian: true, fDegree: false, fGrad: false, fPolarLabelColor: 1, fRadialLabelColor: 1, + fAxisAngle: 0, fPolarOffset: 0.04, fPolarTextSize: 0.04, fRadialOffset: 0.025, fRadialTextSize: 0.035, + fRwrmin: 0, fRwrmax: 1, fRwtmin: 0, fRwtmax: 2*Math.PI, fTickpolarSize: 0.02, + fPolarLabelFont: 62, fRadialLabelFont: 62, fCutRadial: 0, fNdivRad: 508, fNdivPol: 508 }); + break; + case 'TPolyLine': + JSROOT.Create("TObject", obj); + JSROOT.Create("TAttLine", obj); + JSROOT.Create("TAttFill", obj); + JSROOT.extend(obj, { fLastPoint: -1, fN: 0, fOption: "", fX: null, fY: null }); + break; + case 'TGaxis': + JSROOT.Create("TLine", obj); + JSROOT.Create("TAttText", obj); + JSROOT.extend(obj, { fChopt: "", fFunctionName: "", fGridLength: 0, + fLabelColor: 1, fLabelFont: 42, fLabelOffset: 0.005, fLabelSize: 0.035, + fName: "", fNdiv: 12, fTickSize: 0.02, fTimeFormat: "", + fTitle: "", fTitleOffset: 1, fTitleSize: 0.035, + fWmax: 100, fWmin: 0 }); + break; + case 'TAttPad': + JSROOT.extend(obj, { fLeftMargin: JSROOT.gStyle.fPadLeftMargin, + fRightMargin: JSROOT.gStyle.fPadRightMargin, + fBottomMargin: JSROOT.gStyle.fPadBottomMargin, + fTopMargin: JSROOT.gStyle.fPadTopMargin, + fXfile: 2, fYfile: 2, fAfile: 1, fXstat: 0.99, fYstat: 0.99, fAstat: 2, + fFrameFillColor: JSROOT.gStyle.fFrameFillColor, + fFrameFillStyle: JSROOT.gStyle.fFrameFillStyle, + fFrameLineColor: JSROOT.gStyle.fFrameLineColor, + fFrameLineWidth: JSROOT.gStyle.fFrameLineWidth, + fFrameLineStyle: JSROOT.gStyle.fFrameLineStyle, + fFrameBorderSize: JSROOT.gStyle.fFrameBorderSize, + fFrameBorderMode: JSROOT.gStyle.fFrameBorderMode }); + break; + case 'TPad': + JSROOT.Create("TObject", obj); + JSROOT.Create("TAttLine", obj); + JSROOT.Create("TAttFill", obj); + JSROOT.Create("TAttPad", obj); + JSROOT.extend(obj, { fX1: 0, fY1: 0, fX2: 1, fY2: 1, fXtoAbsPixelk: 1, fXtoPixelk: 1, + fXtoPixel: 1, fYtoAbsPixelk: 1, fYtoPixelk: 1, fYtoPixel: 1, + fUtoAbsPixelk: 1, fUtoPixelk: 1, fUtoPixel: 1, fVtoAbsPixelk: 1, + fVtoPixelk: 1, fVtoPixel: 1, fAbsPixeltoXk: 1, fPixeltoXk: 1, + fPixeltoX: 1, fAbsPixeltoYk: 1, fPixeltoYk: 1, fPixeltoY: 1, + fXlowNDC: 0, fYlowNDC: 0, fXUpNDC: 0, fYUpNDC: 0, fWNDC: 1, fHNDC: 1, + fAbsXlowNDC: 0, fAbsYlowNDC: 0, fAbsWNDC: 1, fAbsHNDC: 1, + fUxmin: 0, fUymin: 0, fUxmax: 0, fUymax: 0, fTheta: 30, fPhi: 30, fAspectRatio: 0, + fNumber: 0, fLogx: JSROOT.gStyle.fOptLogx, fLogy: JSROOT.gStyle.fOptLogy, fLogz: JSROOT.gStyle.fOptLogz, + fTickx: JSROOT.gStyle.fPadTickX, + fTicky: JSROOT.gStyle.fPadTickY, + fPadPaint: 0, fCrosshair: 0, fCrosshairPos: 0, fBorderSize: 2, + fBorderMode: 0, fModified: false, + fGridx: JSROOT.gStyle.fPadGridX, + fGridy: JSROOT.gStyle.fPadGridY, + fAbsCoord: false, fEditable: true, fFixedAspectRatio: false, + fPrimitives: JSROOT.Create("TList"), fExecs: null, + fName: "pad", fTitle: "canvas" }); + + break; + case 'TAttCanvas': + JSROOT.extend(obj, { fXBetween: 2, fYBetween: 2, fTitleFromTop: 1.2, + fXdate: 0.2, fYdate: 0.3, fAdate: 1 }); + break; + case 'TCanvas': + JSROOT.Create("TPad", obj); + JSROOT.extend(obj, { fNumPaletteColor: 0, fNextPaletteColor: 0, fDISPLAY: "$DISPLAY", + fDoubleBuffer: 0, fRetained: true, fXsizeUser: 0, + fYsizeUser: 0, fXsizeReal: 20, fYsizeReal: 10, + fWindowTopX: 0, fWindowTopY: 0, fWindowWidth: 0, fWindowHeight: 0, + fCw: 500, fCh: 300, fCatt: JSROOT.Create("TAttCanvas"), + kMoveOpaque: true, kResizeOpaque: true, fHighLightColor: 5, + fBatch: true, kShowEventStatus: false, kAutoExec: true, kMenuBar: true }); + break; + case 'TGeoVolume': + JSROOT.Create("TNamed", obj); + JSROOT.Create("TAttLine", obj); + JSROOT.Create("TAttFill", obj); + JSROOT.extend(obj, { fGeoAtt:0, fFinder: null, fMedium: null, fNodes: null, fNtotal: 0, fNumber: 0, fRefCount: 0, fShape: null, fVoxels: null }); + break; + case 'TGeoNode': + JSROOT.Create("TNamed", obj); + JSROOT.extend(obj, { fGeoAtt:0, fMother: null, fNovlp: 0, fNumber: 0, fOverlaps: null, fVolume: null }); + break; + case 'TGeoNodeMatrix': + JSROOT.Create("TGeoNode", obj); + JSROOT.extend(obj, { fMatrix: null }); + break; + case 'TGeoTrack': + JSROOT.Create("TObject", obj); + JSROOT.Create("TAttLine", obj); + JSROOT.Create("TAttMarker", obj); + JSROOT.extend(obj, { fGeoAtt:0, fNpoints: 0, fPoints: [] }); + break; + } + + obj._typename = typename; + this.addMethods(obj); + return obj; + } + + /** @summary Create TList + * @desc obsolete, use JSROOT.Create("TList") instead + * @deprecated */ + JSROOT.CreateTList = function() { return JSROOT.Create("TList"); } + + /** @summary Create TAxis + * @desc obsolete, use JSROOT.Create("TAxis") instead + * @deprecated */ + JSROOT.CreateTAxis = function() { return JSROOT.Create("TAxis"); } + + /** @summary Create histogram object + * @param {string} typename - histogram typename like TH1I or TH2F + * @param {number} nbinsx - number of bins on X-axis + * @param {number} [nbinsy] - number of bins on Y-axis (for 2D/3D histograms) + * @param {number} [nbinsz] - number of bins on Z-axis (for 3D histograms) + */ + JSROOT.CreateHistogram = function(typename, nbinsx, nbinsy, nbinsz) { + // create histogram object of specified type + // if bins numbers are specified, appropriate typed array will be created + var histo = JSROOT.Create(typename); + if (!histo.fXaxis || !histo.fYaxis || !histo.fZaxis) return null; + histo.fName = "hist"; histo.fTitle = "title"; + if (nbinsx) JSROOT.extend(histo.fXaxis, { fNbins: nbinsx, fXmin: 0, fXmax: nbinsx }); + if (nbinsy) JSROOT.extend(histo.fYaxis, { fNbins: nbinsy, fXmin: 0, fXmax: nbinsy }); + if (nbinsz) JSROOT.extend(histo.fZaxis, { fNbins: nbinsz, fXmin: 0, fXmax: nbinsz }); + switch (parseInt(typename[2])) { + case 1: if (nbinsx) histo.fNcells = nbinsx+2; break; + case 2: if (nbinsx && nbinsy) histo.fNcells = (nbinsx+2) * (nbinsy+2); break; + case 3: if (nbinsx && nbinsy && nbinsz) histo.fNcells = (nbinsx+2) * (nbinsy+2) * (nbinsz+2); break; + } + if (histo.fNcells > 0) { + switch (typename[3]) { + case "C" : histo.fArray = new Int8Array(histo.fNcells); break; + case "S" : histo.fArray = new Int16Array(histo.fNcells); break; + case "I" : histo.fArray = new Int32Array(histo.fNcells); break; + case "F" : histo.fArray = new Float32Array(histo.fNcells); break; + case "L" : histo.fArray = new Float64Array(histo.fNcells); break; + case "D" : histo.fArray = new Float64Array(histo.fNcells); break; + default: histo.fArray = new Array(histo.fNcells); break; + } + for (var i=0;i<histo.fNcells;++i) histo.fArray[i] = 0; + } + return histo; + } + + /** @summary Create 1-d histogram + * @desc obsolete, use JSROOT.CreateHistogram() instead + * @deprecated */ + JSROOT.CreateTH1 = function(nbinsx) { + return JSROOT.CreateHistogram("TH1I", nbinsx); + } + + /** @summary Create 2-d histogram + * @desc obsolete, use JSROOT.CreateHistogram() instead + * @deprecated */ + JSROOT.CreateTH2 = function(nbinsx, nbinsy) { + return JSROOT.CreateHistogram("TH2I", nbinsx, nbinsy); + } + + /** @summary Create 3-d histogram + * @desc obsolete, use JSROOT.CreateHistogram() instead + * @deprecated */ + JSROOT.CreateTH3 = function(nbinsx, nbinsy, nbinsz) { + return JSROOT.CreateHistogram("TH3I", nbinsx, nbinsy, nbinsz); + } + + /** @summary Creates TPolyLine object + * @param {number} npoints - number of points + * @param {boolean} [use_int32] - use Int32Array type for points, default is Float32Array */ + JSROOT.CreateTPolyLine = function(npoints, use_int32) { + var poly = JSROOT.Create("TPolyLine"); + if (npoints) { + poly.fN = npoints; + if (use_int32) { + poly.fX = new Int32Array(npoints); + poly.fY = new Int32Array(npoints); + } else { + poly.fX = new Float32Array(npoints); + poly.fY = new Float32Array(npoints); + } + } + + return poly; + } + + /** @summary Creates TGraph object + * @param {number} npoints - number of points in TGraph + * @param {array} [xpts] - array with X coordinates + * @param {array} [ypts] - array with Y coordinates */ + JSROOT.CreateTGraph = function(npoints, xpts, ypts) { + var graph = JSROOT.extend(JSROOT.Create("TGraph"), { fBits: 0x3000408, fName: "graph", fTitle: "title" }); + + if (npoints>0) { + graph.fMaxSize = graph.fNpoints = npoints; + + var usex = (typeof xpts == 'object') && (xpts.length === npoints); + var usey = (typeof ypts == 'object') && (ypts.length === npoints); + + for (var i=0;i<npoints;++i) { + graph.fX.push(usex ? xpts[i] : i/npoints); + graph.fY.push(usey ? ypts[i] : i/npoints); + } + } + + return graph; + } + + /** @summary Creates THStack object + * @desc + * As arguments one could specify any number of histograms objects + * @example + * var nbinsx = 20; + * var h1 = JSROOT.CreateHistogram("TH1F", nbinsx); + * var h2 = JSROOT.CreateHistogram("TH1F", nbinsx); + * var h3 = JSROOT.CreateHistogram("TH1F", nbinsx); + * var stack = JSROOT.CreateTHStack(h1, h2, h3); + * */ + JSROOT.CreateTHStack = function() { + var stack = JSROOT.Create("THStack"); + for(var i=0; i<arguments.length; ++i) + stack.fHists.Add(arguments[i], ""); + return stack; + } + + /** @summary Creates TMultiGraph object + * @desc + * As arguments one could specify any number of TGraph objects */ + JSROOT.CreateTMultiGraph = function() { + var mgraph = JSROOT.Create("TMultiGraph"); + for(var i=0; i<arguments.length; ++i) + mgraph.fGraphs.Add(arguments[i], ""); + return mgraph; + } + + JSROOT.methodsCache = {}; // variable used to keep methods for known classes + + /** @summary Returns methods for given typename + * @private + */ + JSROOT.getMethods = function(typename, obj) { + + var m = JSROOT.methodsCache[typename], + has_methods = (m!==undefined); + + if (!has_methods) m = {}; + + // Due to binary I/O such TObject methods may not be set for derived classes + // Therefore when methods requested for given object, check also that basic methods are there + if ((typename=="TObject") || (typename=="TNamed") || (obj && (obj.fBits!==undefined))) + if (m.TestBit === undefined) { + m.TestBit = function (f) { return (this.fBits & f) != 0; }; + m.InvertBit = function (f) { this.fBits = this.fBits ^ (f & 0xffffff); }; + } + + if (has_methods) return m; + + if ((typename === 'TList') || (typename === 'THashList')) { + m.Clear = function() { + this.arr = []; + this.opt = []; + } + m.Add = function(obj,opt) { + this.arr.push(obj); + this.opt.push((opt && typeof opt=='string') ? opt : ""); + } + m.AddFirst = function(obj,opt) { + this.arr.unshift(obj); + this.opt.unshift((opt && typeof opt=='string') ? opt : ""); + } + m.RemoveAt = function(indx) { + this.arr.splice(indx, 1); + this.opt.splice(indx, 1); + } + } + + if ((typename === "TPaveText") || (typename === "TPaveStats")) { + m.AddText = function(txt) { + // this.fLines.Add({ _typename: 'TLatex', fTitle: txt, fTextColor: 1 }); + var line = JSROOT.Create("TLatex"); + line.fTitle = txt; + this.fLines.Add(line); + } + m.Clear = function() { + this.fLines.Clear(); + } + } + + if ((typename.indexOf("TF1") == 0) || (typename === "TF2")) { + m.addFormula = function(obj) { + if (!obj) return; + if (this.formulas === undefined) this.formulas = []; + this.formulas.push(obj); + } + + m.evalPar = function(x, y) { + if (! ('_func' in this) || (this._title !== this.fTitle)) { + + var _func = this.fTitle, isformula = false, pprefix = "["; + if (_func === "gaus") _func = "gaus(0)"; + if (this.fFormula && typeof this.fFormula.fFormula == "string") { + if (this.fFormula.fFormula.indexOf("[](double*x,double*p)")==0) { + isformula = true; pprefix = "p["; + _func = this.fFormula.fFormula.substr(21); + } else { + _func = this.fFormula.fFormula; + pprefix = "[p"; + } + if (this.fFormula.fClingParameters && this.fFormula.fParams) { + for (var i=0;i<this.fFormula.fParams.length;++i) { + var regex = new RegExp('(\\[' + this.fFormula.fParams[i].first + '\\])', 'g'), + parvalue = this.fFormula.fClingParameters[this.fFormula.fParams[i].second]; + _func = _func.replace(regex, (parvalue < 0) ? "(" + parvalue + ")" : parvalue); + } + } + } + + if ('formulas' in this) + for (var i=0;i<this.formulas.length;++i) + while (_func.indexOf(this.formulas[i].fName) >= 0) + _func = _func.replace(this.formulas[i].fName, this.formulas[i].fTitle); + _func = _func.replace(/\b(abs)\b/g, 'TMath::Abs') + .replace(/TMath::Exp\(/g, 'Math.exp(') + .replace(/TMath::Abs\(/g, 'Math.abs('); + if (typeof JSROOT.Math == 'object') { + this._math = JSROOT.Math; + _func = _func.replace(/TMath::Prob\(/g, 'this._math.Prob(') + .replace(/TMath::Gaus\(/g, 'this._math.Gaus(') + .replace(/TMath::BreitWigner\(/g, 'this._math.BreitWigner(') + .replace(/xygaus\(/g, 'this._math.gausxy(this, x, y, ') + .replace(/gaus\(/g, 'this._math.gaus(this, x, ') + .replace(/gausn\(/g, 'this._math.gausn(this, x, ') + .replace(/expo\(/g, 'this._math.expo(this, x, ') + .replace(/landau\(/g, 'this._math.landau(this, x, ') + .replace(/landaun\(/g, 'this._math.landaun(this, x, ') + .replace(/ROOT::Math::/g, 'this._math.'); + } + for (var i=0;i<this.fNpar;++i) { + var parname = pprefix + i + "]"; + while(_func.indexOf(parname) != -1) + _func = _func.replace(parname, '('+this.GetParValue(i)+')'); + } + _func = _func.replace(/\b(sin)\b/gi, 'Math.sin') + .replace(/\b(cos)\b/gi, 'Math.cos') + .replace(/\b(tan)\b/gi, 'Math.tan') + .replace(/\b(exp)\b/gi, 'Math.exp') + .replace(/\b(pow)\b/gi, 'Math.pow') + .replace(/pi/g, 'Math.PI'); + for (var n=2;n<10;++n) + _func = _func.replace('x^'+n, 'Math.pow(x,'+n+')'); + + if (isformula) { + _func = _func.replace(/x\[0\]/g,"x"); + if (this._typename==="TF2") { + _func = _func.replace(/x\[1\]/g,"y"); + this._func = new Function("x", "y", _func).bind(this); + } else { + this._func = new Function("x", _func).bind(this); + } + } else + if (this._typename==="TF2") + this._func = new Function("x", "y", "return " + _func).bind(this); + else + this._func = new Function("x", "return " + _func).bind(this); + + this._title = this.fTitle; + } + + return this._func(x, y); + } + m.GetParName = function(n) { + if (this.fFormula && this.fFormula.fParams) return this.fFormula.fParams[n].first; + if (this.fNames && this.fNames[n]) return this.fNames[n]; + return "p"+n; + } + m.GetParValue = function(n) { + if (this.fFormula && this.fFormula.fClingParameters) return this.fFormula.fClingParameters[n]; + if (this.fParams) return this.fParams[n]; + return undefined; + } + m.GetParError = function(n) { + return this.fParErrors ? this.fParErrors[n] : undefined; + } + m.GetNumPars = function() { + return this.fNpar; + } + } + + if (((typename.indexOf("TGraph") == 0) || (typename == "TCutG")) && (typename != "TGraphPolargram") && (typename != "TGraphTime")) { + // check if point inside figure specified by the TGraph + m.IsInside = function(xp,yp) { + var i, j = this.fNpoints - 1, x = this.fX, y = this.fY, oddNodes = false; + + for (i=0; i<this.fNpoints; ++i) { + if ((y[i]<yp && y[j]>=yp) || (y[j]<yp && y[i]>=yp)) { + if (x[i]+(yp-y[i])/(y[j]-y[i])*(x[j]-x[i])<xp) { + oddNodes = !oddNodes; + } + } + j=i; + } + + return oddNodes; + }; + } + + if (typename.indexOf("TH1") == 0 || + typename.indexOf("TH2") == 0 || + typename.indexOf("TH3") == 0) { + m.getBinError = function(bin) { + // -*-*-*-*-*Return value of error associated to bin number bin*-*-*-*-* + // if the sum of squares of weights has been defined (via Sumw2), + // this function returns the sqrt(sum of w2). + // otherwise it returns the sqrt(contents) for this bin. + if (bin >= this.fNcells) bin = this.fNcells - 1; + if (bin < 0) bin = 0; + if (bin < this.fSumw2.length) + return Math.sqrt(this.fSumw2[bin]); + return Math.sqrt(Math.abs(this.fArray[bin])); + }; + m.setBinContent = function(bin, content) { + // Set bin content - only trivial case, without expansion + this.fEntries++; + this.fTsumw = 0; + if ((bin>=0) && (bin<this.fArray.length)) + this.fArray[bin] = content; + }; + } + + if (typename.indexOf("TH1") == 0) { + m.getBin = function(x) { return x; } + m.getBinContent = function(bin) { return this.fArray[bin]; } + m.Fill = function(x, weight) { + var axis = this.fXaxis, + bin = 1 + Math.floor((x - axis.fXmin) / (axis.fXmax - axis.fXmin) * axis.fNbins); + if (bin < 0) bin = 0; else + if (bin > axis.fNbins + 1) bin = axis.fNbins + 1; + this.fArray[bin] += ((weight===undefined) ? 1 : weight); + } + } + + if (typename.indexOf("TH2") == 0) { + m.getBin = function(x, y) { return (x + (this.fXaxis.fNbins+2) * y); } + m.getBinContent = function(x, y) { return this.fArray[this.getBin(x, y)]; } + m.Fill = function(x, y, weight) { + var axis1 = this.fXaxis, axis2 = this.fYaxis, + bin1 = 1 + Math.floor((x - axis1.fXmin) / (axis1.fXmax - axis1.fXmin) * axis1.fNbins), + bin2 = 1 + Math.floor((y - axis2.fXmin) / (axis2.fXmax - axis2.fXmin) * axis2.fNbins); + if (bin1 < 0) bin1 = 0; else + if (bin1 > axis1.fNbins + 1) bin1 = axis1.fNbins + 1; + if (bin2 < 0) bin2 = 0; else + if (bin2 > axis2.fNbins + 1) bin2 = axis2.fNbins + 1; + this.fArray[bin1 + (axis1.fNbins+2)*bin2] += ((weight===undefined) ? 1 : weight); + } + } + + if (typename.indexOf("TH3") == 0) { + m.getBin = function(x, y, z) { return (x + (this.fXaxis.fNbins+2) * (y + (this.fYaxis.fNbins+2) * z)); } + m.getBinContent = function(x, y, z) { return this.fArray[this.getBin(x, y, z)]; }; + m.Fill = function(x, y, z, weight) { + var axis1 = this.fXaxis, axis2 = this.fYaxis, axis3 = this.fZaxis, + bin1 = 1 + Math.floor((x - axis1.fXmin) / (axis1.fXmax - axis1.fXmin) * axis1.fNbins), + bin2 = 1 + Math.floor((y - axis2.fXmin) / (axis2.fXmax - axis2.fXmin) * axis2.fNbins), + bin2 = 1 + Math.floor((z - axis3.fXmin) / (axis3.fXmax - axis3.fXmin) * axis3.fNbins); + if (bin1 < 0) bin1 = 0; else + if (bin1 > axis1.fNbins + 1) bin1 = axis1.fNbins + 1; + if (bin2 < 0) bin2 = 0; else + if (bin2 > axis2.fNbins + 1) bin2 = axis2.fNbins + 1; + if (bin3 < 0) bin3 = 0; else + if (bin3 > axis3.fNbins + 1) bin3 = axis3.fNbins + 1; + this.fArray[bin1 + (axis1.fNbins+2)* (bin2+(axis2.fNbins+2)*bin3)] += ((weight===undefined) ? 1 : weight); + } + } + + if (typename.indexOf("TProfile") == 0) { + if (typename.indexOf("TProfile2D") == 0) { + m.getBin = function(x, y) { return (x + (this.fXaxis.fNbins+2) * y); } + m.getBinContent = function(x, y) { + var bin = this.getBin(x, y); + if (bin < 0 || bin >= this.fNcells) return 0; + if (this.fBinEntries[bin] < 1e-300) return 0; + if (!this.fArray) return 0; + return this.fArray[bin]/this.fBinEntries[bin]; + } + m.getBinEntries = function(x, y) { + var bin = this.getBin(x, y); + if (bin < 0 || bin >= this.fNcells) return 0; + return this.fBinEntries[bin]; + } + } + else { + m.getBin = function(x) { return x; } + m.getBinContent = function(bin) { + if (bin < 0 || bin >= this.fNcells) return 0; + if (this.fBinEntries[bin] < 1e-300) return 0; + if (!this.fArray) return 0; + return this.fArray[bin]/this.fBinEntries[bin]; + }; + } + m.getBinEffectiveEntries = function(bin) { + if (bin < 0 || bin >= this.fNcells) return 0; + var sumOfWeights = this.fBinEntries[bin]; + if ( !this.fBinSumw2 || this.fBinSumw2.length != this.fNcells) { + // this can happen when reading an old file + return sumOfWeights; + } + var sumOfWeightsSquare = this.fBinSumw2[bin]; + return (sumOfWeightsSquare > 0) ? sumOfWeights * sumOfWeights / sumOfWeightsSquare : 0; + }; + m.getBinError = function(bin) { + if (bin < 0 || bin >= this.fNcells) return 0; + var cont = this.fArray[bin], // sum of bin w *y + sum = this.fBinEntries[bin], // sum of bin weights + err2 = this.fSumw2[bin], // sum of bin w * y^2 + neff = this.getBinEffectiveEntries(bin); // (sum of w)^2 / (sum of w^2) + if (sum < 1e-300) return 0; // for empty bins + var EErrorType = { kERRORMEAN : 0, kERRORSPREAD : 1, kERRORSPREADI : 2, kERRORSPREADG : 3 }; + // case the values y are gaussian distributed y +/- sigma and w = 1/sigma^2 + if (this.fErrorMode === EErrorType.kERRORSPREADG) + return 1.0/Math.sqrt(sum); + // compute variance in y (eprim2) and standard deviation in y (eprim) + var contsum = cont/sum, eprim = Math.sqrt(Math.abs(err2/sum - contsum*contsum)); + if (this.fErrorMode === EErrorType.kERRORSPREADI) { + if (eprim != 0) return eprim/Math.sqrt(neff); + // in case content y is an integer (so each my has an error +/- 1/sqrt(12) + // when the std(y) is zero + return 1.0/Math.sqrt(12*neff); + } + // if approximate compute the sums (of w, wy and wy2) using all the bins + // when the variance in y is zero + // case option "S" return standard deviation in y + if (this.fErrorMode === EErrorType.kERRORSPREAD) return eprim; + // default case : fErrorMode = kERRORMEAN + // return standard error on the mean of y + return (eprim/Math.sqrt(neff)); + }; + } + + if (typename == "TAxis") { + m.GetBinLowEdge = function(bin) { + if (this.fNbins <= 0) return 0; + if ((this.fXbins.length > 0) && (bin > 0) && (bin <= this.fNbins)) return this.fXbins[bin-1]; + return this.fXmin + (bin-1) * (this.fXmax - this.fXmin) / this.fNbins; + } + m.GetBinCenter = function(bin) { + if (this.fNbins <= 0) return 0; + if ((this.fXbins.length > 0) && (bin > 0) && (bin < this.fNbins)) return (this.fXbins[bin-1] + this.fXbins[bin])/2; + return this.fXmin + (bin-0.5) * (this.fXmax - this.fXmin) / this.fNbins; + } + } + + if (typeof JSROOT.getMoreMethods == "function") + JSROOT.getMoreMethods(m, typename, obj); + + JSROOT.methodsCache[typename] = m; + return m; + } + + /** @summary Returns true if object represents basic ROOT collections + * @private */ + JSROOT.IsRootCollection = function(lst, typename) { + if (lst && (typeof lst === 'object')) { + if ((lst.$kind === "TList") || (lst.$kind === "TObjArray")) return true; + if (!typename) typename = lst._typename; + } + if (!typename) return false; + return (typename === 'TList') || (typename === 'THashList') || (typename === 'TMap') || + (typename === 'TObjArray') || (typename === 'TClonesArray'); + } + + /** @summary Adds specific methods to the object. + * + * JSROOT implements some basic methods for different ROOT classes. + * @param {object} obj - object where methods are assigned + * @param {string} typename - optional typename, if not specified, obj._typename will be used + * @private + */ + JSROOT.addMethods = function(obj, typename) { + this.extend(obj, JSROOT.getMethods(typename || obj._typename, obj)); + } + + JSROOT.lastFFormat = ""; + + /** @summary Converts numeric value to string according to specified format. + * + * @param {number} value - value to convert + * @param {strting} fmt - format can be like 5.4g or 4.2e or 6.4f + * @returns {string} - converted value + * @private + */ + JSROOT.FFormat = function(value, fmt) { + if (!fmt) fmt = "6.4g"; + + JSROOT.lastFFormat = ""; + + fmt = fmt.trim(); + var len = fmt.length; + if (len<2) return value.toFixed(4); + var last = fmt[len-1]; + fmt = fmt.slice(0,len-1); + var isexp = null; + var prec = fmt.indexOf("."); + if (prec<0) prec = 4; else prec = Number(fmt.slice(prec+1)); + if (isNaN(prec) || (prec<0) || (prec==null)) prec = 4; + + var significance = false; + if ((last=='e') || (last=='E')) { isexp = true; } else + if (last=='Q') { isexp = true; significance = true; } else + if ((last=='f') || (last=='F')) { isexp = false; } else + if (last=='W') { isexp = false; significance = true; } else + if ((last=='g') || (last=='G')) { + var se = JSROOT.FFormat(value, fmt+'Q'), + _fmt = JSROOT.lastFFormat, + sg = JSROOT.FFormat(value, fmt+'W'); + + if (se.length < sg.length) { + JSROOT.lastFFormat = _fmt; + return se; + } + return sg; + } else { + isexp = false; + prec = 4; + } + + if (isexp) { + // for exponential representation only one significant digit befor point + if (significance) prec--; + if (prec<0) prec = 0; + + JSROOT.lastFFormat = '5.'+prec+'e'; + + return value.toExponential(prec); + } + + var sg = value.toFixed(prec); + + if (significance) { + + // when using fixed representation, one could get 0.0 + if ((value!=0) && (Number(sg)==0.) && (prec>0)) { + prec = 20; sg = value.toFixed(prec); + } + + var l = 0; + while ((l<sg.length) && (sg[l] == '0' || sg[l] == '-' || sg[l] == '.')) l++; + + var diff = sg.length - l - prec; + if (sg.indexOf(".")>l) diff--; + + if (diff != 0) { + prec-=diff; + if (prec<0) prec = 0; else if (prec>20) prec = 20; + sg = value.toFixed(prec); + } + } + + JSROOT.lastFFormat = '5.'+prec+'f'; + + return sg; + } + + /** @summary Implements log10 + * @private */ + JSROOT.log10 = function(n) { + return Math.log(n) / Math.log(10); + } + + // Dummy function, will be redefined when JSRootPainter is loaded + JSROOT.progress = function(msg, tmout) { + if ((msg !== undefined) && (typeof msg=="string")) JSROOT.console(msg); + } + + // connect to the TWebWindow instance + JSROOT.ConnectWebWindow = function(arg) { + if (typeof arg == 'function') arg = { callback: arg }; + + if (arg.openui5src) JSROOT.openui5src = arg.openui5src; + if (arg.openui5libs) JSROOT.openui5libs = arg.openui5libs; + JSROOT.AssertPrerequisites("2d;" + (arg && arg.prereq ? arg.prereq : ""), function() { + if (arg && arg.prereq) delete arg.prereq; + JSROOT.ConnectWebWindow(arg); + }, (arg ? arg.prereq_logdiv : undefined)); + } + + /** Initialize JSROOT. + * Called when script is loaded. Process URL parameters, supplied with JSRootCore.js script + * @private + */ + JSROOT.Initialize = function() { + + if (JSROOT.source_fullpath.length === 0) return this; + + function window_on_load(func) { + if (func!=null) { + if (document.attachEvent ? document.readyState === 'complete' : document.readyState !== 'loading') + func(); + else + window.onload = func; + } + return JSROOT; + } + + var src = JSROOT.source_fullpath; + + if (JSROOT.GetUrlOption('nocache', src)!=null) JSROOT.nocache = (new Date).getTime(); // use timestamp to overcome cache limitation + + if (JSROOT.GetUrlOption('gui', src) !== null) + return window_on_load( function() { JSROOT.BuildSimpleGUI(); } ); + + if ( typeof define === "function" && define.amd ) + return window_on_load( function() { JSROOT.BuildSimpleGUI('check_existing_elements'); } ); + + var prereq = ""; + if (JSROOT.GetUrlOption('io', src)!=null) prereq += "io;"; + if (JSROOT.GetUrlOption('tree', src)!=null) prereq += "tree;"; + if (JSROOT.GetUrlOption('2d', src)!=null) prereq += "2d;"; + if (JSROOT.GetUrlOption('v7', src)!=null) prereq += "v7;"; + if (JSROOT.GetUrlOption('hist', src)!=null) prereq += "2d;hist;"; + if (JSROOT.GetUrlOption('hierarchy', src)!=null) prereq += "2d;hierarchy;"; + if (JSROOT.GetUrlOption('jq2d', src)!=null) prereq += "2d;hierarchy;jq2d;"; + if (JSROOT.GetUrlOption('more2d', src)!=null) prereq += "more2d;"; + if (JSROOT.GetUrlOption('geom', src)!=null) prereq += "geom;"; + if (JSROOT.GetUrlOption('3d', src)!=null) prereq += "3d;"; + if (JSROOT.GetUrlOption('math', src)!=null) prereq += "math;"; + if (JSROOT.GetUrlOption('mathjax', src)!=null) prereq += "mathjax;"; + if (JSROOT.GetUrlOption('openui5', src)!=null) prereq += "openui5;"; + var user = JSROOT.GetUrlOption('load', src), + onload = JSROOT.GetUrlOption('onload', src), + bower = JSROOT.GetUrlOption('bower', src); + + if (user) prereq += "io;2d;load:" + user; + if ((bower===null) && (JSROOT.source_dir.indexOf("bower_components/jsroot/")>=0)) bower = ""; + if (bower!==null) { + if (bower.length>0) JSROOT.bower_dir = bower; else + if (JSROOT.source_dir.indexOf("jsroot/") == JSROOT.source_dir.length - 7) + JSROOT.bower_dir = JSROOT.source_dir.substr(0, JSROOT.source_dir.length - 7); + if (JSROOT.bower_dir !== null) console.log("Set JSROOT.bower_dir to " + JSROOT.bower_dir); + } + + if ((prereq.length>0) || (onload!=null)) + window_on_load(function() { + if (prereq.length>0) JSROOT.AssertPrerequisites(prereq, onload); else + if (onload!=null) { + onload = JSROOT.findFunction(onload); + if (typeof onload == 'function') onload(); + } + }); + + return this; + } + + return JSROOT.Initialize(); + +})); + +/// JSRootCore.js ends + diff --git a/js/scripts/JSRootGeoBase.js b/js/scripts/JSRootGeoBase.js new file mode 100644 index 00000000000..7f5a491ee8f --- /dev/null +++ b/js/scripts/JSRootGeoBase.js @@ -0,0 +1,3392 @@ +/** @file JSRootGeoBase.js */ +/// Basic functions for work with TGeo classes + +(function( factory ) { + if ( typeof define === "function" && define.amd ) { + define( [ 'JSRootCore', 'threejs', 'ThreeCSG' ], factory ); + } else + if (typeof exports === 'object' && typeof module !== 'undefined') { + factory(require("./JSRootCore.js"), require("./three.min.js"), require("./ThreeCSG.js")); + } else { + + if (typeof JSROOT == 'undefined') + throw new Error('JSROOT is not defined', 'JSRootGeoBase.js'); + + if (typeof THREE == 'undefined') + throw new Error('THREE is not defined', 'JSRootGeoBase.js'); + + if (typeof ThreeBSP == 'undefined') + throw new Error('ThreeBSP is not defined', 'JSRootGeoBase.js'); + + factory(JSROOT, THREE, ThreeBSP); + } +} (function( JSROOT, THREE, ThreeBSP ) { + + "use strict"; + + /** @namespace JSROOT.GEO */ + /// Holder of all TGeo-related functions and classes + JSROOT.GEO = { + GradPerSegm: 6, // grad per segment in cylinder/spherical symmetry shapes + CompressComp: true, // use faces compression in composite shapes + CompLimit: 20 // maximal number of components in composite shape + }; + + /** @memberOf JSROOT.GEO */ + JSROOT.GEO.BITS = { + kVisOverride : JSROOT.BIT(0), // volume's vis. attributes are overwritten + kVisNone : JSROOT.BIT(1), // the volume/node is invisible, as well as daughters + kVisThis : JSROOT.BIT(2), // this volume/node is visible + kVisDaughters : JSROOT.BIT(3), // all leaves are visible + kVisOneLevel : JSROOT.BIT(4), // first level daughters are visible + kVisStreamed : JSROOT.BIT(5), // true if attributes have been streamed + kVisTouched : JSROOT.BIT(6), // true if attributes are changed after closing geom + kVisOnScreen : JSROOT.BIT(7), // true if volume is visible on screen + kVisContainers : JSROOT.BIT(12), // all containers visible + kVisOnly : JSROOT.BIT(13), // just this visible + kVisBranch : JSROOT.BIT(14), // only a given branch visible + kVisRaytrace : JSROOT.BIT(15) // raytracing flag + }; + + /** @memberOf JSROOT.GEO */ + JSROOT.GEO.TestBit = function(volume, f) { + var att = volume.fGeoAtt; + return att === undefined ? false : ((att & f) !== 0); + } + + /** @memberOf JSROOT.GEO */ + JSROOT.GEO.SetBit = function(volume, f, value) { + if (volume.fGeoAtt === undefined) return; + volume.fGeoAtt = value ? (volume.fGeoAtt | f) : (volume.fGeoAtt & ~f); + } + + /** @memberOf JSROOT.GEO */ + JSROOT.GEO.ToggleBit = function(volume, f) { + if (volume.fGeoAtt !== undefined) + volume.fGeoAtt = volume.fGeoAtt ^ (f & 0xffffff); + } + + /** @memberOf JSROOT.GEO + * implementation of TGeoVolume::InvisibleAll */ + JSROOT.GEO.InvisibleAll = function(flag) { + if (flag===undefined) flag = true; + + JSROOT.GEO.SetBit(this, JSROOT.GEO.BITS.kVisThis, !flag); + JSROOT.GEO.SetBit(this, JSROOT.GEO.BITS.kVisDaughters, !flag); + JSROOT.GEO.SetBit(this, JSROOT.GEO.BITS.kVisOneLevel, false); + + if (this.fNodes) + for (var n=0;n<this.fNodes.arr.length;++n) { + var sub = this.fNodes.arr[n].fVolume; + JSROOT.GEO.SetBit(sub, JSROOT.GEO.BITS.kVisThis, !flag); + // JSROOT.GEO.SetBit(sub, JSROOT.GEO.BITS.kVisDaughters, !flag); + //JSROOT.GEO.SetBit(sub, JSROOT.GEO.BITS.kVisOneLevel, false); + } + } + + /** method used to avoid duplication of warnings + * @memberOf JSROOT.GEO */ + JSROOT.GEO.warn = function(msg) { + if (JSROOT.GEO._warn_msgs === undefined) JSROOT.GEO._warn_msgs = {}; + if (JSROOT.GEO._warn_msgs[msg] !== undefined) return; + JSROOT.GEO._warn_msgs[msg] = true; + console.warn(msg); + } + + /** @memberOf JSROOT.GEO */ + JSROOT.GEO.NodeKind = function(obj) { + // return kind of the geo nodes + // 0 - TGeoNode + // 1 - TEveGeoNode + // -1 - unsupported type + + if ((obj === undefined) || (obj === null) || (typeof obj !== 'object')) return -1; + + return ('fShape' in obj) && ('fTrans' in obj) ? 1 : 0; + } + + JSROOT.GEO.CountNumShapes = function(shape) { + if (!shape) return 0; + if (shape._typename!=='TGeoCompositeShape') return 1; + return JSROOT.GEO.CountNumShapes(shape.fNode.fLeft) + JSROOT.GEO.CountNumShapes(shape.fNode.fRight); + } + + // ========================================================================== + + JSROOT.GEO.GeometryCreator = function(numfaces) { + this.nfaces = numfaces; + this.indx = 0; + this.pos = new Float32Array(numfaces*9); + this.norm = new Float32Array(numfaces*9); + + return this; + } + + JSROOT.GEO.GeometryCreator.prototype.AddFace3 = function(x1,y1,z1, + x2,y2,z2, + x3,y3,z3) { + var indx = this.indx, pos = this.pos; + pos[indx] = x1; + pos[indx+1] = y1; + pos[indx+2] = z1; + pos[indx+3] = x2; + pos[indx+4] = y2; + pos[indx+5] = z2; + pos[indx+6] = x3; + pos[indx+7] = y3; + pos[indx+8] = z3; + this.last4 = false; + this.indx = indx + 9; + } + + JSROOT.GEO.GeometryCreator.prototype.StartPolygon = function() {} + JSROOT.GEO.GeometryCreator.prototype.StopPolygon = function() {} + + JSROOT.GEO.GeometryCreator.prototype.AddFace4 = function(x1,y1,z1, + x2,y2,z2, + x3,y3,z3, + x4,y4,z4, + reduce) { + // from four vertices one normally creates two faces (1,2,3) and (1,3,4) + // if (reduce==1), first face is reduced + // if (reduce==2), second face is reduced + + var indx = this.indx, pos = this.pos; + + if (reduce!==1) { + pos[indx] = x1; + pos[indx+1] = y1; + pos[indx+2] = z1; + pos[indx+3] = x2; + pos[indx+4] = y2; + pos[indx+5] = z2; + pos[indx+6] = x3; + pos[indx+7] = y3; + pos[indx+8] = z3; + indx+=9; + } + + if (reduce!==2) { + pos[indx] = x1; + pos[indx+1] = y1; + pos[indx+2] = z1; + pos[indx+3] = x3; + pos[indx+4] = y3; + pos[indx+5] = z3; + pos[indx+6] = x4; + pos[indx+7] = y4; + pos[indx+8] = z4; + indx+=9; + } + + this.last4 = (indx !== this.indx + 9); + this.indx = indx; + } + + JSROOT.GEO.GeometryCreator.prototype.SetNormal4 = function(nx1,ny1,nz1, + nx2,ny2,nz2, + nx3,ny3,nz3, + nx4,ny4,nz4, + reduce) { + // same as AddFace4, assign normals for each individual vertex + // reduce has same meaning and should be the same + + if (this.last4 && reduce) + return console.error('missmatch between AddFace4 and SetNormal4 calls'); + + var indx = this.indx - (this.last4 ? 18 : 9), norm = this.norm; + + if (reduce!==1) { + norm[indx] = nx1; + norm[indx+1] = ny1; + norm[indx+2] = nz1; + norm[indx+3] = nx2; + norm[indx+4] = ny2; + norm[indx+5] = nz2; + norm[indx+6] = nx3; + norm[indx+7] = ny3; + norm[indx+8] = nz3; + indx+=9; + } + + if (reduce!==2) { + norm[indx] = nx1; + norm[indx+1] = ny1; + norm[indx+2] = nz1; + norm[indx+3] = nx3; + norm[indx+4] = ny3; + norm[indx+5] = nz3; + norm[indx+6] = nx4; + norm[indx+7] = ny4; + norm[indx+8] = nz4; + } + } + + JSROOT.GEO.GeometryCreator.prototype.RecalcZ = function(func) { + var pos = this.pos, + last = this.indx, + indx = last - (this.last4 ? 18 : 9); + + while (indx < last) { + pos[indx+2] = func(pos[indx], pos[indx+1], pos[indx+2]); + indx+=3; + } + } + + JSROOT.GEO.GetNormal = function(x1,y1,z1,x2,y2,z2,x3,y3,z3) { + + var pA = new THREE.Vector3(x1,y1,z1), + pB = new THREE.Vector3(x2,y2,z2), + pC = new THREE.Vector3(x3,y3,z3), + cb = new THREE.Vector3(), + ab = new THREE.Vector3(); + + cb.subVectors( pC, pB ); + ab.subVectors( pA, pB ); + cb.cross(ab ); + + return cb; + } + + JSROOT.GEO.GeometryCreator.prototype.CalcNormal = function() { + var indx = this.indx, norm = this.norm; + + if (!this.cb) { + this.pA = new THREE.Vector3(); + this.pB = new THREE.Vector3(); + this.pC = new THREE.Vector3(); + this.cb = new THREE.Vector3(); + this.ab = new THREE.Vector3(); + } + + this.pA.fromArray( this.pos, this.indx - 9 ); + this.pB.fromArray( this.pos, this.indx - 6 ); + this.pC.fromArray( this.pos, this.indx - 3 ); + + this.cb.subVectors( this.pC, this.pB ); + this.ab.subVectors( this.pA, this.pB ); + this.cb.cross( this.ab ); + + this.SetNormal(this.cb.x, this.cb.y, this.cb.z); + } + + JSROOT.GEO.GeometryCreator.prototype.SetNormal = function(nx,ny,nz) { + var indx = this.indx - 9, norm = this.norm; + + norm[indx] = norm[indx+3] = norm[indx+6] = nx; + norm[indx+1] = norm[indx+4] = norm[indx+7] = ny; + norm[indx+2] = norm[indx+5] = norm[indx+8] = nz; + + if (this.last4) { + indx -= 9; + norm[indx] = norm[indx+3] = norm[indx+6] = nx; + norm[indx+1] = norm[indx+4] = norm[indx+7] = ny; + norm[indx+2] = norm[indx+5] = norm[indx+8] = nz; + } + } + + JSROOT.GEO.GeometryCreator.prototype.SetNormal_12_34 = function(nx12,ny12,nz12,nx34,ny34,nz34,reduce) { + // special shortcut, when same normals can be applied for 1-2 point and 3-4 point + if (reduce===undefined) reduce = 0; + + var indx = this.indx - ((reduce>0) ? 9 : 18), norm = this.norm; + + if (reduce!==1) { + norm[indx] = nx12; + norm[indx+1] = ny12; + norm[indx+2] = nz12; + norm[indx+3] = nx12; + norm[indx+4] = ny12; + norm[indx+5] = nz12; + norm[indx+6] = nx34; + norm[indx+7] = ny34; + norm[indx+8] = nz34; + indx+=9; + } + + if (reduce!==2) { + norm[indx] = nx12; + norm[indx+1] = ny12; + norm[indx+2] = nz12; + norm[indx+3] = nx34; + norm[indx+4] = ny34; + norm[indx+5] = nz34; + norm[indx+6] = nx34; + norm[indx+7] = ny34; + norm[indx+8] = nz34; + indx+=9; + } + } + + JSROOT.GEO.GeometryCreator.prototype.Create = function() { + if (this.nfaces !== this.indx/9) + console.error('Mismatch with created ' + this.nfaces + ' and filled ' + this.indx/9 + ' number of faces'); + + var geometry = new THREE.BufferGeometry(); + geometry.addAttribute( 'position', new THREE.BufferAttribute( this.pos, 3 ) ); + geometry.addAttribute( 'normal', new THREE.BufferAttribute( this.norm, 3 ) ); + return geometry; + } + + // ================================================================================ + + // same methods as GeometryCreator, but with different implementation + + JSROOT.GEO.PolygonsCreator = function() { + this.polygons = []; + } + + JSROOT.GEO.PolygonsCreator.prototype.StartPolygon = function(normal) { + this.multi = 1; + this.mnormal = normal; + } + + JSROOT.GEO.PolygonsCreator.prototype.StopPolygon = function() { + if (!this.multi) return; + this.multi = 0; + console.error('Polygon should be already closed at this moment'); + } + + JSROOT.GEO.PolygonsCreator.prototype.AddFace3 = function(x1,y1,z1, + x2,y2,z2, + x3,y3,z3) { + this.AddFace4(x1,y1,z1,x2,y2,z2,x3,y3,z3,x3,y3,z3,2); + } + + + JSROOT.GEO.PolygonsCreator.prototype.AddFace4 = function(x1,y1,z1, + x2,y2,z2, + x3,y3,z3, + x4,y4,z4, + reduce) { + // from four vertices one normally creates two faces (1,2,3) and (1,3,4) + // if (reduce==1), first face is reduced + // if (reduce==2), second face is reduced + + if (reduce === undefined) reduce = 0; + + this.v1 = new ThreeBSP.Vertex( x1, y1, z1, 0, 0, 0 ); + this.v2 = (reduce===1) ? null : new ThreeBSP.Vertex( x2, y2, z2, 0, 0, 0 ); + this.v3 = new ThreeBSP.Vertex( x3, y3, z3, 0, 0, 0 ); + this.v4 = (reduce===2) ? null : new ThreeBSP.Vertex( x4, y4, z4, 0, 0, 0 ); + + this.reduce = reduce; + + if (this.multi) { + + if (reduce!==2) console.error('polygon not supported for not-reduced faces'); + + var polygon; + + if (this.multi++ === 1) { + polygon = new ThreeBSP.Polygon; + + polygon.vertices.push(this.mnormal ? this.v2 : this.v3); + this.polygons.push(polygon); + } else { + polygon = this.polygons[this.polygons.length-1]; + // check that last vertice equals to v2 + var last = this.mnormal ? polygon.vertices[polygon.vertices.length-1] : polygon.vertices[0], + comp = this.mnormal ? this.v2 : this.v3; + + if (comp.diff(last) > 1e-12) + console.error('vertex missmatch when building polygon'); + } + + var first = this.mnormal ? polygon.vertices[0] : polygon.vertices[polygon.vertices.length-1], + next = this.mnormal ? this.v3 : this.v2; + + if (next.diff(first) < 1e-12) { + //console.log('polygon closed!!!', polygon.vertices.length); + this.multi = 0; + } else + if (this.mnormal) { + polygon.vertices.push(this.v3); + } else { + polygon.vertices.unshift(this.v2); + } + + return; + + } + + var polygon = new ThreeBSP.Polygon; + + switch (reduce) { + case 0: polygon.vertices.push(this.v1, this.v2, this.v3, this.v4); break; + case 1: polygon.vertices.push(this.v1, this.v3, this.v4); break; + case 2: polygon.vertices.push(this.v1, this.v2, this.v3); break; + } + + this.polygons.push(polygon); + } + + JSROOT.GEO.PolygonsCreator.prototype.SetNormal4 = function(nx1,ny1,nz1, + nx2,ny2,nz2, + nx3,ny3,nz3, + nx4,ny4,nz4, + reduce) { + this.v1.setnormal(nx1,ny1,nz1); + if (this.v2) this.v2.setnormal(nx2,ny2,nz2); + this.v3.setnormal(nx3,ny3,nz3); + if (this.v4) this.v4.setnormal(nx4,ny4,nz4); + } + + JSROOT.GEO.PolygonsCreator.prototype.SetNormal_12_34 = function(nx12,ny12,nz12,nx34,ny34,nz34,reduce) { + // special shortcut, when same normals can be applied for 1-2 point and 3-4 point + this.v1.setnormal(nx12,ny12,nz12); + if (this.v2) this.v2.setnormal(nx12,ny12,nz12); + this.v3.setnormal(nx34,ny34,nz34); + if (this.v4) this.v4.setnormal(nx34,ny34,nz34); + } + + JSROOT.GEO.PolygonsCreator.prototype.CalcNormal = function() { + + if (!this.cb) { + this.pA = new THREE.Vector3(); + this.pB = new THREE.Vector3(); + this.pC = new THREE.Vector3(); + this.cb = new THREE.Vector3(); + this.ab = new THREE.Vector3(); + } + + this.pA.set( this.v1.x, this.v1.y, this.v1.z); + + if (this.reduce!==1) { + this.pB.set( this.v2.x, this.v2.y, this.v2.z); + this.pC.set( this.v3.x, this.v3.y, this.v3.z); + } else { + this.pB.set( this.v3.x, this.v3.y, this.v3.z); + this.pC.set( this.v4.x, this.v4.y, this.v4.z); + } + + this.cb.subVectors( this.pC, this.pB ); + this.ab.subVectors( this.pA, this.pB ); + this.cb.cross( this.ab ); + + this.SetNormal(this.cb.x, this.cb.y, this.cb.z); + } + + + JSROOT.GEO.PolygonsCreator.prototype.SetNormal = function(nx,ny,nz) { + this.v1.setnormal(nx,ny,nz); + if (this.v2) this.v2.setnormal(nx,ny,nz); + this.v3.setnormal(nx,ny,nz); + if (this.v4) this.v4.setnormal(nx,ny,nz); + } + + JSROOT.GEO.PolygonsCreator.prototype.RecalcZ = function(func) { + this.v1.z = func(this.v1.x, this.v1.y, this.v1.z); + if (this.v2) this.v2.z = func(this.v2.x, this.v2.y, this.v2.z); + this.v3.z = func(this.v3.x, this.v3.y, this.v3.z); + if (this.v4) this.v4.z = func(this.v4.x, this.v4.y, this.v4.z); + } + + JSROOT.GEO.PolygonsCreator.prototype.Create = function() { + return { polygons: this.polygons }; + } + + // ================= all functions to create geometry =================================== + + /** @memberOf JSROOT.GEO */ + JSROOT.GEO.createCubeBuffer = function(shape, faces_limit) { + + if (faces_limit < 0) return 12; + + var dx = shape.fDX, dy = shape.fDY, dz = shape.fDZ; + + var creator = faces_limit ? new JSROOT.GEO.PolygonsCreator : new JSROOT.GEO.GeometryCreator(12); + + creator.AddFace4(dx,dy,dz, dx,-dy,dz, dx,-dy,-dz, dx,dy,-dz); creator.SetNormal(1,0,0); + + creator.AddFace4(-dx,dy,-dz, -dx,-dy,-dz, -dx,-dy,dz, -dx,dy,dz); creator.SetNormal(-1,0,0); + + creator.AddFace4(-dx,dy,-dz, -dx,dy,dz, dx,dy,dz, dx,dy,-dz); creator.SetNormal(0,1,0); + + creator.AddFace4(-dx,-dy,dz, -dx,-dy,-dz, dx,-dy,-dz, dx,-dy,dz); creator.SetNormal(0,-1,0); + + creator.AddFace4(-dx,dy,dz, -dx,-dy,dz, dx,-dy,dz, dx,dy,dz); creator.SetNormal(0,0,1); + + creator.AddFace4(dx,dy,-dz, dx,-dy,-dz, -dx,-dy,-dz, -dx,dy,-dz); creator.SetNormal(0,0,-1); + + return creator.Create(); + } + + /** @memberOf JSROOT.GEO */ + JSROOT.GEO.create8edgesBuffer = function( v, faces_limit ) { + + var indicies = [ 4,7,6,5, 0,3,7,4, 4,5,1,0, 6,2,1,5, 7,3,2,6, 1,2,3,0 ]; + + var creator = (faces_limit > 0) ? new JSROOT.GEO.PolygonsCreator : new JSROOT.GEO.GeometryCreator(12); + + for (var n=0;n<indicies.length;n+=4) { + var i1 = indicies[n]*3, + i2 = indicies[n+1]*3, + i3 = indicies[n+2]*3, + i4 = indicies[n+3]*3; + creator.AddFace4(v[i1], v[i1+1], v[i1+2], v[i2], v[i2+1], v[i2+2], + v[i3], v[i3+1], v[i3+2], v[i4], v[i4+1], v[i4+2]); + if (n===0) creator.SetNormal(0,0,1); else + if (n===20) creator.SetNormal(0,0,-1); else creator.CalcNormal(); + } + + return creator.Create(); + } + + /** @memberOf JSROOT.GEO */ + JSROOT.GEO.createParaBuffer = function( shape, faces_limit ) { + + if (faces_limit < 0) return 12; + + var txy = shape.fTxy, txz = shape.fTxz, tyz = shape.fTyz; + + var v = [ + -shape.fZ*txz-txy*shape.fY-shape.fX, -shape.fY-shape.fZ*tyz, -shape.fZ, + -shape.fZ*txz+txy*shape.fY-shape.fX, shape.fY-shape.fZ*tyz, -shape.fZ, + -shape.fZ*txz+txy*shape.fY+shape.fX, shape.fY-shape.fZ*tyz, -shape.fZ, + -shape.fZ*txz-txy*shape.fY+shape.fX, -shape.fY-shape.fZ*tyz, -shape.fZ, + shape.fZ*txz-txy*shape.fY-shape.fX, -shape.fY+shape.fZ*tyz, shape.fZ, + shape.fZ*txz+txy*shape.fY-shape.fX, shape.fY+shape.fZ*tyz, shape.fZ, + shape.fZ*txz+txy*shape.fY+shape.fX, shape.fY+shape.fZ*tyz, shape.fZ, + shape.fZ*txz-txy*shape.fY+shape.fX, -shape.fY+shape.fZ*tyz, shape.fZ ]; + + return JSROOT.GEO.create8edgesBuffer(v, faces_limit ); + } + + /** @memberOf JSROOT.GEO */ + JSROOT.GEO.createTrapezoidBuffer = function( shape, faces_limit ) { + + if (faces_limit < 0) return 12; + + var y1, y2; + if (shape._typename == "TGeoTrd1") { + y1 = y2 = shape.fDY; + } else { + y1 = shape.fDy1; y2 = shape.fDy2; + } + + var v = [ + -shape.fDx1, y1, -shape.fDZ, + shape.fDx1, y1, -shape.fDZ, + shape.fDx1, -y1, -shape.fDZ, + -shape.fDx1, -y1, -shape.fDZ, + -shape.fDx2, y2, shape.fDZ, + shape.fDx2, y2, shape.fDZ, + shape.fDx2, -y2, shape.fDZ, + -shape.fDx2, -y2, shape.fDZ + ]; + + return JSROOT.GEO.create8edgesBuffer(v, faces_limit ); + } + + + /** @memberOf JSROOT.GEO */ + JSROOT.GEO.createArb8Buffer = function( shape, faces_limit ) { + + if (faces_limit < 0) return 12; + + var vertices = [ + shape.fXY[0][0], shape.fXY[0][1], -shape.fDZ, + shape.fXY[1][0], shape.fXY[1][1], -shape.fDZ, + shape.fXY[2][0], shape.fXY[2][1], -shape.fDZ, + shape.fXY[3][0], shape.fXY[3][1], -shape.fDZ, + shape.fXY[4][0], shape.fXY[4][1], shape.fDZ, + shape.fXY[5][0], shape.fXY[5][1], shape.fDZ, + shape.fXY[6][0], shape.fXY[6][1], shape.fDZ, + shape.fXY[7][0], shape.fXY[7][1], shape.fDZ + ], + indicies = [ + 4,7,6, 6,5,4, 0,3,7, 7,4,0, + 4,5,1, 1,0,4, 6,2,1, 1,5,6, + 7,3,2, 2,6,7, 1,2,3, 3,0,1 ]; + + // detect same vertices on both Z-layers + for (var side=0;side<vertices.length;side += vertices.length/2) + for (var n1 = side; n1 < side + vertices.length/2 - 3 ; n1+=3) + for (var n2 = n1+3; n2 < side + vertices.length/2 ; n2+=3) + if ((vertices[n1] === vertices[n2]) && + (vertices[n1+1] === vertices[n2+1]) && + (vertices[n1+2] === vertices[n2+2])) { + for (var k=0;k<indicies.length;++k) + if (indicies[k] === n2/3) indicies[k] = n1/3; + } + + + var map = [], // list of existing faces (with all rotations) + numfaces = 0; + + for (var k=0;k<indicies.length;k+=3) { + var id1 = indicies[k]*100 + indicies[k+1]*10 + indicies[k+2], + id2 = indicies[k+1]*100 + indicies[k+2]*10 + indicies[k], + id3 = indicies[k+2]*100 + indicies[k]*10 + indicies[k+1]; + + if ((indicies[k] == indicies[k+1]) || (indicies[k] == indicies[k+2]) || (indicies[k+1] == indicies[k+2]) || + (map.indexOf(id1)>=0) || (map.indexOf(id2)>=0) || (map.indexOf(id3)>=0)) { + indicies[k] = indicies[k+1] = indicies[k+2] = -1; + } else { + map.push(id1,id2,id3); + numfaces++; + } + } + + var creator = faces_limit ? new JSROOT.GEO.PolygonsCreator : new JSROOT.GEO.GeometryCreator(numfaces); + + // var creator = new JSROOT.GEO.GeometryCreator(numfaces); + + for (var n=0; n < indicies.length; n+=6) { + var i1 = indicies[n] * 3, + i2 = indicies[n+1] * 3, + i3 = indicies[n+2] * 3, + i4 = indicies[n+3] * 3, + i5 = indicies[n+4] * 3, + i6 = indicies[n+5] * 3, + norm = null; + + if ((i1>=0) && (i4>=0) && faces_limit) { + // try to identify two faces with same normal - very useful if one can create face4 + if (n===0) norm = new THREE.Vector3(0,0,1); else + if (n===30) norm = new THREE.Vector3(0,0,-1); else { + var norm1 = JSROOT.GEO.GetNormal(vertices[i1], vertices[i1+1], vertices[i1+2], + vertices[i2], vertices[i2+1], vertices[i2+2], + vertices[i3], vertices[i3+1], vertices[i3+2]); + + norm1.normalize(); + + var norm2 = JSROOT.GEO.GetNormal(vertices[i4], vertices[i4+1], vertices[i4+2], + vertices[i5], vertices[i5+1], vertices[i5+2], + vertices[i6], vertices[i6+1], vertices[i6+2]); + + norm2.normalize(); + + if (norm1.distanceToSquared(norm2) < 1e-12) norm = norm1; + } + } + + if (norm !== null) { + creator.AddFace4(vertices[i1], vertices[i1+1], vertices[i1+2], + vertices[i2], vertices[i2+1], vertices[i2+2], + vertices[i3], vertices[i3+1], vertices[i3+2], + vertices[i5], vertices[i5+1], vertices[i5+2]); + creator.SetNormal(norm.x, norm.y, norm.z); + } else { + if (i1>=0) { + creator.AddFace3(vertices[i1], vertices[i1+1], vertices[i1+2], + vertices[i2], vertices[i2+1], vertices[i2+2], + vertices[i3], vertices[i3+1], vertices[i3+2]); + creator.CalcNormal(); + } + if (i4>=0) { + creator.AddFace3(vertices[i4], vertices[i4+1], vertices[i4+2], + vertices[i5], vertices[i5+1], vertices[i5+2], + vertices[i6], vertices[i6+1], vertices[i6+2]); + creator.CalcNormal(); + } + } + } + + return creator.Create(); + } + + /** @memberOf JSROOT.GEO */ + JSROOT.GEO.createSphereBuffer = function( shape, faces_limit ) { + var radius = [shape.fRmax, shape.fRmin], + phiStart = shape.fPhi1, + phiLength = shape.fPhi2 - shape.fPhi1, + thetaStart = shape.fTheta1, + thetaLength = shape.fTheta2 - shape.fTheta1, + widthSegments = shape.fNseg, + heightSegments = shape.fNz, + noInside = (radius[1] <= 0); + + // widthSegments = 20; heightSegments = 10; + // phiStart = 0; phiLength = 360; thetaStart = 0; thetaLength = 180; + + if (faces_limit > 0) { + var fact = (noInside ? 2 : 4) * widthSegments * heightSegments / faces_limit; + + if (fact > 1.) { + widthSegments = Math.max(4, Math.floor(widthSegments/Math.sqrt(fact))); + heightSegments = Math.max(4, Math.floor(heightSegments/Math.sqrt(fact))); + } + } + + var numoutside = widthSegments * heightSegments * 2, + numtop = widthSegments * 2, + numbottom = widthSegments * 2, + numcut = phiLength === 360 ? 0 : heightSegments * (noInside ? 2 : 4), + epsilon = 1e-10; + + if (noInside) numbottom = numtop = widthSegments; + + if (faces_limit < 0) return numoutside * (noInside ? 1 : 2) + numtop + numbottom + numcut; + + var _sinp = new Float32Array(widthSegments+1), + _cosp = new Float32Array(widthSegments+1), + _sint = new Float32Array(heightSegments+1), + _cost = new Float32Array(heightSegments+1); + + for (var n=0;n<=heightSegments;++n) { + var theta = (thetaStart + thetaLength/heightSegments*n)*Math.PI/180; + _sint[n] = Math.sin(theta); + _cost[n] = Math.cos(theta); + } + + for (var n=0;n<=widthSegments;++n) { + var phi = (phiStart + phiLength/widthSegments*n)*Math.PI/180; + _sinp[n] = Math.sin(phi); + _cosp[n] = Math.cos(phi); + } + + if (Math.abs(_sint[0]) <= epsilon) { numoutside -= widthSegments; numtop = 0; } + if (Math.abs(_sint[heightSegments]) <= epsilon) { numoutside -= widthSegments; numbottom = 0; } + + var numfaces = numoutside * (noInside ? 1 : 2) + numtop + numbottom + numcut; + + var creator = faces_limit ? new JSROOT.GEO.PolygonsCreator : new JSROOT.GEO.GeometryCreator(numfaces); + + // var creator = new JSROOT.GEO.GeometryCreator(numfaces); + + for (var side=0;side<2;++side) { + if ((side===1) && noInside) break; + + var r = radius[side], + s = (side===0) ? 1 : -1, + d1 = 1 - side, d2 = 1 - d1; + + // use direct algorithm for the sphere - here normals and position can be calculated directly + for (var k=0;k<heightSegments;++k) { + + var k1 = k + d1, k2 = k + d2; + + var skip = 0; + if (Math.abs(_sint[k1]) <= epsilon) skip = 1; else + if (Math.abs(_sint[k2]) <= epsilon) skip = 2; + + for (var n=0;n<widthSegments;++n) { + creator.AddFace4( + r*_sint[k1]*_cosp[n], r*_sint[k1] *_sinp[n], r*_cost[k1], + r*_sint[k1]*_cosp[n+1], r*_sint[k1] *_sinp[n+1], r*_cost[k1], + r*_sint[k2]*_cosp[n+1], r*_sint[k2] *_sinp[n+1], r*_cost[k2], + r*_sint[k2]*_cosp[n], r*_sint[k2] *_sinp[n], r*_cost[k2], + skip); + creator.SetNormal4( + s*_sint[k1]*_cosp[n], s*_sint[k1] *_sinp[n], s*_cost[k1], + s*_sint[k1]*_cosp[n+1], s*_sint[k1] *_sinp[n+1], s*_cost[k1], + s*_sint[k2]*_cosp[n+1], s*_sint[k2] *_sinp[n+1], s*_cost[k2], + s*_sint[k2]*_cosp[n], s*_sint[k2] *_sinp[n], s*_cost[k2], + skip); + } + } + } + + // top/bottom + for (var side=0; side<=heightSegments; side+=heightSegments) + if (Math.abs(_sint[side]) >= epsilon) { + var ss = _sint[side], cc = _cost[side], + d1 = (side===0) ? 0 : 1, d2 = 1 - d1; + for (var n=0;n<widthSegments;++n) { + creator.AddFace4( + radius[1] * ss * _cosp[n+d1], radius[1] * ss * _sinp[n+d1], radius[1] * cc, + radius[0] * ss * _cosp[n+d1], radius[0] * ss * _sinp[n+d1], radius[0] * cc, + radius[0] * ss * _cosp[n+d2], radius[0] * ss * _sinp[n+d2], radius[0] * cc, + radius[1] * ss * _cosp[n+d2], radius[1] * ss * _sinp[n+d2], radius[1] * cc, + noInside ? 2 : 0); + creator.CalcNormal(); + } + } + + // cut left/right sides + if (phiLength < 360) { + for (var side=0;side<=widthSegments;side+=widthSegments) { + var ss = _sinp[side], cc = _cosp[side], + d1 = (side === 0) ? 1 : 0, d2 = 1 - d1; + + for (var k=0;k<heightSegments;++k) { + creator.AddFace4( + radius[1] * _sint[k+d1] * cc, radius[1] * _sint[k+d1] * ss, radius[1] * _cost[k+d1], + radius[0] * _sint[k+d1] * cc, radius[0] * _sint[k+d1] * ss, radius[0] * _cost[k+d1], + radius[0] * _sint[k+d2] * cc, radius[0] * _sint[k+d2] * ss, radius[0] * _cost[k+d2], + radius[1] * _sint[k+d2] * cc, radius[1] * _sint[k+d2] * ss, radius[1] * _cost[k+d2], + noInside ? 2 : 0); + creator.CalcNormal(); + } + } + } + + return creator.Create(); + } + + /** @memberOf JSROOT.GEO */ + JSROOT.GEO.createTubeBuffer = function( shape, faces_limit) { + var outerR, innerR; // inner/outer tube radius + if ((shape._typename == "TGeoCone") || (shape._typename == "TGeoConeSeg")) { + outerR = [ shape.fRmax2, shape.fRmax1 ]; + innerR = [ shape.fRmin2, shape.fRmin1 ]; + } else { + outerR = [ shape.fRmax, shape.fRmax ]; + innerR = [ shape.fRmin, shape.fRmin ]; + } + + var hasrmin = (innerR[0] > 0) || (innerR[1] > 0), + thetaStart = 0, thetaLength = 360; + + if ((shape._typename == "TGeoConeSeg") || (shape._typename == "TGeoTubeSeg") || (shape._typename == "TGeoCtub")) { + thetaStart = shape.fPhi1; + thetaLength = shape.fPhi2 - shape.fPhi1; + } + + var radiusSegments = Math.max(4, Math.round(thetaLength/JSROOT.GEO.GradPerSegm)); + + // external surface + var numfaces = radiusSegments * (((outerR[0] <= 0) || (outerR[1] <= 0)) ? 1 : 2); + + // internal surface + if (hasrmin) + numfaces += radiusSegments * (((innerR[0] <= 0) || (innerR[1] <= 0)) ? 1 : 2); + + // upper cap + if (outerR[0] > 0) numfaces += radiusSegments * ((innerR[0]>0) ? 2 : 1); + // bottom cup + if (outerR[1] > 0) numfaces += radiusSegments * ((innerR[1]>0) ? 2 : 1); + + if (thetaLength < 360) + numfaces += ((outerR[0] > innerR[0]) ? 2 : 0) + ((outerR[1] > innerR[1]) ? 2 : 0); + + if (faces_limit < 0) return numfaces; + + var phi0 = thetaStart*Math.PI/180, + dphi = thetaLength/radiusSegments*Math.PI/180, + _sin = new Float32Array(radiusSegments+1), + _cos = new Float32Array(radiusSegments+1); + + for (var seg=0; seg<=radiusSegments; ++seg) { + _cos[seg] = Math.cos(phi0+seg*dphi); + _sin[seg] = Math.sin(phi0+seg*dphi); + } + + var creator = faces_limit ? new JSROOT.GEO.PolygonsCreator : new JSROOT.GEO.GeometryCreator(numfaces); + + // var creator = new JSROOT.GEO.GeometryCreator(numfaces); + + var calcZ; + + if (shape._typename == "TGeoCtub") + calcZ = function(x,y,z) { + var arr = (z<0) ? shape.fNlow : shape.fNhigh; + return ((z<0) ? -shape.fDz : shape.fDz) - (x*arr[0] + y*arr[1]) / arr[2]; + } + + // create outer/inner tube + for (var side = 0; side<2; ++side) { + if ((side === 1) && !hasrmin) break; + + var R = (side === 0) ? outerR : innerR, + d1 = side, d2 = 1 - side, nxy = 1., nz = 0; + + if (R[0] !== R[1]) { + var angle = Math.atan2((R[1]-R[0]), 2*shape.fDZ); + nxy = Math.cos(angle); + nz = Math.sin(angle); + } + + if (side === 1) { nxy *= -1; nz *= -1; }; + + var reduce = 0; + if (R[0] <= 0) reduce = 2; else + if (R[1] <= 0) reduce = 1; + + for (var seg=0;seg<radiusSegments;++seg) { + creator.AddFace4( + R[0] * _cos[seg+d1], R[0] * _sin[seg+d1], shape.fDZ, + R[1] * _cos[seg+d1], R[1] * _sin[seg+d1], -shape.fDZ, + R[1] * _cos[seg+d2], R[1] * _sin[seg+d2], -shape.fDZ, + R[0] * _cos[seg+d2], R[0] * _sin[seg+d2], shape.fDZ, + reduce ); + + if (calcZ) creator.RecalcZ(calcZ); + + creator.SetNormal_12_34(nxy*_cos[seg+d1], nxy*_sin[seg+d1], nz, + nxy*_cos[seg+d2], nxy*_sin[seg+d2], nz, + reduce); + } + } + + // create upper/bottom part + for (var side = 0; side<2; ++side) { + if (outerR[side] <= 0) continue; + + var d1 = side, d2 = 1- side, + sign = (side == 0) ? 1 : -1, + reduce = (innerR[side] <= 0) ? 2 : 0; + if ((reduce==2) && (thetaLength === 360) && !calcZ ) creator.StartPolygon(side===0); + for (var seg=0;seg<radiusSegments;++seg) { + creator.AddFace4( + innerR[side] * _cos[seg+d1], innerR[side] * _sin[seg+d1], sign*shape.fDZ, + outerR[side] * _cos[seg+d1], outerR[side] * _sin[seg+d1], sign*shape.fDZ, + outerR[side] * _cos[seg+d2], outerR[side] * _sin[seg+d2], sign*shape.fDZ, + innerR[side] * _cos[seg+d2], innerR[side] * _sin[seg+d2], sign*shape.fDZ, + reduce); + if (calcZ) { + creator.RecalcZ(calcZ); + creator.CalcNormal(); + } else { + creator.SetNormal(0,0,sign); + } + } + + creator.StopPolygon(); + } + + // create cut surfaces + if (thetaLength < 360) { + creator.AddFace4(innerR[1] * _cos[0], innerR[1] * _sin[0], -shape.fDZ, + outerR[1] * _cos[0], outerR[1] * _sin[0], -shape.fDZ, + outerR[0] * _cos[0], outerR[0] * _sin[0], shape.fDZ, + innerR[0] * _cos[0], innerR[0] * _sin[0], shape.fDZ, + (outerR[0] === innerR[0]) ? 2 : ((innerR[1]===outerR[1]) ? 1 : 0) ); + if (calcZ) creator.RecalcZ(calcZ); + creator.CalcNormal(); + + creator.AddFace4(innerR[0] * _cos[radiusSegments], innerR[0] * _sin[radiusSegments], shape.fDZ, + outerR[0] * _cos[radiusSegments], outerR[0] * _sin[radiusSegments], shape.fDZ, + outerR[1] * _cos[radiusSegments], outerR[1] * _sin[radiusSegments], -shape.fDZ, + innerR[1] * _cos[radiusSegments], innerR[1] * _sin[radiusSegments], -shape.fDZ, + (outerR[0] === innerR[0]) ? 1 : ((innerR[1]===outerR[1]) ? 2 : 0)); + + if (calcZ) creator.RecalcZ(calcZ); + creator.CalcNormal(); + } + + return creator.Create(); + } + + /** @memberOf JSROOT.GEO */ + JSROOT.GEO.createEltuBuffer = function( shape , faces_limit ) { + var radiusSegments = Math.max(4, Math.round(360/JSROOT.GEO.GradPerSegm)); + + if (faces_limit < 0) return radiusSegments*4; + + // calculate all sin/cos tables in advance + var x = new Float32Array(radiusSegments+1), + y = new Float32Array(radiusSegments+1); + for (var seg=0; seg<=radiusSegments; ++seg) { + var phi = seg/radiusSegments*2*Math.PI; + x[seg] = shape.fRmin*Math.cos(phi); + y[seg] = shape.fRmax*Math.sin(phi); + } + + var creator = faces_limit ? new JSROOT.GEO.PolygonsCreator : new JSROOT.GEO.GeometryCreator(radiusSegments*4), + nx1 = 1, ny1 = 0, nx2 = 1, ny2 = 0; + + // create tube faces + for (var seg=0; seg<radiusSegments; ++seg) { + creator.AddFace4(x[seg], y[seg], +shape.fDZ, + x[seg], y[seg], -shape.fDZ, + x[seg+1], y[seg+1], -shape.fDZ, + x[seg+1], y[seg+1], shape.fDZ); + + // calculate normals ourself + nx1 = nx2; ny1 = ny2; + nx2 = x[seg+1] * shape.fRmax / shape.fRmin; + ny2 = y[seg+1] * shape.fRmin / shape.fRmax; + var dist = Math.sqrt(nx2*nx2 + ny2*ny2); + nx2 = nx2 / dist; ny2 = ny2/dist; + + creator.SetNormal_12_34(nx1,ny1,0,nx2,ny2,0); + } + + // create top/bottom sides + for (var side=0;side<2;++side) { + var sign = (side===0) ? 1 : -1, d1 = side, d2 = 1 - side; + for (var seg=0; seg<radiusSegments; ++seg) { + creator.AddFace3(0, 0, sign*shape.fDZ, + x[seg+d1], y[seg+d1], sign*shape.fDZ, + x[seg+d2], y[seg+d2], sign*shape.fDZ); + creator.SetNormal(0, 0, sign); + } + } + + return creator.Create(); + } + + /** @memberOf JSROOT.GEO */ + JSROOT.GEO.createTorusBuffer = function( shape, faces_limit ) { + var radius = shape.fR, + radialSegments = Math.max(6, Math.round(360/JSROOT.GEO.GradPerSegm)), + tubularSegments = Math.max(8, Math.round(shape.fDphi/JSROOT.GEO.GradPerSegm)); + + var numfaces = (shape.fRmin > 0 ? 4 : 2) * radialSegments * (tubularSegments + (shape.fDphi !== 360 ? 1 : 0)); + + if (faces_limit < 0) return numfaces; + + if ((faces_limit > 0) && (numfaces > faces_limit)) { + radialSegments = Math.floor(radialSegments/Math.sqrt(numfaces / faces_limit)); + tubularSegments = Math.floor(tubularSegments/Math.sqrt(numfaces / faces_limit)); + numfaces = (shape.fRmin > 0 ? 4 : 2) * radialSegments * (tubularSegments + (shape.fDphi !== 360 ? 1 : 0)); + } + + var _sinr = new Float32Array(radialSegments+1), + _cosr = new Float32Array(radialSegments+1), + _sint = new Float32Array(tubularSegments+1), + _cost = new Float32Array(tubularSegments+1); + + for (var n=0;n<=radialSegments;++n) { + _sinr[n] = Math.sin(n/radialSegments*2*Math.PI); + _cosr[n] = Math.cos(n/radialSegments*2*Math.PI); + } + + for (var t=0;t<=tubularSegments;++t) { + var angle = (shape.fPhi1 + shape.fDphi*t/tubularSegments)/180*Math.PI; + _sint[t] = Math.sin(angle); + _cost[t] = Math.cos(angle); + } + + var creator = faces_limit ? new JSROOT.GEO.PolygonsCreator : new JSROOT.GEO.GeometryCreator(numfaces); + + // use vectors for normals calculation + var p1 = new THREE.Vector3(), p2 = new THREE.Vector3(), p3 = new THREE.Vector3(), p4 = new THREE.Vector3(), + n1 = new THREE.Vector3(), n2 = new THREE.Vector3(), n3 = new THREE.Vector3(), n4 = new THREE.Vector3(), + center1 = new THREE.Vector3(), center2 = new THREE.Vector3(); + + for (var side=0;side<2;++side) { + if ((side > 0) && (shape.fRmin <= 0)) break; + var tube = (side > 0) ? shape.fRmin : shape.fRmax, + d1 = 1 - side, d2 = 1 - d1, ns = side>0 ? -1 : 1; + + for (var t=0;t<tubularSegments;++t) { + var t1 = t + d1, t2 = t + d2; + center1.x = radius * _cost[t1]; center1.y = radius * _sint[t1]; + center2.x = radius * _cost[t2]; center2.y = radius * _sint[t2]; + + for (var n=0;n<radialSegments;++n) { + p1.x = (radius + tube * _cosr[n]) * _cost[t1]; p1.y = (radius + tube * _cosr[n]) * _sint[t1]; p1.z = tube*_sinr[n]; + p2.x = (radius + tube * _cosr[n+1]) * _cost[t1]; p2.y = (radius + tube * _cosr[n+1]) * _sint[t1]; p2.z = tube*_sinr[n+1]; + p3.x = (radius + tube * _cosr[n+1]) * _cost[t2]; p3.y = (radius + tube * _cosr[n+1]) * _sint[t2]; p3.z = tube*_sinr[n+1]; + p4.x = (radius + tube * _cosr[n]) * _cost[t2]; p4.y = (radius + tube * _cosr[n]) * _sint[t2]; p4.z = tube*_sinr[n]; + + creator.AddFace4(p1.x, p1.y, p1.z, + p2.x, p2.y, p2.z, + p3.x, p3.y, p3.z, + p4.x, p4.y, p4.z); + + n1.subVectors( p1, center1 ).normalize(); + n2.subVectors( p2, center1 ).normalize(); + n3.subVectors( p3, center2 ).normalize(); + n4.subVectors( p4, center2 ).normalize(); + + creator.SetNormal4(ns*n1.x, ns*n1.y, ns*n1.z, + ns*n2.x, ns*n2.y, ns*n2.z, + ns*n3.x, ns*n3.y, ns*n3.z, + ns*n4.x, ns*n4.y, ns*n4.z); + } + } + } + + if (shape.fDphi !== 360) + for (var t=0;t<=tubularSegments;t+=tubularSegments) { + var tube1 = shape.fRmax, tube2 = shape.fRmin, + d1 = (t>0) ? 0 : 1, d2 = 1 - d1, + skip = (shape.fRmin) > 0 ? 0 : 1, + nsign = t>0 ? 1 : -1; + for (var n=0;n<radialSegments;++n) { + creator.AddFace4((radius + tube1 * _cosr[n+d1]) * _cost[t], (radius + tube1 * _cosr[n+d1]) * _sint[t], tube1*_sinr[n+d1], + (radius + tube2 * _cosr[n+d1]) * _cost[t], (radius + tube2 * _cosr[n+d1]) * _sint[t], tube2*_sinr[n+d1], + (radius + tube2 * _cosr[n+d2]) * _cost[t], (radius + tube2 * _cosr[n+d2]) * _sint[t], tube2*_sinr[n+d2], + (radius + tube1 * _cosr[n+d2]) * _cost[t], (radius + tube1 * _cosr[n+d2]) * _sint[t], tube1*_sinr[n+d2], skip); + creator.SetNormal(-nsign* _sint[t], nsign * _cost[t], 0); + } + } + + return creator.Create(); + } + + + /** @memberOf JSROOT.GEO */ + JSROOT.GEO.createPolygonBuffer = function( shape, faces_limit ) { + var thetaStart = shape.fPhi1, + thetaLength = shape.fDphi, + radiusSegments = 60; + + if ( shape._typename == "TGeoPgon" ) + radiusSegments = shape.fNedges; + else + radiusSegments = Math.max(5, Math.round(thetaLength/JSROOT.GEO.GradPerSegm)); + + var usage = new Int16Array(2*shape.fNz), numusedlayers = 0, hasrmin = false; + + for (var layer=0; layer < shape.fNz; ++layer) + if (shape.fRmin[layer] > 0) hasrmin = true; + + // return very rough estimation, number of faces may be much less + if (faces_limit < 0) return (hasrmin ? 4 : 2) * radiusSegments * (shape.fNz-1); + + // coordinate of point on cut edge (x,z) + var pnts = (thetaLength === 360) ? null : []; + + // first analyse levels - if we need to create all of them + for (var side = 0; side < 2; ++side) { + var rside = (side === 0) ? 'fRmax' : 'fRmin'; + + for (var layer=0; layer < shape.fNz; ++layer) { + + // first create points for the layer + var layerz = shape.fZ[layer], rad = shape[rside][layer]; + + usage[layer*2+side] = 0; + + if ((layer > 0) && (layer < shape.fNz-1)) + if (((shape.fZ[layer-1] === layerz) && (shape[rside][layer-1] === rad)) || + ((shape[rside][layer+1] === rad) && (shape[rside][layer-1] === rad))) { + + // same Z and R as before - ignore + // or same R before and after + + continue; + } + + if ((layer>0) && ((side === 0) || hasrmin)) { + usage[layer*2+side] = 1; + numusedlayers++; + } + + if (pnts !== null) { + if (side === 0) { + pnts.push(new THREE.Vector2(rad, layerz)); + } else + if (rad < shape.fRmax[layer]) { + pnts.unshift(new THREE.Vector2(rad, layerz)); + } + } + } + } + + var numfaces = numusedlayers*radiusSegments*2; + if (shape.fRmin[0] !== shape.fRmax[0]) numfaces += radiusSegments * (hasrmin ? 2 : 1); + if (shape.fRmin[shape.fNz-1] !== shape.fRmax[shape.fNz-1]) numfaces += radiusSegments * (hasrmin ? 2 : 1); + + var cut_faces = null; + + if (pnts!==null) { + if (pnts.length === shape.fNz * 2) { + // special case - all layers are there, create faces ourself + cut_faces = []; + for (var layer = shape.fNz-1; layer>0; --layer) { + if (shape.fZ[layer] === shape.fZ[layer-1]) continue; + var right = 2*shape.fNz - 1 - layer; + cut_faces.push([right, layer - 1, layer]); + cut_faces.push([right, right + 1, layer-1]); + } + + } else { + // let three.js calculate our faces + // console.log('triangulate polygon ' + shape.fShapeId); + cut_faces = THREE.ShapeUtils.triangulateShape(pnts, []); + } + numfaces += cut_faces.length*2; + } + + var phi0 = thetaStart*Math.PI/180, dphi = thetaLength/radiusSegments*Math.PI/180; + + // calculate all sin/cos tables in advance + var _sin = new Float32Array(radiusSegments+1), + _cos = new Float32Array(radiusSegments+1); + for (var seg=0;seg<=radiusSegments;++seg) { + _cos[seg] = Math.cos(phi0+seg*dphi); + _sin[seg] = Math.sin(phi0+seg*dphi); + } + + var creator = faces_limit ? new JSROOT.GEO.PolygonsCreator : new JSROOT.GEO.GeometryCreator(numfaces); + + // add sides + for (var side = 0; side < 2; ++side) { + var rside = (side === 0) ? 'fRmax' : 'fRmin', + z1 = shape.fZ[0], r1 = shape[rside][0], + d1 = 1 - side, d2 = side; + + for (var layer=0; layer < shape.fNz; ++layer) { + + if (usage[layer*2+side] === 0) continue; + + var z2 = shape.fZ[layer], r2 = shape[rside][layer], + nxy = 1, nz = 0; + + if ((r2 !== r1)) { + var angle = Math.atan2((r2-r1), (z2-z1)); + nxy = Math.cos(angle); + nz = Math.sin(angle); + } + + if (side>0) { nxy*=-1; nz*=-1; } + + for (var seg=0;seg < radiusSegments;++seg) { + creator.AddFace4(r1 * _cos[seg+d1], r1 * _sin[seg+d1], z1, + r2 * _cos[seg+d1], r2 * _sin[seg+d1], z2, + r2 * _cos[seg+d2], r2 * _sin[seg+d2], z2, + r1 * _cos[seg+d2], r1 * _sin[seg+d2], z1); + creator.SetNormal_12_34(nxy*_cos[seg+d1], nxy*_sin[seg+d1], nz, nxy*_cos[seg+d2], nxy*_sin[seg+d2], nz); + } + + z1 = z2; r1 = r2; + } + } + + // add top/bottom + for (var layer=0; layer < shape.fNz; layer += (shape.fNz-1)) { + + var rmin = shape.fRmin[layer], rmax = shape.fRmax[layer]; + + if (rmin === rmax) continue; + + var layerz = shape.fZ[layer], + d1 = (layer===0) ? 1 : 0, d2 = 1 - d1, + normalz = (layer===0) ? -1: 1; + + if (!hasrmin && !cut_faces) creator.StartPolygon(layer>0); + + for (var seg=0;seg < radiusSegments;++seg) { + creator.AddFace4(rmin * _cos[seg+d1], rmin * _sin[seg+d1], layerz, + rmax * _cos[seg+d1], rmax * _sin[seg+d1], layerz, + rmax * _cos[seg+d2], rmax * _sin[seg+d2], layerz, + rmin * _cos[seg+d2], rmin * _sin[seg+d2], layerz, + hasrmin ? 0 : 2); + creator.SetNormal(0, 0, normalz); + } + + creator.StopPolygon(); + } + + if (cut_faces) + for (var seg = 0; seg <= radiusSegments; seg += radiusSegments) { + var d1 = (seg === 0) ? 1 : 2, d2 = 3 - d1; + for (var n=0;n<cut_faces.length;++n) { + var a = pnts[cut_faces[n][0]], + b = pnts[cut_faces[n][d1]], + c = pnts[cut_faces[n][d2]]; + + creator.AddFace3(a.x * _cos[seg], a.x * _sin[seg], a.y, + b.x * _cos[seg], b.x * _sin[seg], b.y, + c.x * _cos[seg], c.x * _sin[seg], c.y); + + creator.CalcNormal(); + } + } + + return creator.Create(); + } + + /** @memberOf JSROOT.GEO */ + JSROOT.GEO.createXtruBuffer = function( shape, faces_limit ) { + var nfaces = (shape.fNz-1) * shape.fNvert * 2; + + if (faces_limit < 0) return nfaces + shape.fNvert*3; + + // create points + var pnts = []; + for (var vert = 0; vert < shape.fNvert; ++vert) + pnts.push(new THREE.Vector2(shape.fX[vert], shape.fY[vert])); + + // console.log('triangulate Xtru ' + shape.fShapeId); + var faces = THREE.ShapeUtils.triangulateShape(pnts , []); + if (faces.length < pnts.length-2) { + JSROOT.GEO.warn('Problem with XTRU shape ' +shape.fName + ' with ' + pnts.length + ' vertices'); + faces = []; + } else { + nfaces += faces.length * 2; + } + + var creator = faces_limit ? new JSROOT.GEO.PolygonsCreator : new JSROOT.GEO.GeometryCreator(nfaces); + + for (var layer = 0; layer < shape.fNz-1; ++layer) { + var z1 = shape.fZ[layer], scale1 = shape.fScale[layer], + z2 = shape.fZ[layer+1], scale2 = shape.fScale[layer+1]; + + for (var vert1 = 0; vert1 < shape.fNvert; ++vert1) { + var vert2 = (vert1+1) % shape.fNvert; + creator.AddFace4(scale1 * shape.fX[vert1], scale1 * shape.fY[vert1], z1, + scale2 * shape.fX[vert1], scale2 * shape.fY[vert1], z2, + scale2 * shape.fX[vert2], scale2 * shape.fY[vert2], z2, + scale1 * shape.fX[vert2], scale1 * shape.fY[vert2], z1); + creator.CalcNormal(); + } + } + + for (layer = 0; layer <= shape.fNz-1; layer+=(shape.fNz-1)) { + var z = shape.fZ[layer], scale = shape.fScale[layer]; + + for (var n=0;n<faces.length;++n) { + var face = faces[n], + pnt1 = pnts[face[0]], + pnt2 = pnts[face[(layer===0) ? 2 : 1]], + pnt3 = pnts[face[(layer===0) ? 1 : 2]]; + + creator.AddFace3(scale * pnt1.x, scale * pnt1.y, z, + scale * pnt2.x, scale * pnt2.y, z, + scale * pnt3.x, scale * pnt3.y, z); + creator.SetNormal(0,0,layer===0 ? -1 : 1); + } + } + + return creator.Create(); + } + + /** @memberOf JSROOT.GEO */ + JSROOT.GEO.createParaboloidBuffer = function( shape, faces_limit ) { + + var radiusSegments = Math.max(4, Math.round(360/JSROOT.GEO.GradPerSegm)), + heightSegments = 30; + + if (faces_limit > 0) { + var fact = 2*radiusSegments*(heightSegments+1) / faces_limit; + if (fact > 1.) { + radiusSegments = Math.max(5, Math.floor(radiusSegments/Math.sqrt(fact))); + heightSegments = Math.max(5, Math.floor(heightSegments/Math.sqrt(fact))); + } + } + + var zmin = -shape.fDZ, zmax = shape.fDZ, rmin = shape.fRlo, rmax = shape.fRhi; + + // if no radius at -z, find intersection + if (shape.fA >= 0) { + if (shape.fB > zmin) zmin = shape.fB; + } else { + if (shape.fB < zmax) zmax = shape.fB; + } + + var ttmin = Math.atan2(zmin, rmin), ttmax = Math.atan2(zmax, rmax); + + var numfaces = (heightSegments+1)*radiusSegments*2; + if (rmin===0) numfaces -= radiusSegments*2; // complete layer + if (rmax===0) numfaces -= radiusSegments*2; // complete layer + + if (faces_limit < 0) return numfaces; + + // calculate all sin/cos tables in advance + var _sin = new Float32Array(radiusSegments+1), + _cos = new Float32Array(radiusSegments+1); + for (var seg=0;seg<=radiusSegments;++seg) { + _cos[seg] = Math.cos(seg/radiusSegments*2*Math.PI); + _sin[seg] = Math.sin(seg/radiusSegments*2*Math.PI); + } + + var creator = faces_limit ? new JSROOT.GEO.PolygonsCreator : new JSROOT.GEO.GeometryCreator(numfaces); + + var lastz = zmin, lastr = 0, lastnxy = 0, lastnz = -1; + + for (var layer = 0; layer <= heightSegments + 1; ++layer) { + + var layerz = 0, radius = 0, nxy = 0, nz = -1; + + if ((layer === 0) && (rmin===0)) continue; + + if ((layer === heightSegments + 1) && (lastr === 0)) break; + + switch (layer) { + case 0: layerz = zmin; radius = rmin; break; + case heightSegments: layerz = zmax; radius = rmax; break; + case heightSegments + 1: layerz = zmax; radius = 0; break; + default: { + var tt = Math.tan(ttmin + (ttmax-ttmin) * layer / heightSegments); + var delta = tt*tt - 4*shape.fA*shape.fB; // should be always positive (a*b<0) + radius = 0.5*(tt+Math.sqrt(delta))/shape.fA; + if (radius < 1e-6) radius = 0; + layerz = radius*tt; + } + } + + nxy = shape.fA * radius; + nz = (shape.fA > 0) ? -1 : 1; + + var skip = 0; + if (lastr === 0) skip = 1; else + if (radius === 0) skip = 2; + + for (var seg=0; seg<radiusSegments; ++seg) { + creator.AddFace4(radius*_cos[seg], radius*_sin[seg], layerz, + lastr*_cos[seg], lastr*_sin[seg], lastz, + lastr*_cos[seg+1], lastr*_sin[seg+1], lastz, + radius*_cos[seg+1], radius*_sin[seg+1], layerz, skip); + + // use analytic normal values when open/closing paraboloid around 0 + // cut faces (top or bottom) set with simple normal + if ((skip===0) || ((layer===1) && (rmin===0)) || ((layer===heightSegments+1) && (rmax===0))) + creator.SetNormal4(nxy*_cos[seg], nxy*_sin[seg], nz, + lastnxy*_cos[seg], lastnxy*_sin[seg], lastnz, + lastnxy*_cos[seg+1], lastnxy*_sin[seg+1], lastnz, + nxy*_cos[seg+1], nxy*_sin[seg+1], nz, skip); + else + creator.SetNormal(0, 0, (layer < heightSegments) ? -1 : 1); + } + + lastz = layerz; lastr = radius; + lastnxy = nxy; lastnz = nz; + } + + return creator.Create(); + } + + /** @memberOf JSROOT.GEO */ + JSROOT.GEO.createHypeBuffer = function( shape, faces_limit ) { + + if ((shape.fTin===0) && (shape.fTout===0)) + return JSROOT.GEO.createTubeBuffer(shape, faces_limit); + + var radiusSegments = Math.max(4, Math.round(360/JSROOT.GEO.GradPerSegm)), + heightSegments = 30; + + var numfaces = radiusSegments * (heightSegments + 1) * ((shape.fRmin > 0) ? 4 : 2); + + if (faces_limit < 0) return numfaces; + + if ((faces_limit > 0) && (faces_limit > numfaces)) { + radiusSegments = Math.max(4, Math.floor(radiusSegments/Math.sqrt(numfaces/faces_limit))); + heightSegments = Math.max(4, Math.floor(heightSegments/Math.sqrt(numfaces/faces_limit))); + numfaces = radiusSegments * (heightSegments + 1) * ((shape.fRmin > 0) ? 4 : 2); + } + + // calculate all sin/cos tables in advance + var _sin = new Float32Array(radiusSegments+1), _cos = new Float32Array(radiusSegments+1); + for (var seg=0;seg<=radiusSegments;++seg) { + _cos[seg] = Math.cos(seg/radiusSegments*2*Math.PI); + _sin[seg] = Math.sin(seg/radiusSegments*2*Math.PI); + } + + var creator = faces_limit ? new JSROOT.GEO.PolygonsCreator : new JSROOT.GEO.GeometryCreator(numfaces); + + // in-out side + for (var side=0;side<2;++side) { + if ((side > 0) && (shape.fRmin <= 0)) break; + + var r0 = (side > 0) ? shape.fRmin : shape.fRmax, + tsq = (side > 0) ? shape.fTinsq : shape.fToutsq, + d1 = 1- side, d2 = 1 - d1; + + // vertical layers + for (var layer=0;layer<heightSegments;++layer) { + var z1 = -shape.fDz + layer/heightSegments*2*shape.fDz, + z2 = -shape.fDz + (layer+1)/heightSegments*2*shape.fDz, + r1 = Math.sqrt(r0*r0+tsq*z1*z1), + r2 = Math.sqrt(r0*r0+tsq*z2*z2); + + for (var seg=0; seg<radiusSegments; ++seg) { + creator.AddFace4(r1 * _cos[seg+d1], r1 * _sin[seg+d1], z1, + r2 * _cos[seg+d1], r2 * _sin[seg+d1], z2, + r2 * _cos[seg+d2], r2 * _sin[seg+d2], z2, + r1 * _cos[seg+d2], r1 * _sin[seg+d2], z1); + creator.CalcNormal(); + } + } + } + + // add caps + for(var layer=0; layer<2; ++layer) { + var z = (layer === 0) ? shape.fDz : -shape.fDz, + r1 = Math.sqrt(shape.fRmax*shape.fRmax + shape.fToutsq*z*z), + r2 = (shape.fRmin > 0) ? Math.sqrt(shape.fRmin*shape.fRmin + shape.fTinsq*z*z) : 0, + skip = (shape.fRmin > 0) ? 0 : 1, + d1 = 1 - layer, d2 = 1 - d1; + for (var seg=0; seg<radiusSegments; ++seg) { + creator.AddFace4(r1 * _cos[seg+d1], r1 * _sin[seg+d1], z, + r2 * _cos[seg+d1], r2 * _sin[seg+d1], z, + r2 * _cos[seg+d2], r2 * _sin[seg+d2], z, + r1 * _cos[seg+d2], r1 * _sin[seg+d2], z, skip); + creator.SetNormal(0,0, (layer===0) ? 1 : -1) + } + + } + + return creator.Create(); + } + + + /** @memberOf JSROOT.GEO */ + JSROOT.GEO.createMatrix = function(matrix) { + + if (!matrix) return null; + + var translation = null, rotation = null, scale = null; + + switch (matrix._typename) { + case 'TGeoTranslation': translation = matrix.fTranslation; break; + case 'TGeoRotation': rotation = matrix.fRotationMatrix; break; + case 'TGeoScale': scale = matrix.fScale; break; + case 'TGeoGenTrans': + scale = matrix.fScale; // no break, translation and rotation follows + case 'TGeoCombiTrans': + translation = matrix.fTranslation; + if (matrix.fRotation) rotation = matrix.fRotation.fRotationMatrix; + break; + case 'TGeoHMatrix': + translation = matrix.fTranslation; + rotation = matrix.fRotationMatrix; + scale = matrix.fScale; + break; + case 'TGeoIdentity': + break; + default: + console.warn('unsupported matrix ' + matrix._typename); + } + + if (!translation && !rotation && !scale) return null; + + var res = new THREE.Matrix4(); + + if (rotation) + res.set(rotation[0], rotation[1], rotation[2], 0, + rotation[3], rotation[4], rotation[5], 0, + rotation[6], rotation[7], rotation[8], 0, + 0, 0, 0, 1); + + if (translation) + res.setPosition(new THREE.Vector3(translation[0], translation[1], translation[2])); + + if (scale) + res.scale(new THREE.Vector3(scale[0], scale[1], scale[2])); + + return res; + } + + /** @memberOf JSROOT.GEO */ + JSROOT.GEO.getNodeMatrix = function(kind, node) { + // returns transformation matrix for the node + // created after node visibility flag is checked and volume cut is performed + + var matrix = null; + + if (kind === 1) { + // special handling for EVE nodes + + matrix = new THREE.Matrix4(); + + if (node.fTrans!==null) { + matrix.set(node.fTrans[0], node.fTrans[4], node.fTrans[8], 0, + node.fTrans[1], node.fTrans[5], node.fTrans[9], 0, + node.fTrans[2], node.fTrans[6], node.fTrans[10], 0, + 0, 0, 0, 1); + // second - set position with proper sign + matrix.setPosition({ x: node.fTrans[12], y: node.fTrans[13], z: node.fTrans[14] }); + } + } else + if (('fMatrix' in node) && (node.fMatrix !== null)) + matrix = JSROOT.GEO.createMatrix(node.fMatrix); + else + if ((node._typename == "TGeoNodeOffset") && (node.fFinder !== null)) { + var kPatternReflected = JSROOT.BIT(14); + if ((node.fFinder.fBits & kPatternReflected) !== 0) + JSROOT.GEO.warn('Unsupported reflected pattern ' + node.fFinder._typename); + + // if (node.fFinder._typename === 'TGeoPatternCylR') { } + // if (node.fFinder._typename === 'TGeoPatternSphR') { } + // if (node.fFinder._typename === 'TGeoPatternSphTheta') { } + // if (node.fFinder._typename === 'TGeoPatternSphPhi') { } + // if (node.fFinder._typename === 'TGeoPatternHoneycomb') { } + switch(node.fFinder._typename) { + case 'TGeoPatternX': + case 'TGeoPatternY': + case 'TGeoPatternZ': + case 'TGeoPatternParaX': + case 'TGeoPatternParaY': + case 'TGeoPatternParaZ': + var _shift = node.fFinder.fStart + (node.fIndex + 0.5) * node.fFinder.fStep; + + matrix = new THREE.Matrix4(); + + switch (node.fFinder._typename[node.fFinder._typename.length-1]) { + case 'X': matrix.setPosition(new THREE.Vector3(_shift, 0, 0)); break; + case 'Y': matrix.setPosition(new THREE.Vector3(0, _shift, 0)); break; + case 'Z': matrix.setPosition(new THREE.Vector3(0, 0, _shift)); break; + } + break; + + case 'TGeoPatternCylPhi': + var phi = (Math.PI/180)*(node.fFinder.fStart+(node.fIndex+0.5)*node.fFinder.fStep), + _cos = Math.cos(phi), _sin = Math.sin(phi); + + matrix = new THREE.Matrix4(); + + matrix.set(_cos, -_sin, 0, 0, + _sin, _cos, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1); + break; + + case 'TGeoPatternCylR': + // seems to be, require no transformation + matrix = new THREE.Matrix4(); + break; + + case 'TGeoPatternTrapZ': + var dz = node.fFinder.fStart + (node.fIndex+0.5)*node.fFinder.fStep; + matrix = new THREE.Matrix4(); + matrix.setPosition(new THREE.Vector3(node.fFinder.fTxz*dz, node.fFinder.fTyz*dz, dz)); + break; + + default: + JSROOT.GEO.warn('Unsupported pattern type ' + node.fFinder._typename); + break; + } + } + + return matrix; + } + + /** @memberOf JSROOT.GEO */ + JSROOT.GEO.createComposite = function ( shape, faces_limit ) { + + /* + if ((faces_limit === -1) || (faces_limit === 0)) { + var cnt = JSROOT.GEO.CountNumShapes(shape); + + if (cnt > JSROOT.GEO.CompLimit) { + JSROOT.GEO.warn("composite shape " + shape.fShapeId + " has " + cnt + " components, replace by most left"); + var matrix = new THREE.Matrix4(); + while (shape.fNode && shape.fNode.fLeft) { + var m1 = JSROOT.GEO.createMatrix(shape.fNode.fLeftMat); + if (m1) matrix.multiply(m1); + shape = shape.fNode.fLeft; + } + var res = JSROOT.GEO.createGeometry(shape, faces_limit); + if (res && (faces_limit===0)) res.applyMatrix(matrix); + return res; + } + } + */ + + if (faces_limit < 0) + return JSROOT.GEO.createGeometry(shape.fNode.fLeft, -10) + + JSROOT.GEO.createGeometry(shape.fNode.fRight, -10); + + var geom1, geom2, bsp1, bsp2, return_bsp = false, + matrix1 = JSROOT.GEO.createMatrix(shape.fNode.fLeftMat), + matrix2 = JSROOT.GEO.createMatrix(shape.fNode.fRightMat); + + // seems to be, IE has smaller stack for functions calls and ThreeCSG fails with large shapes + if (faces_limit === 0) faces_limit = (JSROOT.browser && JSROOT.browser.isIE) ? 2000 : 4000; + else return_bsp = true; + + if (matrix1 && (matrix1.determinant() < -0.9)) + JSROOT.GEO.warn('Axis reflection in left composite shape - not supported'); + + if (matrix2 && (matrix2.determinant() < -0.9)) + JSROOT.GEO.warn('Axis reflections in right composite shape - not supported'); + + geom1 = JSROOT.GEO.createGeometry(shape.fNode.fLeft, faces_limit); + if (!geom1) return null; + + var n1 = JSROOT.GEO.numGeometryFaces(geom1), n2 = 0; + if (geom1._exceed_limit) n1 += faces_limit; + + if (n1 < faces_limit) { + geom2 = JSROOT.GEO.createGeometry(shape.fNode.fRight, faces_limit); + n2 = JSROOT.GEO.numGeometryFaces(geom2); + } + + if ((n1 + n2 >= faces_limit) || !geom2) { + if (geom1.polygons) { + geom1 = ThreeBSP.CreateBufferGeometry(geom1.polygons); + n1 = JSROOT.GEO.numGeometryFaces(geom1); + } + if (matrix1) geom1.applyMatrix(matrix1); + // if (!geom1._exceed_limit) console.log('reach faces limit', faces_limit, 'got', n1, n2); + geom1._exceed_limit = true; + return geom1; + } + + bsp1 = new ThreeBSP.Geometry(geom1, matrix1, JSROOT.GEO.CompressComp ? 0 : undefined); + + bsp2 = new ThreeBSP.Geometry(geom2, matrix2, bsp1.maxid); + + // take over maxid from both geometries + bsp1.maxid = bsp2.maxid; + + switch(shape.fNode._typename) { + case 'TGeoIntersection': bsp1.direct_intersect(bsp2); break; // "*" + case 'TGeoUnion': bsp1.direct_union(bsp2); break; // "+" + case 'TGeoSubtraction': bsp1.direct_subtract(bsp2); break; // "/" + default: + JSROOT.GEO.warn('unsupported bool operation ' + shape.fNode._typename + ', use first geom'); + } + + if (JSROOT.GEO.numGeometryFaces(bsp1) === 0) { + JSROOT.GEO.warn('Zero faces in comp shape' + + ' left: ' + shape.fNode.fLeft._typename + ' ' + JSROOT.GEO.numGeometryFaces(geom1) + ' faces' + + ' right: ' + shape.fNode.fRight._typename + ' ' + JSROOT.GEO.numGeometryFaces(geom2) + ' faces' + + ' use first'); + bsp1 = new ThreeBSP.Geometry(geom1, matrix1); + } + + return return_bsp ? { polygons: bsp1.toPolygons() } : bsp1.toBufferGeometry(); + } + + /** @memberOf JSROOT.GEO */ + JSROOT.GEO.projectGeometry = function(geom, matrix, projection, position, flippedMesh) { + + if (!geom.boundingBox) geom.computeBoundingBox(); + + var box = geom.boundingBox.clone(); + + box.applyMatrix4(matrix); + + if (!position) position = 0; + + if (((box.min[projection]>=position) && (box.max[projection]>=position)) || + ((box.min[projection]<=position) && (box.max[projection]<=position))) { + return null; // not interesting + } + + var bsp1 = new ThreeBSP.Geometry(geom, matrix, 0, flippedMesh), + sizex = 2*Math.max(Math.abs(box.min.x), Math.abs(box.max.x)), + sizey = 2*Math.max(Math.abs(box.min.y), Math.abs(box.max.y)), + sizez = 2*Math.max(Math.abs(box.min.z), Math.abs(box.max.z)), + size = 10000; + + switch (projection) { + case "x": size = Math.max(sizey,sizez); break; + case "y": size = Math.max(sizex,sizez); break; + case "z": size = Math.max(sizex,sizey); break; + } + + var bsp2 = ThreeBSP.CreateNormal(projection, position, size); + + bsp1.cut_from_plane(bsp2); + + return bsp2.toBufferGeometry(); + } + + /** + * Creates geometry model for the provided shape + * @memberOf JSROOT.GEO + * + * If @par limit === 0 (or undefined) returns THREE.BufferGeometry + * If @par limit < 0 just returns estimated number of faces + * If @par limit > 0 return list of ThreeBSP polygons (used only for composite shapes) + * */ + JSROOT.GEO.createGeometry = function( shape, limit ) { + if (limit === undefined) limit = 0; + + try { + switch (shape._typename) { + case "TGeoBBox": return JSROOT.GEO.createCubeBuffer( shape, limit ); + case "TGeoPara": return JSROOT.GEO.createParaBuffer( shape, limit ); + case "TGeoTrd1": + case "TGeoTrd2": return JSROOT.GEO.createTrapezoidBuffer( shape, limit ); + case "TGeoArb8": + case "TGeoTrap": + case "TGeoGtra": return JSROOT.GEO.createArb8Buffer( shape, limit ); + case "TGeoSphere": return JSROOT.GEO.createSphereBuffer( shape , limit ); + case "TGeoCone": + case "TGeoConeSeg": + case "TGeoTube": + case "TGeoTubeSeg": + case "TGeoCtub": return JSROOT.GEO.createTubeBuffer( shape, limit ); + case "TGeoEltu": return JSROOT.GEO.createEltuBuffer( shape, limit ); + case "TGeoTorus": return JSROOT.GEO.createTorusBuffer( shape, limit ); + case "TGeoPcon": + case "TGeoPgon": return JSROOT.GEO.createPolygonBuffer( shape, limit ); + case "TGeoXtru": return JSROOT.GEO.createXtruBuffer( shape, limit ); + case "TGeoParaboloid": return JSROOT.GEO.createParaboloidBuffer( shape, limit ); + case "TGeoHype": return JSROOT.GEO.createHypeBuffer( shape, limit ); + case "TGeoCompositeShape": return JSROOT.GEO.createComposite( shape, limit ); + case "TGeoShapeAssembly": break; + case "TGeoScaledShape": { + var res = JSROOT.GEO.createGeometry(shape.fShape, limit); + if (shape.fScale && (limit>=0) && (typeof res === 'object') && (typeof res.scale === 'function')) + res.scale(shape.fScale.fScale[0],shape.fScale.fScale[1],shape.fScale.fScale[2]); + return res; + } + default: JSROOT.GEO.warn('unsupported shape type ' + shape._typename); + } + } catch(e) { + var place = ""; + if (e.stack !== undefined) { + place = e.stack.split("\n")[0]; + if (place.indexOf(e.message) >= 0) place = e.stack.split("\n")[1]; + else place = " at: " + place; + } + JSROOT.GEO.warn(shape._typename + " err: " + e.message + place); + } + + return limit < 0 ? 0 : null; + } + + /** Provides info about geo object, used for tooltip info */ + JSROOT.GEO.provideInfo = function(obj) { + var info = [], shape = null; + + if (obj.fVolume !== undefined) shape = obj.fVolume.fShape; else + if (obj.fShape !== undefined) shape = obj.fShape; else + if ((obj.fShapeBits !== undefined) && (obj.fShapeId !== undefined)) shape = obj; + + if (!shape) { + info.push(obj._typename); + return info; + } + + var sz = Math.max(shape.fDX, shape.fDY, shape.fDZ); + var useexp = (sz>1e7) || (sz<1e-7); + + function conv(v) { + if (v===undefined) return "???"; + if ((v==Math.round(v) && v<1e7)) return Math.round(v); + return useexp ? v.toExponential(4) : v.toPrecision(7); + } + + info.push(shape._typename); + + info.push("DX="+conv(shape.fDX) + " DY="+conv(shape.fDY) + " DZ="+conv(shape.fDZ)); + + switch (shape._typename) { + case "TGeoBBox": break; + case "TGeoPara": info.push("Alpha=" + shape.fAlpha + " Phi=" + shape.fPhi + " Theta=" + shape.fTheta); break; + case "TGeoTrd2": info.push("Dy1=" + conv(shape.fDy1) + " Dy2=" + conv(shape.fDy1)); + case "TGeoTrd1": info.push("Dx1=" + conv(shape.fDx1) + " Dx2=" + conv(shape.fDx1)); break; + case "TGeoArb8": break; + case "TGeoTrap": break; + case "TGeoGtra": break; + case "TGeoSphere": + info.push("Rmin=" + conv(shape.fRmin) + " Rmax=" + conv(shape.fRmax)); + info.push("Phi1=" + shape.fPhi1 + " Phi2=" + shape.fPhi2); + info.push("Theta1=" + shape.fTheta1 + " Theta2=" + shape.fTheta2); + break; + case "TGeoConeSeg": + info.push("Phi1=" + shape.fPhi1 + " Phi2=" + shape.fPhi2); + case "TGeoCone": + info.push("Rmin1=" + conv(shape.fRmin1) + " Rmax1=" + conv(shape.fRmax1)); + info.push("Rmin2=" + conv(shape.fRmin2) + " Rmax2=" + conv(shape.fRmax2)); + break; + case "TGeoCtub": + case "TGeoTubeSeg": + info.push("Phi1=" + shape.fPhi1 + " Phi2=" + shape.fPhi2); + case "TGeoEltu": + case "TGeoTube": + info.push("Rmin=" + conv(shape.fRmin) + " Rmax=" + conv(shape.fRmax)); + break; + case "TGeoTorus": + info.push("Rmin=" + conv(shape.fRmin) + " Rmax=" + conv(shape.fRmax)); + info.push("Phi1=" + shape.fPhi1 + " Dphi=" + shape.fDphi); + break; + case "TGeoPcon": + case "TGeoPgon": break; + case "TGeoXtru": break; + case "TGeoParaboloid": + info.push("Rlo=" + conv(shape.fRlo) + " Rhi=" + conv(shape.fRhi)); + info.push("A=" + conv(shape.fA) + " B=" + conv(shape.fB)); + break; + case "TGeoHype": + info.push("Rmin=" + conv(shape.fRmin) + " Rmax=" + conv(shape.fRmax)); + info.push("StIn=" + conv(shape.fStIn) + " StOut=" + conv(shape.fStOut)); + break; + case "TGeoCompositeShape": break; + case "TGeoShapeAssembly": break; + case "TGeoScaledShape": + info = JSROOT.GEO.provideInfo(shape.fShape); + if (shape.fScale) + info.unshift('Scale X=' + shape.fScale.fScale[0] + " Y=" + shape.fScale.fScale[1] + " Z=" + shape.fScale.fScale[2]); + break; + } + + return info; + } + + /** @memberOf JSROOT.GEO */ + JSROOT.GEO.CreateProjectionMatrix = function(camera) { + var cameraProjectionMatrix = new THREE.Matrix4(); + + camera.updateMatrixWorld(); + camera.matrixWorldInverse.getInverse( camera.matrixWorld ); + cameraProjectionMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse); + + return cameraProjectionMatrix; + } + + /** @memberOf JSROOT.GEO */ + JSROOT.GEO.CreateFrustum = function(source) { + if (!source) return null; + + if (source instanceof THREE.PerspectiveCamera) + source = JSROOT.GEO.CreateProjectionMatrix(source); + + var frustum = new THREE.Frustum(); + frustum.setFromMatrix(source); + + frustum.corners = new Float32Array([ + 1, 1, 1, + 1, 1, -1, + 1, -1, 1, + 1, -1, -1, + -1, 1, 1, + -1, 1, -1, + -1, -1, 1, + -1, -1, -1, + 0, 0, 0 // also check center of the shape + ]); + + frustum.test = new THREE.Vector3(0,0,0); + + frustum.CheckShape = function(matrix, shape) { + var pnt = this.test, len = this.corners.length, corners = this.corners, i; + + for (i = 0; i < len; i+=3) { + pnt.x = corners[i] * shape.fDX; + pnt.y = corners[i+1] * shape.fDY; + pnt.z = corners[i+2] * shape.fDZ; + if (this.containsPoint(pnt.applyMatrix4(matrix))) return true; + } + + return false; + } + + frustum.CheckBox = function(box) { + var pnt = this.test, cnt = 0; + pnt.set(box.min.x, box.min.y, box.min.z); + if (this.containsPoint(pnt)) cnt++; + pnt.set(box.min.x, box.min.y, box.max.z); + if (this.containsPoint(pnt)) cnt++; + pnt.set(box.min.x, box.max.y, box.min.z); + if (this.containsPoint(pnt)) cnt++; + pnt.set(box.min.x, box.max.y, box.max.z); + if (this.containsPoint(pnt)) cnt++; + pnt.set(box.max.x, box.max.y, box.max.z); + if (this.containsPoint(pnt)) cnt++; + pnt.set(box.max.x, box.min.y, box.max.z); + if (this.containsPoint(pnt)) cnt++; + pnt.set(box.max.x, box.max.y, box.min.z); + if (this.containsPoint(pnt)) cnt++; + pnt.set(box.max.x, box.max.y, box.max.z); + if (this.containsPoint(pnt)) cnt++; + return cnt>5; // only if 6 edges and more are seen, we think that box is fully visible + } + + return frustum; + } + + /** @memberOf JSROOT.GEO */ + JSROOT.GEO.VisibleByCamera = function(camera, matrix, shape) { + var frustum = new THREE.Frustum(); + var cameraProjectionMatrix = new THREE.Matrix4(); + + camera.updateMatrixWorld(); + camera.matrixWorldInverse.getInverse( camera.matrixWorld ); + cameraProjectionMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse); + frustum.setFromMatrix( cameraProjectionMatrix ); + + var corners = [ + new THREE.Vector3( shape.fDX/2.0, shape.fDY/2.0, shape.fDZ/2.0 ), + new THREE.Vector3( shape.fDX/2.0, shape.fDY/2.0, -shape.fDZ/2.0 ), + new THREE.Vector3( shape.fDX/2.0, -shape.fDY/2.0, shape.fDZ/2.0 ), + new THREE.Vector3( shape.fDX/2.0, -shape.fDY/2.0, -shape.fDZ/2.0 ), + new THREE.Vector3( -shape.fDX/2.0, shape.fDY/2.0, shape.fDZ/2.0 ), + new THREE.Vector3( -shape.fDX/2.0, shape.fDY/2.0, -shape.fDZ/2.0 ), + new THREE.Vector3( -shape.fDX/2.0, -shape.fDY/2.0, shape.fDZ/2.0 ), + new THREE.Vector3( -shape.fDX/2.0, -shape.fDY/2.0, -shape.fDZ/2.0 ) + ]; + for (var i = 0; i < corners.length; i++) { + if (frustum.containsPoint(corners[i].applyMatrix4(matrix))) return true; + } + + return false; + } + + /** @memberOf JSROOT.GEO */ + JSROOT.GEO.numGeometryFaces = function(geom) { + if (!geom) return 0; + + if (geom instanceof ThreeBSP.Geometry) + return geom.tree.numPolygons(); + + if (geom.type == 'BufferGeometry') { + var attr = geom.getAttribute('position'); + return attr ? attr.count / 3 : 0; + } + + // special array of polygons + if (geom && geom.polygons) return geom.polygons.length; + + return geom.faces.length; + } + + /** @memberOf JSROOT.GEO */ + JSROOT.GEO.numGeometryVertices = function(geom) { + if (!geom) return 0; + + if (geom instanceof ThreeBSP.Geometry) + return geom.tree.numPolygons() * 3; + + if (geom.type == 'BufferGeometry') { + var attr = geom.getAttribute('position'); + return attr ? attr.count : 0; + } + + if (geom && geom.polygons) return geom.polygons.length * 4; + + return geom.vertices.length; + } + + /** Compares two stacks. Returns length where stacks are the same + * @memberOf JSROOT.GEO + * @private */ + JSROOT.GEO.CompareStacks = function(stack1, stack2) { + if (!stack1 || !stack2) return 0; + if (stack1 === stack2) return stack1.length; + var len = Math.min(stack1.length, stack2.length); + for (var k=0;k<len;++k) + if (stack1[k] !== stack2[k]) return k; + return len; + } + + /** Checks if two stack arrays are identical + * @memberOf JSROOT.GEO + * @private */ + JSROOT.GEO.IsSameStack = function(stack1, stack2) { + if (!stack1 || !stack2) return false; + if (stack1 === stack2) return true; + if (stack1.length !== stack2.length) return false; + for (var k=0;k<stack1.length;++k) + if (stack1[k] !== stack2[k]) return false; + return true; + } + + + // ==================================================================== + + // class for working with cloned nodes + + JSROOT.GEO.ClonedNodes = function(obj, clones) { + this.toplevel = true; // indicate if object creates top-level structure with Nodes and Volumes folder + this.name_prefix = ""; // name prefix used for nodes names + this.maxdepth = 1; // maximal hierarchy depth, required for transparency + + if (obj) { + if (obj.$geoh) this.toplevel = false; + this.CreateClones(obj); + } else + if (clones) this.nodes = clones; + } + + JSROOT.GEO.ClonedNodes.prototype.GetNodeShape = function(indx) { + if (!this.origin || !this.nodes) return null; + var obj = this.origin[indx], clone = this.nodes[indx]; + if (!obj || !clone) return null; + if (clone.kind === 0) { + if (obj.fVolume) return obj.fVolume.fShape; + } else { + return obj.fShape; + } + return null; + } + + JSROOT.GEO.ClonedNodes.prototype.Cleanup = function(drawnodes, drawshapes) { + // function to cleanup as much as possible structures + // drawnodes and drawshapes are arrays created during building of geometry + + if (drawnodes) { + for (var n=0;n<drawnodes.length;++n) { + delete drawnodes[n].stack; + drawnodes[n] = undefined; + } + } + + if (drawshapes) { + for (var n=0;n<drawshapes.length;++n) { + delete drawshapes[n].geom; + drawshapes[n] = undefined; + } + } + + if (this.nodes) + for (var n=0;n<this.nodes.length;++n) + delete this.nodes[n].chlds; + + delete this.nodes; + delete this.origin; + + delete this.sortmap; + + } + + JSROOT.GEO.ClonedNodes.prototype.CreateClones = function(obj, sublevel, kind) { + if (!sublevel) { + this.origin = []; + sublevel = 1; + kind = JSROOT.GEO.NodeKind(obj); + } + + if ((kind < 0) || !obj || ('_refid' in obj)) return; + + obj._refid = this.origin.length; + this.origin.push(obj); + if (sublevel>this.maxdepth) this.maxdepth = sublevel; + + var chlds = null; + if (kind===0) + chlds = (obj.fVolume && obj.fVolume.fNodes) ? obj.fVolume.fNodes.arr : null; + else + chlds = obj.fElements ? obj.fElements.arr : null; + + if (chlds !== null) { + JSROOT.GEO.CheckDuplicates(obj, chlds); + for (var i = 0; i < chlds.length; ++i) + this.CreateClones(chlds[i], sublevel+1, kind); + } + + if (sublevel > 1) return; + + this.nodes = []; + + var sortarr = []; + + // first create nodes objects + for (var n=0; n<this.origin.length; ++n) { + var obj = this.origin[n]; + var node = { id: n, kind: kind, vol: 0, nfaces: 0, numvischld: 1, idshift: 0 }; + this.nodes.push(node); + sortarr.push(node); // array use to produce sortmap + } + + // than fill children lists + for (var n=0;n<this.origin.length;++n) { + var obj = this.origin[n], clone = this.nodes[n]; + + var chlds = null, shape = null; + + if (kind===1) { + shape = obj.fShape; + if (obj.fElements) chlds = obj.fElements.arr; + } else + if (obj.fVolume) { + shape = obj.fVolume.fShape; + if (obj.fVolume.fNodes) chlds = obj.fVolume.fNodes.arr; + } + + var matrix = JSROOT.GEO.getNodeMatrix(kind, obj); + if (matrix) { + clone.matrix = matrix.elements; // take only matrix elements, matrix will be constructed in worker + if (clone.matrix[0] === 1) { + var issimple = true; + for (var k=1;(k<clone.matrix.length) && issimple;++k) + issimple = (clone.matrix[k] === ((k===5) || (k===10) || (k===15) ? 1 : 0)); + if (issimple) delete clone.matrix; + } + } + if (shape) { + clone.fDX = shape.fDX; + clone.fDY = shape.fDY; + clone.fDZ = shape.fDZ; + clone.vol = shape.fDX*shape.fDY*shape.fDZ; + if (shape.$nfaces === undefined) + shape.$nfaces = JSROOT.GEO.createGeometry(shape, -1); + clone.nfaces = shape.$nfaces; + if (clone.nfaces <= 0) clone.vol = 0; + + // if (clone.nfaces < -10) console.log('Problem with node ' + obj.fName + ':' + obj.fMother.fName); + } + + if (!chlds) continue; + + // in cloned object children is only list of ids + clone.chlds = new Int32Array(chlds.length); + for (var k=0;k<chlds.length;++k) + clone.chlds[k] = chlds[k]._refid; + } + + // remove _refid identifiers from original objects + for (var n=0;n<this.origin.length;++n) + delete this.origin[n]._refid; + + // do sorting once + sortarr.sort(function(a,b) { return b.vol - a.vol; }); + + // remember sort map and also sortid + this.sortmap = new Int32Array(this.nodes.length); + for (var n=0;n<this.nodes.length;++n) { + this.sortmap[n] = sortarr[n].id; + sortarr[n].sortid = n; + } + } + + + JSROOT.GEO.ClonedNodes.prototype.MarkVisisble = function(on_screen, copy_bits, cloning) { + if (!this.nodes) return 0; + + var res = 0, simple_copy = cloning && (cloning.length === this.nodes.length); + + if (!simple_copy && !this.origin) return 0; + + for (var n=0;n<this.nodes.length;++n) { + var clone = this.nodes[n]; + + clone.vis = false; + clone.numvischld = 1; // reset vis counter, will be filled with next scan + clone.idshift = 0; + delete clone.depth; + + if (simple_copy) { + clone.vis = cloning[n].vis; + if (cloning[n].depth !== undefined) clone.depth = cloning[n].depth; + if (clone.vis) res++; + continue; + } + + var obj = this.origin[n]; + + if (clone.kind === 0) { + if (obj.fVolume) { + if (on_screen) { + clone.vis = JSROOT.GEO.TestBit(obj.fVolume, JSROOT.GEO.BITS.kVisOnScreen); + if (copy_bits) { + JSROOT.GEO.SetBit(obj.fVolume, JSROOT.GEO.BITS.kVisNone, false); + JSROOT.GEO.SetBit(obj.fVolume, JSROOT.GEO.BITS.kVisThis, clone.vis); + JSROOT.GEO.SetBit(obj.fVolume, JSROOT.GEO.BITS.kVisDaughters, true); + } + } else { + clone.vis = !JSROOT.GEO.TestBit(obj.fVolume, JSROOT.GEO.BITS.kVisNone) && + JSROOT.GEO.TestBit(obj.fVolume, JSROOT.GEO.BITS.kVisThis) && !obj.fFinder; + if (!JSROOT.GEO.TestBit(obj.fVolume, JSROOT.GEO.BITS.kVisDaughters)) + clone.depth = JSROOT.GEO.TestBit(obj.fVolume, JSROOT.GEO.BITS.kVisOneLevel) ? 1 : 0; + } + } + } else { + clone.vis = obj.fRnrSelf; + + // when the only node is selected, draw it + if ((n===0) && (this.nodes.length===1)) clone.vis = true; + } + + // shape with zero volume or without faces will not be observed + if ((clone.vol <= 0) || (clone.nfaces <= 0)) clone.vis = false; + + if (clone.vis) res++; + } + + return res; + } + + JSROOT.GEO.ClonedNodes.prototype.GetVisibleFlags = function() { + // function extract only visibility flags, used to transfer them to the worker + var res = []; + for (var n=0;n<this.nodes.length;++n) { + var elem = { vis: this.nodes[n].vis }; + if ('depth' in this.nodes[n]) elem.depth = this.nodes[n].depth; + res.push(elem); + } + return res; + } + + JSROOT.GEO.ClonedNodes.prototype.ScanVisible = function(arg, vislvl) { + // Scan visible nodes in hierarchy, starting from nodeid + // Each entry in hierarchy get its unique id, which is not changed with visibility flags + + if (!this.nodes) return 0; + + if (vislvl === undefined) { + vislvl = 99999; + if (!arg) arg = {}; + arg.stack = new Array(100); // current stack + arg.nodeid = 0; + arg.counter = 0; // sequence ID of the node, used to identify it later + arg.last = 0; + arg.CopyStack = function(factor) { + var entry = { nodeid: this.nodeid, seqid: this.counter, stack: (this.last>10) ? new Int32Array(this.last) : new Array(this.last) }; + if (factor) entry.factor = factor; // factor used to indicate importance of entry, will be build as first + for (var n=0;n<this.last;++n) entry.stack[n] = this.stack[n+1]; // copy stack + return entry; + } + + if (arg.domatrix) { + arg.matrices = []; + arg.mpool = [ new THREE.Matrix4() ]; // pool of Matrix objects to avoid permanent creation + arg.getmatrix = function() { return this.matrices[this.last]; } + } + } + + var res = 0, node = this.nodes[arg.nodeid]; + + if (arg.domatrix) { + if (!arg.mpool[arg.last+1]) + arg.mpool[arg.last+1] = new THREE.Matrix4(); + + var prnt = (arg.last > 0) ? arg.matrices[arg.last-1] : new THREE.Matrix4(); + if (node.matrix) { + arg.matrices[arg.last] = arg.mpool[arg.last].fromArray(prnt.elements); + arg.matrices[arg.last].multiply(arg.mpool[arg.last+1].fromArray(node.matrix)); + } else { + arg.matrices[arg.last] = prnt; + } + } + + if (node.vis && (vislvl>=0)) { + if (!arg.func || arg.func(node)) res++; + } + + arg.counter++; + + if ((node.depth !== undefined) && (vislvl > node.depth)) vislvl = node.depth; + + //if (arg.last > arg.stack.length - 2) + // throw 'ScanVisible: stack capacity ' + arg.stack.length + ' is not enough'; + + if (node.chlds && (node.numvischld > 0)) { + var currid = arg.counter, numvischld = 0; + arg.last++; + for (var i = 0; i < node.chlds.length; ++i) { + arg.nodeid = node.chlds[i]; + arg.stack[arg.last] = i; // in the stack one store index of child, it is path in the hierarchy + numvischld += this.ScanVisible(arg, vislvl-1); + } + arg.last--; + res += numvischld; + if (numvischld === 0) { + node.numvischld = 0; + node.idshift = arg.counter - currid; + } + } else { + arg.counter += node.idshift; + } + + if (arg.last === 0) { + delete arg.last; + delete arg.stack; + delete arg.CopyStack; + delete arg.counter; + delete arg.matrices; + delete arg.mpool; + delete arg.getmatrix; + } + + return res; + } + + /** Return node name with given id. + * Either original object or description is used + * @private */ + JSROOT.GEO.ClonedNodes.prototype.GetNodeName = function(nodeid) { + if (this.origin) { + var obj = this.origin[nodeid]; + return obj ? JSROOT.GEO.ObjectName(obj) : ""; + } + var node = this.nodes[nodeid]; + return node ? node.name : ""; + } + + JSROOT.GEO.ClonedNodes.prototype.ResolveStack = function(stack, withmatrix) { + + var res = { id: 0, obj: null, node: this.nodes[0], name: this.name_prefix }; + + // if (!this.toplevel || (this.nodes.length === 1) || (res.node.kind === 1)) res.name = ""; + + if (withmatrix) { + res.matrix = new THREE.Matrix4(); + if (res.node.matrix) res.matrix.fromArray(res.node.matrix); + } + + if (this.origin) + res.obj = this.origin[0]; + + //if (!res.name) + // res.name = this.GetNodeName(0); + + if (stack) + for(var lvl=0;lvl<stack.length;++lvl) { + res.id = res.node.chlds[stack[lvl]]; + res.node = this.nodes[res.id]; + + if (this.origin) + res.obj = this.origin[res.id]; + + var subname = this.GetNodeName(res.id); + if (subname) { + if (res.name) res.name+="/"; + res.name += subname; + } + + if (withmatrix && res.node.matrix) + res.matrix.multiply(new THREE.Matrix4().fromArray(res.node.matrix)); + } + + return res; + } + + /** Create stack array based on nodes ids array. + * Ids list should correspond to existing nodes hierarchy */ + JSROOT.GEO.ClonedNodes.prototype.MakeStackByIds = function(ids) { + var stack = []; + + if (ids[0] !== 0) { + console.error('wrong ids - first should be 0'); + return null; + } + + var node = this.nodes[0]; + + for (var k=1;k<ids.length;++k) { + var nodeid = ids[k]; + var chindx = node.chlds.indexOf(nodeid); + if (chindx < 0) { + console.error('wrong nodes ids ' + ids[k] + ' is not child of ' + ids[k-1]); + return null; + } + + stack.push(chindx); + node = this.nodes[nodeid]; + } + + return stack; + } + + /** Returns true if stack includes at any place provided nodeid */ + JSROOT.GEO.ClonedNodes.prototype.IsNodeInStack = function(nodeid, stack) { + + if (!nodeid) return true; + + var node = this.nodes[0], id = 0; + + for(var lvl = 0; lvl < stack.length; ++lvl) { + id = node.chlds[stack[lvl]]; + if (id == nodeid) return true; + node = this.nodes[id]; + } + + return false; + } + + /** find stack by name which include names of all parents */ + JSROOT.GEO.ClonedNodes.prototype.FindStackByName = function(fullname) { + + var names = fullname.split('/'), currid = 0, stack = []; + + if (this.GetNodeName(currid) !== names[0]) return null; + + for (var n=1;n<names.length;++n) { + var node = this.nodes[currid]; + if (!node.chlds) return null; + + for (var k=0;k<node.chlds.length;++k) { + var chldid = node.chlds[k]; + if (this.GetNodeName(chldid) === names[n]) { stack.push(k); currid = chldid; break; } + } + + // no new entry - not found stack + if (stack.length === n - 1) return null; + } + + return stack; + } + + /** returns different properties of draw entry nodeid */ + JSROOT.GEO.ClonedNodes.prototype.getDrawEntryProperties = function(entry) { + // function return different properties for specified node + // Only if node visible, material will be created + + var clone = this.nodes[entry.nodeid]; + var visible = true; + + if (clone.kind === 2) { + var prop = { name: clone.name, nname: clone.name, shape: null, material: null, chlds: null }; + var _opacity = entry.opacity; + prop.fillcolor = new THREE.Color( entry.color ? "rgb(" + entry.color + ")" : "blue" ); + prop.material = new THREE.MeshLambertMaterial( { transparent: _opacity < 1, + opacity: _opacity, wireframe: false, color: prop.fillcolor, + side: THREE.FrontSide /* THREE.DoubleSide*/, vertexColors: THREE.NoColors /*THREE.VertexColors */, + overdraw: 0., depthWrite: _opacity == 1 } ); + prop.material.inherentOpacity = _opacity; + + return prop; + } + + if (!this.origin) { + console.error('origin not there - kind', clone.kind, entry.nodeid, clone); + return null; + } + + var node = this.origin[entry.nodeid]; + + if (clone.kind === 1) { + // special handling for EVE nodes + + var prop = { name: JSROOT.GEO.ObjectName(node), nname: JSROOT.GEO.ObjectName(node), shape: node.fShape, material: null, chlds: null }; + + if (node.fElements !== null) prop.chlds = node.fElements.arr; + + if (visible) { + var _opacity = Math.min(1, node.fRGBA[3]); + prop.fillcolor = new THREE.Color( node.fRGBA[0], node.fRGBA[1], node.fRGBA[2] ); + prop.material = new THREE.MeshLambertMaterial( { transparent: _opacity < 1, + opacity: _opacity, wireframe: false, color: prop.fillcolor, + side: THREE.FrontSide /* THREE.DoubleSide*/, vertexColors: THREE.NoColors /*THREE.VertexColors */, + overdraw: 0., depthWrite: _opacity == 1 } ); + prop.material.inherentOpacity = _opacity; + } + + return prop; + } + + var volume = node.fVolume; + + var prop = { name: JSROOT.GEO.ObjectName(volume), nname: JSROOT.GEO.ObjectName(node), volume: node.fVolume, shape: volume.fShape, material: null, chlds: null }; + + if (node.fVolume.fNodes !== null) prop.chlds = node.fVolume.fNodes.arr; + + if (volume) prop.linewidth = volume.fLineWidth; + + if (visible) { + var _opacity = 1.0; + if ((volume.fFillColor > 1) && (volume.fLineColor == 1)) + prop.fillcolor = JSROOT.Painter.root_colors[volume.fFillColor]; + else + if (volume.fLineColor >= 0) + prop.fillcolor = JSROOT.Painter.root_colors[volume.fLineColor]; + + if (volume.fMedium && volume.fMedium.fMaterial) { + var fillstyle = volume.fMedium.fMaterial.fFillStyle; + var transparency = (fillstyle < 3000 || fillstyle > 3100) ? 0 : fillstyle - 3000; + if (transparency > 0) + _opacity = (100.0 - transparency) / 100.0; + if (prop.fillcolor === undefined) + prop.fillcolor = JSROOT.Painter.root_colors[volume.fMedium.fMaterial.fFillColor]; + } + if (prop.fillcolor === undefined) + prop.fillcolor = "lightgrey"; + + prop.material = new THREE.MeshLambertMaterial( { transparent: _opacity < 1, + opacity: _opacity, wireframe: false, color: prop.fillcolor, + side: THREE.FrontSide /* THREE.DoubleSide */, vertexColors: THREE.NoColors /*THREE.VertexColors*/, + overdraw: 0., depthWrite: _opacity == 1 } ); + prop.material.inherentOpacity = _opacity; + + } + + return prop; + } + + JSROOT.GEO.ClonedNodes.prototype.CreateObject3D = function(stack, toplevel, options) { + // create hierarchy of Object3D for given stack entry + // such hierarchy repeats hierarchy of TGeoNodes and set matrix for the objects drawing + // also set renderOrder, required to handle transparency + + var node = this.nodes[0], three_prnt = toplevel, draw_depth = 0, + force = (typeof options == 'object') || (options==='force'); + + for(var lvl=0; lvl<=stack.length; ++lvl) { + var nchld = (lvl > 0) ? stack[lvl-1] : 0; + // extract current node + if (lvl>0) node = this.nodes[node.chlds[nchld]]; + + var obj3d = undefined; + + if (three_prnt.children) + for (var i=0;i<three_prnt.children.length;++i) { + if (three_prnt.children[i].nchld === nchld) { + obj3d = three_prnt.children[i]; + break; + } + } + + if (obj3d) { + three_prnt = obj3d; + if (obj3d.$jsroot_drawable) draw_depth++; + continue; + } + + if (!force) return null; + + obj3d = new THREE.Object3D(); + + if (node.matrix) { + // console.log(stack.toString(), lvl, 'matrix ', node.matrix.toString()); + obj3d.matrix.fromArray(node.matrix); + obj3d.matrix.decompose( obj3d.position, obj3d.quaternion, obj3d.scale ); + } + + // this.accountNodes(obj3d); + obj3d.nchld = nchld; // mark index to find it again later + + // add the mesh to the scene + three_prnt.add(obj3d); + + // this is only for debugging - test inversion of whole geometry + if ((lvl==0) && (typeof options == 'object') && options.scale) { + if ((options.scale.x<0) || (options.scale.y<0) || (options.scale.z<0)) { + obj3d.scale.copy(options.scale); + obj3d.updateMatrix(); + } + } + + obj3d.updateMatrixWorld(); + + three_prnt = obj3d; + } + + if ((options === 'mesh') || (options === 'delete_mesh')) { + var mesh = null; + if (three_prnt) + for (var n=0; (n<three_prnt.children.length) && !mesh;++n) { + var chld = three_prnt.children[n]; + if ((chld.type === 'Mesh') && (chld.nchld === undefined)) mesh = chld; + } + + if ((options === 'mesh') || !mesh) return mesh; + + var res = three_prnt; + while (mesh && (mesh !== toplevel)) { + three_prnt = mesh.parent; + three_prnt.remove(mesh); + mesh = (three_prnt.children.length == 0) ? three_prnt : null; + } + + return res; + } + + if (three_prnt) { + three_prnt.$jsroot_drawable = true; + three_prnt.$jsroot_depth = draw_depth; + } + + return three_prnt; + } + + JSROOT.GEO.ClonedNodes.prototype.GetVolumeBoundary = function(viscnt, facelimit, nodeslimit) { + + var result = { min: 0, max: 1, sortidcut: 0 }; + + if (!this.sortmap) { + console.error('sorting map do not exist'); + return result; + } + + var maxNode, currNode, cnt=0, facecnt=0; + + for (var n = 0; (n < this.sortmap.length) && (cnt < nodeslimit) && (facecnt < facelimit); ++n) { + var id = this.sortmap[n]; + if (viscnt[id] === 0) continue; + currNode = this.nodes[id]; + if (!maxNode) maxNode = currNode; + cnt += viscnt[id]; + facecnt += viscnt[id] * currNode.nfaces; + } + + if (!currNode) { + console.error('no volumes selected'); + return result; + } + + // console.log('Volume boundary ' + currNode.vol + ' cnt ' + cnt + ' faces ' + facecnt); + result.max = maxNode.vol; + result.min = currNode.vol; + result.sortidcut = currNode.sortid; // latest node is not included + return result; + } + + JSROOT.GEO.ClonedNodes.prototype.CollectVisibles = function(maxnumfaces, frustum, maxnumnodes) { + // function collects visible nodes, using maxlimit + // one can use map to define cut based on the volume or serious of cuts + + if (!maxnumnodes) maxnumnodes = maxnumfaces/100; + + var arg = { + facecnt: 0, + viscnt: new Int32Array(this.nodes.length), // counter for each node + // nodes: this.nodes, + func: function(node) { + this.facecnt += node.nfaces; + this.viscnt[node.id]++; + return true; + } + }; + + for (var n=0;n<arg.viscnt.length;++n) arg.viscnt[n] = 0; + + var total = this.ScanVisible(arg), minVol = 0, maxVol = 0, camVol = -1, camFact = 10, sortidcut = this.nodes.length + 1; + + // console.log('Total visible nodes ' + total + ' numfaces ' + arg.facecnt); + + if (arg.facecnt > maxnumfaces) { + + var bignumfaces = maxnumfaces * (frustum ? 0.8 : 1.0), + bignumnodes = maxnumnodes * (frustum ? 0.8 : 1.0); + + // define minimal volume, which always to shown + var boundary = this.GetVolumeBoundary(arg.viscnt, bignumfaces, bignumnodes); + + minVol = boundary.min; + maxVol = boundary.max; + sortidcut = boundary.sortidcut; + + if (frustum) { + arg.domatrix = true; + arg.frustum = frustum; + arg.totalcam = 0; + arg.func = function(node) { + if (node.vol <= minVol) // only small volumes are interesting + if (this.frustum.CheckShape(this.getmatrix(), node)) { + this.viscnt[node.id]++; + this.totalcam += node.nfaces; + } + + return true; + } + + for (var n=0;n<arg.viscnt.length;++n) arg.viscnt[n] = 0; + + this.ScanVisible(arg); + + if (arg.totalcam > maxnumfaces*0.2) + camVol = this.GetVolumeBoundary(arg.viscnt, maxnumfaces*0.2, maxnumnodes*0.2).min; + else + camVol = 0; + + camFact = maxVol / ((camVol>0) ? (camVol>0) : minVol); + + // console.log('Limit for camera ' + camVol + ' faces in camera view ' + arg.totalcam); + } + } + + arg.items = []; + + arg.func = function(node) { + if (node.sortid < sortidcut) { + this.items.push(this.CopyStack()); + } else + if ((camVol >= 0) && (node.vol > camVol)) + if (this.frustum.CheckShape(this.getmatrix(), node)) { + this.items.push(this.CopyStack(camFact)); + } + return true; + } + + this.ScanVisible(arg); + + return { lst: arg.items, complete: minVol === 0 }; + } + + JSROOT.GEO.ClonedNodes.prototype.MergeVisibles = function(current, prev) { + // merge list of drawn objects + // in current list we should mark if object already exists + // from previous list we should collect objects which are not there + + var indx2 = 0, del = []; + for (var indx1=0; (indx1<current.length) && (indx2<prev.length); ++indx1) { + + while ((indx2 < prev.length) && (prev[indx2].seqid < current[indx1].seqid)) { + del.push(prev[indx2++]); // this entry should be removed + } + + if ((indx2 < prev.length) && (prev[indx2].seqid === current[indx1].seqid)) { + if (prev[indx2].done) current[indx1].done = true; // copy ready flag + indx2++; + } + } + + // remove rest + while (indx2<prev.length) + del.push(prev[indx2++]); + + return del; // + } + + JSROOT.GEO.ClonedNodes.prototype.CollectShapes = function(lst) { + // based on list of visible nodes, collect all uniques shapes which should be build + + var shapes = []; + + for (var i=0;i<lst.length;++i) { + var entry = lst[i]; + var shape = this.GetNodeShape(entry.nodeid); + + if (!shape) continue; // strange, but avoid misleading + + if (shape._id === undefined) { + shape._id = shapes.length; + + shapes.push({ id: shape._id, shape: shape, vol: this.nodes[entry.nodeid].vol, refcnt: 1, factor: 1, ready: false }); + + // shapes.push( { obj: shape, vol: this.nodes[entry.nodeid].vol }); + } else { + shapes[shape._id].refcnt++; + } + + entry.shape = shapes[shape._id]; // remember shape used + + // use maximal importance factor to push element to the front + if (entry.factor && (entry.factor>entry.shape.factor)) + entry.shape.factor = entry.factor; + } + + // now sort shapes in volume decrease order + shapes.sort(function(a,b) { return b.vol*b.factor - a.vol*a.factor; }) + + // now set new shape ids according to the sorted order and delete temporary field + for (var n=0;n<shapes.length;++n) { + var item = shapes[n]; + item.id = n; // set new ID + delete item.shape._id; // remove temporary field + } + + // as last action set current shape id to each entry + for (var i=0;i<lst.length;++i) { + var entry = lst[i]; + if (entry.shape) { + entry.shapeid = entry.shape.id; // keep only id for the entry + delete entry.shape; // remove direct references + } + } + + return shapes; + } + + JSROOT.GEO.ClonedNodes.prototype.MergeShapesLists = function(oldlst, newlst) { + + if (!oldlst) return newlst; + + // set geometry to shape object itself + for (var n=0;n<oldlst.length;++n) { + var item = oldlst[n]; + + item.shape._geom = item.geom; + delete item.geom; + + if (item.geomZ!==undefined) { + item.shape._geomZ = item.geomZ; + delete item.geomZ; + } + } + + // take from shape (if match) + for (var n=0;n<newlst.length;++n) { + var item = newlst[n]; + + if (item.shape._geom !== undefined) { + item.geom = item.shape._geom; + delete item.shape._geom; + } + + if (item.shape._geomZ !== undefined) { + item.geomZ = item.shape._geomZ; + delete item.shape._geomZ; + } + } + + // now delete all unused geometries + for (var n=0;n<oldlst.length;++n) { + var item = oldlst[n]; + delete item.shape._geom; + delete item.shape._geomZ; + } + + return newlst; + } + + JSROOT.GEO.ClonedNodes.prototype.BuildShapes = function(lst, limit, timelimit) { + + var created = 0, + tm1 = new Date().getTime(), + res = { done: false, shapes: 0, faces: 0, notusedshapes: 0 }; + + for (var n=0;n<lst.length;++n) { + var item = lst[n]; + + // if enough faces are produced, nothing else is required + if (res.done) { item.ready = true; continue; } + + if (!item.ready) { + if (item.geom === undefined) { + item.geom = JSROOT.GEO.createGeometry(item.shape); + if (item.geom) created++; // indicate that at least one shape was created + } + item.nfaces = JSROOT.GEO.numGeometryFaces(item.geom); + item.ready = true; + } + + res.shapes++; + if (!item.used) res.notusedshapes++; + res.faces += item.nfaces*item.refcnt; + + if (res.faces >= limit) { + res.done = true; + } else + if ((created > 0.01*lst.length) && (timelimit!==undefined)) { + var tm2 = new Date().getTime(); + if (tm2-tm1 > timelimit) return res; + } + } + + res.done = true; + + return res; + } + + JSROOT.GEO.ObjectName = function(obj) { + if (!obj || !obj.fName) return ""; + return obj.fName + (obj.$geo_suffix ? obj.$geo_suffix : ""); + } + + JSROOT.GEO.CheckDuplicates = function(parent, chlds) { + if (parent) { + if (parent.$geo_checked) return; + parent.$geo_checked = true; + } + + var names = [], cnts = [], obj = null; + for (var k=0;k<chlds.length;++k) { + var chld = chlds[k]; + if (!chld || !chld.fName) continue; + if (!chld.$geo_suffix) { + var indx = names.indexOf(chld.fName); + if (indx>=0) { + var cnt = cnts[indx] || 1; + while(names.indexOf(chld.fName+"#"+cnt)>=0) ++cnt; + chld.$geo_suffix = "#" + cnt; + cnts[indx] = cnt+1; + } + } + names.push(JSROOT.GEO.ObjectName(chld)); + } + } + + JSROOT.GEO.createFlippedMesh = function(parent, shape, material) { + // when transformation matrix includes one or several inversion of axis, + // one should inverse geometry object, otherwise THREE.js cannot correctly draw it + + var flip = new THREE.Vector3(1,1,-1); + + if (shape.geomZ === undefined) { + + if (shape.geom.type == 'BufferGeometry') { + + var pos = shape.geom.getAttribute('position').array, + norm = shape.geom.getAttribute('normal').array; + + var index = shape.geom.getIndex(); + + if (index) { + // we need to unfold all points to + var arr = index.array, + i0 = shape.geom.drawRange.start, + ilen = shape.geom.drawRange.count; + if (i0 + ilen > arr.length) ilen = arr.length - i0; + + var dpos = new Float32Array(ilen*3), dnorm = new Float32Array(ilen*3); + for (var ii = 0; ii < ilen; ++ii) { + var k = arr[i0 + ii]; + if ((k<0) || (k*3>=pos.length)) console.log('strange index', k*3, pos.length); + dpos[ii*3] = pos[k*3]; + dpos[ii*3+1] = pos[k*3+1]; + dpos[ii*3+2] = pos[k*3+2]; + dnorm[ii*3] = norm[k*3]; + dnorm[ii*3+1] = norm[k*3+1]; + dnorm[ii*3+2] = norm[k*3+2]; + } + + pos = dpos; norm = dnorm; + } + + var len = pos.length, n, shift = 0, + newpos = new Float32Array(len), + newnorm = new Float32Array(len); + + // we should swap second and third point in each face + for (n=0; n<len; n+=3) { + newpos[n] = pos[n+shift]; + newpos[n+1] = pos[n+1+shift]; + newpos[n+2] = -pos[n+2+shift]; + + newnorm[n] = norm[n+shift]; + newnorm[n+1] = norm[n+1+shift]; + newnorm[n+2] = -norm[n+2+shift]; + + shift+=3; if (shift===6) shift=-3; // values 0,3,-3 + } + + shape.geomZ = new THREE.BufferGeometry(); + shape.geomZ.addAttribute( 'position', new THREE.BufferAttribute( newpos, 3 ) ); + shape.geomZ.addAttribute( 'normal', new THREE.BufferAttribute( newnorm, 3 ) ); + // normals are calculated with normal geometry and correctly scaled + // geom.computeVertexNormals(); + + } else { + + shape.geomZ = shape.geom.clone(); + + shape.geomZ.scale(flip.x, flip.y, flip.z); + + var face, d, n = 0; + while(n < shape.geomZ.faces.length) { + face = geom.faces[n++]; + d = face.b; face.b = face.c; face.c = d; + } + + // normals are calculated with normal geometry and correctly scaled + // geom.computeFaceNormals(); + } + } + + var mesh = new THREE.Mesh( shape.geomZ, material ); + mesh.scale.copy(flip); + mesh.updateMatrix(); + + mesh._flippedMesh = true; + + return mesh; + } + + /** Cleanup shape entity + * @private */ + JSROOT.GEO.cleanupShape = function(shape) { + if (!shape) return; + + if (shape.geom && (typeof shape.geom.dispose == 'funciton')) + shape.geom.dispose(); + + if (shape.geomZ && (typeof shape.geomZ.dispose == 'funciton')) + shape.geomZ.dispose(); + + delete shape.geom; + delete shape.geomZ; + } + + JSROOT.GEO.produceRenderOrder = function(toplevel, origin, method, clones) { + // function scans throug hierarchy of objects and try to set renderOrder + // algorithm is not perfect, but better then nothing + + var raycast = new THREE.Raycaster(); + + function setdefaults(top) { + if (!top) return; + top.traverse(function(obj) { + obj.renderOrder = 0; + if (obj.material) obj.material.depthWrite = true; // by default depthWriting enabled + }); + } + + function traverse(obj, lvl, arr) { + // traverse hierarchy and extract all children of given level + // if (obj.$jsroot_depth===undefined) return; + + if (!obj.children) return; + + for (var k=0;k<obj.children.length;++k) { + var chld = obj.children[k]; + if (chld.$jsroot_order === lvl) { + if (chld.material) { + if (chld.material.transparent) { + chld.material.depthWrite = false; // disable depth writing for transparent + arr.push(chld); + } else { + setdefaults(chld); + } + } + } else + if ((obj.$jsroot_depth===undefined) || (obj.$jsroot_depth < lvl)) traverse(chld, lvl, arr); + } + } + + function sort(arr, minorder, maxorder) { + // resort meshes using ray caster and camera position + // idea to identify meshes which are in front or behind + + if (arr.length>300) { + // too many of them, just set basic level and exit + for (var i=0;i<arr.length;++i) arr[i].renderOrder = (minorder + maxorder)/2; + return false; + } + + // first calculate distance to the camera + // it gives preliminary order of volumes + + for (var i=0;i<arr.length;++i) { + var mesh = arr[i], + box3 = mesh.$jsroot_box3; + + if (!box3) + mesh.$jsroot_box3 = box3 = JSROOT.GEO.getBoundingBox(mesh); + + if (method === 'size') { + mesh.$jsroot_distance = box3.getSize(new THREE.Vector3()); + continue; + } + + if (method === "pnt") { + mesh.$jsroot_distance = origin.distanceTo(box3.getCenter()); + continue; + } + + var dist = Math.min(dist, origin.distanceTo(box3.min), origin.distanceTo(box3.max)); + + var pnt = new THREE.Vector3(box3.min.x, box3.min.y, box3.max.z); + dist = Math.min(dist, origin.distanceTo(pnt)); + pnt.set(box3.min.x, box3.max.y, box3.min.z) + dist = Math.min(dist, origin.distanceTo(pnt)); + pnt.set(box3.max.x, box3.min.y, box3.min.z) + dist = Math.min(dist, origin.distanceTo(pnt)); + + pnt.set(box3.max.x, box3.max.y, box3.min.z) + dist = Math.min(dist, origin.distanceTo(pnt)); + + pnt.set(box3.max.x, box3.min.y, box3.max.z) + dist = Math.min(dist, origin.distanceTo(pnt)); + + pnt.set(box3.min.x, box3.max.y, box3.max.z) + dist = Math.min(dist, origin.distanceTo(pnt)); + + mesh.$jsroot_distance = dist; + } + + arr.sort(function(a,b) { return a.$jsroot_distance - b.$jsroot_distance; }); + + var resort = new Array(arr.length); + + for (var i=0;i<arr.length;++i) { + arr[i].$jsroot_index = i; + resort[i] = arr[i]; + } + + if (method==="ray") + for (var i=arr.length-1;i>=0;--i) { + var mesh = arr[i], + box3 = mesh.$jsroot_box3, + direction = box3.getCenter(); + + for(var ntry=0; ntry<2;++ntry) { + + direction.sub(origin).normalize(); + + raycast.set( origin, direction ); + + var intersects = raycast.intersectObjects(arr, false); // only plain array + + var unique = []; + + for (var k1=0;k1<intersects.length;++k1) { + if (unique.indexOf(intersects[k1].object)<0) unique.push(intersects[k1].object); + // if (intersects[k1].object === mesh) break; // trace until object itself + } + + intersects = unique; + + if ((intersects.indexOf(mesh)<0) && (ntry>0)) + console.log('MISS', clones ? clones.ResolveStack(mesh.stack).name : "???"); + + if ((intersects.indexOf(mesh)>=0) || (ntry>0)) break; + + var pos = mesh.geometry.attributes.position.array; + + direction = new THREE.Vector3((pos[0]+pos[3]+pos[6])/3, (pos[1]+pos[4]+pos[7])/3, (pos[2]+pos[5]+pos[8])/3); + + direction.applyMatrix4(mesh.matrixWorld); + } + + // now push first object in intersects to the front + for (var k1=0;k1<intersects.length-1;++k1) { + var mesh1 = intersects[k1], mesh2 = intersects[k1+1], + i1 = mesh1.$jsroot_index, i2 = mesh2.$jsroot_index; + if (i1<i2) continue; + for (var ii=i2;ii<i1;++ii) { + resort[ii] = resort[ii+1]; + resort[ii].$jsroot_index = ii; + } + resort[i1] = mesh2; + mesh2.$jsroot_index = i1; + } + + } + + for (var i=0;i<resort.length;++i) { + resort[i].renderOrder = maxorder - (i+1) / (resort.length+1) * (maxorder-minorder); + delete resort[i].$jsroot_index; + delete resort[i].$jsroot_distance; + } + + return true; + } + + function process(obj, lvl, minorder, maxorder) { + var arr = [], did_sort = false; + + traverse(obj, lvl, arr); + + if (!arr.length) return; + + if (minorder === maxorder) { + for (var k=0;k<arr.length;++k) + arr[k].renderOrder = minorder; + } else { + did_sort = sort(arr, minorder, maxorder); + if (!did_sort) minorder = maxorder = (minorder + maxorder) / 2; + } + + for (var k=0;k<arr.length;++k) { + var next = arr[k].parent, min = minorder, max = maxorder; + + if (did_sort) { + max = arr[k].renderOrder; + min = max - (maxorder - minorder) / (arr.length + 2); + } + + process(next, lvl+1, min, max); + } + } + + if (!method || (method==="dflt")) + setdefaults(toplevel); + else + process(toplevel, 0, 1, 1000000); + } + + JSROOT.GEO.build = function(obj, opt, call_back) { + // function can be used to build three.js model for TGeo object + + if (!obj) return; + + if (!opt) opt = {}; + if (!opt.numfaces) opt.numfaces = 100000; + if (!opt.numnodes) opt.numnodes = 1000; + + opt.res_mesh = opt.res_faces = 0; + + var shape = null; + + if (('fShapeBits' in obj) && ('fShapeId' in obj)) { + shape = obj; obj = null; + } else + if ((obj._typename === 'TGeoVolumeAssembly') || (obj._typename === 'TGeoVolume')) { + shape = obj.fShape; + } else + if ((obj._typename === "TEveGeoShapeExtract") || (obj._typename === "ROOT::Experimental::TEveGeoShapeExtract") ) { + shape = obj.fShape; + } else + if (obj._typename === 'TGeoManager') { + obj = obj.fMasterVolume; + JSROOT.GEO.SetBit(obj, JSROOT.GEO.BITS.kVisThis, false); + shape = obj.fShape; + } else + if ('fVolume' in obj) { + if (obj.fVolume) shape = obj.fVolume.fShape; + } else { + obj = null; + } + + if (opt.composite && shape && (shape._typename == 'TGeoCompositeShape') && shape.fNode) + obj = JSROOT.GEO.buildCompositeVolume(shape); + + if (!obj && shape) + obj = JSROOT.extend(JSROOT.Create("TEveGeoShapeExtract"), + { fTrans: null, fShape: shape, fRGBA: [0, 1, 0, 1], fElements: null, fRnrSelf: true }); + + if (!obj) return null; + + if (obj._typename.indexOf('TGeoVolume') === 0) + obj = { _typename:"TGeoNode", fVolume: obj, fName: obj.fName, $geoh: obj.$geoh, _proxy: true }; + + var clones = new JSROOT.GEO.ClonedNodes(obj); + + var uniquevis = clones.MarkVisisble(true); + + if (uniquevis <= 0) + uniquevis = clones.MarkVisisble(false); + else + uniquevis = clones.MarkVisisble(true, true); // copy bits once and use normal visibility bits + + var numvis = clones.MarkVisisble(); + + var frustum = null; + + // collect visible nodes + var res = clones.CollectVisibles(opt.numfaces, frustum, opt.numnodes); + + var draw_nodes = res.lst; + + // collect shapes + var shapes = clones.CollectShapes(draw_nodes); + + clones.BuildShapes(shapes, opt.numfaces); + + var toplevel = new THREE.Object3D(); + + for (var n=0; n < draw_nodes.length;++n) { + var entry = draw_nodes[n]; + if (entry.done) continue; + + var shape = shapes[entry.shapeid]; + if (!shape.ready) { + console.warn('shape marked as not ready when should'); + break; + } + entry.done = true; + shape.used = true; // indicate that shape was used in building + + if (!shape.geom || (shape.nfaces === 0)) { + // node is visible, but shape does not created + clones.CreateObject3D(entry.stack, toplevel, 'delete_mesh'); + continue; + } + + var prop = clones.getDrawEntryProperties(entry); + + opt.res_mesh++; + opt.res_faces += shape.nfaces; + + var obj3d = clones.CreateObject3D(entry.stack, toplevel, opt); + + prop.material.wireframe = opt.wireframe; + + prop.material.side = opt.doubleside ? THREE.DoubleSide : THREE.FrontSide; + + var mesh = null; + + if (obj3d.matrixWorld.determinant() > -0.9) { + mesh = new THREE.Mesh( shape.geom, prop.material ); + } else { + mesh = JSROOT.GEO.createFlippedMesh(obj3d, shape, prop.material); + } + + obj3d.add(mesh); + // specify rendering order, required for transparency handling + //if (obj3d.$jsroot_depth !== undefined) + // mesh.renderOrder = clones.maxdepth - obj3d.$jsroot_depth; + //else + // mesh.renderOrder = clones.maxdepth - entry.stack.length; + } + + JSROOT.CallBack(call_back, toplevel); + + return toplevel; + } + + JSROOT.GEO.getBoundingBox = function(node, box3) { + + // extract code of Box3.expandByObject + // Major difference - do not traverse hierarchy + + if (!node || !node.geometry) return box3; + + if (!box3) { box3 = new THREE.Box3(); box3.makeEmpty(); } + + node.updateMatrixWorld(); + + var v1 = new THREE.Vector3(), + geometry = node.geometry; + + if ( geometry.isGeometry ) { + var vertices = geometry.vertices; + for (var i = 0, l = vertices.length; i < l; i ++ ) { + v1.copy( vertices[ i ] ); + v1.applyMatrix4( node.matrixWorld ); + box3.expandByPoint( v1 ); + } + } else if ( geometry.isBufferGeometry ) { + var attribute = geometry.attributes.position; + if ( attribute !== undefined ) { + for (var i = 0, l = attribute.count; i < l; i ++ ) { + // v1.fromAttribute( attribute, i ).applyMatrix4( node.matrixWorld ); + v1.fromBufferAttribute( attribute, i ).applyMatrix4( node.matrixWorld ); + box3.expandByPoint( v1 ); + } + } + } + + return box3; + } + + + return JSROOT; + +})); + diff --git a/js/scripts/JSRootGeoPainter.js b/js/scripts/JSRootGeoPainter.js new file mode 100644 index 00000000000..718c0e26cd8 --- /dev/null +++ b/js/scripts/JSRootGeoPainter.js @@ -0,0 +1,4125 @@ +/** JavaScript ROOT 3D geometry painter + * @file JSRootGeoPainter.js */ + +(function( factory ) { + if ( typeof define === "function" && define.amd ) { + define( [ 'JSRootPainter', 'd3', 'threejs', 'dat.gui', 'JSRoot3DPainter', 'JSRootGeoBase' ], factory ); + } else + if (typeof exports === 'object' && typeof module !== 'undefined') { + var jsroot = require("./JSRootCore.js"); + if (!jsroot.nodejs && (typeof window != 'undefined')) require("./dat.gui.min.js"); + factory(jsroot, require("./d3.min.js"), require("./three.min.js"), require("./JSRoot3DPainter.js"), require("./JSRootGeoBase.js"), + jsroot.nodejs || (typeof document=='undefined') ? jsroot.nodejs_document : document); + } else { + + if (typeof JSROOT == 'undefined') + throw new Error('JSROOT is not defined', 'JSRootGeoPainter.js'); + + if (typeof JSROOT.Painter != 'object') + throw new Error('JSROOT.Painter is not defined', 'JSRootGeoPainter.js'); + + if (typeof d3 == 'undefined') + throw new Error('d3 is not defined', 'JSRootGeoPainter.js'); + + if (typeof THREE == 'undefined') + throw new Error('THREE is not defined', 'JSRootGeoPainter.js'); + + if (typeof dat == 'undefined') + throw new Error('dat.gui is not defined', 'JSRootGeoPainter.js'); + + factory( JSROOT, d3, THREE ); + } +} (function( JSROOT, d3, THREE, _3d, _geo, document ) { + + "use strict"; + + JSROOT.sources.push("geom"); + + if ((typeof document=='undefined') && (typeof window=='object')) document = window.document; + + if ( typeof define === "function" && define.amd ) + JSROOT.loadScript('$$$style/JSRootGeoPainter.css'); + + if (typeof JSROOT.GEO !== 'object') + console.error('JSROOT.GEO namespace is not defined') + + // ============================================================================================ + + function Toolbar(container, buttons, bright) { + this.bright = bright; + if ((container !== undefined) && (typeof container.append == 'function')) { + this.element = container.append("div").attr('class','jsroot'); + this.addButtons(buttons); + } + } + + Toolbar.prototype.addButtons = function(buttons) { + var pthis = this; + + this.buttonsNames = []; + buttons.forEach(function(buttonGroup) { + var group = pthis.element.append('div').attr('class', 'toolbar-group'); + + buttonGroup.forEach(function(buttonConfig) { + var buttonName = buttonConfig.name; + if (!buttonName) { + throw new Error('must provide button \'name\' in button config'); + } + if (pthis.buttonsNames.indexOf(buttonName) !== -1) { + throw new Error('button name \'' + buttonName + '\' is taken'); + } + pthis.buttonsNames.push(buttonName); + + pthis.createButton(group, buttonConfig); + }); + }); + }; + + Toolbar.prototype.createButton = function(group, config) { + + var title = config.title; + if (title === undefined) title = config.name; + + if (typeof config.click !== 'function') + throw new Error('must provide button \'click\' function in button config'); + + var button = group.append('a') + .attr('class', this.bright ? 'toolbar-btn-bright' : 'toolbar-btn') + .attr('rel', 'tooltip') + .attr('data-title', title) + .on('click', config.click); + + this.createIcon(button, config.icon || JSROOT.ToolbarIcons.question); + } + + + Toolbar.prototype.changeBrightness = function(bright) { + this.bright = bright; + if (!this.element) return; + + this.element.selectAll(bright ? '.toolbar-btn' : ".toolbar-btn-bright") + .attr("class", !bright ? 'toolbar-btn' : "toolbar-btn-bright"); + } + + + Toolbar.prototype.createIcon = function(button, thisIcon) { + var dimensions = thisIcon.size ? thisIcon.size.split(' ') : [512, 512], + width = dimensions[0], + height = dimensions[1] || dimensions[0], + scale = thisIcon.scale || 1, + svg = button.append("svg:svg") + .attr('height', '1em') + .attr('width', '1em') + .attr('viewBox', [0, 0, width, height].join(' ')); + + if ('recs' in thisIcon) { + var rec = {}; + for (var n=0;n<thisIcon.recs.length;++n) { + JSROOT.extend(rec, thisIcon.recs[n]); + svg.append('rect').attr("x", rec.x).attr("y", rec.y) + .attr("width", rec.w).attr("height", rec.h) + .attr("fill", rec.f); + } + } else { + var elem = svg.append('svg:path').attr('d',thisIcon.path); + if (scale !== 1) + elem.attr('transform', 'scale(' + scale + ' ' + scale +')'); + } + }; + + Toolbar.prototype.removeAllButtons = function() { + this.element.remove(); + }; + + /** + * @class JSROOT.TGeoPainter Holder of different functions and classes for drawing geometries + */ + + function TGeoPainter(obj) { + + if (obj && (obj._typename === "TGeoManager")) { + this.geo_manager = obj; + obj = obj.fMasterVolume; + } + + if (obj && (obj._typename.indexOf('TGeoVolume') === 0)) + obj = { _typename:"TGeoNode", fVolume: obj, fName: obj.fName, $geoh: obj.$geoh, _proxy: true }; + + JSROOT.TObjectPainter.call(this, obj); + + this.no_default_title = true; // do not set title to main DIV + this.mode3d = true; // indication of 3D mode + this.drawing_stage = 0; // + + this.Cleanup(true); + } + + TGeoPainter.prototype = Object.create( JSROOT.TObjectPainter.prototype ); + + TGeoPainter.prototype.CreateToolbar = function(args) { + if (this._toolbar || this._usesvg || this._usesvgimg) return; + var painter = this; + var buttonList = [{ + name: 'toImage', + title: 'Save as PNG', + icon: JSROOT.ToolbarIcons.camera, + click: function() { + painter.Render3D(0); + var dataUrl = painter._renderer.domElement.toDataURL("image/png"); + dataUrl.replace("image/png", "image/octet-stream"); + var link = document.createElement('a'); + if (typeof link.download === 'string') { + document.body.appendChild(link); //Firefox requires the link to be in the body + link.download = "geometry.png"; + link.href = dataUrl; + link.click(); + document.body.removeChild(link); //remove the link when done + } + } + }]; + + buttonList.push({ + name: 'control', + title: 'Toggle control UI', + icon: JSROOT.ToolbarIcons.rect, + click: function() { painter.showControlOptions('toggle'); } + }); + + buttonList.push({ + name: 'enlarge', + title: 'Enlarge geometry drawing', + icon: JSROOT.ToolbarIcons.circle, + click: function() { painter.ToggleEnlarge(); } + }); + + // Only show VR icon if WebVR API available. + if (navigator.getVRDisplays) { + buttonList.push({ + name: 'entervr', + title: 'Enter VR (It requires a VR Headset connected)', + icon: JSROOT.ToolbarIcons.vrgoggles, + click: function() { painter.ToggleVRMode(); } + }); + this.InitVRMode(); + } + + if (JSROOT.gStyle.ContextMenu) + buttonList.push({ + name: 'menu', + title: 'Show context menu', + icon: JSROOT.ToolbarIcons.question, + click: function() { + + d3.event.preventDefault(); + d3.event.stopPropagation(); + + var evnt = d3.event; + + if (!JSROOT.Painter.closeMenu()) + JSROOT.Painter.createMenu(painter, function(menu) { + menu.painter.FillContextMenu(menu); + menu.show(evnt); + }); + } + }); + + var bkgr = new THREE.Color(this.options.background); + + this._toolbar = new Toolbar( this.select_main(), [buttonList], (bkgr.r + bkgr.g + bkgr.b) < 1); + } + + TGeoPainter.prototype.InitVRMode = function() { + var pthis = this; + // Dolly contains camera and controllers in VR Mode + // Allows moving the user in the scene + this._dolly = new THREE.Group(); + this._scene.add(this._dolly); + this._standingMatrix = new THREE.Matrix4(); + + // Raycaster temp variables to avoid one per frame allocation. + this._raycasterEnd = new THREE.Vector3(); + this._raycasterOrigin = new THREE.Vector3(); + + navigator.getVRDisplays().then(function (displays) { + var vrDisplay = displays[0]; + if (!vrDisplay) return; + pthis._renderer.vr.setDevice(vrDisplay); + pthis._vrDisplay = vrDisplay; + pthis._standingMatrix.fromArray(vrDisplay.stageParameters.sittingToStandingTransform); + pthis.InitVRControllersGeometry(); + }); + } + + TGeoPainter.prototype.InitVRControllersGeometry = function() { + + let geometry = new THREE.SphereGeometry(0.025, 18, 36); + let material = new THREE.MeshBasicMaterial({color: 'grey'}); + let rayMaterial = new THREE.MeshBasicMaterial({color: 'fuchsia'}); + let rayGeometry = new THREE.BoxBufferGeometry(0.001, 0.001, 2); + let ray1Mesh = new THREE.Mesh(rayGeometry, rayMaterial); + let ray2Mesh = new THREE.Mesh(rayGeometry, rayMaterial); + let sphere1 = new THREE.Mesh(geometry, material); + let sphere2 = new THREE.Mesh(geometry, material); + + this._controllersMeshes = []; + this._controllersMeshes.push(sphere1); + this._controllersMeshes.push(sphere2); + ray1Mesh.position.z -= 1; + ray2Mesh.position.z -= 1; + sphere1.add(ray1Mesh); + sphere2.add(ray2Mesh); + this._dolly.add(sphere1); + this._dolly.add(sphere2); + // Controller mesh hidden by default + sphere1.visible = false; + sphere2.visible = false; + } + + TGeoPainter.prototype.UpdateVRControllersList = function() { + var gamepads = navigator.getGamepads && navigator.getGamepads(); + // Has controller list changed? + if (this.vrControllers && (gamepads.length === this.vrControllers.length)) { return; } + // Hide meshes. + this._controllersMeshes.forEach(function (mesh) { mesh.visible = false; }); + this._vrControllers = []; + for (var i = 0; i < gamepads.length; ++i) { + if (!gamepads[i].pose) { continue; } + this._vrControllers.push({ + gamepad: gamepads[i], + mesh: this._controllersMeshes[i] + }); + this._controllersMeshes[i].visible = true; + } + } + + TGeoPainter.prototype.ProcessVRControllerIntersections = function() { + var intersects = [] + for (var i = 0; i < this._vrControllers.length; ++i) { + let controller = this._vrControllers[i].mesh; + let end = controller.localToWorld(this._raycasterEnd.set(0, 0, -1)); + let origin = controller.localToWorld(this._raycasterOrigin.set(0, 0, 0)); + end.sub(origin).normalize(); + intersects = intersects.concat(this._controls.GetOriginDirectionIntersects(origin, end)); + } + // Remove duplicates. + intersects = intersects.filter(function (item, pos) {return intersects.indexOf(item) === pos}); + this._controls.ProcessMouseMove(intersects); + } + + TGeoPainter.prototype.UpdateVRControllers = function() { + this.UpdateVRControllersList(); + // Update pose. + for (var i = 0; i < this._vrControllers.length; ++i) { + let controller = this._vrControllers[i]; + let orientation = controller.gamepad.pose.orientation; + let position = controller.gamepad.pose.position; + let controllerMesh = controller.mesh; + if (orientation) { controllerMesh.quaternion.fromArray(orientation); } + if (position) { controllerMesh.position.fromArray(position); } + controllerMesh.updateMatrix(); + controllerMesh.applyMatrix(this._standingMatrix); + controllerMesh.matrixWorldNeedsUpdate = true; + } + this.ProcessVRControllerIntersections(); + } + + TGeoPainter.prototype.ToggleVRMode = function() { + var pthis = this; + if (!this._vrDisplay) return; + // Toggle VR mode off + if (this._vrDisplay.isPresenting) { + this.ExitVRMode(); + return; + } + this._previousCameraPosition = this._camera.position.clone(); + this._previousCameraRotation = this._camera.rotation.clone(); + this._vrDisplay.requestPresent([{ source: this._renderer.domElement }]).then(function() { + pthis._previousCameraNear = pthis._camera.near; + pthis._dolly.add(pthis._camera); + pthis._camera.near = 0.1; + pthis._camera.updateProjectionMatrix(); + pthis._renderer.vr.enabled = true; + pthis._renderer.setAnimationLoop(function () { + pthis.UpdateVRControllers(); + pthis.Render3D(0); + }); + }); + this._renderer.vr.enabled = true; + + window.addEventListener( 'keydown', function ( event ) { + // Esc Key turns VR mode off + if (event.keyCode === 27) pthis.ExitVRMode(); + }); + } + + TGeoPainter.prototype.ExitVRMode = function() { + var pthis = this; + if (!this._vrDisplay.isPresenting) return; + this._renderer.vr.enabled = false; + this._dolly.remove(this._camera); + this._scene.add(this._camera); + // Restore Camera pose + this._camera.position.copy(this._previousCameraPosition); + this._previousCameraPosition = undefined; + this._camera.rotation.copy(this._previousCameraRotation); + this._previousCameraRotation = undefined; + this._camera.near = this._previousCameraNear; + this._camera.updateProjectionMatrix(); + this._vrDisplay.exitPresent(); + } + + TGeoPainter.prototype.GetGeometry = function() { + return this.GetObject(); + } + + TGeoPainter.prototype.ModifyVisisbility = function(name, sign) { + if (JSROOT.GEO.NodeKind(this.GetGeometry()) !== 0) return; + + if (name == "") + return JSROOT.GEO.SetBit(this.GetGeometry().fVolume, JSROOT.GEO.BITS.kVisThis, (sign === "+")); + + var regexp, exact = false; + + //arg.node.fVolume + if (name.indexOf("*") < 0) { + regexp = new RegExp("^"+name+"$"); + exact = true; + } else { + regexp = new RegExp("^" + name.split("*").join(".*") + "$"); + exact = false; + } + + this.FindNodeWithVolume(regexp, function(arg) { + JSROOT.GEO.InvisibleAll.call(arg.node.fVolume, (sign !== "+")); + return exact ? arg : null; // continue search if not exact expression provided + }); + } + + TGeoPainter.prototype.decodeOptions = function(opt) { + if (typeof opt != "string") opt = ""; + + var res = { _grid: false, _bound: false, _debug: false, + _full: false, _axis: false, _axis_center: false, + _count: false, wireframe: false, + scale: new THREE.Vector3(1,1,1), zoom: 1.0, + more: 1, maxlimit: 100000, maxnodeslimit: 3000, + use_worker: false, update_browser: true, show_controls: false, + highlight: false, highlight_scene: false, select_in_view: false, + project: '', is_main: false, tracks: false, ortho_camera: false, + clipx: false, clipy: false, clipz: false, ssao: false, + script_name: "", transparency: 0, autoRotate: false, background: '#FFFFFF', + depthMethod: "box" }; + + var _opt = JSROOT.GetUrlOption('_grid'); + if (_opt !== null && _opt == "true") res._grid = true; + var _opt = JSROOT.GetUrlOption('_debug'); + if (_opt !== null && _opt == "true") { res._debug = true; res._grid = true; } + if (_opt !== null && _opt == "bound") { res._debug = true; res._grid = true; res._bound = true; } + if (_opt !== null && _opt == "full") { res._debug = true; res._grid = true; res._full = true; res._bound = true; } + + var macro = opt.indexOf("macro:"); + if (macro>=0) { + var separ = opt.indexOf(";", macro+6); + if (separ<0) separ = opt.length; + res.script_name = opt.substr(macro+6,separ-macro-6); + opt = opt.substr(0, macro) + opt.substr(separ+1); + console.log('script', res.script_name, 'rest', opt); + } + + while (true) { + var pp = opt.indexOf("+"), pm = opt.indexOf("-"); + if ((pp<0) && (pm<0)) break; + var p1 = pp, sign = "+"; + if ((p1<0) || ((pm>=0) && (pm<pp))) { p1 = pm; sign = "-"; } + + var p2 = p1+1, regexp = new RegExp('[,; .]'); + while ((p2<opt.length) && !regexp.test(opt[p2]) && (opt[p2]!='+') && (opt[p2]!='-')) p2++; + + var name = opt.substring(p1+1, p2); + opt = opt.substr(0,p1) + opt.substr(p2); + // console.log("Modify visibility", sign,':',name); + + this.ModifyVisisbility(name, sign); + } + + var d = new JSROOT.DrawOptions(opt); + + if (d.check("MAIN")) res.is_main = true; + + if (d.check("TRACKS")) res.tracks = true; + if (d.check("ORTHO_CAMERA")) res.ortho_camera = true; + + if (d.check("DEPTHRAY") || d.check("DRAY")) res.depthMethod = "ray"; + if (d.check("DEPTHBOX") || d.check("DBOX")) res.depthMethod = "box"; + if (d.check("DEPTHPNT") || d.check("DPNT")) res.depthMethod = "pnt"; + if (d.check("DEPTHSIZE") || d.check("DSIZE")) res.depthMethod = "size"; + if (d.check("DEPTHDFLT") || d.check("DDFLT")) res.depthMethod = "dflt"; + + if (d.check("ZOOM", true)) res.zoom = d.partAsInt(0, 100) / 100; + + if (d.check('BLACK')) res.background = "#000000"; + if (d.check('WHITE')) res.background = "#FFFFFF"; + + if (d.check('BKGR_', true)) { + var bckgr = null; + if (d.partAsInt(1)>0) bckgr = JSROOT.Painter.root_colors[d.partAsInt()]; else + for (var col=0;col<8;++col) + if (JSROOT.Painter.root_colors[col].toUpperCase() === d.part) bckgr = JSROOT.Painter.root_colors[col]; + if (bckgr) res.background = "#" + new THREE.Color(bckgr).getHexString(); + } + + if (d.check("MORE3")) res.more = 3; + if (d.check("MORE")) res.more = 2; + if (d.check("ALL")) res.more = 100; + + if (d.check("CONTROLS") || d.check("CTRL")) res.show_controls = true; + + if (d.check("CLIPXYZ")) res.clipx = res.clipy = res.clipz = true; + if (d.check("CLIPX")) res.clipx = true; + if (d.check("CLIPY")) res.clipy = true; + if (d.check("CLIPZ")) res.clipz = true; + if (d.check("CLIP")) res.clipx = res.clipy = res.clipz = true; + + if (d.check("PROJX", true)) { res.project = 'x'; if (d.partAsInt(1)>0) res.projectPos = d.partAsInt(); } + if (d.check("PROJY", true)) { res.project = 'y'; if (d.partAsInt(1)>0) res.projectPos = d.partAsInt(); } + if (d.check("PROJZ", true)) { res.project = 'z'; if (d.partAsInt(1)>0) res.projectPos = d.partAsInt(); } + + if (d.check("DFLT_COLORS") || d.check("DFLT")) this.SetRootDefaultColors(); + if (d.check("SSAO")) res.ssao = true; + + if (d.check("NOWORKER")) res.use_worker = -1; + if (d.check("WORKER")) res.use_worker = 1; + + if (d.check("NOHIGHLIGHT") || d.check("NOHIGH")) res.highlight = res.highlight_scene = 0; + if (d.check("HIGHLIGHT")) res.highlight_scene = res.highlight = true; + if (d.check("HSCENEONLY")) { res.highlight_scene = true; res.highlight = 0; } + if (d.check("NOHSCENE")) res.highlight_scene = 0; + if (d.check("HSCENE")) res.highlight_scene = true; + + if (d.check("WIRE")) res.wireframe = true; + if (d.check("ROTATE")) res.autoRotate = true; + + if (d.check("INVX") || d.check("INVERTX")) res.scale.x = -1; + if (d.check("INVY") || d.check("INVERTY")) res.scale.y = -1; + if (d.check("INVZ") || d.check("INVERTZ")) res.scale.z = -1; + + if (d.check("COUNT")) res._count = true; + + if (d.check('TRANSP',true)) + res.transparency = d.partAsInt(0,100)/100; + + if (d.check('OPACITY',true)) + res.transparency = 1 - d.partAsInt(0,100)/100; + + if (d.check("AXISCENTER") || d.check("AC")) { res._axis = true; res._axis_center = true; } + + if (d.check("AXIS") || d.check("A")) res._axis = true; + + if (d.check("D")) res._debug = true; + if (d.check("G")) res._grid = true; + if (d.check("B")) res._bound = true; + if (d.check("W")) res.wireframe = true; + if (d.check("F")) res._full = true; + if (d.check("Y")) res._yup = true; + if (d.check("Z")) res._yup = false; + + // when drawing geometry without TCanvas, yup = true by default + if (res._yup === undefined) + res._yup = this.svg_canvas().empty(); + + return res; + } + + TGeoPainter.prototype.ActivateInBrowser = function(names, force) { + // if (this.GetItemName() === null) return; + + if (typeof names == 'string') names = [ names ]; + + if (this._hpainter) { + // show browser if it not visible + this._hpainter.activate(names, force); + + // if highlight in the browser disabled, suppress in few seconds + if (!this.options.update_browser) + setTimeout(this._hpainter.activate.bind(this._hpainter, []), 2000); + } + } + + TGeoPainter.prototype.TestMatrixes = function() { + // method can be used to check matrix calculations with current three.js model + + var painter = this, errcnt = 0, totalcnt = 0, totalmax = 0; + + var arg = { + domatrix: true, + func: function(node) { + + var m2 = this.getmatrix(); + + var entry = this.CopyStack(); + + var mesh = painter._clones.CreateObject3D(entry.stack, painter._toplevel, 'mesh'); + + if (!mesh) return true; + + totalcnt++; + + var m1 = mesh.matrixWorld, flip, origm2; + + if (m1.equals(m2)) return true + if ((m1.determinant()>0) && (m2.determinant()<-0.9)) { + flip = THREE.Vector3(1,1,-1); + origm2 = m2; + m2 = m2.clone().scale(flip); + if (m1.equals(m2)) return true; + } + + var max = 0; + for (var k=0;k<16;++k) + max = Math.max(max, Math.abs(m1.elements[k] - m2.elements[k])); + + totalmax = Math.max(max, totalmax); + + if (max < 1e-4) return true; + + console.log(painter._clones.ResolveStack(entry.stack).name, 'maxdiff', max, 'determ', m1.determinant(), m2.determinant()); + + errcnt++; + + return false; + } + }; + + + tm1 = new Date().getTime(); + + var cnt = this._clones.ScanVisible(arg); + + tm2 = new Date().getTime(); + + console.log('Compare matrixes total',totalcnt,'errors',errcnt, 'takes', tm2-tm1, 'maxdiff', totalmax); + } + + + TGeoPainter.prototype.FillContextMenu = function(menu) { + menu.add("header: Draw options"); + + menu.addchk(this.options.update_browser, "Browser update", function() { + this.options.update_browser = !this.options.update_browser; + if (!this.options.update_browser) this.ActivateInBrowser([]); + }); + menu.addchk(this.options.show_controls, "Show Controls", function() { + this.showControlOptions('toggle'); + }); + menu.addchk(this.TestAxisVisibility, "Show axes", function() { + this.toggleAxisDraw(); + }); + menu.addchk(this.options.wireframe, "Wire frame", function() { + this.options.wireframe = !this.options.wireframe; + this.changeWireFrame(this._scene, this.options.wireframe); + }); + menu.addchk(this.options.highlight, "Highlight volumes", function() { + this.options.highlight = !this.options.highlight; + }); + menu.addchk(this.options.highlight_scene, "Highlight scene", function() { + this.options.highlight_scene = !this.options.highlight_scene; + }); + menu.add("Reset camera position", function() { + this.focusCamera(); + this.Render3D(); + }); + if (!this.options.project) + menu.addchk(this.options.autoRotate, "Autorotate", function() { + this.options.autoRotate = !this.options.autoRotate; + this.autorotate(2.5); + }); + menu.addchk(this.options.select_in_view, "Select in view", function() { + this.options.select_in_view = !this.options.select_in_view; + if (this.options.select_in_view) this.startDrawGeometry(); + }); + } + + /** Method used to set transparency for all geometrical shapes + * As transperency value one could provide function */ + TGeoPainter.prototype.changeGlobalTransparency = function(transparency, skip_render) { + var func = (typeof transparency == 'function') ? transparency : null; + if (func) transparency = this.options.transparency; + this._toplevel.traverse( function (node) { + if (node && node.material && (node.material.inherentOpacity !== undefined)) { + var t = func ? func(node) : undefined; + if (t !== undefined) + node.material.opacity = 1 - t; + else + node.material.opacity = Math.min(1 - (transparency || 0), node.material.inherentOpacity); + node.material.transparent = node.material.opacity < 1; + } + }); + if (!skip_render) this.Render3D(0); + } + + TGeoPainter.prototype.showControlOptions = function(on) { + if (on==='toggle') on = !this._datgui; + + this.options.show_controls = on; + + if (this._datgui) { + if (on) return; + d3.select(this._datgui.domElement).remove(); + this._datgui.destroy(); + delete this._datgui; + return; + } + if (!on) return; + + var painter = this; + + this._datgui = new dat.GUI({ autoPlace: false, width: Math.min(650, painter._renderer.domElement.width / 2) }); + + var main = this.select_main(); + if (main.style('position')=='static') main.style('position','relative'); + + d3.select(this._datgui.domElement) + .style('position','absolute') + .style('top',0).style('right',0); + + main.node().appendChild(this._datgui.domElement); + + if (this.options.project) { + + var bound = this.getGeomBoundingBox(this.getProjectionSource(), 0.01); + + var axis = this.options.project; + + if (this.options.projectPos === undefined) + this.options.projectPos = (bound.min[axis] + bound.max[axis])/2; + + this._datgui.add(this.options, 'projectPos', bound.min[axis], bound.max[axis]) + .name(axis.toUpperCase() + ' projection') + .onChange(function (value) { + painter.startDrawGeometry(); + }); + + } else { + // Clipping Options + + var bound = this.getGeomBoundingBox(this._toplevel, 0.01); + + var clipFolder = this._datgui.addFolder('Clipping'); + + for (var naxis=0;naxis<3;++naxis) { + var axis = !naxis ? "x" : ((naxis===1) ? "y" : "z"), + axisC = axis.toUpperCase(); + + clipFolder.add(this, 'enable' + axisC).name('Enable '+axisC) + .listen() // react if option changed outside + .onChange( function (value) { + painter._enableSSAO = value ? false : painter._enableSSAO; + painter.updateClipping(); + }); + + var clip = "clip" + axisC; + if (this[clip] === 0) this[clip] = (bound.min[axis]+bound.max[axis])/2; + + var item = clipFolder.add(this, clip, bound.min[axis], bound.max[axis]) + .name(axisC + ' Position') + .onChange(function (value) { + if (painter[this.enbale_flag]) painter.updateClipping(); + }); + + item.enbale_flag = "enable"+axisC; + } + + } + + // Appearance Options + + var appearance = this._datgui.addFolder('Appearance'); + + if (this._webgl) { + appearance.add(this, '_enableSSAO').name('Smooth Lighting (SSAO)').onChange( function (value) { + painter._renderer.antialias = !painter._renderer.antialias; + painter.enableX = value ? false : painter.enableX; + painter.enableY = value ? false : painter.enableY; + painter.enableZ = value ? false : painter.enableZ; + painter.updateClipping(); + }).listen(); + } + + appearance.add(this.options, 'highlight').name('Highlight Selection').listen().onChange( function (value) { + if (!value) painter.HighlightMesh(null); + }); + + appearance.add(this.options, 'transparency', 0.0, 1.0, 0.001) + .listen().onChange(this.changeGlobalTransparency.bind(this)); + + appearance.add(this.options, 'wireframe').name('Wireframe').listen().onChange( function (value) { + painter.changeWireFrame(painter._scene, painter.options.wireframe); + }); + + appearance.addColor(this.options, 'background').name('Background').onChange( function() { + painter._renderer.setClearColor(painter.options.background, 1); + painter.Render3D(0); + var bkgr = new THREE.Color(painter.options.background); + painter._toolbar.changeBrightness((bkgr.r + bkgr.g + bkgr.b) < 1); + }); + + appearance.add(this, 'focusCamera').name('Reset camera position'); + + // Advanced Options + + if (this._webgl) { + var advanced = this._datgui.addFolder('Advanced'); + + advanced.add( this._advceOptions, 'aoClamp', 0.0, 1.0).listen().onChange( function (value) { + painter._ssaoPass.uniforms[ 'aoClamp' ].value = value; + painter._enableSSAO = true; + painter.Render3D(0); + }); + + advanced.add( this._advceOptions, 'lumInfluence', 0.0, 1.0).listen().onChange( function (value) { + painter._ssaoPass.uniforms[ 'lumInfluence' ].value = value; + painter._enableSSAO = true; + painter.Render3D(0); + }); + + advanced.add( this._advceOptions, 'clipIntersection').listen().onChange( function (value) { + painter.clipIntersection = value; + painter.updateClipping(); + }); + + advanced.add(this._advceOptions, 'depthTest').onChange( function (value) { + painter._toplevel.traverse( function (node) { + if (node instanceof THREE.Mesh) { + node.material.depthTest = value; + } + }); + painter.Render3D(0); + }).listen(); + + advanced.add(this, 'resetAdvanced').name('Reset'); + } + } + + + TGeoPainter.prototype.OrbitContext = function(evnt, intersects) { + + JSROOT.Painter.createMenu(this, function(menu) { + var numitems = 0, numnodes = 0, cnt = 0; + if (intersects) + for (var n=0;n<intersects.length;++n) { + if (intersects[n].object.stack) numnodes++; + if (intersects[n].object.geo_name) numitems++; + } + + if (numnodes + numitems === 0) { + menu.painter.FillContextMenu(menu); + } else { + var many = (numnodes + numitems) > 1; + + if (many) menu.add("header:" + ((numitems > 0) ? "Items" : "Nodes")); + + for (var n=0;n<intersects.length;++n) { + var obj = intersects[n].object, + name, itemname, hdr; + + if (obj.geo_name) { + itemname = obj.geo_name; + name = itemname.substr(itemname.lastIndexOf("/")+1); + if (!name) name = itemname; + hdr = name; + } else + if (obj.stack) { + name = menu.painter._clones.ResolveStack(obj.stack).name; + itemname = menu.painter.GetStackFullName(obj.stack); + hdr = menu.painter.GetItemName(); + if (name.indexOf("Nodes/") === 0) hdr = name.substr(6); else + if (name.length > 0) hdr = name; else + if (!hdr) hdr = "header"; + + } else + continue; + + + menu.add((many ? "sub:" : "header:") + hdr, itemname, function(arg) { this.ActivateInBrowser([arg], true); }); + + menu.add("Browse", itemname, function(arg) { this.ActivateInBrowser([arg], true); }); + + if (menu.painter._hpainter) + menu.add("Inspect", itemname, function(arg) { this._hpainter.display(itemname, "inspect"); }); + + if (obj.geo_name) { + menu.add("Hide", n, function(indx) { + var mesh = intersects[indx].object; + mesh.visible = false; // just disable mesh + if (mesh.geo_object) mesh.geo_object.$hidden_via_menu = true; // and hide object for further redraw + menu.painter.Render3D(); + }); + + if (many) menu.add("endsub:"); + + continue; + } + + var wireframe = menu.painter.accessObjectWireFrame(obj); + + if (wireframe!==undefined) + menu.addchk(wireframe, "Wireframe", n, function(indx) { + var m = intersects[indx].object.material; + m.wireframe = !m.wireframe; + this.Render3D(); + }); + + if (++cnt>1) + menu.add("Manifest", n, function(indx) { + + if (this._last_manifest) + this._last_manifest.wireframe = !this._last_manifest.wireframe; + + if (this._last_hidden) + this._last_hidden.forEach(function(obj) { obj.visible = true; }); + + this._last_hidden = []; + + for (var i=0;i<indx;++i) + this._last_hidden.push(intersects[i].object); + + this._last_hidden.forEach(function(obj) { obj.visible = false; }); + + this._last_manifest = intersects[indx].object.material; + + this._last_manifest.wireframe = !this._last_manifest.wireframe; + + this.Render3D(); + }); + + + menu.add("Focus", n, function(indx) { + this.focusCamera(intersects[indx].object); + }); + + if (!menu.painter._geom_viewer) + menu.add("Hide", n, function(indx) { + var resolve = menu.painter._clones.ResolveStack(intersects[indx].object.stack); + + if (resolve.obj && (resolve.node.kind === 0) && resolve.obj.fVolume) { + JSROOT.GEO.SetBit(resolve.obj.fVolume, JSROOT.GEO.BITS.kVisThis, false); + JSROOT.GEO.updateBrowserIcons(resolve.obj.fVolume, this._hpainter); + } else + if (resolve.obj && (resolve.node.kind === 1)) { + resolve.obj.fRnrSelf = false; + JSROOT.GEO.updateBrowserIcons(resolve.obj, this._hpainter); + } + // intersects[arg].object.visible = false; + // this.Render3D(); + + this.testGeomChanges();// while many volumes may disappear, recheck all of them + }); + + if (many) menu.add("endsub:"); + } + } + menu.show(evnt); + }); + } + + TGeoPainter.prototype.FilterIntersects = function(intersects) { + + if (!intersects.length) return intersects; + + // check redirections + for (var n=0;n<intersects.length;++n) + if (intersects[n].object.geo_highlight) + intersects[n].object = intersects[n].object.geo_highlight; + + // remove all elements without stack - indicator that this is geometry object + // also remove all objects which are mostly transparent + for (var n=intersects.length-1; n>=0; --n) { + + var obj = intersects[n].object; + + var unique = (obj.stack !== undefined) || (obj.geo_name !== undefined); + + if (unique && obj.material && (obj.material.opacity !== undefined)) + unique = obj.material.opacity >= 0.1; + + if (obj.jsroot_special) unique = false; + + for (var k=0;(k<n) && unique;++k) + if (intersects[k].object === obj) unique = false; + + if (!unique) intersects.splice(n,1); + } + + if (this.enableX || this.enableY || this.enableZ) { + var clippedIntersects = []; + + function myXor(a,b) { return ( a && !b ) || (!a && b); } + + for (var i = 0; i < intersects.length; ++i) { + var point = intersects[i].point, special = (intersects[i].object.type == "Points"), clipped = true; + + if (this.enableX && myXor(this._clipPlanes[0].normal.dot(point) > this._clipPlanes[0].constant, special)) clipped = false; + if (this.enableY && myXor(this._clipPlanes[1].normal.dot(point) > this._clipPlanes[1].constant, special)) clipped = false; + if (this.enableZ && (this._clipPlanes[2].normal.dot(point) > this._clipPlanes[2].constant)) clipped = false; + + if (!clipped) clippedIntersects.push(intersects[i]); + } + + intersects = clippedIntersects; + } + + return intersects; + } + + TGeoPainter.prototype.testCameraPositionChange = function() { + // function analyzes camera position and start redraw of geometry if + // objects in view may be changed + + if (!this.options.select_in_view || this._draw_all_nodes) return; + + + var matrix = JSROOT.GEO.CreateProjectionMatrix(this._camera); + + var frustum = JSROOT.GEO.CreateFrustum(matrix); + + // check if overall bounding box seen + if (!frustum.CheckBox(this.getGeomBoundingBox(this._toplevel))) + this.startDrawGeometry(); + } + + TGeoPainter.prototype.ResolveStack = function(stack) { + return this._clones && stack ? this._clones.ResolveStack(stack) : null; + } + + TGeoPainter.prototype.GetStackFullName = function(stack) { + var mainitemname = this.GetItemName(), + sub = this.ResolveStack(stack); + if (!sub || !sub.name) return mainitemname; + return mainitemname ? (mainitemname + "/" + sub.name) : sub.name; + } + + /** Add handler which will be called when element is highlighted in geometry drawing + * Handler should have HighlightMesh function with same arguments as TGeoPainter */ + TGeoPainter.prototype.AddHighlightHandler = function(handler) { + if (!handler || typeof handler.HighlightMesh != 'function') return; + if (!this._highlight_handlers) this._highlight_handlers = []; + this._highlight_handlers.push(handler); + } + + ////////////////////// + + function GeoDrawingControl(mesh) { + JSROOT.Painter.InteractiveControl.call(this); + this.mesh = (mesh && mesh.material) ? mesh : null; + } + + GeoDrawingControl.prototype = Object.create(JSROOT.Painter.InteractiveControl.prototype); + + GeoDrawingControl.prototype.setHighlight = function(col, indx) { + return this.drawSpecial(col, indx); + } + + GeoDrawingControl.prototype.drawSpecial = function(col, indx) { + var c = this.mesh; + if (!c || !c.material) return; + + if (col) { + if (!c.origin) + c.origin = { + color: c.material.color, + opacity: c.material.opacity, + width: c.material.linewidth, + size: c.material.size + }; + c.material.color = new THREE.Color( col ); + c.material.opacity = 1.; + if (c.hightlightWidthScale && !JSROOT.browser.isWin) + c.material.linewidth = c.origin.width * c.hightlightWidthScale; + if (c.highlightScale) + c.material.size = c.origin.size * c.highlightScale; + return true; + } else if (c.origin) { + c.material.color = c.origin.color; + c.material.opacity = c.origin.opacity; + if (c.hightlightWidthScale) + c.material.linewidth = c.origin.width; + if (c.highlightScale) + c.material.size = c.origin.size; + return true; + } + } + + //////////////////////// + + TGeoPainter.prototype.HighlightMesh = function(active_mesh, color, geo_object, geo_index, geo_stack, no_recursive) { + + if (geo_object) { + active_mesh = active_mesh ? [ active_mesh ] : []; + var extras = this.getExtrasContainer(); + if (extras) + extras.traverse(function(obj3d) { + if ((obj3d.geo_object === geo_object) && (active_mesh.indexOf(obj3d)<0)) active_mesh.push(obj3d); + }); + } else if (geo_stack && this._toplevel) { + active_mesh = []; + this._toplevel.traverse(function(mesh) { + if ((mesh instanceof THREE.Mesh) && JSROOT.GEO.IsSameStack(mesh.stack, geo_stack)) active_mesh.push(mesh); + }); + } else { + active_mesh = active_mesh ? [ active_mesh ] : []; + } + + if (!active_mesh.length) active_mesh = null; + + if (active_mesh) { + // check if highlight is disabled for correspondent objects kinds + if (active_mesh[0].geo_object) { + if (!this.options.highlight_scene) active_mesh = null; + } else { + if (!this.options.highlight) active_mesh = null; + } + } + + if (!no_recursive) { + // check all other painters + + if (active_mesh) { + if (!geo_object) geo_object = active_mesh[0].geo_object; + if (!geo_stack) geo_stack = active_mesh[0].stack; + } + + var lst = this._highlight_handlers || (!this._main_painter ? this._slave_painters : this._main_painter._slave_painters.concat([this._main_painter])); + + for (var k=0;k<lst.length;++k) + if (lst[k]!==this) lst[k].HighlightMesh(null, color, geo_object, geo_index, geo_stack, true); + } + + var curr_mesh = this._selected_mesh; + + function get_ctrl(mesh) { + return mesh.get_ctrl ? mesh.get_ctrl() : new GeoDrawingControl(mesh); + } + + // check if selections are the same + if (!curr_mesh && !active_mesh) return false; + var same = false; + if (curr_mesh && active_mesh && (curr_mesh.length == active_mesh.length)) { + same = true; + for (var k=0;(k<curr_mesh.length) && same;++k) { + if ((curr_mesh[k] !== active_mesh[k]) || get_ctrl(curr_mesh[k]).checkHighlightIndex(geo_index)) same = false; + } + } + if (same) return !!curr_mesh; + + if (curr_mesh) + for (var k=0;k<curr_mesh.length;++k) + get_ctrl(curr_mesh[k]).setHighlight(); + + this._selected_mesh = active_mesh; + + if (active_mesh) + for (var k=0;k<active_mesh.length;++k) + get_ctrl(active_mesh[k]).setHighlight(color || 0xffaa33, geo_index); + + this.Render3D(0); + + return !!active_mesh; + } + + TGeoPainter.prototype.ProcessMouseClick = function(pnt, intersects, evnt) { + if (!intersects.length) return; + + var mesh = intersects[0].object; + if (!mesh.get_ctrl) return; + + var ctrl = mesh.get_ctrl(); + + var click_indx = ctrl.extractIndex(intersects[0]); + + ctrl.evnt = evnt; + + if (ctrl.setSelected("blue", click_indx)) + this.Render3D(); + + ctrl.evnt = null; + } + + TGeoPainter.prototype.addOrbitControls = function() { + + if (this._controls || this._usesvg || JSROOT.BatchMode) return; + + var painter = this; + + this.SetTooltipAllowed(JSROOT.gStyle.Tooltip > 0); + + this._controls = JSROOT.Painter.CreateOrbitControl(this, this._camera, this._scene, this._renderer, this._lookat); + + if (this.options.project || this.options.ortho_camera) this._controls.enableRotate = false; + + this._controls.ContextMenu = this.OrbitContext.bind(this); + + this._controls.ProcessMouseMove = function(intersects) { + + var active_mesh = null, tooltip = null, resolve = null, names = [], geo_object, geo_index; + + // try to find mesh from intersections + for (var k=0;k<intersects.length;++k) { + var obj = intersects[k].object, info = null; + if (!obj) continue; + if (obj.geo_object) info = obj.geo_name; else + if (obj.stack) info = painter.GetStackFullName(obj.stack); + if (info===null) continue; + + if (info.indexOf("<prnt>")==0) + info = painter.GetItemName() + info.substr(6); + + names.push(info); + + if (!active_mesh) { + active_mesh = obj; + tooltip = info; + geo_object = obj.geo_object; + if (obj.get_ctrl) { + geo_index = obj.get_ctrl().extractIndex(intersects[k]); + if ((geo_index !== undefined) && (typeof tooltip == "string")) tooltip += " indx:" + JSON.stringify(geo_index); + } + if (active_mesh.stack) resolve = painter.ResolveStack(active_mesh.stack); + } + } + + painter.HighlightMesh(active_mesh, undefined, geo_object, geo_index); + + if (painter.options.update_browser) { + if (painter.options.highlight && tooltip) names = [ tooltip ]; + painter.ActivateInBrowser(names); + } + + if (!resolve || !resolve.obj) return tooltip; + + var lines = JSROOT.GEO.provideInfo(resolve.obj); + lines.unshift(tooltip); + + return { name: resolve.obj.fName, title: resolve.obj.fTitle || resolve.obj._typename, lines: lines }; + } + + this._controls.ProcessMouseLeave = function() { + this.ProcessMouseMove([]); // to disable highlight and reset browser + } + + this._controls.ProcessDblClick = function() { + if (painter._last_manifest) { + painter._last_manifest.wireframe = !painter._last_manifest.wireframe; + if (painter._last_hidden) + painter._last_hidden.forEach(function(obj) { obj.visible = true; }); + delete painter._last_hidden; + delete painter._last_manifest; + painter.Render3D(); + } else { + painter.adjustCameraPosition(); + } + } + } + + TGeoPainter.prototype.addTransformControl = function() { + if (this._tcontrols) return; + + if ( !this.options._debug && !this.options._grid ) return; + + // FIXME: at the moment THREE.TransformControls is bogus in three.js, should be fixed and check again + //return; + + this._tcontrols = new THREE.TransformControls( this._camera, this._renderer.domElement ); + this._scene.add( this._tcontrols ); + this._tcontrols.attach( this._toplevel ); + //this._tcontrols.setSize( 1.1 ); + var painter = this; + + window.addEventListener( 'keydown', function ( event ) { + switch ( event.keyCode ) { + case 81: // Q + painter._tcontrols.setSpace( painter._tcontrols.space === "local" ? "world" : "local" ); + break; + case 17: // Ctrl + painter._tcontrols.setTranslationSnap( Math.ceil( painter._overall_size ) / 50 ); + painter._tcontrols.setRotationSnap( THREE.Math.degToRad( 15 ) ); + break; + case 84: // T (Translate) + painter._tcontrols.setMode( "translate" ); + break; + case 82: // R (Rotate) + painter._tcontrols.setMode( "rotate" ); + break; + case 83: // S (Scale) + painter._tcontrols.setMode( "scale" ); + break; + case 187: + case 107: // +, =, num+ + painter._tcontrols.setSize( painter._tcontrols.size + 0.1 ); + break; + case 189: + case 109: // -, _, num- + painter._tcontrols.setSize( Math.max( painter._tcontrols.size - 0.1, 0.1 ) ); + break; + } + }); + window.addEventListener( 'keyup', function ( event ) { + switch ( event.keyCode ) { + case 17: // Ctrl + painter._tcontrols.setTranslationSnap( null ); + painter._tcontrols.setRotationSnap( null ); + break; + } + }); + + this._tcontrols.addEventListener( 'change', function() { painter.Render3D(0); }); + } + + TGeoPainter.prototype.nextDrawAction = function() { + // return false when nothing todo + // return true if one could perform next action immediately + // return 1 when call after short timeout required + // return 2 when call must be done from processWorkerReply + + if (!this._clones || (this.drawing_stage == 0)) return false; + + if (this.drawing_stage == 1) { + + if (this._geom_viewer) { + this._draw_all_nodes = false; + this.drawing_stage = 3; + return true; + } + + // wait until worker is really started + if (this.options.use_worker>0) { + if (!this._worker) { this.startWorker(); return 1; } + if (!this._worker_ready) return 1; + } + + // first copy visibility flags and check how many unique visible nodes exists + var numvis = this._clones.MarkVisisble(), + matrix = null, frustum = null; + + if (this.options.select_in_view && !this._first_drawing) { + // extract camera projection matrix for selection + + matrix = JSROOT.GEO.CreateProjectionMatrix(this._camera); + + frustum = JSROOT.GEO.CreateFrustum(matrix); + + // check if overall bounding box seen + if (frustum.CheckBox(this.getGeomBoundingBox(this._toplevel))) { + matrix = null; // not use camera for the moment + frustum = null; + } + } + + this._current_face_limit = this.options.maxlimit; + this._current_nodes_limit = this.options.maxnodeslimit; + if (matrix) { + this._current_face_limit*=1.25; + this._current_nodes_limit*=1.25; + } + + // here we decide if we need worker for the drawings + // main reason - too large geometry and large time to scan all camera positions + var need_worker = !JSROOT.BatchMode && ((numvis > 10000) || (matrix && (this._clones.ScanVisible() > 1e5))); + + // worker does not work when starting from file system + if (need_worker && JSROOT.source_dir.indexOf("file://")==0) { + console.log('disable worker for jsroot from file system'); + need_worker = false; + } + + if (need_worker && !this._worker && (this.options.use_worker >= 0)) + this.startWorker(); // we starting worker, but it may not be ready so fast + + if (!need_worker || !this._worker_ready) { + //var tm1 = new Date().getTime(); + var res = this._clones.CollectVisibles(this._current_face_limit, frustum, this._current_nodes_limit); + this._new_draw_nodes = res.lst; + this._draw_all_nodes = res.complete; + //var tm2 = new Date().getTime(); + //console.log('Collect visibles', this._new_draw_nodes.length, 'takes', tm2-tm1); + this.drawing_stage = 3; + return true; + } + + var job = { + collect: this._current_face_limit, // indicator for the command + collect_nodes: this._current_nodes_limit, + visible: this._clones.GetVisibleFlags(), + matrix: matrix ? matrix.elements : null + }; + + this.submitToWorker(job); + + this.drawing_stage = 2; + + this.drawing_log = "Worker select visibles"; + + return 2; // we now waiting for the worker reply + } + + if (this.drawing_stage == 2) { + // do nothing, we are waiting for worker reply + + this.drawing_log = "Worker select visibles"; + + return 2; + } + + if (this.drawing_stage == 3) { + // here we merge new and old list of nodes for drawing, + // normally operation is fast and can be implemented with one call + + this.drawing_log = "Analyse visibles"; + + if (this._new_append_nodes) { + + this._new_draw_nodes = this._draw_nodes.concat(this._new_append_nodes); + + delete this._new_append_nodes; + + } else if (this._draw_nodes) { + + var del; + if (this._geom_viewer) + del = this._draw_nodes; + else + del = this._clones.MergeVisibles(this._new_draw_nodes, this._draw_nodes); + + // remove should be fast, do it here + for (var n=0;n<del.length;++n) + this._clones.CreateObject3D(del[n].stack, this._toplevel, 'delete_mesh'); + + if (del.length > 0) + this.drawing_log = "Delete " + del.length + " nodes"; + } + + this._draw_nodes = this._new_draw_nodes; + delete this._new_draw_nodes; + this.drawing_stage = 4; + return true; + } + + if (this.drawing_stage === 4) { + + this.drawing_log = "Collect shapes"; + + // collect shapes + var shapes = this._clones.CollectShapes(this._draw_nodes); + + // merge old and new list with produced shapes + this._build_shapes = this._clones.MergeShapesLists(this._build_shapes, shapes); + + this.drawing_stage = 5; + return true; + } + + + if (this.drawing_stage === 5) { + // this is building of geometries, + // one can ask worker to build them or do it ourself + + if (this.canSubmitToWorker()) { + var job = { limit: this._current_face_limit, shapes: [] }, cnt = 0; + for (var n=0;n<this._build_shapes.length;++n) { + var clone = null, item = this._build_shapes[n]; + // only submit not-done items + if (item.ready || item.geom) { + // this is place holder for existing geometry + clone = { id: item.id, ready: true, nfaces: JSROOT.GEO.numGeometryFaces(item.geom), refcnt: item.refcnt }; + } else { + clone = JSROOT.clone(item, null, true); + cnt++; + } + + job.shapes.push(clone); + } + + if (cnt > 0) { + /// only if some geom missing, submit job to the worker + this.submitToWorker(job); + this.drawing_log = "Worker build shapes"; + this.drawing_stage = 6; + return 2; + } + } + + this.drawing_stage = 7; + } + + if (this.drawing_stage === 6) { + // waiting shapes from the worker, worker should activate our code + return 2; + } + + if ((this.drawing_stage === 7) || (this.drawing_stage === 8)) { + + if (this.drawing_stage === 7) { + // building shapes + var res = this._clones.BuildShapes(this._build_shapes, this._current_face_limit, 500); + if (res.done) { + this.drawing_stage = 8; + } else { + this.drawing_log = "Creating: " + res.shapes + " / " + this._build_shapes.length + " shapes, " + res.faces + " faces"; + if (res.notusedshapes < 30) return true; + } + } + + // final stage, create all meshes + + var tm0 = new Date().getTime(), ready = true, + toplevel = this.options.project ? this._full_geom : this._toplevel; + + for (var n = 0; n < this._draw_nodes.length; ++n) { + var entry = this._draw_nodes[n]; + if (entry.done) continue; + + /// shape can be provided with entry itself + var shape = entry.server_shape || this._build_shapes[entry.shapeid]; + if (!shape.ready) { + if (this.drawing_stage === 8) console.warn('shape marked as not ready when should'); + ready = false; + continue; + } + + entry.done = true; + shape.used = true; // indicate that shape was used in building + + if (this.createEntryMesh(entry, shape, toplevel)) { + this._num_meshes++; + this._num_faces += shape.nfaces; + } + + var tm1 = new Date().getTime(); + if (tm1 - tm0 > 500) { ready = false; break; } + } + + if (ready) { + if (this.options.project) { + this.drawing_log = "Build projection"; + this.drawing_stage = 10; + return true; + } + + this.drawing_log = "Building done"; + this.drawing_stage = 0; + return false; + } + + if (this.drawing_stage > 7) + this.drawing_log = "Building meshes " + this._num_meshes + " / " + this._num_faces; + return true; + } + + if (this.drawing_stage === 9) { + // wait for main painter to be ready + + if (!this._main_painter) { + console.warn('MAIN PAINTER DISAPPER'); + this.drawing_stage = 0; + return false; + } + if (!this._main_painter._drawing_ready) return 1; + + this.drawing_stage = 10; // just do projection + } + + if (this.drawing_stage === 10) { + this.doProjection(); + this.drawing_log = "Building done"; + this.drawing_stage = 0; + return false; + } + + console.error('never come here stage = ' + this.drawing_stage); + + return false; + } + + /** Insert appropriate mesh for given entry + * @private*/ + TGeoPainter.prototype.createEntryMesh = function(entry, shape, toplevel) { + if (!shape.geom || (shape.nfaces === 0)) { + // node is visible, but shape does not created + this._clones.CreateObject3D(entry.stack, toplevel, 'delete_mesh'); + return false; + } + + var prop = this._clones.getDrawEntryProperties(entry); + + var obj3d = this._clones.CreateObject3D(entry.stack, toplevel, this.options); + + prop.material.wireframe = this.options.wireframe; + + prop.material.side = this.bothSides ? THREE.DoubleSide : THREE.FrontSide; + + var mesh; + + if (obj3d.matrixWorld.determinant() > -0.9) { + mesh = new THREE.Mesh( shape.geom, prop.material ); + } else { + mesh = JSROOT.GEO.createFlippedMesh(obj3d, shape, prop.material); + } + + obj3d.add(mesh); + + // keep full stack of nodes + mesh.stack = entry.stack; + mesh.renderOrder = this._clones.maxdepth - entry.stack.length; // order of transparency handling + + // keep hierarchy level + mesh.$jsroot_order = obj3d.$jsroot_depth; + + // set initial render order, when camera moves, one must refine it + //mesh.$jsroot_order = mesh.renderOrder = + // this._clones.maxdepth - ((obj3d.$jsroot_depth !== undefined) ? obj3d.$jsroot_depth : entry.stack.length); + + if (this.options._debug || this.options._full) { + var wfg = new THREE.WireframeGeometry( mesh.geometry ), + wfm = new THREE.LineBasicMaterial( { color: prop.fillcolor, linewidth: prop.linewidth || 1 } ), + helper = new THREE.LineSegments(wfg, wfm); + obj3d.add(helper); + } + + if (this.options._bound || this.options._full) { + var boxHelper = new THREE.BoxHelper( mesh ); + obj3d.add( boxHelper ); + } + + return true; + } + + /** function used by geometry viewer to show more nodes + * These nodes excluded from selecton logic and always inserted into the model + * Shape already should be created and assigned to the node + * @private */ + TGeoPainter.prototype.appendMoreNodes = function(nodes, from_drawing) { + if (this.drawing_stage && !from_drawing) { + this._provided_more_nodes = nodes; + return; + } + + // delete old nodes + if (this._more_nodes) + for (var n=0;n<this._more_nodes.length;++n) { + var entry = this._more_nodes[n]; + var obj3d = this._clones.CreateObject3D(entry.stack, this._toplevel, 'delete_mesh'); + JSROOT.Painter.DisposeThreejsObject(obj3d); + JSROOT.GEO.cleanupShape(entry.server_shape); + delete entry.server_shape; + } + + delete this._more_nodes; + + if (!nodes) return; + + var real_nodes = []; + + for (var k=0;k<nodes.length;++k) { + var entry = nodes[k]; + var shape = entry.server_shape; + if (!shape || !shape.ready) continue; + + entry.done = true; + shape.used = true; // indicate that shape was used in building + + if (this.createEntryMesh(entry, shape, this._toplevel)) + real_nodes.push(entry); + } + + // remember additional nodes only if they include shape - otherwise one can ignore them + if (real_nodes) this._more_nodes = real_nodes; + + if (!from_drawing) this.Render3D(); + } + + /** Returns hierarchy of 3D objects used to produce projection. + * Typically external master painter is used, but also intenral data can be used + * @private */ + + TGeoPainter.prototype.getProjectionSource = function() { + if (this._clones_owner) + return this._full_geom; + if (!this._main_painter) { + console.warn('MAIN PAINTER DISAPPER'); + return null; + } + if (!this._main_painter._drawing_ready) { + console.warn('MAIN PAINTER NOT READY WHEN DO PROJECTION'); + return null; + } + return this._main_painter._toplevel; + } + + TGeoPainter.prototype.getGeomBoundingBox = function(topitem, scalar) { + var box3 = new THREE.Box3(), check_any = !this._clones; + + if (!topitem) { + box3.min.x = box3.min.y = box3.min.z = -1; + box3.max.x = box3.max.y = box3.max.z = 1; + return box3; + } + + box3.makeEmpty(); + + topitem.traverse(function(mesh) { + if (check_any || ((mesh instanceof THREE.Mesh) && mesh.stack)) JSROOT.GEO.getBoundingBox(mesh, box3); + }); + + if (scalar !== undefined) box3.expandByVector(box3.getSize(new THREE.Vector3()).multiplyScalar(scalar)); + + return box3; + } + + + TGeoPainter.prototype.doProjection = function() { + var toplevel = this.getProjectionSource(), pthis = this; + + if (!toplevel) return false; + + JSROOT.Painter.DisposeThreejsObject(this._toplevel, true); + + var axis = this.options.project; + + if (this.options.projectPos === undefined) { + + var bound = this.getGeomBoundingBox(toplevel), + min = bound.min[this.options.project], max = bound.max[this.options.project], + mean = (min+max)/2; + + if ((min<0) && (max>0) && (Math.abs(mean) < 0.2*Math.max(-min,max))) mean = 0; // if middle is around 0, use 0 + + this.options.projectPos = mean; + } + + toplevel.traverse(function(mesh) { + if (!(mesh instanceof THREE.Mesh) || !mesh.stack) return; + + var geom2 = JSROOT.GEO.projectGeometry(mesh.geometry, mesh.parent.matrixWorld, pthis.options.project, pthis.options.projectPos, mesh._flippedMesh); + + if (!geom2) return; + + var mesh2 = new THREE.Mesh( geom2, mesh.material.clone() ); + + pthis._toplevel.add(mesh2); + + mesh2.stack = mesh.stack; + }); + + return true; + } + + TGeoPainter.prototype.SameMaterial = function(node1, node2) { + + if ((node1===null) || (node2===null)) return node1 === node2; + + if (node1.fVolume.fLineColor >= 0) + return (node1.fVolume.fLineColor === node2.fVolume.fLineColor); + + var m1 = (node1.fVolume.fMedium !== null) ? node1.fVolume.fMedium.fMaterial : null; + var m2 = (node2.fVolume.fMedium !== null) ? node2.fVolume.fMedium.fMaterial : null; + + if (m1 === m2) return true; + + if ((m1 === null) || (m2 === null)) return false; + + return (m1.fFillStyle === m2.fFillStyle) && (m1.fFillColor === m2.fFillColor); + } + + TGeoPainter.prototype.createScene = function(w, h) { + // three.js 3D drawing + this._scene = new THREE.Scene(); + this._scene.fog = new THREE.Fog(0xffffff, 1, 10000); + this._scene.overrideMaterial = new THREE.MeshLambertMaterial( { color: 0x7000ff, transparent: true, opacity: 0.2, depthTest: false } ); + + this._scene_width = w; + this._scene_height = h; + + if (this.options.ortho_camera) { + this._camera = new THREE.OrthographicCamera(-600, 600, -600, 600, 1, 10000); + } else { + this._camera = new THREE.PerspectiveCamera(25, w / h, 1, 10000); + this._camera.up = this.options._yup ? new THREE.Vector3(0,1,0) : new THREE.Vector3(0,0,1); + } + + this._scene.add( this._camera ); + + this._selected_mesh = null; + + this._overall_size = 10; + + this._toplevel = new THREE.Object3D(); + + this._scene.add(this._toplevel); + + var rrr = JSROOT.Painter.Create3DRenderer(w, h, this._usesvg, this._usesvgimg, this._webgl, + { antialias: true, logarithmicDepthBuffer: false, preserveDrawingBuffer: true }); + + this._webgl = rrr.usewebgl; + this._renderer = rrr.renderer; + + if (this._renderer.setPixelRatio && !JSROOT.nodejs) + this._renderer.setPixelRatio(window.devicePixelRatio); + this._renderer.setSize(w, h, !this._fit_main_area); + this._renderer.localClippingEnabled = true; + + this._renderer.setClearColor(this.options.background, 1); + +/* if (usesvg) { + // this._renderer = new THREE.SVGRenderer( { precision: 0, astext: true } ); + this._renderer = THREE.CreateSVGRenderer(false, 0, document); + if (this._renderer.makeOuterHTML !== undefined) { + // this is indication of new three.js functionality + if (!JSROOT.svg_workaround) JSROOT.svg_workaround = []; + this._renderer.workaround_id = JSROOT.svg_workaround.length; + JSROOT.svg_workaround[this._renderer.workaround_id] = "<svg></svg>"; // dummy, need to be replaced + + this._renderer.domElement = document.createElementNS( 'http://www.w3.org/2000/svg', 'path'); + this._renderer.domElement.setAttribute('jsroot_svg_workaround', this._renderer.workaround_id); + } + } else { + this._renderer = webgl ? + new THREE.WebGLRenderer({ antialias: true, logarithmicDepthBuffer: false, + preserveDrawingBuffer: true }) : + new THREE.CanvasRenderer({ antialias: true }); + this._renderer.setPixelRatio(window.devicePixelRatio); + } + this._renderer.setSize(w, h, !this._fit_main_area); + this._renderer.localClippingEnabled = true; + + */ + + if (this._fit_main_area && !this._usesvg) { + this._renderer.domElement.style.width = "100%"; + this._renderer.domElement.style.height = "100%"; + var main = this.select_main(); + if (main.style('position')=='static') main.style('position','relative'); + } + + this._animating = false; + + // Clipping Planes + + this.clipIntersection = true; + this.bothSides = false; // which material kind should be used + this.enableX = this.enableY = this.enableZ = false; + this.clipX = this.clipY = this.clipZ = 0.0; + + this._clipPlanes = [ new THREE.Plane(new THREE.Vector3( 1, 0, 0), this.clipX), + new THREE.Plane(new THREE.Vector3( 0, this.options._yup ? -1 : 1, 0), this.clipY), + new THREE.Plane(new THREE.Vector3( 0, 0, this.options._yup ? 1 : -1), this.clipZ) ]; + + // Lights + + //var light = new THREE.HemisphereLight( 0xffffff, 0x999999, 0.5 ); + //this._scene.add(light); + + /* + var directionalLight = new THREE.DirectionalLight( 0xffffff, 0.2 ); + directionalLight.position.set( 0, 1, 0 ); + this._scene.add( directionalLight ); + + this._lights = new THREE.Object3D(); + var a = new THREE.PointLight(0xefefef, 0.2); + var b = new THREE.PointLight(0xefefef, 0.2); + var c = new THREE.PointLight(0xefefef, 0.2); + var d = new THREE.PointLight(0xefefef, 0.2); + this._lights.add(a); + this._lights.add(b); + this._lights.add(c); + this._lights.add(d); + this._camera.add( this._lights ); + a.position.set( 20000, 20000, 20000 ); + b.position.set( -20000, 20000, 20000 ); + c.position.set( 20000, -20000, 20000 ); + d.position.set( -20000, -20000, 20000 ); + */ + this._pointLight = new THREE.PointLight(0xefefef, 1); + this._camera.add( this._pointLight ); + this._pointLight.position.set(10, 10, 10); + + // Default Settings + + this._defaultAdvanced = { aoClamp: 0.70, + lumInfluence: 0.4, + // shininess: 100, + clipIntersection: true, + depthTest: true + }; + + // Smooth Lighting Shader (Screen Space Ambient Occlusion) + // http://threejs.org/examples/webgl_postprocessing_ssao.html + + this._enableSSAO = this.options.ssao; + + if (this._webgl) { + var renderPass = new THREE.RenderPass( this._scene, this._camera ); + // Setup depth pass + this._depthMaterial = new THREE.MeshDepthMaterial( { side: THREE.DoubleSide }); + this._depthMaterial.depthPacking = THREE.RGBADepthPacking; + this._depthMaterial.blending = THREE.NoBlending; + var pars = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter }; + this._depthRenderTarget = new THREE.WebGLRenderTarget( w, h, pars ); + // Setup SSAO pass + this._ssaoPass = new THREE.ShaderPass( THREE.SSAOShader ); + this._ssaoPass.renderToScreen = true; + this._ssaoPass.uniforms[ "tDepth" ].value = this._depthRenderTarget.texture; + this._ssaoPass.uniforms[ 'size' ].value.set( w, h ); + this._ssaoPass.uniforms[ 'cameraNear' ].value = this._camera.near; + this._ssaoPass.uniforms[ 'cameraFar' ].value = this._camera.far; + this._ssaoPass.uniforms[ 'onlyAO' ].value = false;//( postprocessing.renderMode == 1 ); + this._ssaoPass.uniforms[ 'aoClamp' ].value = this._defaultAdvanced.aoClamp; + this._ssaoPass.uniforms[ 'lumInfluence' ].value = this._defaultAdvanced.lumInfluence; + // Add pass to effect composer + this._effectComposer = new THREE.EffectComposer( this._renderer ); + this._effectComposer.addPass( renderPass ); + this._effectComposer.addPass( this._ssaoPass ); + } + + this._advceOptions = {}; + this.resetAdvanced(); + + if (this._fit_main_area && (this._usesvg || this._usesvgimg)) { + // create top-most SVG for geomtery drawings + var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); + svg.appendChild(rrr.dom); + return svg; + } + + return rrr.dom; + } + + + TGeoPainter.prototype.startDrawGeometry = function(force) { + + if (!force && (this.drawing_stage!==0)) { + this._draw_nodes_again = true; + return; + } + + this._startm = new Date().getTime(); + this._last_render_tm = this._startm; + this._last_render_meshes = 0; + this.drawing_stage = 1; + this._drawing_ready = false; + this.drawing_log = "collect visible"; + this._num_meshes = 0; + this._num_faces = 0; + this._selected_mesh = null; + + if (this.options.project) { + if (this._clones_owner) { + if (this._full_geom) { + this.drawing_stage = 10; + this.drawing_log = "build projection"; + } else { + this._full_geom = new THREE.Object3D(); + } + + } else { + this.drawing_stage = 9; + this.drawing_log = "wait for main painter"; + } + } + + delete this._last_manifest; + delete this._last_hidden; // clear list of hidden objects + + delete this._draw_nodes_again; // forget about such flag + + this.continueDraw(); + } + + TGeoPainter.prototype.resetAdvanced = function() { + if (this._webgl) { + this._advceOptions.aoClamp = this._defaultAdvanced.aoClamp; + this._advceOptions.lumInfluence = this._defaultAdvanced.lumInfluence; + + this._ssaoPass.uniforms[ 'aoClamp' ].value = this._defaultAdvanced.aoClamp; + this._ssaoPass.uniforms[ 'lumInfluence' ].value = this._defaultAdvanced.lumInfluence; + } + + this._advceOptions.depthTest = this._defaultAdvanced.depthTest; + this._advceOptions.clipIntersection = this._defaultAdvanced.clipIntersection; + this.clipIntersection = this._defaultAdvanced.clipIntersection; + + var painter = this; + this._toplevel.traverse( function (node) { + if (node instanceof THREE.Mesh) { + node.material.depthTest = painter._defaultAdvanced.depthTest; + } + }); + + this.Render3D(0); + } + + /** Assign clipping attributes to the meshes - supported only for webgl + * @private */ + TGeoPainter.prototype.updateClipping = function(without_render) { + if (!this._webgl) return; + + this._clipPlanes[0].constant = this.clipX; + this._clipPlanes[1].constant = -this.clipY; + this._clipPlanes[2].constant = this.options._yup ? -this.clipZ : this.clipZ; + + var panels = []; + if (this.enableX) panels.push(this._clipPlanes[0]); + if (this.enableY) panels.push(this._clipPlanes[1]); + if (this.enableZ) panels.push(this._clipPlanes[2]); + if (panels.length == 0) panels = null; + + var any_clipping = !!panels, ci = this.clipIntersection, + material_side = any_clipping ? THREE.DoubleSide : THREE.FrontSide; + + this._scene.traverse( function (node) { + if (node.hasOwnProperty("material") && node.material && (node.material.clippingPlanes !== undefined)) { + + if (node.material.clippingPlanes !== panels) { + node.material.clipIntersection = ci; + node.material.clippingPlanes = panels; + node.material.needsUpdate = true; + } + + if (node.material.emissive !== undefined) { + if (node.material.side != material_side) { + node.material.side = material_side; + node.material.needsUpdate = true; + } + } + } + }); + + this.bothSides = any_clipping; + + if (!without_render) this.Render3D(0); + } + + TGeoPainter.prototype.getGeomBox = function() { + var extras = this.getExtrasContainer('collect'); + + var box = this.getGeomBoundingBox(this._toplevel); + + if (extras) + for (var k=0;k<extras.length;++k) this._toplevel.add(extras[k]); + + return box; + } + + TGeoPainter.prototype.adjustCameraPosition = function(first_time) { + + if (!this._toplevel) return; + + var box = this.getGeomBoundingBox(this._toplevel); + + // if detect of coordinates fails - ignore + if (isNaN(box.min.x)) return; + + var sizex = box.max.x - box.min.x, + sizey = box.max.y - box.min.y, + sizez = box.max.z - box.min.z, + midx = (box.max.x + box.min.x)/2, + midy = (box.max.y + box.min.y)/2, + midz = (box.max.z + box.min.z)/2; + + this._overall_size = 2 * Math.max(sizex, sizey, sizez); + + this._scene.fog.near = this._overall_size * 2; + this._camera.near = this._overall_size / 350; + this._scene.fog.far = this._overall_size * 12; + this._camera.far = this._overall_size * 12; + + + if (this._webgl) { + this._ssaoPass.uniforms[ 'cameraNear' ].value = this._camera.near;//*this._nFactor; + this._ssaoPass.uniforms[ 'cameraFar' ].value = this._camera.far;///this._nFactor; + } + + if (first_time) { + this.clipX = midx; + this.clipY = midy; + this.clipZ = midz; + } + + if (this.options.ortho_camera) { + this._camera.left = box.min.x; + this._camera.right = box.max.x; + this._camera.top = box.max.y; + this._camera.bottom = box.min.y; + } + + // this._camera.far = 100000000000; + + this._camera.updateProjectionMatrix(); + + var k = 2*this.options.zoom; + + if (this.options.ortho_camera) { + this._camera.position.set(midx, midy, Math.max(sizex,sizey)); + } else if (this.options.project) { + switch (this.options.project) { + case 'x': this._camera.position.set(k*1.5*Math.max(sizey,sizez), 0, 0); break; + case 'y': this._camera.position.set(0, k*1.5*Math.max(sizex,sizez), 0); break; + case 'z': this._camera.position.set(0, 0, k*1.5*Math.max(sizex,sizey)); break; + } + } else if (this.options._yup) { + this._camera.position.set(midx-k*Math.max(sizex,sizez), midy+k*sizey, midz-k*Math.max(sizex,sizez)); + } else { + this._camera.position.set(midx-k*Math.max(sizex,sizey), midy-k*Math.max(sizex,sizey), midz+k*sizez); + } + + this._lookat = new THREE.Vector3(midx, midy, midz); + this._camera.lookAt(this._lookat); + + this._pointLight.position.set(sizex/5, sizey/5, sizez/5); + + if (this._controls) { + this._controls.target.copy(this._lookat); + this._controls.update(); + } + + // recheck which elements to draw + if (this.options.select_in_view) + this.startDrawGeometry(); + } + + TGeoPainter.prototype.focusOnItem = function(itemname) { + + if (!itemname || !this._clones) return; + + var stack = this._clones.FindStackByName(itemname); + + if (!stack) return; + + var info = this._clones.ResolveStack(stack, true); + + this.focusCamera( info, false ); + } + + TGeoPainter.prototype.focusCamera = function( focus, clip ) { + + if (this.options.project) return this.adjustCameraPosition(); + + var autoClip = clip === undefined ? false : clip; + + var box = new THREE.Box3(); + if (focus === undefined) { + box = this.getGeomBoundingBox(this._toplevel); + } else if (focus instanceof THREE.Mesh) { + box.setFromObject(focus); + } else { + var center = new THREE.Vector3().setFromMatrixPosition(focus.matrix), + node = focus.node, + halfDelta = new THREE.Vector3( node.fDX, node.fDY, node.fDZ ).multiplyScalar(0.5); + box.min = center.clone().sub(halfDelta); + box.max = center.clone().add(halfDelta); + } + + var sizex = box.max.x - box.min.x, + sizey = box.max.y - box.min.y, + sizez = box.max.z - box.min.z, + midx = (box.max.x + box.min.x)/2, + midy = (box.max.y + box.min.y)/2, + midz = (box.max.z + box.min.z)/2; + + var position; + if (this.options._yup) + position = new THREE.Vector3(midx-2*Math.max(sizex,sizez), midy+2*sizey, midz-2*Math.max(sizex,sizez)); + else + position = new THREE.Vector3(midx-2*Math.max(sizex,sizey), midy-2*Math.max(sizex,sizey), midz+2*sizez); + + var target = new THREE.Vector3(midx, midy, midz); + //console.log("Zooming to x: " + target.x + " y: " + target.y + " z: " + target.z ); + + + // Find to points to animate "lookAt" between + var dist = this._camera.position.distanceTo(target); + var oldTarget = this._controls.target; + + // probably, reduce number of frames + var frames = 50, step = 0; + + // Amount to change camera position at each step + var posIncrement = position.sub(this._camera.position).divideScalar(frames); + // Amount to change "lookAt" so it will end pointed at target + var targetIncrement = target.sub(oldTarget).divideScalar(frames); + // console.log( targetIncrement ); + + // Automatic Clipping + + if (autoClip) { + + var topBox = this.getGeomBoundingBox(this._toplevel); + + this.clipX = this.enableX ? this.clipX : topBox.min.x; + this.clipY = this.enableY ? this.clipY : topBox.min.y; + this.clipZ = this.enableZ ? this.clipZ : topBox.min.z; + + this.enableX = this.enableY = this.enableZ = true; + + // These should be center of volume, box may not be doing this correctly + var incrementX = ((box.max.x + box.min.x) / 2 - this.clipX) / frames, + incrementY = ((box.max.y + box.min.y) / 2 - this.clipY) / frames, + incrementZ = ((box.max.z + box.min.z) / 2 - this.clipZ) / frames; + + this.updateClipping(); + } + + var painter = this; + this._animating = true; + + // Interpolate // + + function animate() { + if (painter._animating === undefined) return; + + if (painter._animating) { + requestAnimationFrame( animate ); + } else { + if (!painter._geom_viewer) + painter.startDrawGeometry(); + } + var smoothFactor = -Math.cos( ( 2.0 * Math.PI * step ) / frames ) + 1.0; + painter._camera.position.add( posIncrement.clone().multiplyScalar( smoothFactor ) ); + oldTarget.add( targetIncrement.clone().multiplyScalar( smoothFactor ) ); + painter._lookat = oldTarget; + painter._camera.lookAt( painter._lookat ); + painter._camera.updateProjectionMatrix(); + + var tm1 = new Date().getTime(); + if (autoClip) { + painter.clipX += incrementX * smoothFactor; + painter.clipY += incrementY * smoothFactor; + painter.clipZ += incrementZ * smoothFactor; + painter.updateClipping(); + } else { + painter.Render3D(0); + } + var tm2 = new Date().getTime(); + if ((step==0) && (tm2-tm1 > 200)) frames = 20; + step++; + painter._animating = step < frames; + } + + animate(); + + // this._controls.update(); + } + + TGeoPainter.prototype.autorotate = function(speed) { + + var rotSpeed = (speed === undefined) ? 2.0 : speed, + painter = this, last = new Date(); + + function animate() { + if (!painter._renderer || !painter.options) return; + + var current = new Date(); + + if ( painter.options.autoRotate ) requestAnimationFrame( animate ); + + if (painter._controls) { + painter._controls.autoRotate = painter.options.autoRotate; + painter._controls.autoRotateSpeed = rotSpeed * ( current.getTime() - last.getTime() ) / 16.6666; + painter._controls.update(); + } + last = new Date(); + painter.Render3D(0); + } + + if (this._webgl) animate(); + } + + TGeoPainter.prototype.completeScene = function() { + + if ( this.options._debug || this.options._grid ) { + if ( this.options._full ) { + var boxHelper = new THREE.BoxHelper(this._toplevel); + this._scene.add( boxHelper ); + } + this._scene.add( new THREE.AxesHelper( 2 * this._overall_size ) ); + this._scene.add( new THREE.GridHelper( Math.ceil( this._overall_size), Math.ceil( this._overall_size ) / 50 ) ); + this.helpText("<font face='verdana' size='1' color='red'><center>Transform Controls<br>" + + "'T' translate | 'R' rotate | 'S' scale<br>" + + "'+' increase size | '-' decrease size<br>" + + "'W' toggle wireframe/solid display<br>"+ + "keep 'Ctrl' down to snap to grid</center></font>"); + } + } + + + TGeoPainter.prototype.drawCount = function(unqievis, clonetm) { + + var res = 'Unique nodes: ' + this._clones.nodes.length + '<br/>' + + 'Unique visible: ' + unqievis + '<br/>' + + 'Time to clone: ' + clonetm + 'ms <br/>'; + + // need to fill cached value line numvischld + this._clones.ScanVisible(); + + var painter = this, nshapes = 0; + + var arg = { + cnt: [], + func: function(node) { + if (this.cnt[this.last]===undefined) + this.cnt[this.last] = 1; + else + this.cnt[this.last]++; + + nshapes += JSROOT.GEO.CountNumShapes(painter._clones.GetNodeShape(node.id)); + + return true; + } + }; + + var tm1 = new Date().getTime(); + var numvis = this._clones.ScanVisible(arg); + var tm2 = new Date().getTime(); + + res += 'Total visible nodes: ' + numvis + '<br/>'; + res += 'Total shapes: ' + nshapes + '<br/>'; + + for (var lvl=0;lvl<arg.cnt.length;++lvl) { + if (arg.cnt[lvl] !== undefined) + res += (' lvl' + lvl + ': ' + arg.cnt[lvl] + '<br/>'); + } + + res += "Time to scan: " + (tm2-tm1) + "ms <br/>"; + + res += "<br/><br/>Check timing for matrix calculations ...<br/>"; + + var elem = this.select_main().style('overflow', 'auto').html(res); + + setTimeout(function() { + arg.domatrix = true; + tm1 = new Date().getTime(); + numvis = painter._clones.ScanVisible(arg); + tm2 = new Date().getTime(); + elem.append("p").text("Time to scan with matrix: " + (tm2-tm1) + "ms"); + painter.DrawingReady(); + }, 100); + + return this; + } + + + TGeoPainter.prototype.PerformDrop = function(obj, itemname, hitem, opt, call_back) { + + if (obj && (obj.$kind==='TTree')) { + // drop tree means function call which must extract tracks from provided tree + + var funcname = "extract_geo_tracks"; + + if (opt && opt.indexOf("$")>0) { + funcname = opt.substr(0, opt.indexOf("$")); + opt = opt.substr(opt.indexOf("$")+1); + } + + var func = JSROOT.findFunction(funcname); + + if (!func) return JSROOT.CallBack(call_back); + + var geo_painter = this; + + return func(obj, opt, function(tracks) { + if (tracks) { + geo_painter.drawExtras(tracks, "", false); // FIXME: probably tracks should be remembered?? + this.updateClipping(true); + geo_painter.Render3D(100); + } + JSROOT.CallBack(call_back); // finally callback + }); + } + + if (this.drawExtras(obj, itemname)) { + if (hitem) hitem._painter = this; // set for the browser item back pointer + } + + JSROOT.CallBack(call_back); + } + + TGeoPainter.prototype.MouseOverHierarchy = function(on, itemname, hitem) { + // function called when mouse is going over the item in the browser + + if (!this.options) return; // protection for cleaned-up painter + + var obj = hitem._obj; + if (this.options._debug) + console.log('Mouse over', on, itemname, (obj ? obj._typename : "---")); + + // let's highlight tracks and hits only for the time being + if (!obj || (obj._typename !== "TEveTrack" && obj._typename !== "TEvePointSet" && obj._typename !== "TPolyMarker3D")) return; + + this.HighlightMesh(null, 0x00ff00, on ? obj : null); + } + + TGeoPainter.prototype.clearExtras = function() { + this.getExtrasContainer("delete"); + delete this._extraObjects; // workaround, later will be normal function + this.Render3D(); + } + + TGeoPainter.prototype.addExtra = function(obj, itemname) { + + // register extra objects like tracks or hits + // Check if object already exists to prevent duplication + + if (this._extraObjects === undefined) + this._extraObjects = JSROOT.Create("TList"); + + if (this._extraObjects.arr.indexOf(obj)>=0) return false; + + this._extraObjects.Add(obj, itemname); + + delete obj.$hidden_via_menu; // remove previous hidden property + + return true; + } + + TGeoPainter.prototype.ExtraObjectVisible = function(hpainter, hitem, toggle) { + if (!this._extraObjects) return; + + var itemname = hpainter.itemFullName(hitem), + indx = this._extraObjects.opt.indexOf(itemname); + + if ((indx<0) && hitem._obj) { + indx = this._extraObjects.arr.indexOf(hitem._obj); + // workaround - if object found, replace its name + if (indx>=0) this._extraObjects.opt[indx] = itemname; + } + + if (indx < 0) return; + + var obj = this._extraObjects.arr[indx], + res = obj.$hidden_via_menu ? false : true; + + if (toggle) { + obj.$hidden_via_menu = res; res = !res; + + var mesh = null; + // either found painted object or just draw once again + this._toplevel.traverse(function(node) { if (node.geo_object === obj) mesh = node; }); + + if (mesh) mesh.visible = res; else + if (res) { + this.drawExtras(obj, "", false); + this.updateClipping(true); + } + + if (mesh || res) this.Render3D(); + } + + return res; + } + + TGeoPainter.prototype.drawExtras = function(obj, itemname, add_objects) { + if (!obj || obj._typename===undefined) return false; + + // if object was hidden via menu, do not redraw it with next draw call + if (!add_objects && obj.$hidden_via_menu) return false; + + var isany = false, do_render = false; + if (add_objects === undefined) { + add_objects = true; + do_render = true; + } + + if ((obj._typename === "TList") || (obj._typename === "TObjArray")) { + if (!obj.arr) return false; + for (var n=0;n<obj.arr.length;++n) { + var sobj = obj.arr[n]; + var sname = (itemname === undefined) ? obj.opt[n] : (itemname + "/[" + n + "]"); + if (this.drawExtras(sobj, sname, add_objects)) isany = true; + } + } else if (obj._typename === 'THREE.Mesh') { + // adding mesh as is + this.getExtrasContainer().add(obj); + isany = true; + } else if (obj._typename === 'TGeoTrack') { + if (add_objects && !this.addExtra(obj, itemname)) return false; + isany = this.drawGeoTrack(obj, itemname); + } else if ((obj._typename === 'TEveTrack') || (obj._typename === 'ROOT::Experimental::TEveTrack')) { + if (add_objects && !this.addExtra(obj, itemname)) return false; + isany = this.drawEveTrack(obj, itemname); + } else if ((obj._typename === 'TEvePointSet') || (obj._typename === "ROOT::Experimental::TEvePointSet") || (obj._typename === "TPolyMarker3D")) { + if (add_objects && !this.addExtra(obj, itemname)) return false; + isany = this.drawHit(obj, itemname); + } else if ((obj._typename === "TEveGeoShapeExtract") || (obj._typename === "ROOT::Experimental::TEveGeoShapeExtract")) { + if (add_objects && !this.addExtra(obj, itemname)) return false; + isany = this.drawExtraShape(obj, itemname); + } + + if (isany && do_render) { + this.updateClipping(true); + this.Render3D(100); + } + + return isany; + } + + TGeoPainter.prototype.getExtrasContainer = function(action, name) { + if (!this._toplevel) return null; + + if (!name) name = "tracks"; + + var extras = null, lst = []; + for (var n=0;n<this._toplevel.children.length;++n) { + var chld = this._toplevel.children[n]; + if (!chld._extras) continue; + if (action==='collect') { lst.push(chld); continue; } + if (chld._extras === name) { extras = chld; break; } + } + + if (action==='collect') { + for (var k=0;k<lst.length;++k) this._toplevel.remove(lst[k]); + return lst; + } + + if (action==="delete") { + if (extras) this._toplevel.remove(extras); + JSROOT.Painter.DisposeThreejsObject(extras); + return null; + } + + if ((action!=="get") && !extras) { + extras = new THREE.Object3D(); + extras._extras = name; + this._toplevel.add(extras); + } + + return extras; + } + + TGeoPainter.prototype.drawGeoTrack = function(track, itemname) { + if (!track || !track.fNpoints) return false; + + var track_width = track.fLineWidth || 1, + track_color = JSROOT.Painter.root_colors[track.fLineColor] || "rgb(255,0,255)"; + + if (JSROOT.browser.isWin) track_width = 1; // not supported on windows + + var npoints = Math.round(track.fNpoints/4), + buf = new Float32Array((npoints-1)*6), + pos = 0, projv = this.options.projectPos, + projx = (this.options.project === "x"), + projy = (this.options.project === "y"), + projz = (this.options.project === "z"); + + for (var k=0;k<npoints-1;++k) { + buf[pos] = projx ? projv : track.fPoints[k*4]; + buf[pos+1] = projy ? projv : track.fPoints[k*4+1]; + buf[pos+2] = projz ? projv : track.fPoints[k*4+2]; + buf[pos+3] = projx ? projv : track.fPoints[k*4+4]; + buf[pos+4] = projy ? projv : track.fPoints[k*4+5]; + buf[pos+5] = projz ? projv : track.fPoints[k*4+6]; + pos+=6; + } + + var lineMaterial = new THREE.LineBasicMaterial({ color: track_color, linewidth: track_width }), + line = JSROOT.Painter.createLineSegments(buf, lineMaterial); + + line.geo_name = itemname; + line.geo_object = track; + line.hightlightWidthScale = 2; + + this.getExtrasContainer().add(line); + + return true; + } + + TGeoPainter.prototype.drawEveTrack = function(track, itemname) { + if (!track || (track.fN <= 0)) return false; + + var track_width = track.fLineWidth || 1, + track_color = JSROOT.Painter.root_colors[track.fLineColor] || "rgb(255,0,255)"; + + if (JSROOT.browser.isWin) track_width = 1; // not supported on windows + + var buf = new Float32Array((track.fN-1)*6), pos = 0, + projv = this.options.projectPos, + projx = (this.options.project === "x"), + projy = (this.options.project === "y"), + projz = (this.options.project === "z"); + + for (var k=0;k<track.fN-1;++k) { + buf[pos] = projx ? projv : track.fP[k*3]; + buf[pos+1] = projy ? projv : track.fP[k*3+1]; + buf[pos+2] = projz ? projv : track.fP[k*3+2]; + buf[pos+3] = projx ? projv : track.fP[k*3+3]; + buf[pos+4] = projy ? projv : track.fP[k*3+4]; + buf[pos+5] = projz ? projv : track.fP[k*3+5]; + pos+=6; + } + + var lineMaterial = new THREE.LineBasicMaterial({ color: track_color, linewidth: track_width }), + line = JSROOT.Painter.createLineSegments(buf, lineMaterial); + + line.geo_name = itemname; + line.geo_object = track; + line.hightlightWidthScale = 2; + + this.getExtrasContainer().add(line); + + return true; + } + + TGeoPainter.prototype.drawHit = function(hit, itemname) { + if (!hit || !hit.fN || (hit.fN < 0)) return false; + + var hit_size = 8*hit.fMarkerSize, + size = hit.fN, + projv = this.options.projectPos, + projx = (this.options.project === "x"), + projy = (this.options.project === "y"), + projz = (this.options.project === "z"), + pnts = new JSROOT.Painter.PointsCreator(size, this._webgl, hit_size); + + for (var i=0;i<size;i++) + pnts.AddPoint(projx ? projv : hit.fP[i*3], + projy ? projv : hit.fP[i*3+1], + projz ? projv : hit.fP[i*3+2]); + + var mesh = pnts.CreatePoints(JSROOT.Painter.root_colors[hit.fMarkerColor] || "rgb(0,0,255)"); + + mesh.highlightScale = 2; + + mesh.geo_name = itemname; + mesh.geo_object = hit; + + this.getExtrasContainer().add(mesh); + + return true; + } + + TGeoPainter.prototype.drawExtraShape = function(obj, itemname) { + var toplevel = JSROOT.GEO.build(obj); + if (!toplevel) return false; + + toplevel.geo_name = itemname; + toplevel.geo_object = obj; + + this.getExtrasContainer().add(toplevel); + return true; + } + + TGeoPainter.prototype.FindNodeWithVolume = function(name, action, prnt, itemname, volumes) { + + var first_level = false, res = null; + + if (!prnt) { + prnt = this.GetGeometry(); + if (!prnt && (JSROOT.GEO.NodeKind(prnt)!==0)) return null; + itemname = this.geo_manager ? prnt.fName : ""; + first_level = true; + volumes = []; + } else { + if (itemname.length>0) itemname += "/"; + itemname += prnt.fName; + } + + if (!prnt.fVolume || prnt.fVolume._searched) return null; + + if (name.test(prnt.fVolume.fName)) { + res = action({ node: prnt, item: itemname }); + if (res) return res; + } + + prnt.fVolume._searched = true; + volumes.push(prnt.fVolume); + + if (prnt.fVolume.fNodes) + for (var n=0;n<prnt.fVolume.fNodes.arr.length;++n) { + res = this.FindNodeWithVolume(name, action, prnt.fVolume.fNodes.arr[n], itemname, volumes); + if (res) break; + } + + if (first_level) + for (var n=0, len=volumes.length; n<len; ++n) + delete volumes[n]._searched; + + return res; + } + + TGeoPainter.prototype.SetRootDefaultColors = function() { + // set default colors like TGeoManager::DefaultColors() does + + var dflt = { kWhite:0, kBlack:1, kGray:920, + kRed:632, kGreen:416, kBlue:600, kYellow:400, kMagenta:616, kCyan:432, + kOrange:800, kSpring:820, kTeal:840, kAzure:860, kViolet:880, kPink:900 }; + + var nmax = 110, col = []; + for (var i=0;i<nmax;i++) col.push(dflt.kGray); + + //here we should create a new TColor with the same rgb as in the default + //ROOT colors used below + col[ 3] = dflt.kYellow-10; + col[ 4] = col[ 5] = dflt.kGreen-10; + col[ 6] = col[ 7] = dflt.kBlue-7; + col[ 8] = col[ 9] = dflt.kMagenta-3; + col[10] = col[11] = dflt.kRed-10; + col[12] = dflt.kGray+1; + col[13] = dflt.kBlue-10; + col[14] = dflt.kOrange+7; + col[16] = dflt.kYellow+1; + col[20] = dflt.kYellow-10; + col[24] = col[25] = col[26] = dflt.kBlue-8; + col[29] = dflt.kOrange+9; + col[79] = dflt.kOrange-2; + + var name = { test:function() { return true; }} // select all volumes + + this.FindNodeWithVolume(name, function(arg) { + var vol = arg.node.fVolume; + var med = vol.fMedium; + if (!med) return null; + var mat = med.fMaterial; + var matZ = Math.round(mat.fZ); + vol.fLineColor = col[matZ]; + if (mat.fDensity<0.1) mat.fFillStyle = 3000+60; // vol.SetTransparency(60) + }); + } + + + TGeoPainter.prototype.checkScript = function(script_name, call_back) { + + var painter = this, draw_obj = this.GetGeometry(), name_prefix = ""; + + if (this.geo_manager) name_prefix = draw_obj.fName; + + if (!script_name || (script_name.length<3) || (JSROOT.GEO.NodeKind(draw_obj)!==0)) + return JSROOT.CallBack(call_back, draw_obj, name_prefix); + + var mgr = { + GetVolume: function (name) { + var regexp = new RegExp("^"+name+"$"); + var currnode = painter.FindNodeWithVolume(regexp, function(arg) { return arg; } ); + + if (!currnode) console.log('Did not found '+name + ' volume'); + + // return proxy object with several methods, typically used in ROOT geom scripts + return { + found: currnode, + fVolume: currnode ? currnode.node.fVolume : null, + InvisibleAll: function(flag) { + JSROOT.GEO.InvisibleAll.call(this.fVolume, flag); + }, + Draw: function() { + if (!this.found || !this.fVolume) return; + draw_obj = this.found.node; + name_prefix = this.found.item; + console.log('Select volume for drawing', this.fVolume.fName, name_prefix); + }, + SetTransparency: function(lvl) { + if (this.fVolume && this.fVolume.fMedium && this.fVolume.fMedium.fMaterial) + this.fVolume.fMedium.fMaterial.fFillStyle = 3000+lvl; + }, + SetLineColor: function(col) { + if (this.fVolume) this.fVolume.fLineColor = col; + } + }; + }, + + DefaultColors: function() { + painter.SetRootDefaultColors(); + }, + + SetMaxVisNodes: function(limit) { + console.log('Automatic visible depth for ' + limit + ' nodes'); + if (limit>0) painter.options.maxnodeslimit = limit; + } + }; + + JSROOT.progress('Loading macro ' + script_name); + + JSROOT.NewHttpRequest(script_name, "text", function(res) { + if (!res || (res.length==0)) + return JSROOT.CallBack(call_back, draw_obj, name_prefix); + + var lines = res.split('\n'); + + ProcessNextLine(0); + + function ProcessNextLine(indx) { + + var first_tm = new Date().getTime(); + while (indx < lines.length) { + var line = lines[indx++].trim(); + + if (line.indexOf('//')==0) continue; + + if (line.indexOf('gGeoManager')<0) continue; + line = line.replace('->GetVolume','.GetVolume'); + line = line.replace('->InvisibleAll','.InvisibleAll'); + line = line.replace('->SetMaxVisNodes','.SetMaxVisNodes'); + line = line.replace('->DefaultColors','.DefaultColors'); + line = line.replace('->Draw','.Draw'); + line = line.replace('->SetTransparency','.SetTransparency'); + line = line.replace('->SetLineColor','.SetLineColor'); + if (line.indexOf('->')>=0) continue; + + // console.log(line); + + try { + var func = new Function('gGeoManager',line); + func(mgr); + } catch(err) { + console.error('Problem by processing ' + line); + } + + var now = new Date().getTime(); + if (now - first_tm > 300) { + JSROOT.progress('exec ' + line); + return setTimeout(ProcessNextLine.bind(this,indx),1); + } + } + + JSROOT.CallBack(call_back, draw_obj, name_prefix); + } + + }).send(); + } + + /** Assign clones, created outside. + * Used by geometry painter, where clones are handled by the server */ + TGeoPainter.prototype.assignClones = function(clones) { + this._clones_owner = true; + this._clones = clones; + } + + TGeoPainter.prototype.prepareObjectDraw = function(draw_obj, name_prefix) { + + if (name_prefix == "__geom_viewer_append__") { + this._new_append_nodes = draw_obj; + this.options.use_worker = 0; + this._geom_viewer = true; // indicate that working with geom viewer + } else if ((name_prefix == "__geom_viewer_selection__") && this._clones) { + // these are selection done from geom viewer + this._new_draw_nodes = draw_obj; + this.options.use_worker = 0; + this._geom_viewer = true; // indicate that working with geom viewer + } else if (this._main_painter) { + + this._clones_owner = false; + + this._clones = this._main_painter._clones; + + console.log('Reuse clones', this._clones.nodes.length, 'from main painter'); + + } else if (!draw_obj) { + + this._clones_owner = false; + + this._clones = null; + + } else { + + this._start_drawing_time = new Date().getTime(); + + this._clones_owner = true; + + this._clones = new JSROOT.GEO.ClonedNodes(draw_obj); + + this._clones.name_prefix = name_prefix; + + var uniquevis = this._clones.MarkVisisble(true); + if (uniquevis <= 0) + uniquevis = this._clones.MarkVisisble(false); + else + uniquevis = this._clones.MarkVisisble(true, true); // copy bits once and use normal visibility bits + + var spent = new Date().getTime() - this._start_drawing_time; + + console.log('Creating clones', this._clones.nodes.length, 'takes', spent, 'uniquevis', uniquevis); + + if (this.options._count) + return this.drawCount(uniquevis, spent); + } + + if (!this._scene) { + + // this is limit for the visible faces, number of volumes does not matter + this.options.maxlimit = (this._webgl ? 200000 : 100000) * this.options.more; + + this._first_drawing = true; + + // activate worker + if (this.options.use_worker > 0) this.startWorker(); + + var size = this.size_for_3d(this._usesvg ? 3 : undefined); + + this._fit_main_area = (size.can3d === -1); + + var dom = this.createScene(size.width, size.height); + + this.add_3d_canvas(size, dom); + + // set top painter only when first child exists + this.AccessTopPainter(true); + } + + this.CreateToolbar(); + + if (this._clones) { + this.showDrawInfo("Drawing geometry"); + this.startDrawGeometry(true); + } else { + this.completeDraw(); + } + } + + TGeoPainter.prototype.showDrawInfo = function(msg) { + // methods show info when first geometry drawing is performed + + if (!this._first_drawing || !this._start_drawing_time) return; + + var main = this._renderer.domElement.parentNode, + info = d3.select(main).select(".geo_info"); + + if (!msg) { + info.remove(); + } else { + var spent = (new Date().getTime() - this._start_drawing_time)*1e-3; + if (info.empty()) info = d3.select(main).append("p").attr("class","geo_info"); + info.html(msg + ", " + spent.toFixed(1) + "s"); + } + + } + + TGeoPainter.prototype.continueDraw = function() { + + // nothing to do - exit + if (this.drawing_stage === 0) return; + + var tm0 = new Date().getTime(), + interval = this._first_drawing ? 1000 : 200, + now = tm0; + + while(true) { + + var res = this.nextDrawAction(); + + if (!res) break; + + now = new Date().getTime(); + + // stop creation after 100 sec, render as is + if (now - this._startm > 1e5) { + this.drawing_stage = 0; + break; + } + + // if we are that fast, do next action + if ((res === true) && (now - tm0 < interval)) continue; + + if ((now - tm0 > interval) || (res === 1) || (res === 2)) { + + JSROOT.progress(this.drawing_log); + + this.showDrawInfo(this.drawing_log); + + if (this._first_drawing && this._webgl && (this._num_meshes - this._last_render_meshes > 100) && (now - this._last_render_tm > 2.5*interval)) { + this.adjustCameraPosition(); + this.Render3D(-1); + this._last_render_tm = new Date().getTime(); + this._last_render_meshes = this._num_meshes; + } + if (res !== 2) setTimeout(this.continueDraw.bind(this), (res === 1) ? 100 : 1); + + return; + } + } + + var take_time = now - this._startm; + + if (this._first_drawing) + JSROOT.console('Create tm = ' + take_time + ' meshes ' + this._num_meshes + ' faces ' + this._num_faces); + + if (take_time > 300) { + JSROOT.progress('Rendering geometry'); + this.showDrawInfo("Rendering"); + return setTimeout(this.completeDraw.bind(this, true), 10); + } + + this.completeDraw(true); + } + + TGeoPainter.prototype.TestCameraPosition = function() { + + this._camera.updateMatrixWorld(); + var origin = this._camera.position.clone(); + + if (this._last_camera_position) { + // if camera position does not changed a lot, ignore such change + var dist = this._last_camera_position.distanceTo(origin); + if (dist < (this._overall_size || 1000)/1e4) return; + } + + this._last_camera_position = origin; // remember current camera position + + if (this._webgl) + JSROOT.GEO.produceRenderOrder(this._toplevel, origin, this.options.depthMethod, this._clones); + } + + TGeoPainter.prototype.Render3D = function(tmout, measure) { + // call 3D rendering of the geometry drawing + // tmout specifies delay, after which actual rendering will be invoked + // Timeout used to avoid multiple rendering of the picture when several 3D drawings + // superimposed with each other. + // If tmeout<=0, rendering performed immediately + // Several special values are used: + // -2222 - rendering performed only if there were previous calls, which causes timeout activation + + if (!this._renderer) { + console.warn('renderer object not exists - check code'); + return; + } + + if (tmout === undefined) tmout = 5; // by default, rendering happens with timeout + + if ((tmout <= 0) || this._usesvg) { + if ('render_tmout' in this) { + clearTimeout(this.render_tmout); + } else { + if (tmout === -2222) return; // special case to check if rendering timeout was active + } + + var tm1 = new Date(); + + if (typeof this.TestAxisVisibility === 'function') + this.TestAxisVisibility(this._camera, this._toplevel); + + this.TestCameraPosition(); + + // do rendering, most consuming time + if (this._webgl && this._enableSSAO) { + this._scene.overrideMaterial = this._depthMaterial; + // this._renderer.logarithmicDepthBuffer = false; + this._renderer.render(this._scene, this._camera, this._depthRenderTarget, true); + this._scene.overrideMaterial = null; + this._effectComposer.render(); + } else { + // this._renderer.logarithmicDepthBuffer = true; + this._renderer.render(this._scene, this._camera); + } + + var tm2 = new Date(); + + this.last_render_tm = tm2.getTime() - tm1.getTime(); + + delete this.render_tmout; + + if ((this.first_render_tm === 0) && measure) { + this.first_render_tm = this.last_render_tm; + JSROOT.console('First render tm = ' + this.first_render_tm); + } + + JSROOT.Painter.AfterRender3D(this._renderer); + + return; + } + + // do not shoot timeout many times + if (!this.render_tmout) + this.render_tmout = setTimeout(this.Render3D.bind(this,0,measure), tmout); + } + + + TGeoPainter.prototype.startWorker = function() { + + if (this._worker) return; + + this._worker_ready = false; + this._worker_jobs = 0; // counter how many requests send to worker + + var pthis = this; + + this._worker = new Worker(JSROOT.source_dir + "scripts/JSRootGeoWorker.js"); + + this._worker.onmessage = function(e) { + + if (typeof e.data !== 'object') return; + + if ('log' in e.data) + return JSROOT.console('geo: ' + e.data.log); + + if ('progress' in e.data) + return JSROOT.progress(e.data.progress); + + e.data.tm3 = new Date().getTime(); + + if ('init' in e.data) { + pthis._worker_ready = true; + return JSROOT.console('Worker ready: ' + (e.data.tm3 - e.data.tm0)); + } + + pthis.processWorkerReply(e.data); + }; + + // send initialization message with clones + this._worker.postMessage( { init: true, browser: JSROOT.browser, tm0: new Date().getTime(), clones: this._clones.nodes, sortmap: this._clones.sortmap } ); + } + + TGeoPainter.prototype.canSubmitToWorker = function(force) { + if (!this._worker) return false; + + return this._worker_ready && ((this._worker_jobs == 0) || force); + } + + TGeoPainter.prototype.submitToWorker = function(job) { + if (!this._worker) return false; + + this._worker_jobs++; + + job.tm0 = new Date().getTime(); + + this._worker.postMessage(job); + } + + TGeoPainter.prototype.processWorkerReply = function(job) { + this._worker_jobs--; + + if ('collect' in job) { + this._new_draw_nodes = job.new_nodes; + this._draw_all_nodes = job.complete; + this.drawing_stage = 3; + // invoke methods immediately + return this.continueDraw(); + } + + if ('shapes' in job) { + + for (var n=0;n<job.shapes.length;++n) { + var item = job.shapes[n], + origin = this._build_shapes[n]; + + // var shape = this._clones.GetNodeShape(item.nodeid); + + if (item.buf_pos && item.buf_norm) { + if (item.buf_pos.length === 0) { + origin.geom = null; + } else if (item.buf_pos.length !== item.buf_norm.length) { + console.error('item.buf_pos',item.buf_pos.length, 'item.buf_norm', item.buf_norm.length); + origin.geom = null; + } else { + origin.geom = new THREE.BufferGeometry(); + + origin.geom.addAttribute( 'position', new THREE.BufferAttribute( item.buf_pos, 3 ) ); + origin.geom.addAttribute( 'normal', new THREE.BufferAttribute( item.buf_norm, 3 ) ); + } + + origin.ready = true; + origin.nfaces = item.nfaces; + } + } + + job.tm4 = new Date().getTime(); + + // console.log('Get reply from worker', job.tm3-job.tm2, ' decode json in ', job.tm4-job.tm3); + + this.drawing_stage = 7; // first check which shapes are used, than build meshes + + // invoke methods immediately + return this.continueDraw(); + } + } + + TGeoPainter.prototype.testGeomChanges = function() { + if (this._main_painter) { + console.warn('Get testGeomChanges call for slave painter'); + return this._main_painter.testGeomChanges(); + } + this.startDrawGeometry(); + for (var k=0;k<this._slave_painters.length;++k) + this._slave_painters[k].startDrawGeometry(); + } + + TGeoPainter.prototype.drawSimpleAxis = function() { + + var box = this.getGeomBoundingBox(this._toplevel); + + this.getExtrasContainer('delete', 'axis'); + var container = this.getExtrasContainer('create', 'axis'); + + var text_size = 0.02 * Math.max( (box.max.x - box.min.x), (box.max.y - box.min.y), (box.max.z - box.min.z)), + center = [0,0,0], + names = ['x','y','z'], + labels = ['X','Y','Z'], + colors = ["red","green","blue"], + ortho = this.options.ortho_camera, + yup = [this.options._yup, this.options._yup, this.options._yup], + numaxis = 3; + + if (this.options._axis_center) + for (var naxis=0;naxis<3;++naxis) { + var name = names[naxis]; + if ((box.min[name]<=0) && (box.max[name]>=0)) continue; + center[naxis] = (box.min[name] + box.max[name])/2; + } + + // only two dimensions are seen by ortho camera, X draws Z, can be configured better later + if (this.options.ortho_camera) { + numaxis = 2; + labels[0] = labels[2]; + colors[0] = colors[2]; + yup[0] = yup[2]; + ortho = true; + } + + for (var naxis=0;naxis<numaxis;++naxis) { + + var buf = new Float32Array(6), axiscol = colors[naxis], name = names[naxis]; + + function Convert(value) { + var range = box.max[name] - box.min[name]; + if (range<2) return value.toFixed(3); + if (Math.abs(value)>1e5) return value.toExponential(3); + return Math.round(value).toString(); + } + + var lbl = Convert(box.max[name]); + + buf[0] = box.min.x; + buf[1] = box.min.y; + buf[2] = box.min.z; + + buf[3] = box.min.x; + buf[4] = box.min.y; + buf[5] = box.min.z; + + switch (naxis) { + case 0: buf[3] = box.max.x; if (yup[0] && !ortho) lbl = labels[0] + " " + lbl; else lbl += " " + labels[0]; break; + case 1: buf[4] = box.max.y; if (yup[1]) lbl += " " + labels[1]; else lbl = labels[1] + " " + lbl; break; + case 2: buf[5] = box.max.z; lbl += " " + labels[2]; break; + } + + if (this.options._axis_center) + for (var k=0;k<6;++k) + if ((k % 3) !== naxis) buf[k] = center[k%3]; + + var lineMaterial = new THREE.LineBasicMaterial({ color: axiscol }), + mesh = JSROOT.Painter.createLineSegments(buf, lineMaterial); + + container.add(mesh); + + var textMaterial = new THREE.MeshBasicMaterial({ color: axiscol }); + + if ((center[naxis]===0) && (center[naxis]>=box.min[name]) && (center[naxis]<=box.max[name])) + if (!this.options._axis_center || (naxis===0)) { + var geom = ortho ? new THREE.CircleBufferGeometry(text_size*0.25) : + new THREE.SphereBufferGeometry(text_size*0.25); + mesh = new THREE.Mesh(geom, textMaterial); + mesh.translateX((naxis===0) ? center[0] : buf[0]); + mesh.translateY((naxis===1) ? center[1] : buf[1]); + mesh.translateZ((naxis===2) ? center[2] : buf[2]); + container.add(mesh); + } + + var text3d = new THREE.TextGeometry(lbl, { font: JSROOT.threejs_font_helvetiker_regular, size: text_size, height: 0, curveSegments: 5 }); + mesh = new THREE.Mesh(text3d, textMaterial); + var textbox = new THREE.Box3().setFromObject(mesh); + + mesh.translateX(buf[3]); + mesh.translateY(buf[4]); + mesh.translateZ(buf[5]); + + if (yup[naxis]) { + switch (naxis) { + case 0: + if (!ortho) { + mesh.rotateY(Math.PI); + mesh.translateX(-textbox.max.x-text_size*0.5); + } else { + mesh.translateX(text_size*0.5); + } + mesh.translateY(-textbox.max.y/2); + break; + case 1: + if (!ortho) { + mesh.rotateX(-Math.PI/2); + mesh.rotateY(-Math.PI/2); + } else { + mesh.rotateZ(Math.PI/2); + } + mesh.translateX(text_size*0.5); + mesh.translateY(-textbox.max.y/2); + break; + case 2: mesh.rotateY(-Math.PI/2); mesh.translateX(text_size*0.5); mesh.translateY(-textbox.max.y/2); break; + } + } else { + switch (naxis) { + case 0: mesh.rotateX(Math.PI/2); mesh.translateY(-textbox.max.y/2); mesh.translateX(text_size*0.5); break; + case 1: mesh.rotateX(Math.PI/2); mesh.rotateY(-Math.PI/2); mesh.translateX(-textbox.max.x-text_size*0.5); mesh.translateY(-textbox.max.y/2); break; + case 2: mesh.rotateX(Math.PI/2); mesh.rotateZ(Math.PI/2); mesh.translateX(text_size*0.5); mesh.translateY(-textbox.max.y/2); break; + } + } + + container.add(mesh); + + text3d = new THREE.TextGeometry(Convert(box.min[name]), { font: JSROOT.threejs_font_helvetiker_regular, size: text_size, height: 0, curveSegments: 5 }); + + mesh = new THREE.Mesh(text3d, textMaterial); + textbox = new THREE.Box3().setFromObject(mesh); + + mesh.translateX(buf[0]); + mesh.translateY(buf[1]); + mesh.translateZ(buf[2]); + + if (yup[naxis]) { + switch (naxis) { + case 0: + if (!ortho) { + mesh.rotateY(Math.PI); + mesh.translateX(text_size*0.5); + } else { + mesh.translateX(-textbox.max.x-text_size*0.5); + } + mesh.translateY(-textbox.max.y/2); + break; + case 1: + if (!ortho) { + mesh.rotateX(-Math.PI/2); + mesh.rotateY(-Math.PI/2); + } else { + mesh.rotateZ(Math.PI/2); + } + mesh.translateY(-textbox.max.y/2); + mesh.translateX(-textbox.max.x-text_size*0.5); + break; + case 2: mesh.rotateY(-Math.PI/2); mesh.translateX(-textbox.max.x-text_size*0.5); mesh.translateY(-textbox.max.y/2); break; + } + } else { + switch (naxis) { + case 0: mesh.rotateX(Math.PI/2); mesh.translateX(-textbox.max.x-text_size*0.5); mesh.translateY(-textbox.max.y/2); break; + case 1: mesh.rotateX(Math.PI/2); mesh.rotateY(-Math.PI/2); mesh.translateY(-textbox.max.y/2); mesh.translateX(text_size*0.5); break; + case 2: mesh.rotateX(Math.PI/2); mesh.rotateZ(Math.PI/2); mesh.translateX(-textbox.max.x-text_size*0.5); mesh.translateY(-textbox.max.y/2); break; + } + } + + container.add(mesh); + } + + this.TestAxisVisibility = function(camera, toplevel) { + if (!camera) { + this.getExtrasContainer('delete', 'axis'); + delete this.TestAxisVisibility; + this.Render3D(); + return; + } + } + } + + TGeoPainter.prototype.toggleAxisDraw = function(force_draw) { + if (this.TestAxisVisibility) { + if (!force_draw) + this.TestAxisVisibility(null, this._toplevel); + } else { + this.drawSimpleAxis(); + } + } + + TGeoPainter.prototype.completeDraw = function(close_progress) { + + var first_time = false, check_extras = true; + + if (!this.options) { + console.warn('options object does not exist in completeDraw - something went wrong'); + return; + } + + if (!this._clones) { + check_extras = false; + // if extra object where append, redraw them at the end + this.getExtrasContainer("delete"); // delete old container + var extras = (this._main_painter ? this._main_painter._extraObjects : null) || this._extraObjects; + this.drawExtras(extras, "", false); + } + + if (this._first_drawing) { + this.adjustCameraPosition(true); + this.showDrawInfo(); + this._first_drawing = false; + first_time = true; + + if (this._webgl) { + this.enableX = this.options.clipx; + this.enableY = this.options.clipy; + this.enableZ = this.options.clipz; + } + if (this.options.tracks && this.geo_manager && this.geo_manager.fTracks) + this.addExtra(this.geo_manager.fTracks, "<prnt>/Tracks"); + } + + if (this.options.transparency!==0) + this.changeGlobalTransparency(this.options.transparency, true); + + if (first_time) { + this.completeScene(); + if (this.options._axis) this.toggleAxisDraw(true); + } + + this._scene.overrideMaterial = null; + + if (this._provided_more_nodes !== undefined) { + this.appendMoreNodes(this._provided_more_nodes, true); + delete this._provided_more_nodes; + } + + if (check_extras) { + // if extra object where append, redraw them at the end + this.getExtrasContainer("delete"); // delete old container + var extras = (this._main_painter ? this._main_painter._extraObjects : null) || this._extraObjects; + this.drawExtras(extras, "", false); + } + + this.updateClipping(true); // do not render + + this.Render3D(0, true); + + if (close_progress) JSROOT.progress(); + + this.addOrbitControls(); + + this.addTransformControl(); + + if (first_time) { + + // after first draw check if highlight can be enabled + if (this.options.highlight === false) + this.options.highlight = (this.first_render_tm < 1000); + + // also highlight of scene object can be assigned at the first draw + if (this.options.highlight_scene === false) + this.options.highlight_scene = this.options.highlight; + + // if rotation was enabled, do it + if (this._webgl && this.options.autoRotate && !this.options.project) this.autorotate(2.5); + if (!this._usesvg && this.options.show_controls && !JSROOT.BatchMode) this.showControlOptions(true); + } + + this.DrawingReady(); + + if (this._draw_nodes_again) + return this.startDrawGeometry(); // relaunch drawing + + this._drawing_ready = true; // indicate that drawing is completed + } + + /** Remove already drawn node. Used by geom viewer */ + TGeoPainter.prototype.RemoveDrawnNode = function(nodeid) { + if (!this._draw_nodes) return; + + var new_nodes = []; + + for (var n = 0; n < this._draw_nodes.length; ++n) { + var entry = this._draw_nodes[n]; + if ((entry.nodeid === nodeid) || (this._clones.IsNodeInStack(nodeid, entry.stack))) { + this._clones.CreateObject3D(entry.stack, this._toplevel, 'delete_mesh'); + } else { + new_nodes.push(entry); + } + } + + if (new_nodes.length < this._draw_nodes.length) { + this._draw_nodes = new_nodes; + this.Render3D(); + } + } + + TGeoPainter.prototype.Cleanup = function(first_time) { + + if (!first_time) { + + this.AccessTopPainter(false); // remove as pointer + + this.helpText(); + + JSROOT.Painter.DisposeThreejsObject(this._scene); + + JSROOT.Painter.DisposeThreejsObject(this._full_geom); + + if (this._tcontrols) + this._tcontrols.dispose(); + + if (this._controls) + this._controls.Cleanup(); + + if (this._context_menu) + this._renderer.domElement.removeEventListener( 'contextmenu', this._context_menu, false ); + + if (this._datgui) + this._datgui.destroy(); + + if (this._worker) this._worker.terminate(); + + JSROOT.TObjectPainter.prototype.Cleanup.call(this); + + delete this.options; + + delete this._animating; + + var obj = this.GetGeometry(); + if (obj && this.options.is_main) { + if (obj.$geo_painter===this) delete obj.$geo_painter; else + if (obj.fVolume && obj.fVolume.$geo_painter===this) delete obj.fVolume.$geo_painter; + } + + if (this._main_painter) { + var pos = this._main_painter._slave_painters.indexOf(this); + if (pos>=0) this._main_painter._slave_painters.splice(pos,1); + } + + for (var k=0;k<this._slave_painters.length;++k) { + var slave = this._slave_painters[k]; + if (slave && (slave._main_painter===this)) slave._main_painter = null; + } + } + + for (var k in this._slave_painters) { + var slave = this._slave_painters[k]; + slave._main_painter = null; + if (slave._clones === this._clones) slave._clones = null; + } + + this._main_painter = null; + this._slave_painters = []; + + if (this._renderer) { + if (this._renderer.dispose) this._renderer.dispose(); + if (this._renderer.context) delete this._renderer.context; + } + + delete this._scene; + this._scene_width = 0; + this._scene_height = 0; + this._renderer = null; + this._toplevel = null; + this._full_geom = null; + this._camera = null; + this._selected_mesh = null; + + if (this._clones && this._clones_owner) this._clones.Cleanup(this._draw_nodes, this._build_shapes); + delete this._clones; + delete this._clones_owner; + delete this._draw_nodes; + delete this._drawing_ready; + delete this._build_shapes; + delete this._new_draw_nodes; + delete this._new_append_nodes; + + this.first_render_tm = 0; + this.last_render_tm = 2000; + + this.drawing_stage = 0; + delete this.drawing_log; + + delete this._datgui; + delete this._controls; + delete this._context_menu; + delete this._tcontrols; + delete this._toolbar; + + delete this._worker; + } + + TGeoPainter.prototype.helpText = function(msg) { + JSROOT.progress(msg); + } + + TGeoPainter.prototype.CheckResize = function(arg) { + var pad_painter = this.canv_painter(); + + // firefox is the only browser which correctly supports resize of embedded canvas, + // for others we should force canvas redrawing at every step + if (pad_painter) + if (!pad_painter.CheckCanvasResize(arg)) return false; + + var sz = this.size_for_3d(); + + if ((this._scene_width === sz.width) && (this._scene_height === sz.height)) return false; + if ((sz.width<10) || (sz.height<10)) return false; + + this._scene_width = sz.width; + this._scene_height = sz.height; + + if (this._camera && this._renderer) { + if (this._camera.type == "PerspectiveCamera") + this._camera.aspect = this._scene_width / this._scene_height; + this._camera.updateProjectionMatrix(); + this._renderer.setSize( this._scene_width, this._scene_height, !this._fit_main_area ); + + if (!this.drawing_stage) this.Render3D(); + } + + return true; + } + + TGeoPainter.prototype.ToggleEnlarge = function() { + + if (d3.event) { + d3.event.preventDefault(); + d3.event.stopPropagation(); + } + + if (this.enlarge_main('toggle')) + this.CheckResize(); + } + + + TGeoPainter.prototype.ownedByTransformControls = function(child) { + var obj = child.parent; + while (obj && !(obj instanceof THREE.TransformControls) ) { + obj = obj.parent; + } + return (obj && (obj instanceof THREE.TransformControls)); + } + + TGeoPainter.prototype.accessObjectWireFrame = function(obj, on) { + // either change mesh wireframe or return current value + // return undefined when wireframe cannot be accessed + + if (!obj.hasOwnProperty("material") || (obj instanceof THREE.GridHelper)) return; + + if (this.ownedByTransformControls(obj)) return; + + if ((on !== undefined) && obj.stack) + obj.material.wireframe = on; + + return obj.material.wireframe; + } + + + TGeoPainter.prototype.changeWireFrame = function(obj, on) { + var painter = this; + + obj.traverse(function(obj2) { painter.accessObjectWireFrame(obj2, on); }); + + this.Render3D(); + } + + JSROOT.Painter.CreateGeoPainter = function(divid, obj, opt) { + JSROOT.GEO.GradPerSegm = JSROOT.gStyle.GeoGradPerSegm; + JSROOT.GEO.CompressComp = JSROOT.gStyle.GeoCompressComp; + + var painter = new TGeoPainter(obj); + + // one could use TGeoManager setting, but for some example JSROOT does not build composites + // if (obj && obj._typename=='TGeoManager' && (obj.fNsegments > 3)) + // JSROOT.GEO.GradPerSegm = 360/obj.fNsegments; + + painter.SetDivId(divid, 5); + + painter._usesvg = JSROOT.Painter.UseSVGFor3D(); + + painter._usesvgimg = !painter._usesvg && JSROOT.BatchMode; + + painter._webgl = !painter._usesvg && JSROOT.Painter.TestWebGL(); + + painter.options = painter.decodeOptions(opt); + + return painter; + } + + JSROOT.Painter.drawGeoObject = function(divid, obj, opt) { + if (!obj) return null; + + var shape = null; + + if (('fShapeBits' in obj) && ('fShapeId' in obj)) { + shape = obj; obj = null; + } else if ((obj._typename === 'TGeoVolumeAssembly') || (obj._typename === 'TGeoVolume')) { + shape = obj.fShape; + } else if ((obj._typename === "TEveGeoShapeExtract") || (obj._typename === "ROOT::Experimental::TEveGeoShapeExtract")) { + shape = obj.fShape; + } else if (obj._typename === 'TGeoManager') { + JSROOT.GEO.SetBit(obj.fMasterVolume, JSROOT.GEO.BITS.kVisThis, false); + shape = obj.fMasterVolume.fShape; + } else if ('fVolume' in obj) { + if (obj.fVolume) shape = obj.fVolume.fShape; + } else { + obj = null; + } + + if (opt && opt.indexOf("comp")==0 && shape && (shape._typename == 'TGeoCompositeShape') && shape.fNode) { + opt = opt.substr(4); + obj = JSROOT.GEO.buildCompositeVolume(shape); + } + + if (!obj && shape) + obj = JSROOT.extend(JSROOT.Create("TEveGeoShapeExtract"), + { fTrans: null, fShape: shape, fRGBA: [0, 1, 0, 1], fElements: null, fRnrSelf: true }); + + if (!obj) return null; + + var painter = JSROOT.Painter.CreateGeoPainter(divid, obj, opt); + + if (painter.options.is_main && !obj.$geo_painter) + obj.$geo_painter = painter; + + if (!painter.options.is_main && painter.options.project && obj.$geo_painter) { + painter._main_painter = obj.$geo_painter; + painter._main_painter._slave_painters.push(painter); + } + + // this.options.script_name = 'https://root.cern/js/files/geom/geomAlice.C' + + painter.checkScript(painter.options.script_name, painter.prepareObjectDraw.bind(painter)); + + return painter; + } + + /// keep for backwards compatibility + JSROOT.Painter.drawGeometry = JSROOT.Painter.drawGeoObject; + + // =============================================================================== + + JSROOT.GEO.buildCompositeVolume = function(comp, side) { + // function used to build hierarchy of elements of composite shapes + + var vol = JSROOT.Create("TGeoVolume"); + if (side && (comp._typename!=='TGeoCompositeShape')) { + vol.fName = side; + JSROOT.GEO.SetBit(vol, JSROOT.GEO.BITS.kVisThis, true); + vol.fLineColor = (side=="Left"? 2 : 3); + vol.fShape = comp; + return vol; + } + + JSROOT.GEO.SetBit(vol, JSROOT.GEO.BITS.kVisDaughters, true); + vol.$geoh = true; // workaround, let know browser that we are in volumes hierarchy + vol.fName = ""; + + var node1 = JSROOT.Create("TGeoNodeMatrix"); + node1.fName = "Left"; + node1.fMatrix = comp.fNode.fLeftMat; + node1.fVolume = JSROOT.GEO.buildCompositeVolume(comp.fNode.fLeft, "Left"); + + var node2 = JSROOT.Create("TGeoNodeMatrix"); + node2.fName = "Right"; + node2.fMatrix = comp.fNode.fRightMat; + node2.fVolume = JSROOT.GEO.buildCompositeVolume(comp.fNode.fRight, "Right"); + + vol.fNodes = JSROOT.Create("TList"); + vol.fNodes.Add(node1); + vol.fNodes.Add(node2); + + return vol; + } + + JSROOT.GEO.provideVisStyle = function(obj) { + if ((obj._typename === 'TEveGeoShapeExtract') || (obj._typename === 'ROOT::Experimental::TEveGeoShapeExtract')) + return obj.fRnrSelf ? " geovis_this" : ""; + + var vis = !JSROOT.GEO.TestBit(obj, JSROOT.GEO.BITS.kVisNone) && + JSROOT.GEO.TestBit(obj, JSROOT.GEO.BITS.kVisThis); + + var chld = JSROOT.GEO.TestBit(obj, JSROOT.GEO.BITS.kVisDaughters) || + JSROOT.GEO.TestBit(obj, JSROOT.GEO.BITS.kVisOneLevel); + + if (chld && (!obj.fNodes || (obj.fNodes.arr.length === 0))) chld = false; + + if (vis && chld) return " geovis_all"; + if (vis) return " geovis_this"; + if (chld) return " geovis_daughters"; + return ""; + } + + + JSROOT.GEO.getBrowserItem = function(item, itemname, callback) { + // mark object as belong to the hierarchy, require to + if (item._geoobj) item._geoobj.$geoh = true; + + JSROOT.CallBack(callback, item, item._geoobj); + } + + + JSROOT.GEO.createItem = function(node, obj, name) { + var sub = { + _kind: "ROOT." + obj._typename, + _name: name ? name : JSROOT.GEO.ObjectName(obj), + _title: obj.fTitle, + _parent: node, + _geoobj: obj, + _get: JSROOT.GEO.getBrowserItem + }; + + var volume, shape, subnodes, iseve = false; + + if (obj._typename == "TGeoMaterial") sub._icon = "img_geomaterial"; else + if (obj._typename == "TGeoMedium") sub._icon = "img_geomedium"; else + if (obj._typename == "TGeoMixture") sub._icon = "img_geomixture"; else + if ((obj._typename.indexOf("TGeoNode")===0) && obj.fVolume) { + sub._title = "node:" + obj._typename; + if (obj.fTitle.length > 0) sub._title += " " + obj.fTitle; + volume = obj.fVolume; + } else + if (obj._typename.indexOf("TGeoVolume")===0) { + volume = obj; + } else + if ((obj._typename == "TEveGeoShapeExtract") || (obj._typename == "ROOT::Experimental::TEveGeoShapeExtract") ) { + iseve = true; + shape = obj.fShape; + subnodes = obj.fElements ? obj.fElements.arr : null; + } else + if ((obj.fShapeBits !== undefined) && (obj.fShapeId !== undefined)) { + shape = obj; + } + + if (volume) { + shape = volume.fShape; + subnodes = volume.fNodes ? volume.fNodes.arr : null; + } + + if (volume || shape || subnodes) { + if (volume) sub._volume = volume; + + if (subnodes) { + sub._more = true; + sub._expand = JSROOT.GEO.expandObject; + } else + if (shape && (shape._typename === "TGeoCompositeShape") && shape.fNode) { + sub._more = true; + sub._shape = shape; + sub._expand = function(node, obj) { + JSROOT.GEO.createItem(node, node._shape.fNode.fLeft, 'Left'); + JSROOT.GEO.createItem(node, node._shape.fNode.fRight, 'Right'); + return true; + } + } + + if (!sub._title && (obj._typename != "TGeoVolume")) sub._title = obj._typename; + + if (shape) { + if (sub._title == "") + sub._title = shape._typename; + + sub._icon = JSROOT.GEO.getShapeIcon(shape); + } else { + sub._icon = sub._more ? "img_geocombi" : "img_geobbox"; + } + + if (volume) + sub._icon += JSROOT.GEO.provideVisStyle(volume); + else if (iseve) + sub._icon += JSROOT.GEO.provideVisStyle(obj); + + sub._menu = JSROOT.GEO.provideMenu; + sub._icon_click = JSROOT.GEO.browserIconClick; + } + + if (!node._childs) node._childs = []; + + if (!sub._name) + if (typeof node._name === 'string') { + sub._name = node._name; + if (sub._name.lastIndexOf("s")===sub._name.length-1) + sub._name = sub._name.substr(0, sub._name.length-1); + sub._name += "_" + node._childs.length; + } else { + sub._name = "item_" + node._childs.length; + } + + node._childs.push(sub); + + return sub; + } + + JSROOT.GEO.createList = function(parent, lst, name, title) { + + if (!lst || !('arr' in lst) || (lst.arr.length==0)) return; + + var item = { + _name: name, + _kind: "ROOT.TList", + _title: title, + _more: true, + _geoobj: lst, + _parent: parent, + } + + item._get = function(item, itemname, callback) { + if ('_geoobj' in item) + return JSROOT.CallBack(callback, item, item._geoobj); + + JSROOT.CallBack(callback, item, null); + } + + item._expand = function(node, lst) { + // only childs + + if ('fVolume' in lst) + lst = lst.fVolume.fNodes; + + if (!('arr' in lst)) return false; + + node._childs = []; + + JSROOT.GEO.CheckDuplicates(null, lst.arr); + + for (var n in lst.arr) + JSROOT.GEO.createItem(node, lst.arr[n]); + + return true; + } + + if (!parent._childs) parent._childs = []; + parent._childs.push(item); + + }; + + JSROOT.GEO.provideMenu = function(menu, item, hpainter) { + + if (!item._geoobj) return false; + + var obj = item._geoobj, vol = item._volume, + iseve = ((obj._typename === 'TEveGeoShapeExtract') || (obj._typename === 'ROOT::Experimental::TEveGeoShapeExtract')); + + if (!vol && !iseve) return false; + + menu.add("separator"); + + function ScanEveVisible(obj, arg, skip_this) { + if (!arg) arg = { visible: 0, hidden: 0 }; + + if (!skip_this) { + if (arg.assign!==undefined) obj.fRnrSelf = arg.assign; else + if (obj.fRnrSelf) arg.vis++; else arg.hidden++; + } + + if (obj.fElements) + for (var n=0;n<obj.fElements.arr.length;++n) + ScanEveVisible(obj.fElements.arr[n], arg, false); + + return arg; + } + + function ToggleEveVisibility(arg) { + if (arg === 'self') { + obj.fRnrSelf = !obj.fRnrSelf; + item._icon = item._icon.split(" ")[0] + JSROOT.GEO.provideVisStyle(obj); + hpainter.UpdateTreeNode(item); + } else { + ScanEveVisible(obj, { assign: (arg === "true") }, true); + hpainter.ForEach(function(m) { + // update all child items + if (m._geoobj && m._icon) { + m._icon = item._icon.split(" ")[0] + JSROOT.GEO.provideVisStyle(m._geoobj); + hpainter.UpdateTreeNode(m); + } + }, item); + } + + JSROOT.GEO.findItemWithPainter(item, 'testGeomChanges'); + } + + function ToggleMenuBit(arg) { + JSROOT.GEO.ToggleBit(vol, arg); + var newname = item._icon.split(" ")[0] + JSROOT.GEO.provideVisStyle(vol); + hpainter.ForEach(function(m) { + // update all items with that volume + if (item._volume === m._volume) { + m._icon = newname; + hpainter.UpdateTreeNode(m); + } + }); + + hpainter.UpdateTreeNode(item); + JSROOT.GEO.findItemWithPainter(item, 'testGeomChanges'); + } + + if ((item._geoobj._typename.indexOf("TGeoNode")===0) && JSROOT.GEO.findItemWithPainter(item)) + menu.add("Focus", function() { + + var drawitem = JSROOT.GEO.findItemWithPainter(item); + + if (!drawitem) return; + + var fullname = hpainter.itemFullName(item, drawitem); + + if (drawitem._painter && typeof drawitem._painter.focusOnItem == 'function') + drawitem._painter.focusOnItem(fullname); + }); + + if (iseve) { + menu.addchk(obj.fRnrSelf, "Visible", "self", ToggleEveVisibility); + var res = ScanEveVisible(obj, undefined, true); + + if (res.hidden + res.visible > 0) + menu.addchk((res.hidden==0), "Daughters", (res.hidden!=0) ? "true" : "false", ToggleEveVisibility); + + } else { + menu.addchk(JSROOT.GEO.TestBit(vol, JSROOT.GEO.BITS.kVisNone), "Invisible", + JSROOT.GEO.BITS.kVisNone, ToggleMenuBit); + menu.addchk(JSROOT.GEO.TestBit(vol, JSROOT.GEO.BITS.kVisThis), "Visible", + JSROOT.GEO.BITS.kVisThis, ToggleMenuBit); + menu.addchk(JSROOT.GEO.TestBit(vol, JSROOT.GEO.BITS.kVisDaughters), "Daughters", + JSROOT.GEO.BITS.kVisDaughters, ToggleMenuBit); + menu.addchk(JSROOT.GEO.TestBit(vol, JSROOT.GEO.BITS.kVisOneLevel), "1lvl daughters", + JSROOT.GEO.BITS.kVisOneLevel, ToggleMenuBit); + } + + return true; + } + + JSROOT.GEO.findItemWithPainter = function(hitem, funcname) { + while (hitem) { + if (hitem._painter && hitem._painter._camera) { + if (funcname && typeof hitem._painter[funcname] == 'function') + hitem._painter[funcname](); + return hitem; + } + hitem = hitem._parent; + } + return null; + } + + JSROOT.GEO.updateBrowserIcons = function(obj, hpainter) { + if (!obj || !hpainter) return; + + hpainter.ForEach(function(m) { + // update all items with that volume + if ((obj === m._volume) || (obj === m._geoobj)) { + m._icon = m._icon.split(" ")[0] + JSROOT.GEO.provideVisStyle(obj); + hpainter.UpdateTreeNode(m); + } + }); + } + + JSROOT.GEO.browserIconClick = function(hitem, hpainter) { + if (hitem._volume) { + if (hitem._more && hitem._volume.fNodes && (hitem._volume.fNodes.arr.length>0)) + JSROOT.GEO.ToggleBit(hitem._volume, JSROOT.GEO.BITS.kVisDaughters); + else + JSROOT.GEO.ToggleBit(hitem._volume, JSROOT.GEO.BITS.kVisThis); + + JSROOT.GEO.updateBrowserIcons(hitem._volume, hpainter); + + JSROOT.GEO.findItemWithPainter(hitem, 'testGeomChanges'); + return false; // no need to update icon - we did it ourself + } + + if (hitem._geoobj && (( hitem._geoobj._typename == "TEveGeoShapeExtract") || ( hitem._geoobj._typename == "ROOT::Experimental::TEveGeoShapeExtract"))) { + hitem._geoobj.fRnrSelf = !hitem._geoobj.fRnrSelf; + + JSROOT.GEO.updateBrowserIcons(hitem._geoobj, hpainter); + JSROOT.GEO.findItemWithPainter(hitem, 'testGeomChanges'); + return false; // no need to update icon - we did it ourself + } + + + // first check that geo painter assigned with the item + var drawitem = JSROOT.GEO.findItemWithPainter(hitem); + if (!drawitem) return false; + + var newstate = drawitem._painter.ExtraObjectVisible(hpainter, hitem, true); + + // return true means browser should update icon for the item + return (newstate!==undefined) ? true : false; + } + + JSROOT.GEO.getShapeIcon = function(shape) { + switch (shape._typename) { + case "TGeoArb8" : return "img_geoarb8"; break; + case "TGeoCone" : return "img_geocone"; break; + case "TGeoConeSeg" : return "img_geoconeseg"; break; + case "TGeoCompositeShape" : return "img_geocomposite"; break; + case "TGeoTube" : return "img_geotube"; break; + case "TGeoTubeSeg" : return "img_geotubeseg"; break; + case "TGeoPara" : return "img_geopara"; break; + case "TGeoParaboloid" : return "img_geoparab"; break; + case "TGeoPcon" : return "img_geopcon"; break; + case "TGeoPgon" : return "img_geopgon"; break; + case "TGeoShapeAssembly" : return "img_geoassembly"; break; + case "TGeoSphere" : return "img_geosphere"; break; + case "TGeoTorus" : return "img_geotorus"; break; + case "TGeoTrd1" : return "img_geotrd1"; break; + case "TGeoTrd2" : return "img_geotrd2"; break; + case "TGeoXtru" : return "img_geoxtru"; break; + case "TGeoTrap" : return "img_geotrap"; break; + case "TGeoGtra" : return "img_geogtra"; break; + case "TGeoEltu" : return "img_geoeltu"; break; + case "TGeoHype" : return "img_geohype"; break; + case "TGeoCtub" : return "img_geoctub"; break; + } + return "img_geotube"; + } + + JSROOT.GEO.getBrowserIcon = function(hitem, hpainter) { + var icon = ""; + if (hitem._kind == 'ROOT.TEveTrack') icon = 'img_evetrack'; else + if (hitem._kind == 'ROOT.TEvePointSet') icon = 'img_evepoints'; else + if (hitem._kind == 'ROOT.TPolyMarker3D') icon = 'img_evepoints'; + if (icon.length>0) { + var drawitem = JSROOT.GEO.findItemWithPainter(hitem); + if (drawitem) + if (drawitem._painter.ExtraObjectVisible(hpainter, hitem)) + icon += " geovis_this"; + } + return icon; + } + + JSROOT.GEO.expandObject = function(parent, obj) { + if (!parent || !obj) return false; + + var isnode = (obj._typename.indexOf('TGeoNode') === 0), + isvolume = (obj._typename.indexOf('TGeoVolume') === 0), + ismanager = (obj._typename === 'TGeoManager'), + iseve = ((obj._typename === 'TEveGeoShapeExtract')||(obj._typename === 'ROOT::Experimental::TEveGeoShapeExtract')); + + if (!isnode && !isvolume && !ismanager && !iseve) return false; + + if (parent._childs) return true; + + if (ismanager) { + JSROOT.GEO.createList(parent, obj.fMaterials, "Materials", "list of materials"); + JSROOT.GEO.createList(parent, obj.fMedia, "Media", "list of media"); + JSROOT.GEO.createList(parent, obj.fTracks, "Tracks", "list of tracks"); + + JSROOT.GEO.SetBit(obj.fMasterVolume, JSROOT.GEO.BITS.kVisThis, false); + JSROOT.GEO.createItem(parent, obj.fMasterVolume); + return true; + } + + var volume, subnodes, shape; + + if (iseve) { + subnodes = obj.fElements ? obj.fElements.arr : null; + shape = obj.fShape; + } else { + volume = (isnode ? obj.fVolume : obj); + subnodes = volume && volume.fNodes ? volume.fNodes.arr : null; + shape = volume ? volume.fShape : null; + } + + if (!subnodes && shape && (shape._typename === "TGeoCompositeShape") && shape.fNode) { + if (!parent._childs) { + JSROOT.GEO.createItem(parent, shape.fNode.fLeft, 'Left'); + JSROOT.GEO.createItem(parent, shape.fNode.fRight, 'Right'); + } + + return true; + } + + if (!subnodes) return false; + + JSROOT.GEO.CheckDuplicates(obj, subnodes); + + for (var i=0;i<subnodes.length;++i) + JSROOT.GEO.createItem(parent, subnodes[i]); + + return true; + } + + JSROOT.addDrawFunc({ name: "TGeoVolumeAssembly", icon: 'img_geoassembly', func: JSROOT.Painter.drawGeoObject, expand: JSROOT.GEO.expandObject, opt: ";more;all;count" }); + JSROOT.addDrawFunc({ name: "TEvePointSet", icon_get: JSROOT.GEO.getBrowserIcon, icon_click: JSROOT.GEO.browserIconClick }); + JSROOT.addDrawFunc({ name: "TEveTrack", icon_get: JSROOT.GEO.getBrowserIcon, icon_click: JSROOT.GEO.browserIconClick }); + + JSROOT.TGeoPainter = TGeoPainter; + + JSROOT.Painter.GeoDrawingControl = GeoDrawingControl; + + return JSROOT.Painter; + +})); diff --git a/js/scripts/JSRootGeoWorker.js b/js/scripts/JSRootGeoWorker.js new file mode 100644 index 00000000000..2b5f0b2e1c0 --- /dev/null +++ b/js/scripts/JSRootGeoWorker.js @@ -0,0 +1,108 @@ +JSROOT = {}; // just place holder for JSROOT.GEO functions + +JSROOT.BIT = function(n) { return 1 << (n); } + +importScripts("three.min.js", "ThreeCSG.js", "JSRootGeoBase.js"); + +// if (console) console.log('geoworker started ' + THREE.REVISION); + +var clones = null; + +onmessage = function(e) { + + if (typeof e.data == 'string') { + console.log('Worker get message ' + e.data); + return; + } + + if (typeof e.data != 'object') return; + + e.data.tm1 = new Date().getTime(); + + if (e.data.init) { + // console.log('start worker ' + (e.data.tm1 - e.data.tm0)); + + var nodes = e.data.clones; + if (nodes) { + // console.log('get clones ' + nodes.length); + clones = new JSROOT.GEO.ClonedNodes(null, nodes); + delete e.data.clones; + clones.sortmap = e.data.sortmap; + } + + // used in composite shape + JSROOT.browser = e.data.browser; + + e.data.tm2 = new Date().getTime(); + + return postMessage(e.data); + } + + if (e.data.shapes) { + // this is task to create geometries in the worker + + var shapes = e.data.shapes, transferables = []; + + // build all shapes up to specified limit, also limit execution time + for (var n=0;n<100;++n) { + var res = clones.BuildShapes(shapes, e.data.limit, 1000); + if (res.done) break; + postMessage({ progress: "Worker creating: " + res.shapes + " / " + shapes.length + " shapes, " + res.faces + " faces" }); + } + + for (var n=0;n<shapes.length;++n) { + var item = shapes[n]; + + if (item.geom) { + var bufgeom; + if (item.geom instanceof THREE.BufferGeometry) { + bufgeom = item.geom; + } else { + var bufgeom = new THREE.BufferGeometry(); + bufgeom.fromGeometry(item.geom); + } + + item.buf_pos = bufgeom.attributes.position.array; + item.buf_norm = bufgeom.attributes.normal.array; + + // use nice feature of HTML workers with transferable + // we allow to take ownership of buffer from local array + // therefore buffer content not need to be copied + transferables.push(item.buf_pos.buffer, item.buf_norm.buffer); + + delete item.geom; + } + + delete item.shape; // no need to send back shape + } + + e.data.tm2 = new Date().getTime(); + + return postMessage(e.data, transferables); + } + + if (e.data.collect !== undefined) { + // this is task to collect visible nodes using camera position + + // first mark all visible flags + clones.MarkVisisble(false, false, e.data.visible); + delete e.data.visible; + + var matrix = null; + if (e.data.matrix) + matrix = new THREE.Matrix4().fromArray(e.data.matrix); + delete e.data.matrix; + + var res = clones.CollectVisibles(e.data.collect, JSROOT.GEO.CreateFrustum(matrix), e.data.collect_nodes); + + e.data.new_nodes = res.lst; + e.data.complete = res.complete; // inform if all nodes are selected + + e.data.tm2 = new Date().getTime(); + + // console.log('Collect visibles in worker ' + e.data.new_nodes.length + ' takes ' + (e.data.tm2-e.data.tm1)); + + return postMessage(e.data); + } + +} diff --git a/js/scripts/JSRootIOEvolution.js b/js/scripts/JSRootIOEvolution.js new file mode 100644 index 00000000000..1fb62da0c73 --- /dev/null +++ b/js/scripts/JSRootIOEvolution.js @@ -0,0 +1,3058 @@ +/// @file JSRootIOEvolution.js +/// I/O methods of JavaScript ROOT + +(function( factory ) { + if ( typeof define === "function" && define.amd ) { + define( ['JSRootCore', 'rawinflate'], factory ); + } else + if (typeof exports === 'object' && typeof module !== 'undefined') { + require("./rawinflate.min.js"); + + factory(require("./JSRootCore.js")); + } else { + if (typeof JSROOT == 'undefined') + throw new Error("JSROOT I/O requires JSRootCore.js", "JSRootIOEvolution.js"); + + if (typeof JSROOT.ZIP == 'undefined') + throw new Error("JSROOT I/O requires rawinflate.js", "JSRootIOEvolution.js"); + + if (typeof JSROOT.IO == "object") + throw new Error("This JSROOT IO already loaded", "JSRootIOEvolution.js"); + + factory(JSROOT); + } +} (function(JSROOT) { + + "use strict"; + + JSROOT.sources.push("io"); + + JSROOT.IO = { + kBase: 0, kOffsetL: 20, kOffsetP: 40, + kChar: 1, kShort: 2, kInt: 3, kLong: 4, kFloat: 5, kCounter: 6, kCharStar: 7, kDouble: 8, kDouble32: 9, kLegacyChar : 10, + kUChar: 11, kUShort: 12, kUInt: 13, kULong: 14, kBits: 15, kLong64: 16, kULong64: 17, kBool: 18, kFloat16: 19, + kObject: 61, kAny: 62, kObjectp: 63, kObjectP: 64, kTString: 65, + kTObject: 66, kTNamed: 67, kAnyp: 68, kAnyP: 69, kAnyPnoVT: 70, kSTLp: 71, + kSkip: 100, kSkipL: 120, kSkipP: 140, kConv: 200, kConvL: 220, kConvP: 240, + kSTL: 300, kSTLstring: 365, kStreamer: 500, kStreamLoop: 501, + kMapOffset: 2, + kByteCountMask: 0x40000000, + kNewClassTag: 0xFFFFFFFF, + kClassMask: 0x80000000, + Mode: "array", // could be string or array, enable usage of ArrayBuffer in http requests + NativeArray: true, // when true, native arrays like Int32Array or Float64Array are used + + TypeNames : ["BASE", "char", "short", "int", "long", "float", "int", "const char*", "double", "Double32_t", + "char", "unsigned char", "unsigned short", "unsigned", "unsigned long", "unsigned", "Long64_t", "ULong64_t", "bool", "Float16_t"], + + // constants used for coding type of STL container + kNotSTL: 0, kSTLvector: 1, kSTLlist: 2, kSTLdeque: 3, kSTLmap: 4, kSTLmultimap: 5, + kSTLset: 6, kSTLmultiset: 7, kSTLbitset: 8, kSTLforwardlist: 9, + kSTLunorderedset : 10, kSTLunorderedmultiset : 11, kSTLunorderedmap : 12, + kSTLunorderedmultimap : 13, kSTLend : 14, + + // names of STL containers + StlNames: [ "", "vector", "list", "deque", "map", "multimap", "set", "multiset", "bitset"], + + // constants of bits in version + kStreamedMemberWise: JSROOT.BIT(14), + + kSplitCollectionOfPointers: 100, + + // map of user-streamer function like func(buf,obj) + // or alias (classname) which can be used to read that function + // or list of read functions + CustomStreamers: {}, + + // these are streamers which do not handle version regularly + // used for special classes like TRef or TBasket + DirectStreamers: {}, + + // TOBject bits + kIsReferenced: JSROOT.BIT(4), + kHasUUID: JSROOT.BIT(5), + + IsInteger: function(typ) { return ((typ>=this.kChar) && (typ<=this.kLong)) || (typ===this.kCounter) || + ((typ>=this.kLegacyChar) && (typ<=this.kBool)); }, + + IsNumeric: function(typ) { return (typ>0) && (typ<=this.kBool) && (typ!==this.kCharStar); }, + + GetTypeId: function(typname, norecursion) { + switch (typname) { + case "bool": + case "Bool_t": return JSROOT.IO.kBool; + case "char": + case "signed char": + case "Char_t": return JSROOT.IO.kChar; + case "Color_t": + case "Style_t": + case "Width_t": + case "short": + case "Short_t": return JSROOT.IO.kShort; + case "int": + case "EErrorType": + case "Int_t": return JSROOT.IO.kInt; + case "long": + case "Long_t": return JSROOT.IO.kLong; + case "float": + case "Float_t": return JSROOT.IO.kFloat; + case "double": + case "Double_t": return JSROOT.IO.kDouble; + case "unsigned char": + case "UChar_t": return JSROOT.IO.kUChar; + case "unsigned short": + case "UShort_t": return JSROOT.IO.kUShort; + case "unsigned": + case "unsigned int": + case "UInt_t": return JSROOT.IO.kUInt; + case "unsigned long": + case "ULong_t": return JSROOT.IO.kULong; + case "int64_t": + case "long long": + case "Long64_t": return JSROOT.IO.kLong64; + case "uint64_t": + case "unsigned long long": + case "ULong64_t": return JSROOT.IO.kULong64; + case "Double32_t": return JSROOT.IO.kDouble32; + case "Float16_t": return JSROOT.IO.kFloat16; + case "char*": + case "const char*": + case "const Char_t*": return JSROOT.IO.kCharStar; + } + + if (!norecursion) { + var replace = JSROOT.IO.CustomStreamers[typname]; + if (typeof replace === "string") return JSROOT.IO.GetTypeId(replace, true); + } + + return -1; + }, + + GetTypeSize: function(typname) { + switch (typname) { + case JSROOT.IO.kBool: return 1; + case JSROOT.IO.kChar: return 1; + case JSROOT.IO.kShort : return 2; + case JSROOT.IO.kInt: return 4; + case JSROOT.IO.kLong: return 8; + case JSROOT.IO.kFloat: return 4; + case JSROOT.IO.kDouble: return 8; + case JSROOT.IO.kUChar: return 1; + case JSROOT.IO.kUShort: return 2; + case JSROOT.IO.kUInt: return 4; + case JSROOT.IO.kULong: return 8; + case JSROOT.IO.kLong64: return 8; + case JSROOT.IO.kULong64: return 8; + } + return -1; + } + + }; + + JSROOT.addUserStreamer = function(type, user_streamer) { + JSROOT.IO.CustomStreamers[type] = user_streamer; + } + + JSROOT.R__unzip = function(arr, tgtsize, noalert, src_shift) { + // Reads header envelope, determines zipped size and unzip content + + var totallen = arr.byteLength, curr = src_shift || 0, fullres = 0, tgtbuf = null, HDRSIZE = 9; + + function getChar(o) { return String.fromCharCode(arr.getUint8(o)); } + + function getCode(o) { return arr.getUint8(o); } + + while (fullres < tgtsize) { + + var fmt = "unknown", off = 0, CHKSUM = 0; + + if (curr + HDRSIZE >= totallen) { + if (!noalert) JSROOT.alert("Error R__unzip: header size exceeds buffer size"); + return null; + } + + if (getChar(curr) == 'Z' && getChar(curr+1) == 'L' && getCode(curr+2) == 8) { fmt = "new"; off = 2; } else + if (getChar(curr) == 'C' && getChar(curr+1) == 'S' && getCode(curr+2) == 8) { fmt = "old"; off = 0; } else + if (getChar(curr) == 'X' && getChar(curr+1) == 'Z') fmt = "LZMA"; else + if (getChar(curr) == 'L' && getChar(curr+1) == '4') { fmt = "LZ4"; off = 0; CHKSUM = 8; } + +/* + if (fmt == "LZMA") { + console.log('find LZMA'); + console.log('chars', getChar(curr), getChar(curr+1), getChar(curr+2)); + + for(var n=0;n<20;++n) + console.log('codes',n,getCode(curr+n)); + + var srcsize = HDRSIZE + ((getCode(curr+3) & 0xff) | ((getCode(curr+4) & 0xff) << 8) | ((getCode(curr+5) & 0xff) << 16)); + + var tgtsize0 = ((getCode(curr+6) & 0xff) | ((getCode(curr+7) & 0xff) << 8) | ((getCode(curr+8) & 0xff) << 16)); + + + console.log('srcsize',srcsize, tgtsize0, tgtsize); + + off = 0; + + var uint8arr = new Uint8Array(arr.buffer, arr.byteOffset + curr + HDRSIZE + off, arr.byteLength - curr - HDRSIZE - off); + + JSROOT.LZMA.decompress(uint8arr, function on_decompress_complete(result) { + console.log("Decompressed done", typeof result, result); + }, function on_decompress_progress_update(percent) { + /// Decompressing progress code goes here. + console.log("Decompressing: " + (percent * 100) + "%"); + }); + + return null; + } +*/ + + /* C H E C K H E A D E R */ + if ((fmt !== "new") && (fmt !== "old") && (fmt !== "LZ4")) { + if (!noalert) JSROOT.alert("R__unzip: " + fmt + " format is not supported!"); + return null; + } + + var srcsize = HDRSIZE + ((getCode(curr+3) & 0xff) | ((getCode(curr+4) & 0xff) << 8) | ((getCode(curr+5) & 0xff) << 16)); + + var uint8arr = new Uint8Array(arr.buffer, arr.byteOffset + curr + HDRSIZE + off + CHKSUM, Math.min(arr.byteLength - curr - HDRSIZE - off - CHKSUM, srcsize - HDRSIZE - CHKSUM)); + + // place for unpacking + if (!tgtbuf) tgtbuf = new ArrayBuffer(tgtsize); + + var tgt8arr = new Uint8Array(tgtbuf, fullres); + + var reslen = (fmt === "LZ4") ? JSROOT.LZ4.uncompress(uint8arr, tgt8arr) + : JSROOT.ZIP.inflate(uint8arr, tgt8arr); + if (reslen<=0) break; + + fullres += reslen; + curr += srcsize; + } + + if (fullres !== tgtsize) { + if (!noalert) JSROOT.alert("R__unzip: fail to unzip data expects " + tgtsize + " , got " + fullres); + return null; + } + + return new DataView(tgtbuf); + } + + // ================================================================================= + + function TBuffer(arr, pos, file, length) { + // buffer takes with DataView as first argument + this._typename = "TBuffer"; + this.arr = arr; + this.o = pos || 0; + this.fFile = file; + this.length = length || (arr ? arr.byteLength : 0); // use size of array view, blob buffer can be much bigger + this.ClearObjectMap(); + this.fTagOffset = 0; + this.last_read_version = 0; + return this; + } + + TBuffer.prototype.locate = function(pos) { + this.o = pos; + } + + TBuffer.prototype.shift = function(cnt) { + this.o += cnt; + } + + TBuffer.prototype.remain = function() { + return this.length - this.o; + } + + TBuffer.prototype.GetMappedObject = function(tag) { + return this.fObjectMap[tag]; + } + + TBuffer.prototype.MapObject = function(tag, obj) { + if (obj!==null) + this.fObjectMap[tag] = obj; + } + + TBuffer.prototype.MapClass = function(tag, classname) { + this.fClassMap[tag] = classname; + } + + TBuffer.prototype.GetMappedClass = function(tag) { + if (tag in this.fClassMap) return this.fClassMap[tag]; + return -1; + } + + TBuffer.prototype.ClearObjectMap = function() { + this.fObjectMap = {}; + this.fClassMap = {}; + this.fObjectMap[0] = null; + this.fDisplacement = 0; + } + + TBuffer.prototype.ReadVersion = function() { + // read class version from I/O buffer + var ver = {}, bytecnt = this.ntou4(); // byte count + + if (bytecnt & JSROOT.IO.kByteCountMask) + ver.bytecnt = bytecnt - JSROOT.IO.kByteCountMask - 2; // one can check between Read version and end of streamer + else + this.o -= 4; // rollback read bytes, this is old buffer without byte count + + this.last_read_version = ver.val = this.ntoi2(); + this.last_read_checksum = 0; + ver.off = this.o; + + if ((ver.val <= 0) && ver.bytecnt && (ver.bytecnt>=4)) { + ver.checksum = this.ntou4(); + if (!this.fFile.FindSinfoCheckum(ver.checksum)) { + // JSROOT.console('Fail to find streamer info with check sum ' + ver.checksum + ' version ' + ver.val); + this.o-=4; // not found checksum in the list + delete ver.checksum; // remove checksum + } else { + this.last_read_checksum = ver.checksum; + } + } + return ver; + } + + TBuffer.prototype.CheckBytecount = function(ver, where) { + if ((ver.bytecnt !== undefined) && (ver.off + ver.bytecnt !== this.o)) { + if (where!=null) { + // alert("Missmatch in " + where + " bytecount expected = " + ver.bytecnt + " got = " + (this.o-ver.off)); + console.log("Missmatch in " + where + " bytecount expected = " + ver.bytecnt + " got = " + (this.o-ver.off)); + } + this.o = ver.off + ver.bytecnt; + return false; + } + return true; + } + + TBuffer.prototype.ReadTString = function() { + // stream a TString object from buffer + // std::string uses similar binary format + var len = this.ntou1(); + // large strings + if (len == 255) len = this.ntou4(); + if (len==0) return ""; + + var pos = this.o; + this.o += len; + + return (this.codeAt(pos) == 0) ? '' : this.substring(pos, pos + len); + } + + TBuffer.prototype.ReadFastString = function(n) { + // read Char_t array as string + // string either contains all symbols or until 0 symbol + + var res = "", code, closed = false; + for (var i = 0; (n < 0) || (i < n); ++i) { + code = this.ntou1(); + if (code==0) { closed = true; if (n<0) break; } + if (!closed) res += String.fromCharCode(code); + } + + return res; + } + + TBuffer.prototype.ntou1 = function() { + return this.arr.getUint8(this.o++); + } + + TBuffer.prototype.ntou2 = function() { + var o = this.o; this.o+=2; + return this.arr.getUint16(o); + } + + TBuffer.prototype.ntou4 = function() { + var o = this.o; this.o+=4; + return this.arr.getUint32(o); + } + + TBuffer.prototype.ntou8 = function() { + var high = this.arr.getUint32(this.o); this.o+=4; + var low = this.arr.getUint32(this.o); this.o+=4; + return high * 0x100000000 + low; + } + + TBuffer.prototype.ntoi1 = function() { + return this.arr.getInt8(this.o++); + } + + TBuffer.prototype.ntoi2 = function() { + var o = this.o; this.o+=2; + return this.arr.getInt16(o); + } + + TBuffer.prototype.ntoi4 = function() { + var o = this.o; this.o+=4; + return this.arr.getInt32(o); + } + + TBuffer.prototype.ntoi8 = function() { + var high = this.arr.getUint32(this.o); this.o+=4; + var low = this.arr.getUint32(this.o); this.o+=4; + if (high < 0x80000000) return high * 0x100000000 + low; + return -1 - ((~high) * 0x100000000 + ~low); + } + + TBuffer.prototype.ntof = function() { + var o = this.o; this.o+=4; + return this.arr.getFloat32(o); + } + + TBuffer.prototype.ntod = function() { + var o = this.o; this.o+=8; + return this.arr.getFloat64(o); + } + + TBuffer.prototype.ReadFastArray = function(n, array_type) { + // read array of n values from the I/O buffer + + var array, i = 0, o = this.o, view = this.arr; + switch (array_type) { + case JSROOT.IO.kDouble: + array = new Float64Array(n); + for (; i < n; ++i, o+=8) + array[i] = view.getFloat64(o); + break; + case JSROOT.IO.kFloat: + array = new Float32Array(n); + for (; i < n; ++i, o+=4) + array[i] = view.getFloat32(o); + break; + case JSROOT.IO.kLong: + case JSROOT.IO.kLong64: + array = new Float64Array(n); + for (; i < n; ++i) + array[i] = this.ntoi8(); + return array; // exit here to avoid conflicts + case JSROOT.IO.kULong: + case JSROOT.IO.kULong64: + array = new Float64Array(n); + for (; i < n; ++i) + array[i] = this.ntou8(); + return array; // exit here to avoid conflicts + case JSROOT.IO.kInt: + case JSROOT.IO.kCounter: + array = new Int32Array(n); + for (; i < n; ++i, o+=4) + array[i] = view.getInt32(o); + break; + case JSROOT.IO.kBits: + case JSROOT.IO.kUInt: + array = new Uint32Array(n); + for (; i < n; ++i, o+=4) + array[i] = view.getUint32(o); + break; + case JSROOT.IO.kShort: + array = new Int16Array(n); + for (; i < n; ++i, o+=2) + array[i] = view.getInt16(o); + break; + case JSROOT.IO.kUShort: + array = new Uint16Array(n); + for (; i < n; ++i, o+=2) + array[i] = view.getUint16(o); + break; + case JSROOT.IO.kChar: + array = new Int8Array(n); + for (; i < n; ++i) + array[i] = view.getInt8(o++); + break; + case JSROOT.IO.kBool: + case JSROOT.IO.kUChar: + array = new Uint8Array(n); + for (; i < n; ++i) + array[i] = view.getUint8(o++); + break; + case JSROOT.IO.kTString: + array = new Array(n); + for (; i < n; ++i) + array[i] = this.ReadTString(); + return array; // exit here to avoid conflicts + case JSROOT.IO.kDouble32: + throw new Error('kDouble32 should not be used in ReadFastArray'); + case JSROOT.IO.kFloat16: + throw new Error('kFloat16 should not be used in ReadFastArray'); + default: + array = new Uint32Array(n); + for (; i < n; ++i, o+=4) + array[i] = view.getUint32(o); + break; + } + + this.o = o; + + return array; + } + + TBuffer.prototype.can_extract = function(place) { + for (var n=0;n<place.length;n+=2) + if (place[n] + place[n+1] > this.length) return false; + return true; + } + + TBuffer.prototype.extract = function(place) { + if (!this.arr || !this.arr.buffer || !this.can_extract(place)) return null; + if (place.length===2) return new DataView(this.arr.buffer, this.arr.byteOffset + place[0], place[1]); + + var res = new Array(place.length/2); + + for (var n=0;n<place.length;n+=2) + res[n/2] = new DataView(this.arr.buffer, this.arr.byteOffset + place[n], place[n+1]); + + return res; // return array of buffers + } + + TBuffer.prototype.codeAt = function(pos) { + return this.arr.getUint8(pos); + } + + TBuffer.prototype.substring = function(beg, end) { + var res = ""; + for (var n=beg;n<end;++n) + res += String.fromCharCode(this.arr.getUint8(n)); + return res; + } + + + JSROOT.IO.GetArrayKind = function(type_name) { + // returns type of array + // 0 - if TString (or equivalent) + // -1 - if any other kind + if ((type_name === "TString") || (type_name === "string") || + (JSROOT.IO.CustomStreamers[type_name] === 'TString')) return 0; + if ((type_name.length < 7) || (type_name.indexOf("TArray")!==0)) return -1; + if (type_name.length == 7) + switch (type_name[6]) { + case 'I': return JSROOT.IO.kInt; + case 'D': return JSROOT.IO.kDouble; + case 'F': return JSROOT.IO.kFloat; + case 'S': return JSROOT.IO.kShort; + case 'C': return JSROOT.IO.kChar; + case 'L': return JSROOT.IO.kLong; + default: return -1; + } + + return type_name == "TArrayL64" ? JSROOT.IO.kLong64 : -1; + } + + TBuffer.prototype.ReadNdimArray = function(handle, func) { + var ndim = handle.fArrayDim, maxindx = handle.fMaxIndex, res; + if ((ndim<1) && (handle.fArrayLength>0)) { ndim = 1; maxindx = [handle.fArrayLength]; } + if (handle.minus1) --ndim; + + if (ndim<1) return func(this, handle); + + if (ndim===1) { + res = new Array(maxindx[0]); + for (var n=0;n<maxindx[0];++n) + res[n] = func(this, handle); + } else + if (ndim===2) { + res = new Array(maxindx[0]); + for (var n=0;n<maxindx[0];++n) { + var res2 = new Array(maxindx[1]); + for (var k=0;k<maxindx[1];++k) + res2[k] = func(this, handle); + res[n] = res2; + } + } else { + var indx = [], arr = [], k; + for (k=0; k<ndim; ++k) { indx[k] = 0; arr[k] = []; } + res = arr[0]; + while (indx[0] < maxindx[0]) { + k = ndim-1; + arr[k].push(func(this, handle)); + ++indx[k]; + while ((indx[k] === maxindx[k]) && (k>0)) { + indx[k] = 0; + arr[k-1].push(arr[k]); + arr[k] = []; + ++indx[--k]; + } + } + } + + return res; + } + + TBuffer.prototype.ReadTKey = function(key) { + if (!key) key = {}; + this.ClassStreamer(key, 'TKey'); + var name = key.fName.replace(/['"]/g,''); + if (name !== key.fName) { + key.fRealName = key.fName; + key.fName = name; + } + return key; + } + + TBuffer.prototype.ReadBasketEntryOffset = function(basket, offset) { + // this is remaining part of TBasket streamer to decode fEntryOffset + // after unzipping of the TBasket data + + this.locate(basket.fLast - offset); + + if (this.remain() <= 0) { + if (!basket.fEntryOffset && (basket.fNevBuf <= 1)) basket.fEntryOffset = [ basket.fKeylen ]; + if (!basket.fEntryOffset) console.warn("No fEntryOffset when expected for basket with", basket.fNevBuf, "entries"); + return; + } + + var nentries = this.ntoi4(); + // there is error in file=reco_103.root&item=Events;2/PCaloHits_g4SimHits_EcalHitsEE_Sim.&opt=dump;num:10;first:101 + // it is workaround, but normally I/O should fail here + if ((nentries < 0) || (nentries > this.remain()*4)) { + console.error("Error when reading entries offset from basket fNevBuf", basket.fNevBuf, "remains", this.remain(), "want to read", nentries); + if (basket.fNevBuf <= 1) basket.fEntryOffset = [ basket.fKeylen ]; + return; + } + + basket.fEntryOffset = this.ReadFastArray(nentries, JSROOT.IO.kInt); + if (!basket.fEntryOffset) basket.fEntryOffset = [ basket.fKeylen ]; + + if (this.remain() > 0) + basket.fDisplacement = this.ReadFastArray(this.ntoi4(), JSROOT.IO.kInt); + else + basket.fDisplacement = undefined; + } + + TBuffer.prototype.ReadClass = function() { + // read class definition from I/O buffer + var classInfo = { name: -1 }, + tag = 0, + bcnt = this.ntou4(), + startpos = this.o; + + if (!(bcnt & JSROOT.IO.kByteCountMask) || (bcnt == JSROOT.IO.kNewClassTag)) { + tag = bcnt; + bcnt = 0; + } else { + tag = this.ntou4(); + } + if (!(tag & JSROOT.IO.kClassMask)) { + classInfo.objtag = tag + this.fDisplacement; // indicate that we have deal with objects tag + return classInfo; + } + if (tag == JSROOT.IO.kNewClassTag) { + // got a new class description followed by a new object + classInfo.name = this.ReadFastString(-1); + + if (this.GetMappedClass(this.fTagOffset + startpos + JSROOT.IO.kMapOffset) === -1) + this.MapClass(this.fTagOffset + startpos + JSROOT.IO.kMapOffset, classInfo.name); + } else { + // got a tag to an already seen class + var clTag = (tag & ~JSROOT.IO.kClassMask) + this.fDisplacement; + classInfo.name = this.GetMappedClass(clTag); + + if (classInfo.name === -1) + JSROOT.alert("Did not found class with tag " + clTag); + } + + return classInfo; + } + + TBuffer.prototype.ReadObjectAny = function() { + var objtag = this.fTagOffset + this.o + JSROOT.IO.kMapOffset, + clRef = this.ReadClass(); + + // class identified as object and should be handled so + if ('objtag' in clRef) + return this.GetMappedObject(clRef.objtag); + + if (clRef.name === -1) return null; + + var arrkind = JSROOT.IO.GetArrayKind(clRef.name), obj; + + if (arrkind === 0) { + obj = this.ReadTString(); + } else + if (arrkind > 0) { + // reading array, can map array only afterwards + obj = this.ReadFastArray(this.ntou4(), arrkind); + this.MapObject(objtag, obj); + } else { + // reading normal object, should map before to + obj = {}; + this.MapObject(objtag, obj); + this.ClassStreamer(obj, clRef.name); + } + + return obj; + } + + TBuffer.prototype.ClassStreamer = function(obj, classname) { + + if (obj._typename === undefined) obj._typename = classname; + + var direct = JSROOT.IO.DirectStreamers[classname]; + if (direct) { + direct(this, obj); + return obj; + } + + var ver = this.ReadVersion(); + + var streamer = this.fFile.GetStreamer(classname, ver); + + if (streamer !== null) { + + for (var n = 0; n < streamer.length; ++n) + streamer[n].func(this, obj); + + } else { + // just skip bytes belonging to not-recognized object + // console.warn('skip object ', classname); + + JSROOT.addMethods(obj); + } + + this.CheckBytecount(ver, classname); + + return obj; + } + + + // ======================================================================= + + JSROOT.CreateTBuffer = function(blob, pos, file, length) { + return new TBuffer(blob, pos, file, length); + } + + JSROOT.ReconstructObject = function(class_name, obj_rawdata, sinfo_rawdata) { + // method can be used to reconstruct ROOT object from binary buffer + // Buffer can be requested from online server with request like: + // http://localhost:8080/Files/job1.root/hpx/root.bin + // One also requires buffer with streamer infos, requested with command + // http://localhost:8080/StreamerInfo/root.bin + // And one should provide class name of the object + // + // Method provided for convenience only to see how binary JSROOT.IO works. + // It is strongly recommended to use JSON representation: + // http://localhost:8080/Files/job1.root/hpx/root.json + + var file = new TFile; + var buf = JSROOT.CreateTBuffer(sinfo_rawdata, 0, file); + file.ExtractStreamerInfos(buf); + + var obj = {}; + + buf = JSROOT.CreateTBuffer(obj_rawdata, 0, file); + buf.MapObject(obj, 1); + buf.ClassStreamer(obj, class_name); + + return obj; + } + + // ============================================================================== + + // A class that reads a TDirectory from a buffer. + + // ctor + function TDirectory(file, dirname, cycle) { + this.fFile = file; + this._typename = "TDirectory"; + this.dir_name = dirname; + this.dir_cycle = cycle; + this.fKeys = []; + return this; + } + + TDirectory.prototype.GetKey = function(keyname, cycle, call_back) { + // retrieve a key by its name and cycle in the list of keys + + if (typeof cycle != 'number') cycle = -1; + var bestkey = null; + for (var i = 0; i < this.fKeys.length; ++i) { + var key = this.fKeys[i]; + if (!key || (key.fName!==keyname)) continue; + if (key.fCycle == cycle) { bestkey = key; break; } + if ((cycle < 0) && (!bestkey || (key.fCycle > bestkey.fCycle))) bestkey = key; + } + if (bestkey) { + JSROOT.CallBack(call_back, bestkey); + return bestkey; + } + + var pos = keyname.lastIndexOf("/"); + // try to handle situation when object name contains slashed (bad practice anyway) + while (pos > 0) { + var dirname = keyname.substr(0, pos), + subname = keyname.substr(pos+1), + dirkey = this.GetKey(dirname); + + if ((dirkey!==null) && (typeof call_back == 'function') && + (dirkey.fClassName.indexOf("TDirectory")==0)) { + + this.fFile.ReadObject(this.dir_name + "/" + dirname, 1, function(newdir) { + if (newdir) newdir.GetKey(subname, cycle, call_back); + }); + return null; + } + + pos = keyname.lastIndexOf("/", pos-1); + } + + JSROOT.CallBack(call_back, null); + return null; + } + + TDirectory.prototype.ReadObject = function(obj_name, cycle, user_call_back) { + this.fFile.ReadObject(this.dir_name + "/" + obj_name, cycle, user_call_back); + } + + TDirectory.prototype.ReadKeys = function(objbuf, readkeys_callback) { + + objbuf.ClassStreamer(this, 'TDirectory'); + + if ((this.fSeekKeys <= 0) || (this.fNbytesKeys <= 0)) + return JSROOT.CallBack(readkeys_callback, this); + + var dir = this, file = this.fFile; + + file.ReadBuffer([this.fSeekKeys, this.fNbytesKeys], function(blob) { + if (!blob) return JSROOT.CallBack(readkeys_callback,null); + + //*-* -------------Read keys of the top directory + + var buf = JSROOT.CreateTBuffer(blob, 0, file); + + buf.ReadTKey(); + var nkeys = buf.ntoi4(); + + for (var i = 0; i < nkeys; ++i) + dir.fKeys.push(buf.ReadTKey()); + + file.fDirectories.push(dir); + + JSROOT.CallBack(readkeys_callback, dir); + }); + } + + // ============================================================================== + // A class that reads ROOT files. + // + //////////////////////////////////////////////////////////////////////////////// + // A ROOT file is a suite of consecutive data records (TKey's) with + // the following format (see also the TKey class). If the key is + // located past the 32 bit file limit (> 2 GB) then some fields will + // be 8 instead of 4 bytes: + // 1->4 Nbytes = Length of compressed object (in bytes) + // 5->6 Version = TKey version identifier + // 7->10 ObjLen = Length of uncompressed object + // 11->14 Datime = Date and time when object was written to file + // 15->16 KeyLen = Length of the key structure (in bytes) + // 17->18 Cycle = Cycle of key + // 19->22 [19->26] SeekKey = Pointer to record itself (consistency check) + // 23->26 [27->34] SeekPdir = Pointer to directory header + // 27->27 [35->35] lname = Number of bytes in the class name + // 28->.. [36->..] ClassName = Object Class Name + // ..->.. lname = Number of bytes in the object name + // ..->.. Name = lName bytes with the name of the object + // ..->.. lTitle = Number of bytes in the object title + // ..->.. Title = Title of the object + // -----> DATA = Data bytes associated to the object + // + + /** + * @summary Interface to read objects from ROOT files. + * + * @desc Use {@link JSROOT.OpenFile} to create instance of the class + * @constructor + * @memberof JSROOT + * @param {string} url - file URL + * @param {function} newfile_callback - function called when file header is read + */ + function TFile(url, newfile_callback) { + this._typename = "TFile"; + this.fEND = 0; + this.fFullURL = url; + this.fURL = url; + this.fAcceptRanges = true; // when disabled ('+' at the end of file name), complete file content read with single operation + this.fUseStampPar = "stamp="+(new Date).getTime(); // use additional time stamp parameter for file name to avoid browser caching problem + this.fFileContent = null; // this can be full or partial content of the file (if ranges are not supported or if 1K header read from file) + // stored as TBuffer instance + this.fMaxRanges = 200; // maximal number of file ranges requested at once + this.fDirectories = []; + this.fKeys = []; + this.fSeekInfo = 0; + this.fNbytesInfo = 0; + this.fTagOffset = 0; + this.fStreamers = 0; + this.fStreamerInfos = null; + this.fFileName = ""; + this.fStreamers = []; + this.fBasicTypes = {}; // custom basic types, in most case enumerations + + if (typeof this.fURL != 'string') return this; + + if (this.fURL[this.fURL.length-1] === "+") { + this.fURL = this.fURL.substr(0, this.fURL.length-1); + this.fAcceptRanges = false; + } + + if (this.fURL[this.fURL.length-1] === "-") { + this.fURL = this.fURL.substr(0, this.fURL.length-1); + this.fUseStampPar = false; + } + + if (this.fURL.indexOf("file://")==0) { + this.fUseStampPar = false; + this.fAcceptRanges = false; + } + + var pos = Math.max(this.fURL.lastIndexOf("/"), this.fURL.lastIndexOf("\\")); + this.fFileName = pos>=0 ? this.fURL.substr(pos+1) : this.fURL; + + if (!this.fAcceptRanges) { + this.ReadKeys(newfile_callback); + } else { + var file = this; + JSROOT.NewHttpRequest(this.fURL, "head", function(res) { + if (!res) + return JSROOT.CallBack(newfile_callback, null); + + var accept_ranges = res.getResponseHeader("Accept-Ranges"); + if (!accept_ranges) file.fAcceptRanges = false; + var len = res.getResponseHeader("Content-Length"); + if (len) file.fEND = parseInt(len); + else file.fAcceptRanges = false; + file.ReadKeys(newfile_callback); + }).send(null); + } + + return this; + } + + /** @summary read buffer(s) from the file + * @private */ + TFile.prototype.ReadBuffer = function(place, result_callback, filename, progress_callback) { + + if ((this.fFileContent!==null) && !filename && (!this.fAcceptRanges || this.fFileContent.can_extract(place))) + return result_callback(this.fFileContent.extract(place)); + + var file = this, fileurl = file.fURL, + first = 0, last = 0, blobs = [], read_callback; // array of requested segments + + if (filename && (typeof filename === 'string') && (filename.length>0)) { + var pos = fileurl.lastIndexOf("/"); + fileurl = (pos<0) ? filename : fileurl.substr(0,pos+1) + filename; + } + + function send_new_request(increment) { + + if (increment) { + first = last; + last = Math.min(first + file.fMaxRanges*2, place.length); + if (first>=place.length) return result_callback(blobs); + } + + var fullurl = fileurl, ranges = "bytes", totalsz = 0; + // try to avoid browser caching by adding stamp parameter to URL + if (file.fUseStampPar) fullurl += ((fullurl.indexOf('?')<0) ? "?" : "&") + file.fUseStampPar; + + for (var n=first;n<last;n+=2) { + ranges += (n>first ? "," : "=") + (place[n] + "-" + (place[n] + place[n+1] - 1)); + totalsz += place[n+1]; // accumulated total size + } + if (last-first>2) totalsz += (last-first)*60; // for multi-range ~100 bytes/per request + + var xhr = JSROOT.NewHttpRequest(fullurl, "buf", read_callback); + + if (file.fAcceptRanges) { + xhr.setRequestHeader("Range", ranges); + xhr.expected_size = Math.max(Math.round(1.1*totalsz), totalsz+200); // 200 if offset for the potential gzip + } + + if (progress_callback && (typeof xhr.addEventListener === 'function')) { + var sum1 = 0, sum2 = 0, sum_total = 0; + for (var n=1;n<place.length;n+=2) { + sum_total+=place[n]; + if (n<first) sum1+=place[n]; + if (n<last) sum2+=place[n]; + } + if (!sum_total) sum_total = 1; + + var progress_offest = sum1/sum_total, progress_this = (sum2-sum1)/sum_total; + xhr.addEventListener("progress", function updateProgress(oEvent) { + if (oEvent.lengthComputable) + progress_callback(progress_offest + progress_this*oEvent.loaded/oEvent.total); + }); + } + + xhr.send(null); + } + + read_callback = function(res) { + + if (!res && file.fUseStampPar && (place[0]===0) && (place.length===2)) { + // if fail to read file with stamp parameter, try once again without it + file.fUseStampPar = false; + return send_new_request(); + } + + if (res && (place[0]===0) && (place.length===2) && !file.fFileContent) { + // special case - keep content of first request (could be complete file) in memory + + file.fFileContent = JSROOT.CreateTBuffer((typeof res == 'string') ? res : new DataView(res)); + + if (!file.fAcceptRanges) + file.fEND = file.fFileContent.length; + + return result_callback(file.fFileContent.extract(place)); + } + + if (!res) { + if ((first===0) && (last > 2) && (file.fMaxRanges>1)) { + // server return no response with multi request - try to decrease ranges count or fail + + if (last/2 > 200) file.fMaxRanges = 200; else + if (last/2 > 50) file.fMaxRanges = 50; else + if (last/2 > 20) file.fMaxRanges = 20; else + if (last/2 > 5) file.fMaxRanges = 5; else file.fMaxRanges = 1; + last = Math.min(last, file.fMaxRanges*2); + // console.log('Change maxranges to ', file.fMaxRanges, 'last', last); + return send_new_request(); + } + + return result_callback(null); + } + + // if only single segment requested, return result as is + if (last - first === 2) { + var b = new DataView(res); + if (place.length===2) return result_callback(b); + blobs.push(b); + return send_new_request(true); + } + + // object to access response data + var hdr = this.getResponseHeader('Content-Type'), + ismulti = (typeof hdr === 'string') && (hdr.indexOf('multipart')>=0), + view = new DataView(res); + + if (!ismulti) { + // server may returns simple buffer, which combines all segments together + + var hdr_range = this.getResponseHeader('Content-Range'), segm_start = 0, segm_last = -1; + + if (hdr_range && hdr_range.indexOf("bytes")>=0) { + var parts = hdr_range.substr(hdr_range.indexOf("bytes") + 6).split(/[\s-\/]+/); + if (parts.length===3) { + segm_start = parseInt(parts[0]); + segm_last = parseInt(parts[1]); + if (isNaN(segm_start) || isNaN(segm_last) || (segm_start > segm_last)) { + segm_start = 0; segm_last = -1; + } + } + } + + var canbe_single_segment = (segm_start<=segm_last); + for(var n=first;n<last;n+=2) + if ((place[n]<segm_start) || (place[n] + place[n+1] -1 > segm_last)) + canbe_single_segment = false; + + if (canbe_single_segment) { + for (var n=first;n<last;n+=2) + blobs.push(new DataView(res, place[n]-segm_start, place[n+1])); + return send_new_request(true); + } + + console.error('Server returns normal response when multipart was requested, disable multirange support'); + + if ((file.fMaxRanges === 1) || (first!==0)) return result_callback(null); + + file.fMaxRanges = 1; + last = Math.min(last, file.fMaxRanges*2); + + return send_new_request(); + } + + // multipart messages requires special handling + + var indx = hdr.indexOf("boundary="), boundary = "", n = first, o = 0; + if (indx > 0) { + boundary = hdr.substr(indx+9); + if ((boundary[0] == '"') && (boundary[boundary.length-1] == '"')) + boundary = boundary.substr(1, boundary.length-2); + boundary = "--" + boundary; + } else console.error('Did not found boundary id in the response header'); + + while (n<last) { + + var code1, code2 = view.getUint8(o), nline = 0, line = "", + finish_header = false, segm_start = 0, segm_last = -1; + + while((o < view.byteLength-1) && !finish_header && (nline<5)) { + code1 = code2; + code2 = view.getUint8(o+1); + + if ((code1==13) && (code2==10)) { + if ((line.length>2) && (line.substr(0,2)=='--') && (line !== boundary)) { + console.error('Decode multipart message, expect boundary ', boundary, 'got ', line); + return result_callback(null); + } + + line = line.toLowerCase(); + + if ((line.indexOf("content-range")>=0) && (line.indexOf("bytes") > 0)) { + var parts = line.substr(line.indexOf("bytes") + 6).split(/[\s-\/]+/); + if (parts.length===3) { + segm_start = parseInt(parts[0]); + segm_last = parseInt(parts[1]); + if (isNaN(segm_start) || isNaN(segm_last) || (segm_start > segm_last)) { + segm_start = 0; segm_last = -1; + } + } else { + console.error('Fail to decode content-range', line, parts); + } + } + + if ((nline > 1) && (line.length===0)) finish_header = true; + + o++; nline++; line = ""; + code2 = view.getUint8(o+1); + } else { + line += String.fromCharCode(code1); + } + o++; + } + + if (!finish_header) { + console.error('Cannot decode header in multipart message '); + return result_callback(null); + } + + if (segm_start > segm_last) { + // fall-back solution, believe that segments same as requested + blobs.push(new DataView(res, o, place[n+1])); + o += place[n+1]; + n += 2; + } else { + while ((n<last) && (place[n] >= segm_start) && (place[n] + place[n+1] - 1 <= segm_last)) { + blobs.push(new DataView(res, o + place[n] - segm_start, place[n+1])); + n += 2; + } + + o += (segm_last-segm_start+1); + } + } + + send_new_request(true); + } + + send_new_request(true); + } + + /** @summary Get directory with given name and cycle + * @desc Function only can be used for already read directories, which are preserved in the memory + * @private */ + TFile.prototype.GetDir = function(dirname, cycle) { + + if ((cycle === undefined) && (typeof dirname == 'string')) { + var pos = dirname.lastIndexOf(';'); + if (pos>0) { cycle = parseInt(dirname.substr(pos+1)); dirname = dirname.substr(0,pos); } + } + + for (var j=0; j < this.fDirectories.length; ++j) { + var dir = this.fDirectories[j]; + if (dir.dir_name != dirname) continue; + if ((cycle !== undefined) && (dir.dir_cycle !== cycle)) continue; + return dir; + } + return null; + } + + /** @summary Retrieve a key by its name and cycle in the list of keys + * @desc callback used when keys must be read first from the directory + * @private */ + TFile.prototype.GetKey = function(keyname, cycle, getkey_callback) { + + if (typeof cycle != 'number') cycle = -1; + var bestkey = null; + for (var i = 0; i < this.fKeys.length; ++i) { + var key = this.fKeys[i]; + if (!key || (key.fName!==keyname)) continue; + if (key.fCycle == cycle) { bestkey = key; break; } + if ((cycle < 0) && (!bestkey || (key.fCycle > bestkey.fCycle))) bestkey = key; + } + if (bestkey) { + JSROOT.CallBack(getkey_callback, bestkey); + return bestkey; + } + + var pos = keyname.lastIndexOf("/"); + // try to handle situation when object name contains slashed (bad practice anyway) + while (pos > 0) { + var dirname = keyname.substr(0, pos), + subname = keyname.substr(pos+1), + dir = this.GetDir(dirname); + + if (dir) return dir.GetKey(subname, cycle, getkey_callback); + + var dirkey = this.GetKey(dirname); + if (dirkey && getkey_callback && (dirkey.fClassName.indexOf("TDirectory")==0)) { + this.ReadObject(dirname, function(newdir) { + if (newdir) newdir.GetKey(subname, cycle, getkey_callback); + }); + return null; + } + + pos = keyname.lastIndexOf("/", pos-1); + } + + JSROOT.CallBack(getkey_callback, null); + return null; + } + + /** @summary Read and inflate object buffer described by its key + * @private */ + TFile.prototype.ReadObjBuffer = function(key, callback) { + + var file = this; + + this.ReadBuffer([key.fSeekKey + key.fKeylen, key.fNbytes - key.fKeylen], function(blob1) { + + if (!blob1) return callback(null); + + var buf = null; + + if (key.fObjlen <= key.fNbytes - key.fKeylen) { + buf = JSROOT.CreateTBuffer(blob1, 0, file); + } else { + var objbuf = JSROOT.R__unzip(blob1, key.fObjlen); + if (!objbuf) return callback(null); + buf = JSROOT.CreateTBuffer(objbuf, 0, file); + } + + buf.fTagOffset = key.fKeylen; + + callback(buf); + }); + } + + /** @summary Method called when TTree object is streamed + * @private */ + TFile.prototype.AddReadTree = function(obj) { + + if (JSROOT.TreeMethods) + return JSROOT.extend(obj, JSROOT.TreeMethods); + + if (this.readTrees===undefined) this.readTrees = []; + + if (this.readTrees.indexOf(obj)<0) this.readTrees.push(obj); + } + + /** @summary Read any object from a root file + * @desc One could specify cycle number in the object name or as separate argument + * Last argument should be callback function, while data reading from file is asynchron + * @param {string} obj_name - name of object, may include cycle number like "hpxpy;1" + * @param {number} [cycle=undefined] - cycle number + * @param {function} user_call_back - function called when object read from the file + * @param {boolean} [only_dir=false] - if true, only TDirectory derived class will be read + */ + TFile.prototype.ReadObject = function(obj_name, cycle, user_call_back, only_dir) { + if (typeof cycle == 'function') { user_call_back = cycle; cycle = -1; } + + var pos = obj_name.lastIndexOf(";"); + if (pos>0) { + cycle = parseInt(obj_name.slice(pos+1)); + obj_name = obj_name.slice(0, pos); + } + + if (typeof cycle != 'number') cycle = -1; + // remove leading slashes + while (obj_name.length && (obj_name[0] == "/")) obj_name = obj_name.substr(1); + + var file = this; + + // we use callback version while in some cases we need to + // read sub-directory to get list of keys + // in such situation calls are asynchrone + this.GetKey(obj_name, cycle, function(key) { + + if (!key) + return JSROOT.CallBack(user_call_back, null); + + if ((obj_name=="StreamerInfo") && (key.fClassName=="TList")) + return file.fStreamerInfos; + + var isdir = false; + if ((key.fClassName == 'TDirectory' || key.fClassName == 'TDirectoryFile')) { + isdir = true; + var dir = file.GetDir(obj_name, cycle); + if (dir) return JSROOT.CallBack(user_call_back, dir); + } + + if (!isdir && only_dir) + return JSROOT.CallBack(user_call_back, null); + + file.ReadObjBuffer(key, function(buf) { + if (!buf) return JSROOT.CallBack(user_call_back, null); + + if (isdir) { + var dir = new TDirectory(file, obj_name, cycle); + dir.fTitle = key.fTitle; + return dir.ReadKeys(buf, user_call_back); + } + + var obj = {}; + buf.MapObject(1, obj); // tag object itself with id==1 + buf.ClassStreamer(obj, key.fClassName); + + if ((key.fClassName==='TF1') || (key.fClassName==='TF2')) + return file.ReadFormulas(obj, user_call_back, -1); + + if (file.readTrees) + return JSROOT.AssertPrerequisites('tree', function() { + if (file.readTrees) { + file.readTrees.forEach(function(t) { JSROOT.extend(t, JSROOT.TreeMethods); }) + delete file.readTrees; + } + JSROOT.CallBack(user_call_back, obj); + }); + + JSROOT.CallBack(user_call_back, obj); + }); // end of ReadObjBuffer callback + }); // end of GetKey callback + } + + /** @summary read formulas from the file + * @private */ + TFile.prototype.ReadFormulas = function(tf1, user_call_back, cnt) { + + var indx = cnt; + while (++indx < this.fKeys.length) { + if (this.fKeys[indx].fClassName == 'TFormula') break; + } + + if (indx >= this.fKeys.length) + return JSROOT.CallBack(user_call_back, tf1); + + var file = this; + + this.ReadObject(this.fKeys[indx].fName, this.fKeys[indx].fCycle, function(formula) { + tf1.addFormula(formula); + file.ReadFormulas(tf1, user_call_back, indx); + }); + } + + /** @summary extract streamer infos + * @private */ + TFile.prototype.ExtractStreamerInfos = function(buf) { + if (!buf) return; + + var lst = {}; + buf.MapObject(1, lst); + buf.ClassStreamer(lst, 'TList'); + + lst._typename = "TStreamerInfoList"; + + this.fStreamerInfos = lst; + + if (typeof JSROOT.addStreamerInfos === 'function') + JSROOT.addStreamerInfos(lst); + + for (var k=0;k<lst.arr.length;++k) { + var si = lst.arr[k]; + if (!si.fElements) continue; + for (var l=0;l<si.fElements.arr.length;++l) { + var elem = si.fElements.arr[l]; + + if (!elem.fTypeName || !elem.fType) continue; + + var typ = elem.fType, typname = elem.fTypeName; + + if (typ >= 60) { + if ((typ===JSROOT.IO.kStreamer) && (elem._typename=="TStreamerSTL") && elem.fSTLtype && elem.fCtype && (elem.fCtype<20)) { + var prefix = (JSROOT.IO.StlNames[elem.fSTLtype] || "undef") + "<"; + if ((typname.indexOf(prefix)===0) && (typname[typname.length-1] == ">")) { + typ = elem.fCtype; + typname = typname.substr(prefix.length, typname.length-prefix.length-1).trim(); + + if ((elem.fSTLtype === JSROOT.IO.kSTLmap) || (elem.fSTLtype === JSROOT.IO.kSTLmultimap)) + if (typname.indexOf(",")>0) typname = typname.substr(0, typname.indexOf(",")).trim(); + else continue; + } + } + if (typ>=60) continue; + } else { + if ((typ>20) && (typname[typname.length-1]=="*")) typname = typname.substr(0,typname.length-1); + typ = typ % 20; + } + + var kind = JSROOT.IO.GetTypeId(typname); + if (kind === typ) continue; + + if ((typ === JSROOT.IO.kBits) && (kind===JSROOT.IO.kUInt)) continue; + if ((typ === JSROOT.IO.kCounter) && (kind===JSROOT.IO.kInt)) continue; + + if (typname && typ && (this.fBasicTypes[typname]!==typ)) { + this.fBasicTypes[typname] = typ; + if (!JSROOT.BatchMode) console.log('Extract basic data type', typ, typname); + } + } + } + } + + /** @summary Read file keys + * @private */ + TFile.prototype.ReadKeys = function(readkeys_callback) { + + var file = this; + + // with the first readbuffer we read bigger amount to create header cache + this.ReadBuffer([0, 1024], function(blob) { + if (!blob) return JSROOT.CallBack(readkeys_callback, null); + + var buf = JSROOT.CreateTBuffer(blob, 0, file); + + if (buf.substring(0, 4) !== 'root') { + JSROOT.alert("NOT A ROOT FILE! " + file.fURL); + return JSROOT.CallBack(readkeys_callback, null); + } + buf.shift(4); + + file.fVersion = buf.ntou4(); + file.fBEGIN = buf.ntou4(); + if (file.fVersion < 1000000) { //small file + file.fEND = buf.ntou4(); + file.fSeekFree = buf.ntou4(); + file.fNbytesFree = buf.ntou4(); + buf.shift(4); // var nfree = buf.ntoi4(); + file.fNbytesName = buf.ntou4(); + file.fUnits = buf.ntou1(); + file.fCompress = buf.ntou4(); + file.fSeekInfo = buf.ntou4(); + file.fNbytesInfo = buf.ntou4(); + } else { // new format to support large files + file.fEND = buf.ntou8(); + file.fSeekFree = buf.ntou8(); + file.fNbytesFree = buf.ntou4(); + buf.shift(4); // var nfree = buf.ntou4(); + file.fNbytesName = buf.ntou4(); + file.fUnits = buf.ntou1(); + file.fCompress = buf.ntou4(); + file.fSeekInfo = buf.ntou8(); + file.fNbytesInfo = buf.ntou4(); + } + + // empty file + if (!file.fSeekInfo || !file.fNbytesInfo) + return JSROOT.CallBack(readkeys_callback, null); + + // extra check to prevent reading of corrupted data + if (!file.fNbytesName || file.fNbytesName > 100000) { + JSROOT.console("Init : cannot read directory info of file " + file.fURL); + return JSROOT.CallBack(readkeys_callback, null); + } + + //*-*-------------Read directory info + var nbytes = file.fNbytesName + 22; + nbytes += 4; // fDatimeC.Sizeof(); + nbytes += 4; // fDatimeM.Sizeof(); + nbytes += 18; // fUUID.Sizeof(); + // assume that the file may be above 2 Gbytes if file version is > 4 + if (file.fVersion >= 40000) nbytes += 12; + + // this part typically read from the header, no need to optimize + file.ReadBuffer([file.fBEGIN, Math.max(300, nbytes)], function(blob3) { + if (!blob3) return JSROOT.CallBack(readkeys_callback, null); + + var buf3 = JSROOT.CreateTBuffer(blob3, 0, file); + + // keep only title from TKey data + file.fTitle = buf3.ReadTKey().fTitle; + + buf3.locate(file.fNbytesName); + + // we read TDirectory part of TFile + buf3.ClassStreamer(file,'TDirectory'); + + if (!file.fSeekKeys) { + JSROOT.console("Empty keys list in " + file.fURL); + return JSROOT.CallBack(readkeys_callback, null); + } + + // read with same request keys and streamer infos + file.ReadBuffer([file.fSeekKeys, file.fNbytesKeys, file.fSeekInfo, file.fNbytesInfo], function(blobs) { + + if (!blobs) return JSROOT.CallBack(readkeys_callback, null); + + var buf4 = JSROOT.CreateTBuffer(blobs[0], 0, file); + + buf4.ReadTKey(); // + var nkeys = buf4.ntoi4(); + for (var i = 0; i < nkeys; ++i) + file.fKeys.push(buf4.ReadTKey()); + + var buf5 = JSROOT.CreateTBuffer(blobs[1], 0, file), + si_key = buf5.ReadTKey(); + if (!si_key) return JSROOT.CallBack(readkeys_callback, null); + + file.fKeys.push(si_key); + file.ReadObjBuffer(si_key, function(blob6) { + if (blob6) file.ExtractStreamerInfos(blob6); + + return JSROOT.CallBack(readkeys_callback, file); + }); + }); + }); + }); + } + + /** @summary Read the directory content from a root file + * @desc If directory was already read - return previously read object + * Same functionality as {@link TFile.ReadObject} + * @param {string} dir_name - directory name + * @param {number} cycle - directory cycle + * @param {function} readdir_callback - callback with read directory */ + TFile.prototype.ReadDirectory = function(dir_name, cycle, readdir_callback) { + this.ReadObject(dir_name, cycle, readdir_callback, true); + } + + JSROOT.IO.AddClassMethods = function(clname, streamer) { + // create additional entries in the streamer, which sets all methods of the class + + if (streamer === null) return streamer; + + var methods = JSROOT.getMethods(clname); + + if (methods !== null) + for (var key in methods) + if ((typeof methods[key] === 'function') || (key.indexOf("_")==0)) + streamer.push({ + name: key, + method: methods[key], + func: function(buf,obj) { obj[this.name] = this.method; } + }); + + return streamer; + } + + /** @summary Search for class streamer info + * @private */ + TFile.prototype.FindStreamerInfo = function(clname, clversion, clchecksum) { + if (this.fStreamerInfos) + for (var i=0; i < this.fStreamerInfos.arr.length; ++i) { + var si = this.fStreamerInfos.arr[i]; + + // checksum is enough to identify class + if ((clchecksum !== undefined) && (si.fCheckSum === clchecksum)) return si; + + if (si.fName !== clname) continue; + + // checksum should match + if (clchecksum !== undefined) continue; + + if ((clversion !== undefined) && (si.fClassVersion !== clversion)) continue; + + return si; + } + + return null; + } + + TFile.prototype.FindSinfoCheckum = function(checksum) { + if (!this.fStreamerInfos) return null; + + var cache = this.fStreamerInfos.cache, + arr = this.fStreamerInfos.arr; + if (!cache) cache = this.fStreamerInfos.cache = {}; + + var si = cache[checksum]; + if (si !== undefined) return si; + + for (var i=0; i < arr.length; ++i) { + si = arr[i]; + if (si.fCheckSum === checksum) { + cache[checksum] = si; + return si; + } + } + + cache[checksum] = null; // checksum didnot found, not try again + return null; + } + + JSROOT.IO.GetPairStreamer = function(si, typname, file) { + + if (!si) { + if (typname.indexOf("pair")!==0) return null; + + si = file.FindStreamerInfo(typname); + + if (!si) { + var p1 = typname.indexOf("<"), p2 = typname.lastIndexOf(">"); + function GetNextName() { + var res = "", p = p1+1, cnt = 0; + while ((p<p2) && (cnt>=0)) { + switch (typname[p]) { + case "<": cnt++; break; + case ",": if (cnt===0) cnt--; break; + case ">": cnt--; break; + } + if (cnt>=0) res+=typname[p]; + p++; + } + p1 = p-1; + return res.trim(); + } + si = { _typename: 'TStreamerInfo', fVersion: 1, fName: typname, fElements: JSROOT.Create("TList") }; + si.fElements.Add(JSROOT.IO.CreateStreamerElement("first", GetNextName(), file)); + si.fElements.Add(JSROOT.IO.CreateStreamerElement("second", GetNextName(), file)); + } + } + + var streamer = file.GetStreamer(typname, null, si); + + if (!streamer) return null; + + if (streamer.length!==2) { + console.error('Streamer for pair class contains ', streamer.length,'elements'); + return null; + + } + + for (var nn=0;nn<2;++nn) + if (streamer[nn].readelem && !streamer[nn].pair_name) { + streamer[nn].pair_name = (nn==0) ? "first" : "second"; + streamer[nn].func = function(buf, obj) { + obj[this.pair_name] = this.readelem(buf); + } + } + + return streamer; + } + + JSROOT.IO.CreateMember = function(element, file) { + // create member entry for streamer element, which is used for reading of such data + + var member = { name: element.fName, type: element.fType, + fArrayLength: element.fArrayLength, + fArrayDim: element.fArrayDim, + fMaxIndex: element.fMaxIndex }; + + if (element.fTypeName === 'BASE') { + if (JSROOT.IO.GetArrayKind(member.name) > 0) { + // this is workaround for arrays as base class + // we create 'fArray' member, which read as any other data member + member.name = 'fArray'; + member.type = JSROOT.IO.kAny; + } else { + // create streamer for base class + member.type = JSROOT.IO.kBase; + // this.GetStreamer(element.fName); + } + } + + switch (member.type) { + case JSROOT.IO.kBase: + member.base = element.fBaseVersion; // indicate base class + member.basename = element.fName; // keep class name + member.func = function(buf, obj) { buf.ClassStreamer(obj, this.basename); }; + break; + case JSROOT.IO.kShort: + member.func = function(buf,obj) { obj[this.name] = buf.ntoi2(); }; break; + case JSROOT.IO.kInt: + case JSROOT.IO.kCounter: + member.func = function(buf,obj) { obj[this.name] = buf.ntoi4(); }; break; + case JSROOT.IO.kLong: + case JSROOT.IO.kLong64: + member.func = function(buf,obj) { obj[this.name] = buf.ntoi8(); }; break; + case JSROOT.IO.kDouble: + member.func = function(buf,obj) { obj[this.name] = buf.ntod(); }; break; + case JSROOT.IO.kFloat: + member.func = function(buf,obj) { obj[this.name] = buf.ntof(); }; break; + case JSROOT.IO.kLegacyChar: + case JSROOT.IO.kUChar: + member.func = function(buf,obj) { obj[this.name] = buf.ntou1(); }; break; + case JSROOT.IO.kUShort: + member.func = function(buf,obj) { obj[this.name] = buf.ntou2(); }; break; + case JSROOT.IO.kBits: + case JSROOT.IO.kUInt: + member.func = function(buf,obj) { obj[this.name] = buf.ntou4(); }; break; + case JSROOT.IO.kULong64: + case JSROOT.IO.kULong: + member.func = function(buf,obj) { obj[this.name] = buf.ntou8(); }; break; + case JSROOT.IO.kBool: + member.func = function(buf,obj) { obj[this.name] = buf.ntou1() != 0; }; break; + case JSROOT.IO.kOffsetL+JSROOT.IO.kBool: + case JSROOT.IO.kOffsetL+JSROOT.IO.kInt: + case JSROOT.IO.kOffsetL+JSROOT.IO.kCounter: + case JSROOT.IO.kOffsetL+JSROOT.IO.kDouble: + case JSROOT.IO.kOffsetL+JSROOT.IO.kUChar: + case JSROOT.IO.kOffsetL+JSROOT.IO.kShort: + case JSROOT.IO.kOffsetL+JSROOT.IO.kUShort: + case JSROOT.IO.kOffsetL+JSROOT.IO.kBits: + case JSROOT.IO.kOffsetL+JSROOT.IO.kUInt: + case JSROOT.IO.kOffsetL+JSROOT.IO.kULong: + case JSROOT.IO.kOffsetL+JSROOT.IO.kULong64: + case JSROOT.IO.kOffsetL+JSROOT.IO.kLong: + case JSROOT.IO.kOffsetL+JSROOT.IO.kLong64: + case JSROOT.IO.kOffsetL+JSROOT.IO.kFloat: + if (element.fArrayDim < 2) { + member.arrlength = element.fArrayLength; + member.func = function(buf, obj) { + obj[this.name] = buf.ReadFastArray(this.arrlength, this.type - JSROOT.IO.kOffsetL); + }; + } else { + member.arrlength = element.fMaxIndex[element.fArrayDim-1]; + member.minus1 = true; + member.func = function(buf, obj) { + obj[this.name] = buf.ReadNdimArray(this, function(buf,handle) { + return buf.ReadFastArray(handle.arrlength, handle.type - JSROOT.IO.kOffsetL); + }); + }; + } + break; + case JSROOT.IO.kOffsetL+JSROOT.IO.kChar: + if (element.fArrayDim < 2) { + member.arrlength = element.fArrayLength; + member.func = function(buf, obj) { + obj[this.name] = buf.ReadFastString(this.arrlength); + }; + } else { + member.minus1 = true; // one dimension used for char* + member.arrlength = element.fMaxIndex[element.fArrayDim-1]; + member.func = function(buf, obj) { + obj[this.name] = buf.ReadNdimArray(this, function(buf,handle) { + return buf.ReadFastString(handle.arrlength); + }); + }; + } + break; + case JSROOT.IO.kOffsetP+JSROOT.IO.kBool: + case JSROOT.IO.kOffsetP+JSROOT.IO.kInt: + case JSROOT.IO.kOffsetP+JSROOT.IO.kDouble: + case JSROOT.IO.kOffsetP+JSROOT.IO.kUChar: + case JSROOT.IO.kOffsetP+JSROOT.IO.kShort: + case JSROOT.IO.kOffsetP+JSROOT.IO.kUShort: + case JSROOT.IO.kOffsetP+JSROOT.IO.kBits: + case JSROOT.IO.kOffsetP+JSROOT.IO.kUInt: + case JSROOT.IO.kOffsetP+JSROOT.IO.kULong: + case JSROOT.IO.kOffsetP+JSROOT.IO.kULong64: + case JSROOT.IO.kOffsetP+JSROOT.IO.kLong: + case JSROOT.IO.kOffsetP+JSROOT.IO.kLong64: + case JSROOT.IO.kOffsetP+JSROOT.IO.kFloat: + member.cntname = element.fCountName; + member.func = function(buf, obj) { + if (buf.ntou1() === 1) + obj[this.name] = buf.ReadFastArray(obj[this.cntname], this.type - JSROOT.IO.kOffsetP); + else + obj[this.name] = new Array(); + }; + break; + case JSROOT.IO.kOffsetP+JSROOT.IO.kChar: + member.cntname = element.fCountName; + member.func = function(buf, obj) { + if (buf.ntou1() === 1) + obj[this.name] = buf.ReadFastString(obj[this.cntname]); + else + obj[this.name] = null; + }; + break; + case JSROOT.IO.kDouble32: + case JSROOT.IO.kOffsetL+JSROOT.IO.kDouble32: + case JSROOT.IO.kOffsetP+JSROOT.IO.kDouble32: + member.double32 = true; + case JSROOT.IO.kFloat16: + case JSROOT.IO.kOffsetL+JSROOT.IO.kFloat16: + case JSROOT.IO.kOffsetP+JSROOT.IO.kFloat16: + if (element.fFactor!==0) { + member.factor = 1./element.fFactor; + member.min = element.fXmin; + member.read = function(buf) { return buf.ntou4() * this.factor + this.min; }; + } else + if ((element.fXmin===0) && member.double32) { + member.read = function(buf) { return buf.ntof(); }; + } else { + member.nbits = Math.round(element.fXmin); + if (member.nbits===0) member.nbits = 12; + member.dv = new DataView(new ArrayBuffer(8), 0); // used to cast from uint32 to float32 + member.read = function(buf) { + var theExp = buf.ntou1(), theMan = buf.ntou2(); + this.dv.setUint32(0, (theExp << 23) | ((theMan & ((1<<(this.nbits+1))-1)) << (23-this.nbits))); + return ((1<<(this.nbits+1) & theMan) ? -1 : 1) * this.dv.getFloat32(0); + }; + } + + member.readarr = function(buf,len) { + var arr = this.double32 ? new Float64Array(len) : new Float32Array(len); + for (var n=0;n<len;++n) arr[n] = this.read(buf); + return arr; + } + + if (member.type < JSROOT.IO.kOffsetL) { + member.func = function(buf,obj) { obj[this.name] = this.read(buf); } + } else + if (member.type > JSROOT.IO.kOffsetP) { + member.cntname = element.fCountName; + member.func = function(buf, obj) { + if (buf.ntou1() === 1) { + obj[this.name] = this.readarr(buf, obj[this.cntname]); + } else { + obj[this.name] = null; + } + }; + } else + if (element.fArrayDim < 2) { + member.arrlength = element.fArrayLength; + member.func = function(buf, obj) { obj[this.name] = this.readarr(buf, this.arrlength); }; + } else { + member.arrlength = element.fMaxIndex[element.fArrayDim-1]; + member.minus1 = true; + member.func = function(buf, obj) { + obj[this.name] = buf.ReadNdimArray(this, function(buf,handle) { return handle.readarr(buf, handle.arrlength); }); + }; + } + break; + + case JSROOT.IO.kAnyP: + case JSROOT.IO.kObjectP: + member.func = function(buf, obj) { + obj[this.name] = buf.ReadNdimArray(this, function(buf) { + return buf.ReadObjectAny(); + }); + }; + break; + + case JSROOT.IO.kAny: + case JSROOT.IO.kAnyp: + case JSROOT.IO.kObjectp: + case JSROOT.IO.kObject: + var classname = (element.fTypeName === 'BASE') ? element.fName : element.fTypeName; + if (classname[classname.length-1] == "*") + classname = classname.substr(0, classname.length - 1); + + var arrkind = JSROOT.IO.GetArrayKind(classname); + + if (arrkind > 0) { + member.arrkind = arrkind; + member.func = function(buf, obj) { + obj[this.name] = buf.ReadFastArray(buf.ntou4(), this.arrkind); + }; + } else + if (arrkind === 0) { + member.func = function(buf,obj) { obj[this.name] = buf.ReadTString(); }; + } else { + member.classname = classname; + + if (element.fArrayLength>1) { + member.func = function(buf, obj) { + obj[this.name] = buf.ReadNdimArray(this, function(buf, handle) { + return buf.ClassStreamer({}, handle.classname); + }); + }; + } else { + member.func = function(buf, obj) { + obj[this.name] = buf.ClassStreamer({}, this.classname); + }; + } + } + break; + case JSROOT.IO.kOffsetL + JSROOT.IO.kObject: + case JSROOT.IO.kOffsetL + JSROOT.IO.kAny: + case JSROOT.IO.kOffsetL + JSROOT.IO.kAnyp: + case JSROOT.IO.kOffsetL + JSROOT.IO.kObjectp: + var classname = element.fTypeName; + if (classname[classname.length-1] == "*") + classname = classname.substr(0, classname.length - 1); + + member.arrkind = JSROOT.IO.GetArrayKind(classname); + if (member.arrkind < 0) member.classname = classname; + member.func = function(buf, obj) { + obj[this.name] = buf.ReadNdimArray(this, function(buf, handle) { + if (handle.arrkind>0) return buf.ReadFastArray(buf.ntou4(), handle.arrkind); + if (handle.arrkind===0) return buf.ReadTString(); + return buf.ClassStreamer({}, handle.classname); + }); + } + break; + case JSROOT.IO.kChar: + member.func = function(buf,obj) { obj[this.name] = buf.ntoi1(); }; break; + case JSROOT.IO.kCharStar: + member.func = function(buf,obj) { + var len = buf.ntoi4(); + obj[this.name] = buf.substring(buf.o, buf.o + len); + buf.o += len; + }; + break; + case JSROOT.IO.kTString: + member.func = function(buf,obj) { obj[this.name] = buf.ReadTString(); }; + break; + case JSROOT.IO.kTObject: + case JSROOT.IO.kTNamed: + member.typename = element.fTypeName; + member.func = function(buf,obj) { obj[this.name] = buf.ClassStreamer({}, this.typename); }; + break; + case JSROOT.IO.kOffsetL+JSROOT.IO.kTString: + case JSROOT.IO.kOffsetL+JSROOT.IO.kTObject: + case JSROOT.IO.kOffsetL+JSROOT.IO.kTNamed: + member.typename = element.fTypeName; + member.func = function(buf, obj) { + var ver = buf.ReadVersion(); + obj[this.name] = buf.ReadNdimArray(this, function(buf, handle) { + if (handle.typename === 'TString') return buf.ReadTString(); + return buf.ClassStreamer({}, handle.typename); + }); + buf.CheckBytecount(ver, this.typename + "[]"); + }; + break; + case JSROOT.IO.kStreamLoop: + case JSROOT.IO.kOffsetL+JSROOT.IO.kStreamLoop: + member.typename = element.fTypeName; + member.cntname = element.fCountName; + + if (member.typename.lastIndexOf("**")>0) { + member.typename = member.typename.substr(0, member.typename.lastIndexOf("**")); + member.isptrptr = true; + } else { + member.typename = member.typename.substr(0, member.typename.lastIndexOf("*")); + member.isptrptr = false; + } + + if (member.isptrptr) { + member.readitem = function(buf) { return buf.ReadObjectAny(); } + } else { + member.arrkind = JSROOT.IO.GetArrayKind(member.typename); + if (member.arrkind > 0) + member.readitem = function(buf) { return buf.ReadFastArray(buf.ntou4(), this.arrkind); } + else if (member.arrkind === 0) + member.readitem = function(buf) { return buf.ReadTString(); } + else + member.readitem = function(buf) { return buf.ClassStreamer({}, this.typename); } + } + + if (member.readitem !== undefined) { + member.read_loop = function(buf,cnt) { + return buf.ReadNdimArray(this, function(buf2,member2) { + var itemarr = new Array(cnt); + for (var i = 0; i < cnt; ++i ) + itemarr[i] = member2.readitem(buf2); + return itemarr; + }); + } + + member.func = function(buf,obj) { + var ver = buf.ReadVersion(); + var res = this.read_loop(buf, obj[this.cntname]); + if (!buf.CheckBytecount(ver, this.typename)) res = null; + obj[this.name] = res; + } + member.branch_func = function(buf,obj) { + // this is special functions, used by branch in the STL container + + var ver = buf.ReadVersion(), sz0 = obj[this.stl_size], res = new Array(sz0); + + for (var loop0=0;loop0<sz0;++loop0) { + var cnt = obj[this.cntname][loop0]; + res[loop0] = this.read_loop(buf, cnt); + } + if (!buf.CheckBytecount(ver, this.typename)) res = null; + obj[this.name] = res; + } + + member.objs_branch_func = function(buf,obj) { + // special function when branch read as part of complete object + // objects already preallocated and only appropriate member must be set + // see code in JSRootTree.js for reference + + var ver = buf.ReadVersion(), arr = obj[this.name0]; // objects array where reading is done + + for (var loop0=0;loop0<arr.length;++loop0) { + var obj1 = this.get(arr,loop0), cnt = obj1[this.cntname]; + obj1[this.name] = this.read_loop(buf, cnt); + } + + buf.CheckBytecount(ver, this.typename); + } + + } else { + JSROOT.console('fail to provide function for ' + element.fName + ' (' + element.fTypeName + ') typ = ' + element.fType); + member.func = function(buf,obj) { + var ver = buf.ReadVersion(); + buf.CheckBytecount(ver); + obj[this.name] = ull; + }; + } + + break; + + case JSROOT.IO.kStreamer: + member.typename = element.fTypeName; + + var stl = (element.fSTLtype || 0) % 40; + + if ((element._typename === 'TStreamerSTLstring') || + (member.typename == "string") || (member.typename == "string*")) { + member.readelem = function(buf) { return buf.ReadTString(); }; + } else + if ((stl === JSROOT.IO.kSTLvector) || (stl === JSROOT.IO.kSTLlist) || + (stl === JSROOT.IO.kSTLdeque) || (stl === JSROOT.IO.kSTLset) || + (stl === JSROOT.IO.kSTLmultiset)) { + var p1 = member.typename.indexOf("<"), + p2 = member.typename.lastIndexOf(">"); + + member.conttype = member.typename.substr(p1+1,p2-p1-1).trim(); + + member.typeid = JSROOT.IO.GetTypeId(member.conttype); + if ((member.typeid<0) && file.fBasicTypes[member.conttype]) { + member.typeid = file.fBasicTypes[member.conttype]; + console.log('!!! Reuse basic type', member.conttype, 'from file streamer infos'); + } + + // check + if (element.fCtype && (element.fCtype < 20) && (element.fCtype !== member.typeid)) { + console.warn('Contained type', member.conttype, 'not recognized as basic type', element.fCtype, 'FORCE'); + member.typeid = element.fCtype; + } + + if (member.typeid > 0) { + member.readelem = function(buf) { + return buf.ReadFastArray(buf.ntoi4(), this.typeid); + }; + } else { + member.isptr = false; + + if (member.conttype.lastIndexOf("*") === member.conttype.length-1) { + member.isptr = true; + member.conttype = member.conttype.substr(0,member.conttype.length-1); + } + + if (element.fCtype === JSROOT.IO.kObjectp) member.isptr = true; + + member.arrkind = JSROOT.IO.GetArrayKind(member.conttype); + + member.readelem = JSROOT.IO.ReadVectorElement; + + if (!member.isptr && (member.arrkind<0)) { + + var subelem = JSROOT.IO.CreateStreamerElement("temp", member.conttype); + + if (subelem.fType === JSROOT.IO.kStreamer) { + subelem.$fictional = true; + member.submember = JSROOT.IO.CreateMember(subelem, file); + } + } + } + } else + if ((stl === JSROOT.IO.kSTLmap) || (stl === JSROOT.IO.kSTLmultimap)) { + + var p1 = member.typename.indexOf("<"), + p2 = member.typename.lastIndexOf(">"); + + member.pairtype = "pair<" + member.typename.substr(p1+1,p2-p1-1) + ">"; + + // remember found streamer info from the file - + // most probably it is the only one which should be used + member.si = file.FindStreamerInfo(member.pairtype); + + member.streamer = JSROOT.IO.GetPairStreamer(member.si, member.pairtype, file); + + if (!member.streamer || (member.streamer.length!==2)) { + JSROOT.console('Fail to build streamer for pair ' + member.pairtype); + delete member.streamer; + } + + if (member.streamer) member.readelem = JSROOT.IO.ReadMapElement; + } else + if (stl === JSROOT.IO.kSTLbitset) { + member.readelem = function(buf,obj) { + return buf.ReadFastArray(buf.ntou4(), JSROOT.IO.kBool); + } + } + + if (!member.readelem) { + JSROOT.console('failed to create streamer for element ' + member.typename + ' ' + member.name + ' element ' + element._typename + ' STL type ' + element.fSTLtype); + member.func = function(buf,obj) { + var ver = buf.ReadVersion(); + buf.CheckBytecount(ver); + obj[this.name] = null; + } + } else + if (!element.$fictional) { + + member.read_version = function(buf, cnt) { + if (cnt===0) return null; + var o = buf.o, ver = buf.ReadVersion(); + this.member_wise = ((ver.val & JSROOT.IO.kStreamedMemberWise) !== 0); + this.stl_version = undefined; + if (this.member_wise) { + this.stl_version = { val: buf.ntoi2() }; + if (this.stl_version.val<=0) this.stl_version.checksum = buf.ntou4(); + } + return ver; + } + + member.func = function(buf,obj) { + var ver = this.read_version(buf); + + var res = buf.ReadNdimArray(this, function(buf2,member2) { return member2.readelem(buf2); }); + + if (!buf.CheckBytecount(ver, this.typename)) res = null; + obj[this.name] = res; + } + + member.branch_func = function(buf,obj) { + // special function to read data from STL branch + var cnt = obj[this.stl_size], arr = new Array(cnt); + + var ver = this.read_version(buf, cnt); + + for (var n=0;n<cnt;++n) + arr[n] = buf.ReadNdimArray(this, function(buf2,member2) { return member2.readelem(buf2); }); + + if (ver) buf.CheckBytecount(ver, "branch " + this.typename); + + obj[this.name] = arr; + } + member.split_func = function(buf, arr, n) { + // function to read array from member-wise streaming + var ver = this.read_version(buf); + for (var i=0;i<n;++i) + arr[i][this.name] = buf.ReadNdimArray(this, function(buf2,member2) { return member2.readelem(buf2); }); + buf.CheckBytecount(ver, this.typename); + } + member.objs_branch_func = function(buf,obj) { + // special function when branch read as part of complete object + // objects already preallocated and only appropriate member must be set + // see code in JSRootTree.js for reference + + var arr = obj[this.name0]; // objects array where reading is done + + var ver = this.read_version(buf, arr.length); + + for (var n=0;n<arr.length;++n) { + var obj1 = this.get(arr,n); + obj1[this.name] = buf.ReadNdimArray(this, function(buf2,member2) { return member2.readelem(buf2); }); + } + + if (ver) buf.CheckBytecount(ver, "branch " + this.typename); + } + } + break; + + default: + JSROOT.console('fail to provide function for ' + element.fName + ' (' + element.fTypeName + ') typ = ' + element.fType); + + member.func = function(buf,obj) {}; // do nothing, fix in the future + } + + return member; + } + + /** @summary Returns streamer for the class 'clname', + * @desc From the list of streamers or generate it from the streamer infos and add it to the list + * @private */ + TFile.prototype.GetStreamer = function(clname, ver, s_i) { + + // these are special cases, which are handled separately + if (clname == 'TQObject' || clname == "TBasket") return null; + + var streamer, fullname = clname; + + if (ver) { + fullname += (ver.checksum ? ("$chksum" + ver.checksum) : ("$ver" + ver.val)); + streamer = this.fStreamers[fullname]; + if (streamer !== undefined) return streamer; + } + + var custom = JSROOT.IO.CustomStreamers[clname]; + + // one can define in the user streamers just aliases + if (typeof custom === 'string') + return this.GetStreamer(custom, ver, s_i); + + // streamer is just separate function + if (typeof custom === 'function') { + streamer = [{ typename: clname, func: custom }]; + return JSROOT.IO.AddClassMethods(clname, streamer); + } + + streamer = []; + + if (typeof custom === 'object') { + if (!custom.name && !custom.func) return custom; + streamer.push(custom); // special read entry, add in the beginning of streamer + } + + // check element in streamer infos, one can have special cases + if (!s_i) s_i = this.FindStreamerInfo(clname, ver.val, ver.checksum); + + if (!s_i) { + delete this.fStreamers[fullname]; + if (!ver.nowarning) + console.warn("Not found streamer for", clname, "ver", ver.val, "checksum", ver.checksum, fullname); + return null; + } + + // for each entry in streamer info produce member function + + if (s_i.fElements) + for (var j=0; j < s_i.fElements.arr.length; ++j) + streamer.push(JSROOT.IO.CreateMember(s_i.fElements.arr[j], this)); + + this.fStreamers[fullname] = streamer; + + return JSROOT.IO.AddClassMethods(clname, streamer); + } + + /** @summary Here we produce list of members, resolving all base classes + * @private */ + TFile.prototype.GetSplittedStreamer = function(streamer, tgt) { + if (!streamer) return tgt; + + if (!tgt) tgt = []; + + for (var n=0;n<streamer.length;++n) { + var elem = streamer[n]; + + if (elem.base === undefined) { + tgt.push(elem); + continue; + } + + if (elem.basename == 'TObject') { + tgt.push({ func: function(buf,obj) { + buf.ntoi2(); // read version, why it here?? + obj.fUniqueID = buf.ntou4(); + obj.fBits = buf.ntou4(); + if (obj.fBits & JSROOT.IO.kIsReferenced) buf.ntou2(); // skip pid + } }); + continue; + } + + var ver = { val: elem.base }; + + if (ver.val === 4294967295) { + // this is -1 and indicates foreign class, need more workarounds + ver.val = 1; // need to search version 1 - that happens when several versions of foreign class exists ??? + } + + var parent = this.GetStreamer(elem.basename, ver); + if (parent) this.GetSplittedStreamer(parent, tgt); + } + + return tgt; + } + + TFile.prototype.Delete = function() { + this.fDirectories = null; + this.fKeys = null; + this.fStreamers = null; + this.fSeekInfo = 0; + this.fNbytesInfo = 0; + this.fTagOffset = 0; + } + + // ============================================================= + + function TLocalFile(file, newfile_callback) { + TFile.call(this, null); + this.fUseStampPar = false; + this.fLocalFile = file; + this.fEND = file.size; + this.fFullURL = file.name; + this.fURL = file.name; + this.fFileName = file.name; + this.ReadKeys(newfile_callback); + return this; + } + + TLocalFile.prototype = Object.create(TFile.prototype); + + TLocalFile.prototype.ReadBuffer = function(place, result_callback, filename, progress_callback) { + + if (filename) + throw new Error("Cannot access other local file "+filename) + + var reader = new FileReader(), cnt = 0, blobs = [], file = this.fLocalFile; + + reader.onload = function(evnt) { + var res = new DataView(evnt.target.result); + if (place.length===2) return result_callback(res); + + blobs.push(res); + cnt+=2; + if (cnt >= place.length) return result_callback(blobs); + reader.readAsArrayBuffer(file.slice(place[cnt], place[cnt]+place[cnt+1])); + } + + reader.readAsArrayBuffer(file.slice(place[0], place[0]+place[1])); + } + + // ============================================================= + + function TNodejsFile(filename, newfile_callback) { + TFile.call(this, null); + this.fUseStampPar = false; + this.fEND = 0; + this.fFullURL = filename; + this.fURL = filename; + this.fFileName = filename; + + var pthis = this; + + pthis.fs = require('fs'); + + pthis.fs.open(filename, 'r', function(status, fd) { + if (status) { + console.log(status.message); + return JSROOT.CallBack(newfile_callback, null); + } + var stats = pthis.fs.fstatSync(fd); + + pthis.fEND = stats.size; + + pthis.fd = fd; + + // return JSROOT.CallBack(newfile_callback, pthis); + + pthis.ReadKeys(newfile_callback); + + //var buffer = new Buffer(100); + //fs.read(fd, buffer, 0, 100, 0, function(err, num) { + // console.log(buffer.toString('utf8', 0, num)); + //}); + }); + return this; + } + + TNodejsFile.prototype = Object.create(TFile.prototype); + + TNodejsFile.prototype.ReadBuffer = function(place, result_callback, filename, progress_callback) { + + if (filename) + throw new Error("Cannot access other local file "+filename); + + if (!this.fs || !this.fd) + throw new Error("File is not opened " + this.fFileName); + + var cnt = 0, blobs = [], file = this; + + function readfunc(err, bytesRead, buf) { + + var res = new DataView(buf.buffer, buf.byteOffset, place[cnt+1]); + if (place.length===2) return result_callback(res); + + blobs.push(res); + cnt+=2; + if (cnt >= place.length) return result_callback(blobs); + file.fs.read(file.fd, new Buffer(place[cnt+1]), 0, place[cnt+1], place[cnt], readfunc); + } + + file.fs.read(file.fd, new Buffer(place[1]), 0, place[1], place[0], readfunc); + } + + // ========================================= + + + JSROOT.IO.ProduceCustomStreamers = function() { + var cs = JSROOT.IO.CustomStreamers; + + cs['TObject'] = cs['TMethodCall'] = function(buf,obj) { + obj.fUniqueID = buf.ntou4(); + obj.fBits = buf.ntou4(); + if (obj.fBits & JSROOT.IO.kIsReferenced) buf.ntou2(); // skip pid + }; + + cs['TNamed'] = [ + { basename: 'TObject', base: 1, func: function(buf,obj) { + if (!obj._typename) obj._typename = 'TNamed'; + buf.ClassStreamer(obj, "TObject"); } + }, + { name: 'fName', func: function(buf,obj) { obj.fName = buf.ReadTString(); } }, + { name: 'fTitle', func: function(buf,obj) { obj.fTitle = buf.ReadTString(); } } + ]; + JSROOT.IO.AddClassMethods('TNamed', cs['TNamed']); + + cs['TObjString'] = [ + { basename: 'TObject', base: 1, func: function(buf,obj) { + if (!obj._typename) obj._typename = 'TObjString'; + buf.ClassStreamer(obj, "TObject"); } + }, + { name: 'fString', func: function(buf, obj) { obj.fString = buf.ReadTString(); } } + ]; + + JSROOT.IO.AddClassMethods('TObjString', cs['TObjString']); + + cs['TList'] = cs['THashList'] = function(buf, obj) { + // stream all objects in the list from the I/O buffer + if (!obj._typename) obj._typename = this.typename; + obj.$kind = "TList"; // all derived classes will be marked as well + if (buf.last_read_version > 3) { + buf.ClassStreamer(obj, "TObject"); + obj.name = buf.ReadTString(); + var nobjects = buf.ntou4(), i = 0; + obj.arr = new Array(nobjects); + obj.opt = new Array(nobjects); + for (; i<nobjects; ++i) { + obj.arr[i] = buf.ReadObjectAny(); + obj.opt[i] = buf.ReadTString(); + } + } else { + obj.name = ""; + obj.arr = []; + obj.opt = []; + } + }; + + cs['TClonesArray'] = function(buf, list) { + if (!list._typename) list._typename = "TClonesArray"; + list.$kind = "TClonesArray"; + list.name = ""; + var ver = buf.last_read_version; + if (ver > 2) buf.ClassStreamer(list, "TObject"); + if (ver > 1) list.name = buf.ReadTString(); + var classv = buf.ReadTString(), clv = 0, + pos = classv.lastIndexOf(";"); + + if (pos > 0) { + clv = parseInt(classv.substr(pos+1)); + classv = classv.substr(0, pos); + } + + var nobjects = buf.ntou4(); + if (nobjects < 0) nobjects = -nobjects; // for backward compatibility + + list.arr = new Array(nobjects); + list.fLast = nobjects-1; + list.fLowerBound = buf.ntou4(); + + var streamer = buf.fFile.GetStreamer(classv, { val: clv }); + streamer = buf.fFile.GetSplittedStreamer(streamer); + + if (!streamer) { + console.log('Cannot get member-wise streamer for', classv, clv); + } else { + // create objects + for (var n=0;n<nobjects;++n) + list.arr[n] = { _typename: classv }; + + // call streamer for all objects member-wise + for (var k=0;k<streamer.length;++k) + for (var n=0;n<nobjects;++n) + streamer[k].func(buf, list.arr[n]); + } + }; + + cs['TMap'] = function(buf, map) { + if (!map._typename) map._typename = "TMap"; + map.name = ""; + map.arr = new Array(); + var ver = buf.last_read_version; + if (ver > 2) buf.ClassStreamer(map, "TObject"); + if (ver > 1) map.name = buf.ReadTString(); + + var nobjects = buf.ntou4(); + // create objects + for (var n=0;n<nobjects;++n) { + var obj = { _typename: "TPair" }; + obj.first = buf.ReadObjectAny(); + obj.second = buf.ReadObjectAny(); + if (obj.first) map.arr.push(obj); + } + }; + + cs['TTreeIndex'] = function(buf, obj) { + var ver = buf.last_read_version; + obj._typename = "TTreeIndex"; + buf.ClassStreamer(obj, "TVirtualIndex"); + obj.fMajorName = buf.ReadTString(); + obj.fMinorName = buf.ReadTString(); + obj.fN = buf.ntoi8(); + obj.fIndexValues = buf.ReadFastArray(obj.fN, JSROOT.IO.kLong64); + if (ver>1) obj.fIndexValuesMinor = buf.ReadFastArray(obj.fN, JSROOT.IO.kLong64); + obj.fIndex = buf.ReadFastArray(obj.fN, JSROOT.IO.kLong64); + }; + + cs['TRefArray'] = function(buf, obj) { + obj._typename = "TRefArray"; + buf.ClassStreamer(obj, "TObject"); + obj.name = buf.ReadTString(); + var nobj = buf.ntoi4(); + obj.fLast = nobj-1; + obj.fLowerBound = buf.ntoi4(); + var pidf = buf.ntou2(); + obj.fUIDs = buf.ReadFastArray(nobj, JSROOT.IO.kUInt); + }; + + cs['TCanvas'] = function(buf, obj) { + obj._typename = "TCanvas"; + buf.ClassStreamer(obj, "TPad"); + obj.fDISPLAY = buf.ReadTString(); + obj.fDoubleBuffer = buf.ntoi4(); + obj.fRetained = (buf.ntou1() !== 0); + obj.fXsizeUser = buf.ntoi4(); + obj.fYsizeUser = buf.ntoi4(); + obj.fXsizeReal = buf.ntoi4(); + obj.fYsizeReal = buf.ntoi4(); + obj.fWindowTopX = buf.ntoi4(); + obj.fWindowTopY = buf.ntoi4(); + obj.fWindowWidth = buf.ntoi4(); + obj.fWindowHeight = buf.ntoi4(); + obj.fCw = buf.ntou4(); + obj.fCh = buf.ntou4(); + obj.fCatt = buf.ClassStreamer({}, "TAttCanvas"); + buf.ntou1(); // ignore b << TestBit(kMoveOpaque); + buf.ntou1(); // ignore b << TestBit(kResizeOpaque); + obj.fHighLightColor = buf.ntoi2(); + obj.fBatch = (buf.ntou1() !== 0); + buf.ntou1(); // ignore b << TestBit(kShowEventStatus); + buf.ntou1(); // ignore b << TestBit(kAutoExec); + buf.ntou1(); // ignore b << TestBit(kMenuBar); + }; + + cs['TObjArray'] = function(buf, list) { + if (!list._typename) list._typename = "TObjArray"; + list.$kind = "TObjArray"; + list.name = ""; + var ver = buf.last_read_version; + if (ver > 2) + buf.ClassStreamer(list, "TObject"); + if (ver > 1) + list.name = buf.ReadTString(); + var nobjects = buf.ntou4(), i = 0; + list.arr = new Array(nobjects); + list.fLast = nobjects-1; + list.fLowerBound = buf.ntou4(); + while (i < nobjects) + list.arr[i++] = buf.ReadObjectAny(); + }; + + cs['TPolyMarker3D'] = function(buf, marker) { + var ver = buf.last_read_version; + buf.ClassStreamer(marker, "TObject"); + buf.ClassStreamer(marker, "TAttMarker"); + marker.fN = buf.ntoi4(); + marker.fP = buf.ReadFastArray(marker.fN*3, JSROOT.IO.kFloat); + marker.fOption = buf.ReadTString(); + marker.fName = (ver > 1) ? buf.ReadTString() : "TPolyMarker3D"; + }; + + cs['TPolyLine3D'] = function(buf, obj) { + buf.ClassStreamer(obj, "TObject"); + buf.ClassStreamer(obj, "TAttLine"); + obj.fN = buf.ntoi4(); + obj.fP = buf.ReadFastArray(obj.fN*3, JSROOT.IO.kFloat); + obj.fOption = buf.ReadTString(); + }; + + cs['TStreamerInfo'] = function(buf, obj) { + // stream an object of class TStreamerInfo from the I/O buffer + buf.ClassStreamer(obj, "TNamed"); + obj.fCheckSum = buf.ntou4(); + obj.fClassVersion = buf.ntou4(); + obj.fElements = buf.ReadObjectAny(); + }; + + cs['TStreamerElement'] = function(buf, element) { + // stream an object of class TStreamerElement + + var ver = buf.last_read_version; + buf.ClassStreamer(element, "TNamed"); + element.fType = buf.ntou4(); + element.fSize = buf.ntou4(); + element.fArrayLength = buf.ntou4(); + element.fArrayDim = buf.ntou4(); + element.fMaxIndex = buf.ReadFastArray((ver == 1) ? buf.ntou4() : 5, JSROOT.IO.kUInt); + element.fTypeName = buf.ReadTString(); + + if ((element.fType === JSROOT.IO.kUChar) && ((element.fTypeName == "Bool_t") || (element.fTypeName == "bool"))) + element.fType = JSROOT.IO.kBool; + + element.fXmin = element.fXmax = element.fFactor = 0; + if (ver === 3) { + element.fXmin = buf.ntod(); + element.fXmax = buf.ntod(); + element.fFactor = buf.ntod(); + } else + if ((ver > 3) && (element.fBits & JSROOT.BIT(6))) { // kHasRange + + var p1 = element.fTitle.indexOf("["); + if ((p1>=0) && (element.fType>JSROOT.IO.kOffsetP)) p1 = element.fTitle.indexOf("[", p1+1); + var p2 = element.fTitle.indexOf("]", p1+1); + + if ((p1>=0) && (p2>=p1+2)) { + var arr = JSROOT.ParseAsArray(element.fTitle.substr(p1, p2-p1+1)), nbits = 32; + + if (arr.length===3) nbits = parseInt(arr[2]); + if (isNaN(nbits) || (nbits<2) || (nbits>32)) nbits = 32; + + function parse_range(val) { + if (!val) return 0; + if (val.indexOf("pi")<0) return parseFloat(val); + val = val.trim(); + var sign = 1.; + if (val[0] == "-") { sign = -1; val = val.substr(1); } + switch(val) { + case "2pi": + case "2*pi": + case "twopi": return sign*2*Math.PI; + case "pi/2": return sign*Math.PI/2; + case "pi/4": return sign*Math.PI/4; + } + return sign*Math.PI; + } + + element.fXmin = parse_range(arr[0]); + element.fXmax = parse_range(arr[1]); + + var bigint = (nbits < 32) ? (1<<nbits) : 0xffffffff; + if (element.fXmin < element.fXmax) element.fFactor = bigint/(element.fXmax - element.fXmin); + else if (nbits<15) element.fXmin = nbits; + } + } + }; + + cs['TStreamerBase'] = function(buf, elem) { + var ver = buf.last_read_version; + buf.ClassStreamer(elem, "TStreamerElement"); + if (ver > 2) elem.fBaseVersion = buf.ntou4(); + }; + + cs['TStreamerBasicPointer'] = cs['TStreamerLoop'] = function(buf,elem) { + if (buf.last_read_version > 1) { + buf.ClassStreamer(elem, "TStreamerElement"); + elem.fCountVersion = buf.ntou4(); + elem.fCountName = buf.ReadTString(); + elem.fCountClass = buf.ReadTString(); + } + }; + + cs['TStreamerSTL'] = function(buf, elem) { + buf.ClassStreamer(elem, "TStreamerElement"); + elem.fSTLtype = buf.ntou4(); + elem.fCtype = buf.ntou4(); + + if ((elem.fSTLtype === JSROOT.IO.kSTLmultimap) && + ((elem.fTypeName.indexOf("std::set")===0) || + (elem.fTypeName.indexOf("set")==0))) elem.fSTLtype = JSROOT.IO.kSTLset; + + if ((elem.fSTLtype === JSROOT.IO.kSTLset) && + ((elem.fTypeName.indexOf("std::multimap")===0) || + (elem.fTypeName.indexOf("multimap")===0))) elem.fSTLtype = JSROOT.IO.kSTLmultimap; + }; + + cs['TStreamerSTLstring'] = function(buf, elem) { + if (buf.last_read_version > 0) + buf.ClassStreamer(elem, "TStreamerSTL"); + }; + + cs['TStreamerObject'] = cs['TStreamerBasicType'] = cs['TStreamerObjectAny'] = + cs['TStreamerString'] = cs['TStreamerObjectPointer'] = function(buf, elem) { + if (buf.last_read_version > 1) + buf.ClassStreamer(elem, "TStreamerElement"); + } + + cs['TStreamerObjectAnyPointer'] = function(buf, elem) { + if (buf.last_read_version > 0) + buf.ClassStreamer(elem, "TStreamerElement"); + } + + cs['TTree'] = { + name: '$file', + func: function(buf,obj) { obj.$kind = "TTree"; obj.$file = buf.fFile; buf.fFile.AddReadTree(obj); } + } + + cs['TVirtualPerfStats'] = "TObject"; // use directly TObject streamer + + cs['RooRealVar'] = function(buf,obj) { + var v = buf.last_read_version; + buf.ClassStreamer(obj, "RooAbsRealLValue"); + if (v==1) { buf.ntod(); buf.ntod(); buf.ntoi4(); } // skip fitMin, fitMax, fitBins + obj._error = buf.ntod(); + obj._asymErrLo = buf.ntod(); + obj._asymErrHi = buf.ntod(); + if (v>=2) obj._binning = buf.ReadObjectAny(); + if (v==3) obj._sharedProp = buf.ReadObjectAny(); + if (v>=4) obj._sharedProp = buf.ClassStreamer({}, "RooRealVarSharedProperties"); + }; + + cs['RooAbsBinning'] = function(buf,obj) { + buf.ClassStreamer(obj, (buf.last_read_version==1) ? "TObject" : "TNamed"); + buf.ClassStreamer(obj, "RooPrintable"); + } + + cs['RooCategory'] = function(buf,obj) { + var v = buf.last_read_version; + buf.ClassStreamer(obj, "RooAbsCategoryLValue"); + obj._sharedProp = (v===1) ? buf.ReadObjectAny() : buf.ClassStreamer({}, "RooCategorySharedProperties"); + }; + + cs['RooWorkspace::CodeRepo'] = function(buf,obj) { + var sz = (buf.last_read_version == 2) ? 3 : 2; + for (var i=0;i<sz;++i) { + var cnt = buf.ntoi4() * ((i==0) ? 4 : 3); + while (cnt--) buf.ReadTString(); + } + } + + cs['RooLinkedList'] = function(buf,obj) { + var v = buf.last_read_version; + buf.ClassStreamer(obj, "TObject"); + var size = buf.ntoi4(); + obj.arr = JSROOT.Create("TList"); + while(size--) + obj.arr.Add(buf.ReadObjectAny()); + if (v>1) obj._name = buf.ReadTString(); + }; + + cs['TASImage'] = function(buf,obj) { + if ((buf.last_read_version==1) && (buf.fFile.fVersion>0) && (buf.fFile.fVersion<50000)) { + return console.warn("old TASImage version - not yet supported"); + } + + buf.ClassStreamer(obj, "TNamed"); + + if (buf.ntou1() != 0) { + var size = buf.ntoi4(); + obj.fPngBuf = buf.ReadFastArray(size, JSROOT.IO.kUChar); + } else { + buf.ClassStreamer(obj, "TAttImage"); + obj.fWidth = buf.ntoi4(); + obj.fHeight = buf.ntoi4(); + obj.fImgBuf = buf.ReadFastArray(obj.fWidth*obj.fHeight, JSROOT.IO.kDouble); + } + } + + cs['TMaterial'] = function(buf,obj) { + var v = buf.last_read_version; + buf.ClassStreamer(obj, "TNamed"); + obj.fNumber = buf.ntoi4(); + obj.fA = buf.ntof(); + obj.fZ = buf.ntof(); + obj.fDensity = buf.ntof(); + if (v>2) { + buf.ClassStreamer(obj, "TAttFill"); + obj.fRadLength = buf.ntof(); + obj.fInterLength = buf.ntof(); + } else { + obj.fRadLength = obj.fInterLength = 0; + } + } + + cs['TMixture'] = function(buf,obj) { + buf.ClassStreamer(obj, "TMaterial"); + obj.fNmixt = buf.ntoi4(); + obj.fAmixt = buf.ReadFastArray(buf.ntoi4(), JSROOT.IO.kFloat); + obj.fZmixt = buf.ReadFastArray(buf.ntoi4(), JSROOT.IO.kFloat); + obj.fWmixt = buf.ReadFastArray(buf.ntoi4(), JSROOT.IO.kFloat); + } + + // these are direct streamers - not follow version/checksum logic + + var ds = JSROOT.IO.DirectStreamers; + + ds['TQObject'] = ds['TGraphStruct'] = ds['TGraphNode'] = ds['TGraphEdge'] = function(buf,obj) { + // do nothing + } + + ds['TDatime'] = function(buf,obj) { + obj.fDatime = buf.ntou4(); +// obj.GetDate = function() { +// var res = new Date(); +// res.setFullYear((this.fDatime >>> 26) + 1995); +// res.setMonth((this.fDatime << 6) >>> 28); +// res.setDate((this.fDatime << 10) >>> 27); +// res.setHours((this.fDatime << 15) >>> 27); +// res.setMinutes((this.fDatime << 20) >>> 26); +// res.setSeconds((this.fDatime << 26) >>> 26); +// res.setMilliseconds(0); +// return res; +// } + } + + ds['TKey'] = function(buf,key) { + key.fNbytes = buf.ntoi4(); + key.fVersion = buf.ntoi2(); + key.fObjlen = buf.ntou4(); + key.fDatime = buf.ClassStreamer({}, 'TDatime'); + key.fKeylen = buf.ntou2(); + key.fCycle = buf.ntou2(); + if (key.fVersion > 1000) { + key.fSeekKey = buf.ntou8(); + buf.shift(8); // skip seekPdir + } else { + key.fSeekKey = buf.ntou4(); + buf.shift(4); // skip seekPdir + } + key.fClassName = buf.ReadTString(); + key.fName = buf.ReadTString(); + key.fTitle = buf.ReadTString(); + } + + ds['TDirectory'] = function(buf, dir) { + var version = buf.ntou2(); + dir.fDatimeC = buf.ClassStreamer({}, 'TDatime'); + dir.fDatimeM = buf.ClassStreamer({}, 'TDatime'); + dir.fNbytesKeys = buf.ntou4(); + dir.fNbytesName = buf.ntou4(); + dir.fSeekDir = (version > 1000) ? buf.ntou8() : buf.ntou4(); + dir.fSeekParent = (version > 1000) ? buf.ntou8() : buf.ntou4(); + dir.fSeekKeys = (version > 1000) ? buf.ntou8() : buf.ntou4(); + // if ((version % 1000) > 2) buf.shift(18); // skip fUUID + } + + ds['TBasket'] = function(buf,obj) { + buf.ClassStreamer(obj, 'TKey'); + var ver = buf.ReadVersion(); + obj.fBufferSize = buf.ntoi4(); + obj.fNevBufSize = buf.ntoi4(); + obj.fNevBuf = buf.ntoi4(); + obj.fLast = buf.ntoi4(); + if (obj.fLast > obj.fBufferSize) obj.fBufferSize = obj.fLast; + var flag = buf.ntoi1(); + + if (flag===0) return; + + if ((flag % 10) != 2) { + if (obj.fNevBuf) { + obj.fEntryOffset = buf.ReadFastArray(buf.ntoi4(), JSROOT.IO.kInt); + if ((20<flag) && (flag<40)) + for(var i=0, kDisplacementMask = 0xFF000000; i<obj.fNevBuf; ++i) + obj.fEntryOffset[i] &= ~kDisplacementMask; + } + + if (flag>40) + obj.fDisplacement = buf.ReadFastArray(buf.ntoi4(), JSROOT.IO.kInt); + } + + if ((flag === 1) || (flag > 10)) { + // here is reading of raw data + var sz = (ver.val <= 1) ? buf.ntoi4() : obj.fLast; + + if (sz > obj.fKeylen) { + // buffer includes again complete TKey data - exclude it + var blob = buf.extract([buf.o + obj.fKeylen, sz - obj.fKeylen]); + + obj.fBufferRef = JSROOT.CreateTBuffer(blob, 0, buf.fFile, sz - obj.fKeylen); + obj.fBufferRef.fTagOffset = obj.fKeylen; + } + + buf.shift(sz); + } + } + + ds['TRef'] = function(buf,obj) { + buf.ClassStreamer(obj, "TObject"); + if (obj.fBits & JSROOT.IO.kHasUUID) + obj.fUUID = buf.ReadTString(); + else + obj.fPID = buf.ntou2(); + } + + ds['TMatrixTSym<float>'] = function(buf,obj) { + buf.ClassStreamer(obj, "TMatrixTBase<float>"); + obj.fElements = new Float32Array(obj.fNelems); + var arr = buf.ReadFastArray((obj.fNrows * (obj.fNcols + 1))/2, JSROOT.IO.kFloat), cnt = 0; + for (var i=0;i<obj.fNrows;++i) + for (var j=i;j<obj.fNcols;++j) + obj.fElements[j*obj.fNcols+i] = obj.fElements[i*obj.fNcols+j] = arr[cnt++]; + } + + ds['TMatrixTSym<double>'] = function(buf,obj) { + buf.ClassStreamer(obj, "TMatrixTBase<double>"); + obj.fElements = new Float64Array(obj.fNelems); + var arr = buf.ReadFastArray((obj.fNrows * (obj.fNcols + 1))/2, JSROOT.IO.kDouble), cnt = 0; + for (var i=0;i<obj.fNrows;++i) + for (var j=i;j<obj.fNcols;++j) + obj.fElements[j*obj.fNcols+i] = obj.fElements[i*obj.fNcols+j] = arr[cnt++]; + } + + } + + JSROOT.IO.CreateStreamerElement = function(name, typename, file) { + // return function, which could be used for element of the map + + var elem = { _typename: 'TStreamerElement', fName: name, fTypeName: typename, + fType: 0, fSize: 0, fArrayLength: 0, fArrayDim: 0, fMaxIndex: [0,0,0,0,0], + fXmin: 0, fXmax: 0, fFactor: 0 }; + + if (typeof typename === "string") { + elem.fType = JSROOT.IO.GetTypeId(typename); + if ((elem.fType<0) && file && file.fBasicTypes[typename]) + elem.fType = file.fBasicTypes[typename]; + } else { + elem.fType = typename; + typename = elem.fTypeName = JSROOT.IO.TypeNames[elem.fType] || "int"; + } + + if (elem.fType > 0) return elem; // basic type + + // check if there are STL containers + var stltype = JSROOT.IO.kNotSTL, pos = typename.indexOf("<"); + if ((pos>0) && (typename.indexOf(">") > pos+2)) + for (var stl=1;stl<JSROOT.IO.StlNames.length;++stl) + if (typename.substr(0, pos) === JSROOT.IO.StlNames[stl]) { + stltype = stl; break; + } + + if (stltype !== JSROOT.IO.kNotSTL) { + elem._typename = 'TStreamerSTL'; + elem.fType = JSROOT.IO.kStreamer; + elem.fSTLtype = stltype; + elem.fCtype = 0; + return elem; + } + + var isptr = false; + + if (typename.lastIndexOf("*") === typename.length-1) { + isptr = true; + elem.fTypeName = typename = typename.substr(0,typename.length-1); + } + + var arrkind = JSROOT.IO.GetArrayKind(typename); + + if (arrkind == 0) { + elem.fType = JSROOT.IO.kTString; + return elem; + } + + elem.fType = isptr ? JSROOT.IO.kAnyP : JSROOT.IO.kAny; + + return elem; + } + + JSROOT.IO.ReadVectorElement = function(buf) { + + if (this.member_wise) { + + var n = buf.ntou4(), streamer = null, ver = this.stl_version; + + if (n===0) return []; // for empty vector no need to search split streamers + + if (n>1000000) { + throw new Error('member-wise streaming of ' + this.conttype + " num " + n + ' member ' + this.name); + return []; + } + + if ((ver.val === this.member_ver) && (ver.checksum === this.member_checksum)) { + streamer = this.member_streamer; + } else { + streamer = buf.fFile.GetStreamer(this.conttype, ver); + + this.member_streamer = streamer = buf.fFile.GetSplittedStreamer(streamer); + this.member_ver = ver.val; + this.member_checksum = ver.checksum; + } + + var res = new Array(n), i, k, member; + + for (i=0;i<n;++i) + res[i] = { _typename: this.conttype }; // create objects + if (!streamer) { + console.error('Fail to create split streamer for', this.conttype, 'need to read ', n, 'objects version', ver ); + } else { + for (k=0;k<streamer.length;++k) { + member = streamer[k]; + if (member.split_func) { + member.split_func(buf, res, n); + } else { + for (i=0;i<n;++i) + member.func(buf, res[i]); + } + } + } + return res; + } + + var n = buf.ntou4(), res = new Array(n), i = 0; + + if (n>200000) { console.error('vector streaming for of', this.conttype, n); return res; } + + if (this.arrkind > 0) { while (i<n) res[i++] = buf.ReadFastArray(buf.ntou4(), this.arrkind); } + else if (this.arrkind===0) { while (i<n) res[i++] = buf.ReadTString(); } + else if (this.isptr) { while (i<n) res[i++] = buf.ReadObjectAny(); } + else if (this.submember) { while (i<n) res[i++] = this.submember.readelem(buf); } + else { while (i<n) res[i++] = buf.ClassStreamer({}, this.conttype); } + + return res; + } + + JSROOT.IO.ReadMapElement = function(buf) { + var streamer = this.streamer; + + if (this.member_wise) { + // when member-wise streaming is used, version is written + var ver = this.stl_version; + + if (this.si) { + var si = buf.fFile.FindStreamerInfo(this.pairtype, ver.val, ver.checksum); + + if (this.si !== si) { + streamer = JSROOT.IO.GetPairStreamer(si, this.pairtype, buf.fFile); + if (!streamer || streamer.length!==2) { + console.log('Fail to produce streamer for ', this.pairtype); + return null; + } + } + } + } + + var i, n = buf.ntoi4(), res = new Array(n); + + for (i=0;i<n;++i) { + res[i] = { _typename: this.pairtype }; + streamer[0].func(buf, res[i]); + if (!this.member_wise) streamer[1].func(buf, res[i]); + } + + // due-to member-wise streaming second element read after first is completed + if (this.member_wise) + for (i=0;i<n;++i) streamer[1].func(buf, res[i]); + + return res; + } + + /** + * @summary Open ROOT file for reading + * + * @desc depending from file location, different class will be created to provide + * access to objects from the file + * @param {string} filename - name of file to open + * @param {File} filename - JS object to access local files, see https://developer.mozilla.org/en-US/docs/Web/API/File + * @param {function} callback - function called with file handle + * @example + * JSROOT.OpenFile("https://root.cern/js/files/hsimple.root", function(f) { + * console.log("Open file", f.fFileName); + * }); + */ + + + JSROOT.OpenFile = function(filename, callback) { + if (JSROOT.nodejs) { + if (filename.indexOf("file://")==0) + return new TNodejsFile(filename.substr(7), callback); + + if (filename.indexOf("http")!==0) + return new TNodejsFile(filename, callback); + } + + if (typeof filename === 'object' && filename.size && filename.name) + return new TLocalFile(filename, callback); + + return new TFile(filename, callback); + } + + JSROOT.IO.NativeArray = JSROOT.nodejs || (window && ('Float64Array' in window)); + + JSROOT.IO.ProduceCustomStreamers(); + + JSROOT.TBuffer = TBuffer; + JSROOT.TDirectory = TDirectory; + JSROOT.TFile = TFile; + JSROOT.TLocalFile = TLocalFile; + JSROOT.TNodejsFile = TNodejsFile; + + return JSROOT; + +})); + + +// JSRootIOEvolution.js ends + diff --git a/js/scripts/JSRootMath.js b/js/scripts/JSRootMath.js new file mode 100644 index 00000000000..c87e4bed1f6 --- /dev/null +++ b/js/scripts/JSRootMath.js @@ -0,0 +1,721 @@ +/** @file JSRootMath.js + * Special mathematical functions */ + +/** @namespace JSROOT.Math + * Holder of mathematical functions, analogue to TMath class of ROOT */ + +(function( factory ) { + if ( typeof define === "function" && define.amd ) { + define( ['JSRootCore'], factory ); + } else + if (typeof exports === 'object' && typeof module !== 'undefined') { + factory(require("./JSRootCore.js")); + } else { + if (typeof JSROOT == 'undefined') + throw new Error("This extension requires JSRootCore.js", "JSRootMath.js"); + + if (typeof JSROOT.Math == "object") + throw new Error("This JSROOT Math already loaded", "JSRootMath.js"); + + factory(JSROOT); + } +} (function(JSROOT) { + // math methods for Javascript ROOT + + "use strict"; + + JSROOT.sources.push("math"); + + JSROOT.Math = {}; + + /** @memberOf JSROOT.Math */ + JSROOT.Math.lgam = function( x ) { + var p, q, u, w, z, i, sgngam = 1; + var kMAXLGM = 2.556348e305; + var LS2PI = 0.91893853320467274178; + + var A = [ + 8.11614167470508450300E-4, + -5.95061904284301438324E-4, + 7.93650340457716943945E-4, + -2.77777777730099687205E-3, + 8.33333333333331927722E-2 + ]; + + var B = [ + -1.37825152569120859100E3, + -3.88016315134637840924E4, + -3.31612992738871184744E5, + -1.16237097492762307383E6, + -1.72173700820839662146E6, + -8.53555664245765465627E5 + ]; + + var C = [ + /* 1.00000000000000000000E0, */ + -3.51815701436523470549E2, + -1.70642106651881159223E4, + -2.20528590553854454839E5, + -1.13933444367982507207E6, + -2.53252307177582951285E6, + -2.01889141433532773231E6 + ]; + + if (x >= Number.POSITIVE_INFINITY) + return(Number.POSITIVE_INFINITY); + + if ( x < -34.0 ) { + q = -x; + w = this.lgam(q); + p = Math.floor(q); + if ( p==q )//_unur_FP_same(p,q) + return (Number.POSITIVE_INFINITY); + i = Math.round(p); + if ( (i & 1) == 0 ) + sgngam = -1; + else + sgngam = 1; + z = q - p; + if ( z > 0.5 ) { + p += 1.0; + z = p - q; + } + z = q * Math.sin( Math.PI * z ); + if ( z < 1e-300 ) + return (Number.POSITIVE_INFINITY); + z = Math.log(Math.PI) - Math.log( z ) - w; + return( z ); + } + if ( x < 13.0 ) { + z = 1.0; + p = 0.0; + u = x; + while ( u >= 3.0 ) { + p -= 1.0; + u = x + p; + z *= u; + } + while ( u < 2.0 ) { + if ( u < 1e-300 ) + return (Number.POSITIVE_INFINITY); + z /= u; + p += 1.0; + u = x + p; + } + if ( z < 0.0 ) { + sgngam = -1; + z = -z; + } + else + sgngam = 1; + if ( u == 2.0 ) + return( Math.log(z) ); + p -= 2.0; + x = x + p; + p = x * this.Polynomialeval(x, B, 5 ) / this.Polynomial1eval( x, C, 6); + return( Math.log(z) + p ); + } + if ( x > kMAXLGM ) + return( sgngam * Number.POSITIVE_INFINITY ); + + q = ( x - 0.5 ) * Math.log(x) - x + LS2PI; + if ( x > 1.0e8 ) + return( q ); + + p = 1.0/(x*x); + if ( x >= 1000.0 ) + q += ((7.9365079365079365079365e-4 * p + - 2.7777777777777777777778e-3) *p + + 0.0833333333333333333333) / x; + else + q += this.Polynomialeval( p, A, 4 ) / x; + return( q ); + }; + + /** + * calculates a value of a polynomial of the form: + * a[0]x^N+a[1]x^(N-1) + ... + a[N] + * + * @memberOf JSROOT.Math + */ + JSROOT.Math.Polynomialeval = function(x, a, N) { + if (N==0) return a[0]; + else { + var pom = a[0]; + for (var i=1; i <= N; ++i) + pom = pom *x + a[i]; + return pom; + } + }; + + /** + * calculates a value of a polynomial of the form: + * x^N+a[0]x^(N-1) + ... + a[N-1] + * + * @memberOf JSROOT.Math + */ + JSROOT.Math.Polynomial1eval = function(x, a, N) { + if (N==0) return a[0]; + else { + var pom = x + a[0]; + for (var i=1; i < N; ++i) + pom = pom *x + a[i]; + return pom; + } + }; + + /** @memberOf JSROOT.Math */ + JSROOT.Math.ndtri = function( y0 ) { + if ( y0 <= 0.0 ) + return( Number.NEGATIVE_INFINITY ); + if ( y0 >= 1.0 ) + return( Number.POSITIVE_INFINITY ); + + var P0 = new Array( + -5.99633501014107895267E1, + 9.80010754185999661536E1, + -5.66762857469070293439E1, + 1.39312609387279679503E1, + -1.23916583867381258016E0 + ); + + var Q0 = new Array( + 1.95448858338141759834E0, + 4.67627912898881538453E0, + 8.63602421390890590575E1, + -2.25462687854119370527E2, + 2.00260212380060660359E2, + -8.20372256168333339912E1, + 1.59056225126211695515E1, + -1.18331621121330003142E0 + ); + + var P1 = new Array( + 4.05544892305962419923E0, + 3.15251094599893866154E1, + 5.71628192246421288162E1, + 4.40805073893200834700E1, + 1.46849561928858024014E1, + 2.18663306850790267539E0, + -1.40256079171354495875E-1, + -3.50424626827848203418E-2, + -8.57456785154685413611E-4 + ); + + var Q1 = new Array( + 1.57799883256466749731E1, + 4.53907635128879210584E1, + 4.13172038254672030440E1, + 1.50425385692907503408E1, + 2.50464946208309415979E0, + -1.42182922854787788574E-1, + -3.80806407691578277194E-2, + -9.33259480895457427372E-4 + ); + + var P2 = new Array( + 3.23774891776946035970E0, + 6.91522889068984211695E0, + 3.93881025292474443415E0, + 1.33303460815807542389E0, + 2.01485389549179081538E-1, + 1.23716634817820021358E-2, + 3.01581553508235416007E-4, + 2.65806974686737550832E-6, + 6.23974539184983293730E-9 + ); + + var Q2 = new Array( + 6.02427039364742014255E0, + 3.67983563856160859403E0, + 1.37702099489081330271E0, + 2.16236993594496635890E-1, + 1.34204006088543189037E-2, + 3.28014464682127739104E-4, + 2.89247864745380683936E-6, + 6.79019408009981274425E-9 + ); + + var s2pi = 2.50662827463100050242e0; + var code = 1; + var y = y0; + var x, z, y2, x0, x1; + + if ( y > (1.0 - 0.13533528323661269189) ) { + y = 1.0 - y; + code = 0; + } + if ( y > 0.13533528323661269189 ) { + y = y - 0.5; + y2 = y * y; + x = y + y * (y2 * this.Polynomialeval( y2, P0, 4)/ this.Polynomial1eval( y2, Q0, 8 )); + x = x * s2pi; + return(x); + } + x = Math.sqrt( -2.0 * Math.log(y) ); + x0 = x - Math.log(x)/x; + z = 1.0/x; + if ( x < 8.0 ) + x1 = z * this.Polynomialeval( z, P1, 8 )/ this.Polynomial1eval( z, Q1, 8 ); + else + x1 = z * this.Polynomialeval( z, P2, 8 )/ this.Polynomial1eval( z, Q2, 8 ); + x = x0 - x1; + if ( code != 0 ) + x = -x; + return( x ); + }; + + JSROOT.Math.normal_quantile = function(z, sigma) { + return sigma * JSROOT.Math.ndtri(z); + }; + + /** @memberOf JSROOT.Math */ + JSROOT.Math.igam = function(a,x) { + var kMACHEP = 1.11022302462515654042363166809e-16; + var kMAXLOG = 709.782712893383973096206318587; + var ans, ax, c, r; + + // LM: for negative values returns 1.0 instead of zero + // This is correct if a is a negative integer since Gamma(-n) = +/- inf + if (a <= 0) return 1.0; + + if (x <= 0) return 0.0; + + if( (x > 1.0) && (x > a ) ) + return 1.0 - this.igamc(a,x); + + /* Compute x**a * exp(-x) / gamma(a) */ + ax = a * Math.log(x) - x - this.lgam(a); + if( ax < -kMAXLOG ) + return 0.0; + + ax = Math.exp(ax); + + /* power series */ + r = a; + c = 1.0; + ans = 1.0; + + do + { + r += 1.0; + c *= x/r; + ans += c; + } + while( c/ans > kMACHEP ); + + return ans * ax/a; + }; + + /** @memberOf JSROOT.Math */ + JSROOT.Math.igamc = function(a,x) { + var kMACHEP = 1.11022302462515654042363166809e-16; + var kMAXLOG = 709.782712893383973096206318587; + + var kBig = 4.503599627370496e15; + var kBiginv = 2.22044604925031308085e-16; + + var ans, ax, c, yc, r, t, y, z; + var pk, pkm1, pkm2, qk, qkm1, qkm2; + + // LM: for negative values returns 0.0 + // This is correct if a is a negative integer since Gamma(-n) = +/- inf + if (a <= 0) return 0.0; + + if (x <= 0) return 1.0; + + if( (x < 1.0) || (x < a) ) + return ( 1.0 - JSROOT.Math.igam(a,x) ); + + ax = a * Math.log(x) - x - JSROOT.Math.lgam(a); + if( ax < -kMAXLOG ) + return( 0.0 ); + + ax = Math.exp(ax); + + /* continued fraction */ + y = 1.0 - a; + z = x + y + 1.0; + c = 0.0; + pkm2 = 1.0; + qkm2 = x; + pkm1 = x + 1.0; + qkm1 = z * x; + ans = pkm1/qkm1; + + do + { + c += 1.0; + y += 1.0; + z += 2.0; + yc = y * c; + pk = pkm1 * z - pkm2 * yc; + qk = qkm1 * z - qkm2 * yc; + if(qk) + { + r = pk/qk; + t = Math.abs( (ans - r)/r ); + ans = r; + } + else + t = 1.0; + pkm2 = pkm1; + pkm1 = pk; + qkm2 = qkm1; + qkm1 = qk; + if( Math.abs(pk) > kBig ) + { + pkm2 *= kBiginv; + pkm1 *= kBiginv; + qkm2 *= kBiginv; + qkm1 *= kBiginv; + } + } + while( t > kMACHEP ); + + return ans * ax; + }; + + /** @memberOf JSROOT.Math */ + JSROOT.Math.igami = function(a, y0) { + var x0, x1, x, yl, yh, y, d, lgm, dithresh, i, dir, + kMACHEP = 1.11022302462515654042363166809e-16; + + // check the domain + if (a <= 0) { + alert("igami : Wrong domain for parameter a (must be > 0)"); + return 0; + } + if (y0 <= 0) { + return Number.POSITIVE_INFINITY; + } + if (y0 >= 1) { + return 0; + } + /* bound the solution */ + var kMAXNUM = Number.MAX_VALUE; + x0 = kMAXNUM; + yl = 0; + x1 = 0; + yh = 1.0; + dithresh = 5.0 * kMACHEP; + + /* approximation to inverse function */ + d = 1.0/(9.0*a); + y = ( 1.0 - d - this.ndtri(y0) * Math.sqrt(d) ); + x = a * y * y * y; + + lgm = this.lgam(a); + + for( i=0; i<10; ++i ) { + if ( x > x0 || x < x1 ) + break; + y = this.igamc(a,x); + if ( y < yl || y > yh ) + break; + if ( y < y0 ) { + x0 = x; + yl = y; + } + else { + x1 = x; + yh = y; + } + /* compute the derivative of the function at this point */ + d = (a - 1.0) * Math.log(x) - x - lgm; + if ( d < -kMAXLOG ) + break; + d = -Math.exp(d); + /* compute the step to the next approximation of x */ + d = (y - y0)/d; + if ( Math.abs(d/x) < kMACHEP ) + return( x ); + x = x - d; + } + /* Resort to interval halving if Newton iteration did not converge. */ + d = 0.0625; + if ( x0 == kMAXNUM ) { + if ( x <= 0.0 ) + x = 1.0; + while ( x0 == kMAXNUM ) { + x = (1.0 + d) * x; + y = this.igamc( a, x ); + if ( y < y0 ) { + x0 = x; + yl = y; + break; + } + d = d + d; + } + } + d = 0.5; + dir = 0; + + for( i=0; i<400; ++i ) { + x = x1 + d * (x0 - x1); + y = this.igamc( a, x ); + lgm = (x0 - x1)/(x1 + x0); + if ( Math.abs(lgm) < dithresh ) + break; + lgm = (y - y0)/y0; + if ( Math.abs(lgm) < dithresh ) + break; + if ( x <= 0.0 ) + break; + if ( y >= y0 ) { + x1 = x; + yh = y; + if ( dir < 0 ) { + dir = 0; + d = 0.5; + } + else if ( dir > 1 ) + d = 0.5 * d + 0.5; + else + d = (y0 - yl)/(yh - yl); + dir += 1; + } + else { + x0 = x; + yl = y; + if ( dir > 0 ) { + dir = 0; + d = 0.5; + } + else if ( dir < -1 ) + d = 0.5 * d; + else + d = (y0 - yl)/(yh - yl); + dir -= 1; + } + } + return x; + }; + + /** @memberOf JSROOT.Math */ + JSROOT.Math.gamma_quantile_c = function(z, alpha, theta) { + return theta * this.igami( alpha, z); + }; + + /** @memberOf JSROOT.Math */ + JSROOT.Math.gamma_quantile = function(z, alpha, theta) { + return theta * this.igami( alpha, 1.- z); + }; + + /** @memberOf JSROOT.Math */ + JSROOT.Math.log10 = function(n) { + return Math.log(n) / Math.log(10); + }; + + /** @memberOf JSROOT.Math */ + JSROOT.Math.landau_pdf = function(x, xi, x0) { + // LANDAU pdf : algorithm from CERNLIB G110 denlan + // same algorithm is used in GSL + if (x0===undefined) x0 = 0; + if (xi <= 0) return 0; + var v = (x - x0)/xi; + var u, ue, us, denlan; + var p1 = new Array(0.4259894875,-0.1249762550, 0.03984243700, -0.006298287635, 0.001511162253); + var q1 = new Array(1.0 ,-0.3388260629, 0.09594393323, -0.01608042283, 0.003778942063); + var p2 = new Array(0.1788541609, 0.1173957403, 0.01488850518, -0.001394989411, 0.0001283617211); + var q2 = new Array(1.0 , 0.7428795082, 0.3153932961, 0.06694219548, 0.008790609714); + var p3 = new Array(0.1788544503, 0.09359161662,0.006325387654, 0.00006611667319,-0.000002031049101); + var q3 = new Array(1.0 , 0.6097809921, 0.2560616665, 0.04746722384, 0.006957301675); + var p4 = new Array(0.9874054407, 118.6723273, 849.2794360, -743.7792444, 427.0262186); + var q4 = new Array(1.0 , 106.8615961, 337.6496214, 2016.712389, 1597.063511); + var p5 = new Array(1.003675074, 167.5702434, 4789.711289, 21217.86767, -22324.94910); + var q5 = new Array(1.0 , 156.9424537, 3745.310488, 9834.698876, 66924.28357); + var p6 = new Array(1.000827619, 664.9143136, 62972.92665, 475554.6998, -5743609.109); + var q6 = new Array(1.0 , 651.4101098, 56974.73333, 165917.4725, -2815759.939); + var a1 = new Array(0.04166666667,-0.01996527778, 0.02709538966); + var a2 = new Array(-1.845568670,-4.284640743); + + if (v < -5.5) { + u = Math.exp(v+1.0); + if (u < 1e-10) return 0.0; + ue = Math.exp(-1/u); + us = Math.sqrt(u); + denlan = 0.3989422803*(ue/us)*(1+(a1[0]+(a1[1]+a1[2]*u)*u)*u); + } else if(v < -1) { + u = Math.exp(-v-1); + denlan = Math.exp(-u)*Math.sqrt(u)* + (p1[0]+(p1[1]+(p1[2]+(p1[3]+p1[4]*v)*v)*v)*v)/ + (q1[0]+(q1[1]+(q1[2]+(q1[3]+q1[4]*v)*v)*v)*v); + } else if(v < 1) { + denlan = (p2[0]+(p2[1]+(p2[2]+(p2[3]+p2[4]*v)*v)*v)*v)/ + (q2[0]+(q2[1]+(q2[2]+(q2[3]+q2[4]*v)*v)*v)*v); + } else if(v < 5) { + denlan = (p3[0]+(p3[1]+(p3[2]+(p3[3]+p3[4]*v)*v)*v)*v)/ + (q3[0]+(q3[1]+(q3[2]+(q3[3]+q3[4]*v)*v)*v)*v); + } else if(v < 12) { + u = 1/v; + denlan = u*u*(p4[0]+(p4[1]+(p4[2]+(p4[3]+p4[4]*u)*u)*u)*u)/ + (q4[0]+(q4[1]+(q4[2]+(q4[3]+q4[4]*u)*u)*u)*u); + } else if(v < 50) { + u = 1/v; + denlan = u*u*(p5[0]+(p5[1]+(p5[2]+(p5[3]+p5[4]*u)*u)*u)*u)/ + (q5[0]+(q5[1]+(q5[2]+(q5[3]+q5[4]*u)*u)*u)*u); + } else if(v < 300) { + u = 1/v; + denlan = u*u*(p6[0]+(p6[1]+(p6[2]+(p6[3]+p6[4]*u)*u)*u)*u)/ + (q6[0]+(q6[1]+(q6[2]+(q6[3]+q6[4]*u)*u)*u)*u); + } else { + u = 1/(v-v*Math.log(v)/(v+1)); + denlan = u*u*(1+(a2[0]+a2[1]*u)*u); + } + return denlan/xi; + }; + + /** @memberOf JSROOT.Math */ + JSROOT.Math.Landau = function(x, mpv, sigma, norm) { + if (sigma <= 0) return 0; + var den = JSROOT.Math.landau_pdf((x - mpv) / sigma, 1, 0); + if (!norm) return den; + return den/sigma; + }; + + /** @memberOf JSROOT.Math */ + JSROOT.Math.inc_gamma_c = function(a,x) { + return JSROOT.Math.igamc(a,x); + }; + + /** @memberOf JSROOT.Math */ + JSROOT.Math.inc_gamma = function(a,x) { + return JSROOT.Math.igam(a,x); + }; + + JSROOT.Math.lgamma = function(z) { + return JSROOT.Math.lgam(z); + }; + + /** @memberOf JSROOT.Math */ + JSROOT.Math.inc_gamma = function(a,x) { + return JSROOT.Math.igam(a,x); + }; + + JSROOT.Math.lgamma = function(z) { + return JSROOT.Math.lgam(z); + }; + + /** @memberOf JSROOT.Math */ + JSROOT.Math.chisquared_cdf_c = function(x,r,x0) { + if (x0===undefined) x0 = 0; + return JSROOT.Math.inc_gamma_c ( 0.5 * r , 0.5*(x-x0) ); + }; + + /** @memberOf JSROOT.Math */ + JSROOT.Math.chisquared_cdf = function(x,r,x0) { + if (x0===undefined) x0 = 0; + return JSROOT.Math.inc_gamma ( 0.5 * r , 0.5*(x-x0) ); + }; + + /** @memberOf JSROOT.Math */ + JSROOT.Math.chisquared_pdf = function(x,r,x0) { + if (x0===undefined) x0 = 0; + if ((x-x0) < 0) return 0.0; + var a = r/2 -1.; + // let return inf for case x = x0 and treat special case of r = 2 otherwise will return nan + if (x == x0 && a == 0) return 0.5; + + return Math.exp ((r/2 - 1) * Math.log((x-x0)/2) - (x-x0)/2 - JSROOT.Math.lgamma(r/2))/2; + }; + + /** @memberOf JSROOT.Math */ + JSROOT.Math.Prob = function(chi2, ndf) { + if (ndf <= 0) return 0; // Set CL to zero in case ndf<=0 + + if (chi2 <= 0) { + if (chi2 < 0) return 0; + else return 1; + } + + return JSROOT.Math.chisquared_cdf_c(chi2,ndf,0); + }; + + /** @memberOf JSROOT.Math */ + JSROOT.Math.Gaus = function(x, mean, sigma) { + return Math.exp(-0.5 * Math.pow((x-mean) / sigma, 2)); + }; + + /** @memberOf JSROOT.Math */ + JSROOT.Math.BreitWigner = function(x, mean, gamma) { + return gamma/((x-mean)*(x-mean) + gamma*gamma/4) / 2 / Math.PI; + } + + /** @memberOf JSROOT.Math */ + JSROOT.Math.gaus = function(f, x, i) { + // function used when gaus(0) used in the TFormula + return f.GetParValue(i+0) * Math.exp(-0.5 * Math.pow((x-f.GetParValue(i+1)) / f.GetParValue(i+2), 2)); + }; + + /** @memberOf JSROOT.Math */ + JSROOT.Math.gausn = function(f, x, i) { + return JSROOT.Math.gaus(f, x, i)/(Math.sqrt(2 * Math.PI) * f.GetParValue(i+2)); + }; + + /** @memberOf JSROOT.Math */ + JSROOT.Math.gausxy = function(f, x, y, i) { + // function used when xygaus(0) used in the TFormula + + return f.GetParValue(i+0) * Math.exp(-0.5 * Math.pow((x-f.GetParValue(i+1)) / f.GetParValue(i+2), 2)) + * Math.exp(-0.5 * Math.pow((y-f.GetParValue(i+3)) / f.GetParValue(i+4), 2)); + }; + + + /** @memberOf JSROOT.Math */ + JSROOT.Math.expo = function(f, x, i) { + return Math.exp(f.GetParValue(i+0) + f.GetParValue(i+1) * x); + }; + + /** @memberOf JSROOT.Math */ + JSROOT.Math.landau = function(f, x, i) { + return JSROOT.Math.Landau(x, f.GetParValue(i+1),f.GetParValue(i+2), false); + }; + + /** @memberOf JSROOT.Math */ + JSROOT.Math.landaun = function(f, x, i) { + return JSROOT.Math.Landau(x, f.GetParValue(i+1),f.GetParValue(i+2), true); + }; + + // ========================================================================= + + JSROOT.getMoreMethods = function(m,typename, obj) { + // different methods which are typically used in TTree::Draw + + if (typename.indexOf("ROOT::Math::LorentzVector")===0) { + m.Px = m.X = function() { return this.fCoordinates.Px(); } + m.Py = m.Y = function() { return this.fCoordinates.Py(); } + m.Pz = m.Z = function() { return this.fCoordinates.Pz(); } + m.E = m.T = function() { return this.fCoordinates.E(); } + m.M2 = function() { return this.fCoordinates.M2(); } + m.M = function() { return this.fCoordinates.M(); } + m.R = m.P = function() { return this.fCoordinates.R(); } + m.P2 = function() { return this.P() * this.P(); } + m.Pt = m.pt = function() { return Math.sqrt(this.P2()); } + m.Phi = m.phi = function() { return Math.atan2(this.fCoordinates.Py(), this.fCoordinates.Px()); } + m.Eta = m.eta = function() { return Math.atanh(this.Pz()/this.P()); } + } + + if (typename.indexOf("ROOT::Math::PxPyPzE4D")===0) { + m.Px = m.X = function() { return this.fX; } + m.Py = m.Y = function() { return this.fY; } + m.Pz = m.Z = function() { return this.fZ; } + m.E = m.T = function() { return this.fT; } + m.P2 = function() { return this.fX*this.fX + this.fY*this.fY + this.fZ*this.fZ; } + m.R = m.P = function() { return Math.sqrt(this.P2()); } + m.Mag2 = m.M2 = function() { return this.fT*this.fT - this.fX*this.fX - this.fY*this.fY - this.fZ*this.fZ; } + m.Mag = m.M = function() { + var mm = this.M2(); + if (mm >= 0) return Math.sqrt(mm); + return -Math.sqrt(-mm); + } + m.Perp2 = m.Pt2 = function() { return this.fX*this.fX + this.fY*this.fY;} + m.Pt = m.pt = function() { return Math.sqrt(this.P2()); } + m.Phi = m.phi = function() { return Math.atan2(this.fY, this.fX); } + m.Eta = m.eta = function() { return Math.atanh(this.Pz/this.P()); } + } + } + + return JSROOT; + +})); diff --git a/js/scripts/JSRootPainter.hierarchy.js b/js/scripts/JSRootPainter.hierarchy.js new file mode 100644 index 00000000000..f0969c6e565 --- /dev/null +++ b/js/scripts/JSRootPainter.hierarchy.js @@ -0,0 +1,2865 @@ +/// @file JSRootPainter.hierarchy.js +/// Hierarchy display functionality + +(function( factory ) { + if ( typeof define === "function" && define.amd ) { + define( ['JSRootCore', 'd3', 'JSRootPainter'], factory ); + } else + if (typeof exports === 'object' && typeof module !== 'undefined') { + factory(require("./JSRootCore.js"), require("./d3.min.js"), require("./JSRootPainter.js")); + } else { + + if (typeof d3 != 'object') + throw new Error('This extension requires d3.js', 'JSRootPainter.hierarchy.js'); + + if (typeof JSROOT == 'undefined') + throw new Error('JSROOT is not defined', 'JSRootPainter.hierarchy.js'); + + if (typeof JSROOT.Painter != 'object') + throw new Error('JSROOT.Painter not defined', 'JSRootPainter.hierarchy.js'); + + factory(JSROOT, d3); + } +} (function(JSROOT, d3) { + + "use strict"; + + JSROOT.sources.push("hierarchy"); + + + // =========================================================================================== + + /// function use to draw all items from TList or TObjArray inserted into the TCanvas list of primitives + function drawList(divid, lst, opt, callback) { + if (!lst || !lst.arr) return JSROOT.CallBack(callback); + + var obj = { + divid: divid, + lst: lst, + opt: opt, + indx: -1, + callback: callback, + draw_next: function() { + while (++this.indx < this.lst.arr.length) { + var handle = { func: this.draw_bind }, + item = this.lst.arr[this.indx], + opt = (this.lst.opt && this.lst.opt[this.indx]) ? this.lst.opt[this.indx] : this.opt; + if (!item) continue; + JSROOT.draw(this.divid, item, opt, handle); + if (!handle.completed) return; + } + + return JSROOT.CallBack(this.callback); + } + } + + obj.draw_bind = obj.draw_next.bind(obj); + + obj.draw_next(); + } + + // ===================== hierarchy scanning functions ================================== + + function FolderHierarchy(item, obj) { + + if (!obj || !('fFolders' in obj) || (obj.fFolders===null)) return false; + + if (obj.fFolders.arr.length===0) { item._more = false; return true; } + + item._childs = []; + + for ( var i = 0; i < obj.fFolders.arr.length; ++i) { + var chld = obj.fFolders.arr[i]; + item._childs.push( { + _name : chld.fName, + _kind : "ROOT." + chld._typename, + _obj : chld + }); + } + return true; + } + + function TaskHierarchy(item, obj) { + // function can be used for different derived classes + // we show not only child tasks, but all complex data members + + if (!obj || !('fTasks' in obj) || (obj.fTasks === null)) return false; + + ObjectHierarchy(item, obj, { exclude: ['fTasks', 'fName'] } ); + + if ((obj.fTasks.arr.length===0) && (item._childs.length==0)) { item._more = false; return true; } + + // item._childs = []; + + for ( var i = 0; i < obj.fTasks.arr.length; ++i) { + var chld = obj.fTasks.arr[i]; + item._childs.push( { + _name : chld.fName, + _kind : "ROOT." + chld._typename, + _obj : chld + }); + } + return true; + } + + function ListHierarchy(folder, lst) { + if (!JSROOT.IsRootCollection(lst)) return false; + + if ((lst.arr === undefined) || (lst.arr.length === 0)) { + folder._more = false; + return true; + } + + var do_context = false, prnt = folder; + while (prnt) { + if (prnt._do_context) do_context = true; + prnt = prnt._parent; + } + + // if list has objects with similar names, create cycle number for them + var ismap = (lst._typename == 'TMap'), names = [], cnt = [], cycle = []; + + for (var i = 0; i < lst.arr.length; ++i) { + var obj = ismap ? lst.arr[i].first : lst.arr[i]; + if (!obj) continue; // for such objects index will be used as name + var objname = obj.fName || obj.name; + if (!objname) continue; + var indx = names.indexOf(objname); + if (indx>=0) { + cnt[indx]++; + } else { + cnt[names.length] = cycle[names.length] = 1; + names.push(objname); + } + } + + folder._childs = []; + for ( var i = 0; i < lst.arr.length; ++i) { + var obj = ismap ? lst.arr[i].first : lst.arr[i]; + + var item; + + if (!obj || !obj._typename) { + item = { + _name: i.toString(), + _kind: "ROOT.NULL", + _title: "NULL", + _value: "null", + _obj: null + } + } else { + item = { + _name: obj.fName || obj.name, + _kind: "ROOT." + obj._typename, + _title: (obj.fTitle || "") + " type:" + obj._typename, + _obj: obj + }; + + switch(obj._typename) { + case 'TColor': item._value = JSROOT.Painter.MakeColorRGB(obj); break; + case 'TText': item._value = obj.fTitle; break; + case 'TLatex': item._value = obj.fTitle; break; + case 'TObjString': item._value = obj.fString; break; + default: if (lst.opt && lst.opt[i] && lst.opt[i].length) item._value = lst.opt[i]; + } + + if (do_context && JSROOT.canDraw(obj._typename)) item._direct_context = true; + + // if name is integer value, it should match array index + if (!item._name || (!isNaN(parseInt(item._name)) && (parseInt(item._name)!==i)) + || (lst.arr.indexOf(obj)<i)) { + item._name = i.toString(); + } else { + // if there are several such names, add cycle number to the item name + var indx = names.indexOf(obj.fName); + if ((indx>=0) && (cnt[indx]>1)) { + item._cycle = cycle[indx]++; + item._keyname = item._name; + item._name = item._keyname + ";" + item._cycle; + } + } + } + + folder._childs.push(item); + } + return true; + } + + function KeysHierarchy(folder, keys, file, dirname) { + + if (keys === undefined) return false; + + folder._childs = []; + + for (var i = 0; i < keys.length; ++i) { + var key = keys[i]; + + var item = { + _name : key.fName + ";" + key.fCycle, + _cycle : key.fCycle, + _kind : "ROOT." + key.fClassName, + _title : key.fTitle, + _keyname : key.fName, + _readobj : null, + _parent : folder + }; + + if (key.fObjlen > 1e5) item._title += ' (size: ' + (key.fObjlen/1e6).toFixed(1) + 'MB)'; + + if ('fRealName' in key) + item._realname = key.fRealName + ";" + key.fCycle; + + if (key.fClassName == 'TDirectory' || key.fClassName == 'TDirectoryFile') { + var dir = null; + if ((dirname!=null) && (file!=null)) dir = file.GetDir(dirname + key.fName); + if (dir == null) { + item._more = true; + item._expand = function(node, obj) { + // one can get expand call from child objects - ignore them + return KeysHierarchy(node, obj.fKeys); + } + } else { + // remove cycle number - we have already directory + item._name = key.fName; + KeysHierarchy(item, dir.fKeys, file, dirname + key.fName + "/"); + } + } else + if ((key.fClassName == 'TList') && (key.fName == 'StreamerInfo')) { + item._name = 'StreamerInfo'; + item._kind = "ROOT.TStreamerInfoList"; + item._title = "List of streamer infos for binary I/O"; + item._readobj = file.fStreamerInfos; + } + + folder._childs.push(item); + } + + return true; + } + + function ObjectHierarchy(top, obj, args) { + if (!top || (obj===null)) return false; + + top._childs = []; + + var proto = Object.prototype.toString.apply(obj); + + if (proto === '[object DataView]') { + + var item = { + _parent: top, + _name: 'size', + _value: obj.byteLength.toString(), + _vclass: 'h_value_num' + }; + + top._childs.push(item); + var namelen = (obj.byteLength < 10) ? 1 : JSROOT.log10(obj.byteLength); + + for (var k=0;k<obj.byteLength;++k) { + if (k % 16 === 0) { + item = { + _parent: top, + _name: k.toString(), + _value: "", + _vclass: 'h_value_num' + }; + while (item._name.length < namelen) item._name = "0" + item._name; + top._childs.push(item); + } + + var val = obj.getUint8(k).toString(16); + while (val.length<2) val = "0"+val; + if (item._value.length>0) + item._value += (k%4===0) ? " | " : " "; + + item._value += val; + } + return true; + } + + // check nosimple property in all parents + var nosimple = true, do_context = false, prnt = top; + while (prnt) { + if (prnt._do_context) do_context = true; + if ('_nosimple' in prnt) { nosimple = prnt._nosimple; break; } + prnt = prnt._parent; + } + + var isarray = (proto.lastIndexOf('Array]') == proto.length-6) && (proto.indexOf('[object')==0) && !isNaN(obj.length), + compress = isarray && (obj.length > JSROOT.gStyle.HierarchyLimit), arrcompress = false; + + if (isarray && (top._name==="Object") && !top._parent) top._name = "Array"; + + if (compress) { + arrcompress = true; + for (var k=0;k<obj.length;++k) { + var typ = typeof obj[k]; + if ((typ === 'number') || (typ === 'boolean') || (typ=='string' && (obj[k].length<16))) continue; + arrcompress = false; break; + } + } + + if (!('_obj' in top)) + top._obj = obj; + else + if (top._obj !== obj) alert('object missmatch'); + + if (!top._title) { + if (obj._typename) + top._title = "ROOT." + obj._typename; + else + if (isarray) top._title = "Array len: " + obj.length; + } + + if (arrcompress) { + for (var k=0;k<obj.length;) { + + var nextk = Math.min(k+10,obj.length), allsame = true, prevk = k; + + while (allsame) { + allsame = true; + for (var d=prevk;d<nextk;++d) + if (obj[k]!==obj[d]) allsame = false; + + if (allsame) { + if (nextk===obj.length) break; + prevk = nextk; + nextk = Math.min(nextk+10,obj.length); + } else + if (prevk !== k) { + // last block with similar + nextk = prevk; + allsame = true; + break; + } + } + + var item = { _parent: top, _name: k+".."+(nextk-1), _vclass: 'h_value_num' }; + + if (allsame) { + item._value = obj[k].toString(); + } else { + item._value = ""; + for (var d=k;d<nextk;++d) + item._value += ((d===k) ? "[ " : ", ") + obj[d].toString(); + item._value += " ]"; + } + + top._childs.push(item); + + k = nextk; + } + return true; + } + + var lastitem, lastkey, lastfield, cnt; + + for (var key in obj) { + if ((key == '_typename') || (key[0]=='$')) continue; + var fld = obj[key]; + if (typeof fld == 'function') continue; + if (args && args.exclude && (args.exclude.indexOf(key)>=0)) continue; + + if (compress && lastitem) { + if (lastfield===fld) { ++cnt; lastkey = key; continue; } + if (cnt>0) lastitem._name += ".." + lastkey; + } + + var item = { _parent: top, _name: key }; + + if (compress) { lastitem = item; lastkey = key; lastfield = fld; cnt = 0; } + + if (fld === null) { + item._value = item._title = "null"; + if (!nosimple) top._childs.push(item); + continue; + } + + var simple = false; + + if (typeof fld == 'object') { + + proto = Object.prototype.toString.apply(fld); + + if ((proto.lastIndexOf('Array]') == proto.length-6) && (proto.indexOf('[object')==0)) { + item._title = "array len=" + fld.length; + simple = (proto != '[object Array]'); + if (fld.length === 0) { + item._value = "[ ]"; + item._more = false; // hpainter will not try to expand again + } else { + item._value = "[...]"; + item._more = true; + item._expand = ObjectHierarchy; + item._obj = fld; + } + } else + if (proto === "[object DataView]") { + item._title = 'DataView len=' + fld.byteLength; + item._value = "[...]"; + item._more = true; + item._expand = ObjectHierarchy; + item._obj = fld; + } else + if (proto === "[object Date]") { + item._more = false; + item._title = 'Date'; + item._value = fld.toString(); + item._vclass = 'h_value_num'; + } else { + + if (fld.$kind || fld._typename) + item._kind = item._title = "ROOT." + (fld.$kind || fld._typename); + + if (fld._typename) { + item._title = fld._typename; + if (do_context && JSROOT.canDraw(fld._typename)) item._direct_context = true; + } + + // check if object already shown in hierarchy (circular dependency) + var curr = top, inparent = false; + while (curr && !inparent) { + inparent = (curr._obj === fld); + curr = curr._parent; + } + + if (inparent) { + item._value = "{ prnt }"; + item._vclass = 'h_value_num'; + item._more = false; + simple = true; + } else { + item._obj = fld; + item._more = false; + + switch(fld._typename) { + case 'TColor': item._value = JSROOT.Painter.MakeColorRGB(fld); break; + case 'TText': item._value = fld.fTitle; break; + case 'TLatex': item._value = fld.fTitle; break; + case 'TObjString': item._value = fld.fString; break; + default: + if (JSROOT.IsRootCollection(fld) && (typeof fld.arr === "object")) { + item._value = fld.arr.length ? "[...]" : "[]"; + item._title += ", size:" + fld.arr.length; + if (fld.arr.length>0) item._more = true; + } else { + item._more = true; + item._value = "{ }"; + } + } + } + } + } else + if ((typeof fld === 'number') || (typeof fld === 'boolean')) { + simple = true; + if (key == 'fBits') + item._value = "0x" + fld.toString(16); + else + item._value = fld.toString(); + item._vclass = 'h_value_num'; + } else + if (typeof fld === 'string') { + simple = true; + item._value = '"' + fld.replace(/\&/g, '&').replace(/\"/g, '"').replace(/</g, '<').replace(/>/g, '>') + '"'; + item._vclass = 'h_value_str'; + } else + if (typeof fld === 'undefined') { + simple = true; + item._value = "undefined"; + item._vclass = 'h_value_num'; + } else { + simple = true; + alert('miss ' + key + ' ' + typeof fld); + } + + if (!simple || !nosimple) + top._childs.push(item); + } + + if (compress && lastitem && (cnt>0)) lastitem._name += ".." + lastkey; + + return true; + } + + // ================================================================================================= + + /// special layout with three different areas for browser (left), status line (bottom) and central drawing + /// Main application is normal browser in JSROOT, but later one should be able to use it in ROOT6 canvas + function BrowserLayout(id, hpainter, objpainter) { + this.gui_div = id; + this.hpainter = hpainter; // painter for brwoser area (if any) + this.objpainter = objpainter; // painter for object area (if any) + this.browser_kind = null; // should be 'float' or 'fix' + } + + BrowserLayout.prototype.main = function() { + return d3.select("#" + this.gui_div); + } + + BrowserLayout.prototype.drawing_divid = function() { + return this.gui_div + "_drawing"; + } + + BrowserLayout.prototype.CheckResize = function() { + if (this.hpainter && (typeof this.hpainter.CheckResize == 'function')) + this.hpainter.CheckResize(); + else if (this.objpainter && (typeof this.objpainter.CheckResize == 'function')) { + this.objpainter.CheckResize(true); + } + } + + /// method used to create basic elements + /// should be called only once + BrowserLayout.prototype.Create = function(with_browser) { + var main = this.main(); + + main.append("div").attr("id", this.drawing_divid()) + .classed("jsroot_draw_area", true) + .style('position',"absolute").style('left',0).style('top',0).style('bottom',0).style('right',0); + + if (with_browser) main.append("div").classed("jsroot_browser", true); + } + + BrowserLayout.prototype.CreateBrowserBtns = function() { + var br = this.main().select(".jsroot_browser"); + if (br.empty()) return; + var btns = br.append("div").classed("jsroot_browser_btns", true).classed("jsroot", true); + btns.style('position',"absolute").style("left","7px").style("top","7px"); + if (JSROOT.touches) btns.style('opacity','0.2'); // on touch devices should be always visible + return btns; + } + + BrowserLayout.prototype.RemoveBrowserBtns = function() { + this.main().select(".jsroot_browser").select(".jsroot_browser_btns").remove(); + } + + BrowserLayout.prototype.SetBrowserContent = function(guiCode) { + var main = d3.select("#" + this.gui_div + " .jsroot_browser"); + if (main.empty()) return; + + main.insert('div', ".jsroot_browser_btns").classed('jsroot_browser_area', true) + .style('position',"absolute").style('left',0).style('top',0).style('bottom',0).style('width','250px') + .style('padding-left','5px') + .style('display','flex').style('flex-direction', 'column') /* use the flex model */ + .html("<p class='jsroot_browser_title'>title</p>" + guiCode); + } + + BrowserLayout.prototype.HasContent = function() { + var main = d3.select("#" + this.gui_div + " .jsroot_browser"); + if (main.empty()) return false; + return !main.select(".jsroot_browser_area").empty(); + } + + BrowserLayout.prototype.DeleteContent = function() { + var main = d3.select("#" + this.gui_div + " .jsroot_browser"); + if (main.empty()) return; + + main.selectAll("*").remove(); + delete this.browser_visible; + } + + BrowserLayout.prototype.HasStatus = function() { + var main = d3.select("#"+this.gui_div+" .jsroot_browser"); + if (main.empty()) return false; + + var id = this.gui_div + "_status", + line = d3.select("#"+id); + + return !line.empty(); + } + + BrowserLayout.prototype.CreateStatusLine = function(height, mode) { + if (!this.gui_div) return ''; + var pthis = this; + JSROOT.AssertPrerequisites('jq2d', function() { + pthis.CreateStatusLine(height, mode); + }); + return this.gui_div + "_status"; + } + + // =========== painter of hierarchical structures ================================= + + JSROOT.hpainter = null; // global pointer + + // HierarchyPainter + + function HierarchyPainter(name, frameid, backgr) { + JSROOT.TBasePainter.call(this); + this.name = name; + this.h = null; // hierarchy + this.with_icons = true; + this.background = backgr; + this.files_monitoring = (frameid == null); // by default files monitored when nobrowser option specified + this.nobrowser = (frameid === null); + if (!this.nobrowser) this.SetDivId(frameid); // this is required to be able cleanup painter + + // remember only very first instance + if (!JSROOT.hpainter) + JSROOT.hpainter = this; + } + + HierarchyPainter.prototype = Object.create(JSROOT.TBasePainter.prototype); + + HierarchyPainter.prototype.Cleanup = function() { + // clear drawing and browser + this.clear(true); + + JSROOT.TBasePainter.prototype.Cleanup.call(this); + + if (JSROOT.hpainter === this) + JSROOT.hpainter = null; + } + + HierarchyPainter.prototype.FileHierarchy = function(file) { + var painter = this; + + var folder = { + _name : file.fFileName, + _title : (file.fTitle ? (file.fTitle + ", path ") : "") + file.fFullURL, + _kind : "ROOT.TFile", + _file : file, + _fullurl : file.fFullURL, + _localfile : file.fLocalFile, + _had_direct_read : false, + // this is central get method, item or itemname can be used + _get : function(item, itemname, callback) { + + var fff = this; // file item + + if (item && item._readobj) + return JSROOT.CallBack(callback, item, item._readobj); + + if (item!=null) itemname = painter.itemFullName(item, fff); + + function ReadFileObject(file) { + if (!fff._file) fff._file = file; + + if (file == null) return JSROOT.CallBack(callback, item, null); + + file.ReadObject(itemname, function(obj) { + + // if object was read even when item did not exist try to reconstruct new hierarchy + if (!item && obj) { + // first try to found last read directory + var d = painter.Find({name:itemname, top:fff, last_exists:true, check_keys:true }); + if ((d!=null) && ('last' in d) && (d.last!=fff)) { + // reconstruct only subdir hierarchy + var dir = file.GetDir(painter.itemFullName(d.last, fff)); + if (dir) { + d.last._name = d.last._keyname; + var dirname = painter.itemFullName(d.last, fff); + KeysHierarchy(d.last, dir.fKeys, file, dirname + "/"); + } + } else { + // reconstruct full file hierarchy + KeysHierarchy(fff, file.fKeys, file, ""); + } + item = painter.Find({name:itemname, top: fff}); + } + + if (item) { + item._readobj = obj; + // remove cycle number for objects supporting expand + if ('_expand' in item) item._name = item._keyname; + } + + JSROOT.CallBack(callback, item, obj); + }); + } + + if (fff._file) ReadFileObject(fff._file); else + if (fff._localfile) new JSROOT.TLocalFile(fff._localfile, ReadFileObject); else + if (fff._fullurl) new JSROOT.TFile(fff._fullurl, ReadFileObject); + } + }; + + KeysHierarchy(folder, file.fKeys, file, ""); + + return folder; + } + + HierarchyPainter.prototype.ForEach = function(callback, top) { + + if (!top) top = this.h; + if (!top || (typeof callback != 'function')) return; + function each_item(item) { + callback(item); + if ('_childs' in item) + for (var n = 0; n < item._childs.length; ++n) { + item._childs[n]._parent = item; + each_item(item._childs[n]); + } + } + + each_item(top); + } + + /** @summary Ssearch item in the hierarchy + * @param {object|string} arg - item name or object with arguments + * @param {string} arg.name - item to search + * @param {boolean} [arg.force = false] - specified elements will be created when not exists + * @param {boolean} [arg.last_exists = false] - when specified last parent element will be returned + * @param {boolean} [arg.check_keys = false] - check TFile keys with cycle suffix + * @param {object} [arg.top = null] - element to start search from + * @private + */ + + HierarchyPainter.prototype.Find = function(arg) { + + function find_in_hierarchy(top, fullname) { + + if (!fullname || (fullname.length == 0) || !top) return top; + + var pos = fullname.length; + + if (!top._parent && (top._kind !== 'TopFolder') && (fullname.indexOf(top._name)===0)) { + // it is allowed to provide item name, which includes top-parent like file.root/folder/item + // but one could skip top-item name, if there are no other items + if (fullname === top._name) return top; + + var len = top._name.length; + if (fullname[len] == "/") { + fullname = fullname.substr(len+1); + pos = fullname.length; + } + } + + function process_child(child, ignore_prnt) { + // set parent pointer when searching child + if (!ignore_prnt) child._parent = top; + + if ((pos >= fullname.length-1) || (pos < 0)) return child; + + return find_in_hierarchy(child, fullname.substr(pos + 1)); + } + + while (pos > 0) { + // we try to find element with slashes inside - start from full name + var localname = (pos >= fullname.length) ? fullname : fullname.substr(0, pos); + + if (top._childs) { + // first try to find direct matched item + for (var i = 0; i < top._childs.length; ++i) + if (top._childs[i]._name == localname) + return process_child(top._childs[i]); + + // if first child online, check its elements + if ((top._kind === 'TopFolder') && (top._childs[0]._online!==undefined)) + for (var i = 0; i < top._childs[0]._childs.length; ++i) + if (top._childs[0]._childs[i]._name == localname) + return process_child(top._childs[0]._childs[i], true); + + // if allowed, try to found item with key + if (arg.check_keys) { + var newest = null; + for (var i = 0; i < top._childs.length; ++i) { + if (top._childs[i]._keyname === localname) { + if (!newest || (newest._cycle < top._childs[i]._cycle)) newest = top._childs[i]; + } + } + if (newest) return process_child(newest); + } + + var allow_index = arg.allow_index; + if ((localname[0] === '[') && (localname[localname.length-1] === ']') && + !isNaN(parseInt(localname.substr(1,localname.length-2)))) { + allow_index = true; + localname = localname.substr(1,localname.length-2); + } + + // when search for the elements it could be allowed to check index + if (allow_index) { + var indx = parseInt(localname); + if (!isNaN(indx) && (indx>=0) && (indx<top._childs.length)) + return process_child(top._childs[indx]); + } + } + + pos = fullname.lastIndexOf("/", pos - 1); + } + + if (arg.force) { + // if did not found element with given name we just generate it + if (top._childs === undefined) top._childs = []; + pos = fullname.indexOf("/"); + var child = { _name: ((pos < 0) ? fullname : fullname.substr(0, pos)) }; + top._childs.push(child); + return process_child(child); + } + + return (arg.last_exists && top) ? { last: top, rest: fullname } : null; + } + + var top = this.h, itemname = ""; + + if (arg === null) return null; else + if (typeof arg == 'string') { itemname = arg; arg = {}; } else + if (typeof arg == 'object') { itemname = arg.name; if ('top' in arg) top = arg.top; } else + return null; + + if (itemname === "__top_folder__") return top; + + if ((typeof itemname == 'string') && (itemname.indexOf("img:")==0)) return null; + + return find_in_hierarchy(top, itemname); + } + + HierarchyPainter.prototype.itemFullName = function(node, uptoparent, compact) { + + if (node && node._kind ==='TopFolder') return "__top_folder__"; + + var res = ""; + + while (node) { + // online items never includes top-level folder + if ((node._online!==undefined) && !uptoparent) return res; + + if ((node === uptoparent) || (node._kind==='TopFolder')) break; + if (compact && !node._parent) break; // in compact form top-parent is not included + if (res.length > 0) res = "/" + res; + res = node._name + res; + node = node._parent; + } + + return res; + } + + HierarchyPainter.prototype.ExecuteCommand = function(itemname, callback) { + // execute item marked as 'Command' + // If command requires additional arguments, they could be specified as extra arguments + // Or they will be requested interactive + + var hitem = this.Find(itemname), + url = this.GetOnlineItemUrl(hitem) + "/cmd.json", + pthis = this, + d3node = d3.select((typeof callback == 'function') ? undefined : callback); + + if ('_numargs' in hitem) + for (var n = 0; n < hitem._numargs; ++n) { + var argname = "arg" + (n+1), argvalue = null; + if (n+2<arguments.length) argvalue = arguments[n+2]; + if (!argvalue && (typeof callback == 'object')) + argvalue = prompt("Input argument " + argname + " for command " + hitem._name, ""); + if (!argvalue) return; + url += ((n==0) ? "?" : "&") + argname + "=" + argvalue; + } + + if (!d3node.empty()) { + d3node.style('background','yellow'); + if (hitem && hitem._title) d3node.attr('title', "Executing " + hitem._title); + } + + JSROOT.NewHttpRequest(url, 'text', function(res) { + if (typeof callback == 'function') return callback(res); + if (d3node.empty()) return; + var col = ((res!=null) && (res!='false')) ? 'green' : 'red'; + if (hitem && hitem._title) d3node.attr('title', hitem._title + " lastres=" + res); + d3node.style('background', col); + setTimeout(function() { d3node.style('background', ''); }, 2000); + if ((col == 'green') && ('_hreload' in hitem)) pthis.reload(); + if ((col == 'green') && ('_update_item' in hitem)) pthis.updateItems(hitem._update_item.split(";")); + }).send(); + } + + HierarchyPainter.prototype.RefreshHtml = function(callback) { + if (!this.divid) return JSROOT.CallBack(callback); + var hpainter = this; + JSROOT.AssertPrerequisites('jq2d', function() { + hpainter.RefreshHtml(callback); + }); + } + + HierarchyPainter.prototype.get = function(arg, call_back, options) { + // get object item with specified name + // depending from provided option, same item can generate different object types + + if (arg===null) return JSROOT.CallBack(call_back, null, null); + + var itemname, item, hpainter = this; + + if (typeof arg === 'string') { + itemname = arg; + } else if (typeof arg === 'object') { + if ((arg._parent!==undefined) && (arg._name!==undefined) && (arg._kind!==undefined)) item = arg; else + if (arg.name!==undefined) itemname = arg.name; else + if (arg.arg!==undefined) itemname = arg.arg; else + if (arg.item!==undefined) item = arg.item; + } + + if ((typeof itemname == 'string') && (itemname.indexOf("img:")==0)) + return JSROOT.CallBack(call_back, null, { + _typename: "TJSImage", // artificial class, can be created by users + fName: itemname.substr(4) + }); + + if (item) itemname = this.itemFullName(item); + else item = this.Find( { name: itemname, allow_index: true, check_keys: true } ); + + // if item not found, try to find nearest parent which could allow us to get inside + var d = (item!=null) ? null : this.Find({ name: itemname, last_exists: true, check_keys: true, allow_index: true }); + + // if item not found, try to expand hierarchy central function + // implements not process get in central method of hierarchy item (if exists) + // if last_parent found, try to expand it + if ((d !== null) && ('last' in d) && (d.last !== null)) { + var parentname = this.itemFullName(d.last); + + // this is indication that expand does not give us better path to searched item + if ((typeof arg == 'object') && ('rest' in arg)) + if ((arg.rest == d.rest) || (arg.rest.length <= d.rest.length)) + return JSROOT.CallBack(call_back); + + return this.expand(parentname, function(res) { + if (!res) JSROOT.CallBack(call_back); + var newparentname = hpainter.itemFullName(d.last); + if (newparentname.length>0) newparentname+="/"; + hpainter.get( { name: newparentname + d.rest, rest: d.rest }, call_back, options); + }, null, true); + } + + if ((item !== null) && (typeof item._obj == 'object')) + return JSROOT.CallBack(call_back, item, item._obj); + + // normally search _get method in the parent items + var curr = item; + while (curr) { + if (('_get' in curr) && (typeof curr._get == 'function')) + return curr._get(item, null, call_back, options); + curr = ('_parent' in curr) ? curr._parent : null; + } + + JSROOT.CallBack(call_back, item, null); + } + + HierarchyPainter.prototype.draw = function(divid, obj, drawopt) { + // just envelope, one should be able to redefine it for sub-classes + return JSROOT.draw(divid, obj, drawopt); + } + + HierarchyPainter.prototype.redraw = function(divid, obj, drawopt) { + // just envelope, one should be able to redefine it for sub-classes + return JSROOT.redraw(divid, obj, drawopt); + } + + HierarchyPainter.prototype.player = function(itemname, option, call_back) { + var item = this.Find(itemname); + + if (!item || !item._player) return JSROOT.CallBack(call_back, null); + + var hpainter = this; + + JSROOT.AssertPrerequisites(item._prereq || '', function() { + + var player_func = JSROOT.findFunction(item._player); + if (!player_func) return JSROOT.CallBack(call_back, null); + + hpainter.CreateDisplay(function(mdi) { + var res = mdi ? player_func(hpainter, itemname, option) : null; + JSROOT.CallBack(call_back, res); + }); + }); + } + + HierarchyPainter.prototype.canDisplay = function(item, drawopt) { + if (!item) return false; + if (item._player) return true; + if (item._can_draw !== undefined) return item._can_draw; + if (drawopt == 'inspect') return true; + var handle = JSROOT.getDrawHandle(item._kind, drawopt); + return handle && (('func' in handle) || ('draw_field' in handle)); + } + + HierarchyPainter.prototype.isItemDisplayed = function(itemname) { + var mdi = this.GetDisplay(); + if (!mdi) return false; + + return mdi.FindFrame(itemname) !== null; + } + + HierarchyPainter.prototype.display = function(itemname, drawopt, call_back) { + var h = this, + painter = null, + updating = false, + item = null, + display_itemname = itemname, + frame_name = itemname, + marker = "::_display_on_frame_::", + p = drawopt ? drawopt.indexOf(marker) : -1; + + if (p>=0) { + frame_name = drawopt.substr(p + marker.length); + drawopt = drawopt.substr(0, p); + } + + function display_callback(respainter) { + if (!updating) JSROOT.progress(); + + if (respainter && (typeof respainter === 'object') && (typeof respainter.SetItemName === 'function')) { + respainter.SetItemName(display_itemname, updating ? null : drawopt, h); // mark painter as created from hierarchy + if (item && !item._painter) item._painter = respainter; + } + JSROOT.CallBack(call_back, respainter || painter, display_itemname); + } + + h.CreateDisplay(function(mdi) { + + if (!mdi) return display_callback(); + + item = h.Find(display_itemname); + + if (item && ('_player' in item)) + return h.player(display_itemname, drawopt, display_callback); + + updating = (typeof(drawopt)=='string') && (drawopt.indexOf("update:")==0); + + if (updating) { + drawopt = drawopt.substr(7); + if (!item || item._doing_update) return display_callback(); + item._doing_update = true; + } + + if (item && !h.canDisplay(item, drawopt)) return display_callback(); + + var divid = ""; + if ((typeof(drawopt)=='string') && (drawopt.indexOf("divid:")>=0)) { + var pos = drawopt.indexOf("divid:"); + divid = drawopt.slice(pos+6); + drawopt = drawopt.slice(0, pos); + } + + if (!updating) JSROOT.progress("Loading " + display_itemname); + + h.get(display_itemname, function(resitem, obj) { + + if (!updating) JSROOT.progress(); + + if (!item) item = resitem; + + if (updating && item) delete item._doing_update; + if (!obj) return display_callback(); + + if (!updating) JSROOT.progress("Drawing " + display_itemname); + + if (divid.length > 0) + return (updating ? JSROOT.redraw : JSROOT.draw)(divid, obj, drawopt, display_callback); + + mdi.ForEachPainter(function(p, frame) { + if (p.GetItemName() != display_itemname) return; + // verify that object was drawn with same option as specified now (if any) + if (!updating && (drawopt!=null) && (p.GetItemDrawOpt()!=drawopt)) return; + mdi.ActivateFrame(frame); + + var handle = null; + if (obj._typename) handle = JSROOT.getDrawHandle("ROOT." + obj._typename); + if (handle && handle.draw_field && obj[handle.draw_field]) + obj = obj[handle.draw_field]; + + if (p.RedrawObject(obj)) painter = p; + }); + + if (painter) return display_callback(); + + if (updating) { + JSROOT.console("something went wrong - did not found painter when doing update of " + display_itemname); + return display_callback(); + } + + var frame = mdi.FindFrame(frame_name, true); + d3.select(frame).html(""); + mdi.ActivateFrame(frame); + + JSROOT.draw(d3.select(frame).attr("id"), obj, drawopt, display_callback); + + if (JSROOT.gStyle.DragAndDrop) + h.enable_dropping(frame, display_itemname); + + }, drawopt); + }); + } + + HierarchyPainter.prototype.enable_dragging = function(element, itemname) { + // here is not defined - implemented with jquery + } + + HierarchyPainter.prototype.enable_dropping = function(frame, itemname) { + // here is not defined - implemented with jquery + } + + HierarchyPainter.prototype.dropitem = function(itemname, divid, opt, call_back) { + var h = this; + + if (opt && typeof opt === 'function') { call_back = opt; opt = ""; } + if (opt===undefined) opt = ""; + + function drop_callback(drop_painter) { + if (drop_painter && (typeof drop_painter === 'object')) drop_painter.SetItemName(itemname, null, h); + JSROOT.CallBack(call_back); + } + + if (itemname == "$legend") + return JSROOT.AssertPrerequisites("v6;hist", function() { + var res = JSROOT.Painter.produceLegend(divid, opt); + JSROOT.CallBack(drop_callback, res); + }); + + h.get(itemname, function(item, obj) { + + if (!obj) return JSROOT.CallBack(call_back); + + var main_painter = JSROOT.GetMainPainter(divid); + + if (main_painter && (typeof main_painter.PerformDrop === 'function')) + return main_painter.PerformDrop(obj, itemname, item, opt, drop_callback); + + if (main_painter && main_painter.accept_drops) + return JSROOT.draw(divid, obj, "same " + opt, drop_callback); + + h.CleanupFrame(divid); + return JSROOT.draw(divid, obj, opt, drop_callback); + }); + + return true; + } + + HierarchyPainter.prototype.updateItems = function(items) { + // argument is item name or array of string with items name + // only already drawn items will be update with same draw option + + if (!this.disp || !items) return; + + var draw_items = [], draw_options = []; + + this.disp.ForEachPainter(function(p) { + var itemname = p.GetItemName(); + if (!itemname || (draw_items.indexOf(itemname)>=0)) return; + if (typeof items == 'array') { + if (items.indexOf(itemname) < 0) return; + } else { + if (items != itemname) return; + } + draw_items.push(itemname); + draw_options.push("update:" + p.GetItemDrawOpt()); + }, true); // only visible panels are considered + + if (draw_items.length > 0) + this.displayAll(draw_items, draw_options); + } + + + HierarchyPainter.prototype.updateAll = function(only_auto_items, only_items) { + // method can be used to fetch new objects and update all existing drawings + // if only_auto_items specified, only automatic items will be updated + + if (!this.disp) return; + + if (only_auto_items === "monitoring") only_auto_items = !this._monitoring_on; + + var allitems = [], options = [], hpainter = this; + + // first collect items + this.disp.ForEachPainter(function(p) { + var itemname = p.GetItemName(), + drawopt = p.GetItemDrawOpt(); + if ((typeof itemname != 'string') || (allitems.indexOf(itemname)>=0)) return; + + var item = hpainter.Find(itemname), forced = false; + if (!item || ('_not_monitor' in item) || ('_player' in item)) return; + + if ('_always_monitor' in item) { + forced = true; + } else { + var handle = JSROOT.getDrawHandle(item._kind); + if (handle && ('monitor' in handle)) { + if ((handle.monitor===false) || (handle.monitor=='never')) return; + if (handle.monitor==='always') forced = true; + } + } + + if (forced || !only_auto_items) { + allitems.push(itemname); + options.push("update:" + drawopt); + } + }, true); // only visible panels are considered + + var painter = this; + + // force all files to read again (normally in non-browser mode) + if (this.files_monitoring && !only_auto_items) + this.ForEachRootFile(function(item) { + painter.ForEach(function(fitem) { delete fitem._readobj; }, item); + delete item._file; + }); + + if (allitems.length > 0) + this.displayAll(allitems, options); + } + + HierarchyPainter.prototype.displayAll = function(items, options, call_back) { + + if (!items || (items.length == 0)) return JSROOT.CallBack(call_back); + + var h = this; + + if (!options) options = []; + while (options.length < items.length) + options.push(""); + + if ((options.length == 1) && (options[0] == "iotest")) { + h.clear(); + d3.select("#" + h.disp_frameid).html("<h2>Start I/O test</h2>") + + var tm0 = new Date(); + return h.get(items[0], function(item, obj) { + var tm1 = new Date(); + d3.select("#" + h.disp_frameid).append("h2").html("Item " + items[0] + " reading time = " + (tm1.getTime() - tm0.getTime()) + "ms"); + return JSROOT.CallBack(call_back); + }); + } + + var dropitems = new Array(items.length), dropopts = new Array(items.length), images = new Array(items.length); + + // First of all check that items are exists, look for cycle extension and plus sign + for (var i = 0; i < items.length; ++i) { + dropitems[i] = dropopts[i] = null; + + var item = items[i], can_split = true; + + if (item && item.indexOf("img:")==0) { images[i] = true; continue; } + + if (item && (item.length>1) && (item[0]=='\'') && (item[item.length-1]=='\'')) { + items[i] = item.substr(1, item.length-2); + can_split = false; + } + + var elem = h.Find({ name: items[i], check_keys: true }); + if (elem) { items[i] = h.itemFullName(elem); continue; } + + if (can_split && (items[i][0]=='[') && (items[i][items[i].length-1]==']')) { + dropitems[i] = JSROOT.ParseAsArray(items[i]); + items[i] = dropitems[i].shift(); + } else + if (can_split && (items[i].indexOf("+") > 0)) { + dropitems[i] = items[i].split("+"); + items[i] = dropitems[i].shift(); + } + + if (dropitems[i] && dropitems[i].length > 0) { + // allow to specify _same_ item in different file + for (var j = 0; j < dropitems[i].length; ++j) { + var pos = dropitems[i][j].indexOf("_same_"); + if ((pos>0) && (h.Find(dropitems[i][j])===null)) + dropitems[i][j] = dropitems[i][j].substr(0,pos) + items[i].substr(pos); + + elem = h.Find({ name: dropitems[i][j], check_keys: true }); + if (elem) dropitems[i][j] = h.itemFullName(elem); + } + + if ((options[i][0] == "[") && (options[i][options[i].length-1] == "]")) { + dropopts[i] = JSROOT.ParseAsArray(options[i]); + options[i] = dropopts[i].shift(); + } else + if (options[i].indexOf("+") > 0) { + dropopts[i] = options[i].split("+"); + options[i] = dropopts[i].shift(); + } else { + dropopts[i] = []; + } + + while (dropopts[i].length < dropitems[i].length) dropopts[i].push(""); + } + + // also check if subsequent items has _same_, than use name from first item + var pos = items[i].indexOf("_same_"); + if ((pos>0) && !h.Find(items[i]) && (i>0)) + items[i] = items[i].substr(0,pos) + items[0].substr(pos); + + elem = h.Find({ name: items[i], check_keys: true }); + if (elem) items[i] = h.itemFullName(elem); + } + + // now check that items can be displayed + for (var n = items.length-1; n>=0; --n) { + if (images[n]) continue; + var hitem = h.Find(items[n]); + if (!hitem || h.canDisplay(hitem, options[n])) continue; + // try to expand specified item + h.expand(items[n], null, null, true); + items.splice(n, 1); + options.splice(n, 1); + dropitems.splice(n, 1); + } + + if (items.length == 0) return JSROOT.CallBack(call_back); + + var frame_names = new Array(items.length), items_wait = new Array(items.length); + for (var n=0; n < items.length;++n) { + items_wait[n] = 0; + var fname = items[n], k = 0; + if (items.indexOf(fname) < n) items_wait[n] = true; // if same item specified, one should wait first drawing before start next + var p = options[n].indexOf("frameid:"); + if (p>=0) { + fname = options[n].substr(p+8); + options[n] = options[n].substr(0,p); + } else { + while (frame_names.indexOf(fname)>=0) + fname = items[n] + "_" + k++; + } + frame_names[n] = fname; + } + + // now check if several same items present - select only one for the drawing + // if draw option includes 'main', such item will be drawn first + for (var n=0; n<items.length;++n) { + if (items_wait[n] !== 0) continue; + var found_main = n; + for (var k=0; k<items.length;++k) + if ((items[n]===items[k]) && (options[k].indexOf('main')>=0)) found_main = k; + for (var k=0; k<items.length;++k) + if (items[n]===items[k]) items_wait[k] = (found_main != k); + } + + h.CreateDisplay(function(mdi) { + if (!mdi) return JSROOT.CallBack(call_back); + + // Than create empty frames for each item + for (var i = 0; i < items.length; ++i) + if (options[i].indexOf('update:')!==0) { + mdi.CreateFrame(frame_names[i]); + options[i] += "::_display_on_frame_::"+frame_names[i]; + } + + function DropNextItem(indx, painter) { + if (painter && dropitems[indx] && (dropitems[indx].length>0)) + return h.dropitem(dropitems[indx].shift(), painter.divid, dropopts[indx].shift(), DropNextItem.bind(h, indx, painter)); + + dropitems[indx] = null; // mark that all drop items are processed + items[indx] = null; // mark item as ready + + var isany = false; + + for (var cnt = 0; cnt < items.length; ++cnt) { + if (dropitems[cnt]) isany = true; + if (items[cnt]===null) continue; // ignore completed item + isany = true; + if (items_wait[cnt] && items.indexOf(items[cnt])===cnt) { + items_wait[cnt] = false; + h.display(items[cnt], options[cnt], DropNextItem.bind(h,cnt)); + } + } + + // only when items drawn and all sub-items dropped, one could perform call-back + if (!isany && call_back) { + JSROOT.CallBack(call_back); + call_back = null; + } + } + + // We start display of all items parallel, but only if they are not the same + for (var i = 0; i < items.length; ++i) + if (!items_wait[i]) + h.display(items[i], options[i], DropNextItem.bind(h,i)); + }); + } + + HierarchyPainter.prototype.reload = function() { + var hpainter = this; + if ('_online' in this.h) + this.OpenOnline(this.h._online, function() { + hpainter.RefreshHtml(); + }); + } + + HierarchyPainter.prototype.UpdateTreeNode = function() { + // dummy function, will be redefined when jquery part loaded + } + + HierarchyPainter.prototype.activate = function(items, force) { + // activate (select) specified item + // if force specified, all required sub-levels will be opened + + if (typeof items == 'string') items = [ items ]; + + var active = [], // array of elements to activate + painter = this, // painter itself + update = []; // array of elements to update + this.ForEach(function(item) { if (item._background) { active.push(item); delete item._background; } }); + + function mark_active() { + if (typeof painter.UpdateBackground !== 'function') return; + + for (var n=update.length-1;n>=0;--n) + painter.UpdateTreeNode(update[n]); + + for (var n=0;n<active.length;++n) + painter.UpdateBackground(active[n], force); + } + + function find_next(itemname, prev_found) { + if (itemname === undefined) { + // extract next element + if (items.length == 0) return mark_active(); + itemname = items.shift(); + } + + var hitem = painter.Find(itemname); + + if (!hitem) { + var d = painter.Find({ name: itemname, last_exists: true, check_keys: true, allow_index: true }); + if (!d || !d.last) return find_next(); + d.now_found = painter.itemFullName(d.last); + + if (force) { + + // if after last expand no better solution found - skip it + if ((prev_found!==undefined) && (d.now_found === prev_found)) return find_next(); + + return painter.expand(d.now_found, function(res) { + if (!res) return find_next(); + var newname = painter.itemFullName(d.last); + if (newname.length>0) newname+="/"; + find_next(newname + d.rest, d.now_found); + }); + } + hitem = d.last; + } + + if (hitem) { + // check that item is visible (opened), otherwise should enable parent + + var prnt = hitem._parent; + while (prnt) { + if (!prnt._isopen) { + if (force) { + prnt._isopen = true; + if (update.indexOf(prnt)<0) update.push(prnt); + } else { + hitem = prnt; break; + } + } + prnt = prnt._parent; + } + + hitem._background = 'grey'; + if (active.indexOf(hitem)<0) active.push(hitem); + } + + find_next(); + } + + if (force && this.brlayout) { + if (!this.brlayout.browser_kind) return this.CreateBrowser('float', true, find_next); + if (!this.brlayout.browser_visible) this.brlayout.ToggleBrowserVisisbility(); + } + + // use recursion + find_next(); + } + + HierarchyPainter.prototype.expand = function(itemname, call_back, d3cont, silent) { + var hpainter = this, hitem = this.Find(itemname); + + if (!hitem && d3cont) return JSROOT.CallBack(call_back); + + function DoExpandItem(_item, _obj, _name) { + if (!_name) _name = hpainter.itemFullName(_item); + + var handle = _item._expand ? null : JSROOT.getDrawHandle(_item._kind, "::expand"); + + if (_obj && handle && handle.expand_item) { + _obj = _obj[handle.expand_item]; // just take specified field from the object + if (_obj && _obj._typename) + handle = JSROOT.getDrawHandle("ROOT."+_obj._typename, "::expand"); + } + + if (handle && handle.expand) { + JSROOT.AssertPrerequisites(handle.prereq, function() { + _item._expand = JSROOT.findFunction(handle.expand); + if (_item._expand) return DoExpandItem(_item, _obj, _name); + JSROOT.CallBack(call_back); + }); + return true; + } + + // try to use expand function + if (_obj && _item && (typeof _item._expand === 'function')) { + if (_item._expand(_item, _obj)) { + _item._isopen = true; + if (_item._parent && !_item._parent._isopen) { + _item._parent._isopen = true; // also show parent + if (!silent) hpainter.UpdateTreeNode(_item._parent); + } else { + if (!silent) hpainter.UpdateTreeNode(_item, d3cont); + } + JSROOT.CallBack(call_back, _item); + return true; + } + } + + if (_obj && ObjectHierarchy(_item, _obj)) { + _item._isopen = true; + if (_item._parent && !_item._parent._isopen) { + _item._parent._isopen = true; // also show parent + if (!silent) hpainter.UpdateTreeNode(_item._parent); + } else { + if (!silent) hpainter.UpdateTreeNode(_item, d3cont); + } + JSROOT.CallBack(call_back, _item); + return true; + } + + return false; + } + + if (hitem) { + // item marked as it cannot be expanded, also top item cannot be changed + if ((hitem._more === false) || (!hitem._parent && hitem._childs)) return JSROOT.CallBack(call_back); + + if (hitem._childs && hitem._isopen) { + hitem._isopen = false; + if (!silent) hpainter.UpdateTreeNode(hitem, d3cont); + return JSROOT.CallBack(call_back); + } + + if (hitem._obj && DoExpandItem(hitem, hitem._obj, itemname)) return; + } + + JSROOT.progress("Loading " + itemname); + + this.get(itemname, function(item, obj) { + + JSROOT.progress(); + + if (obj && DoExpandItem(item, obj)) return; + + JSROOT.CallBack(call_back); + }, "hierarchy_expand" ); // indicate that we getting element for expand, can handle it differently + + } + + HierarchyPainter.prototype.GetTopOnlineItem = function(item) { + if (item) { + while (item && (!('_online' in item))) item = item._parent; + return item; + } + + if (!this.h) return null; + if ('_online' in this.h) return this.h; + if (this.h._childs && ('_online' in this.h._childs[0])) return this.h._childs[0]; + return null; + } + + + HierarchyPainter.prototype.ForEachJsonFile = function(call_back) { + if (!this.h) return; + if ('_jsonfile' in this.h) + return JSROOT.CallBack(call_back, this.h); + + if (this.h._childs) + for (var n = 0; n < this.h._childs.length; ++n) { + var item = this.h._childs[n]; + if ('_jsonfile' in item) JSROOT.CallBack(call_back, item); + } + } + + HierarchyPainter.prototype.OpenJsonFile = function(filepath, call_back) { + var isfileopened = false; + this.ForEachJsonFile(function(item) { if (item._jsonfile==filepath) isfileopened = true; }); + if (isfileopened) return JSROOT.CallBack(call_back); + + var pthis = this; + JSROOT.NewHttpRequest(filepath, 'object', function(res) { + if (!res) return JSROOT.CallBack(call_back); + var h1 = { _jsonfile: filepath, _kind: "ROOT." + res._typename, _jsontmp: res, _name: filepath.split("/").pop() }; + if (res.fTitle) h1._title = res.fTitle; + h1._get = function(item,itemname,callback) { + if (item._jsontmp) + return JSROOT.CallBack(callback, item, item._jsontmp); + JSROOT.NewHttpRequest(item._jsonfile, 'object', function(res) { + item._jsontmp = res; + JSROOT.CallBack(callback, item, item._jsontmp); + }).send(); + } + if (pthis.h == null) pthis.h = h1; else + if (pthis.h._kind == 'TopFolder') pthis.h._childs.push(h1); else { + var h0 = pthis.h, topname = ('_jsonfile' in h0) ? "Files" : "Items"; + pthis.h = { _name: topname, _kind: 'TopFolder', _childs : [h0, h1] }; + } + + pthis.RefreshHtml(call_back); + }).send(null); + } + + HierarchyPainter.prototype.ForEachRootFile = function(call_back) { + if (!this.h) return; + if ((this.h._kind == "ROOT.TFile") && this.h._file) + return JSROOT.CallBack(call_back, this.h); + + if (this.h._childs) + for (var n = 0; n < this.h._childs.length; ++n) { + var item = this.h._childs[n]; + if ((item._kind == 'ROOT.TFile') && ('_fullurl' in item)) + JSROOT.CallBack(call_back, item); + } + } + + HierarchyPainter.prototype.OpenRootFile = function(filepath, call_back) { + // first check that file with such URL already opened + + var isfileopened = false; + this.ForEachRootFile(function(item) { if (item._fullurl===filepath) isfileopened = true; }); + if (isfileopened) return JSROOT.CallBack(call_back); + + var pthis = this; + + JSROOT.progress("Opening " + filepath + " ..."); + JSROOT.OpenFile(filepath, function(file) { + JSROOT.progress(); + if (!file) { + // make CORS warning + if (!d3.select("#gui_fileCORS").style("background","red").empty()) + setTimeout(function() { d3.select("#gui_fileCORS").style("background",''); }, 5000); + return JSROOT.CallBack(call_back, false); + } + + var h1 = pthis.FileHierarchy(file); + h1._isopen = true; + if (pthis.h == null) { + pthis.h = h1; + if (pthis._topname) h1._name = pthis._topname; + } else + if (pthis.h._kind == 'TopFolder') { + pthis.h._childs.push(h1); + } else { + var h0 = pthis.h, topname = (h0._kind == "ROOT.TFile") ? "Files" : "Items"; + pthis.h = { _name: topname, _kind: 'TopFolder', _childs : [h0, h1], _isopen: true }; + } + + pthis.RefreshHtml(call_back); + }); + } + + HierarchyPainter.prototype.ApplyStyle = function(style, call_back) { + if (!style) + return JSROOT.CallBack(call_back); + + if (typeof style === 'object') { + if (style._typename === "TStyle") + JSROOT.extend(JSROOT.gStyle, style); + return JSROOT.CallBack(call_back); + } + + if (typeof style === 'string') { + + var hpainter = this, + item = this.Find( { name: style, allow_index: true, check_keys: true } ); + + if (item!==null) + return this.get(item, function(item2, obj) { hpainter.ApplyStyle(obj, call_back); }); + + if (style.indexOf('.json') > 0) + return JSROOT.NewHttpRequest(style, 'object', function(res) { + hpainter.ApplyStyle(res, call_back); + }).send(null); + } + + return JSROOT.CallBack(call_back); + } + + HierarchyPainter.prototype.GetFileProp = function(itemname) { + var item = this.Find(itemname); + if (item == null) return null; + + var subname = item._name; + while (item._parent) { + item = item._parent; + if ('_file' in item) + return { kind: "file", fileurl: item._file.fURL, itemname: subname, localfile: !!item._file.fLocalFile }; + + if ('_jsonfile' in item) + return { kind: "json", fileurl: item._jsonfile, itemname: subname }; + + subname = item._name + "/" + subname; + } + + return null; + } + + JSROOT.MarkAsStreamerInfo = function(h,item,obj) { + // this function used on THttpServer to mark streamer infos list + // as fictional TStreamerInfoList class, which has special draw function + if (obj && (obj._typename=='TList')) + obj._typename = 'TStreamerInfoList'; + } + + HierarchyPainter.prototype.GetOnlineItemUrl = function(item) { + // returns URL, which could be used to request item from the online server + if (typeof item == "string") item = this.Find(item); + var prnt = item; + while (prnt && (prnt._online===undefined)) prnt = prnt._parent; + return prnt ? (prnt._online + this.itemFullName(item, prnt)) : null; + } + + HierarchyPainter.prototype.isOnlineItem = function(item) { + return this.GetOnlineItemUrl(item)!==null; + } + + HierarchyPainter.prototype.GetOnlineItem = function(item, itemname, callback, option) { + // method used to request object from the http server + + var url = itemname, h_get = false, req = "", req_kind = "object", pthis = this, draw_handle = null; + + if (option === 'hierarchy_expand') { h_get = true; option = undefined; } + + if (item) { + url = this.GetOnlineItemUrl(item); + var func = null; + if ('_kind' in item) draw_handle = JSROOT.getDrawHandle(item._kind); + + if (h_get) { + req = 'h.json?compact=3'; + item._expand = JSROOT.Painter.OnlineHierarchy; // use proper expand function + } else + if ('_make_request' in item) { + func = JSROOT.findFunction(item._make_request); + } else + if ((draw_handle!=null) && ('make_request' in draw_handle)) { + func = draw_handle.make_request; + } + + if (typeof func == 'function') { + // ask to make request + var dreq = func(pthis, item, url, option); + // result can be simple string or object with req and kind fields + if (dreq!=null) + if (typeof dreq == 'string') req = dreq; else { + if ('req' in dreq) req = dreq.req; + if ('kind' in dreq) req_kind = dreq.kind; + } + } + + if ((req.length==0) && (item._kind.indexOf("ROOT.")!=0)) + req = 'item.json.gz?compact=3'; + } + + if (!itemname && item && ('_cached_draw_object' in this) && (req.length == 0)) { + // special handling for drawGUI when cashed + var obj = this._cached_draw_object; + delete this._cached_draw_object; + return JSROOT.CallBack(callback, item, obj); + } + + if (req.length == 0) req = 'root.json.gz?compact=23'; + + if (url.length > 0) url += "/"; + url += req; + + var itemreq = JSROOT.NewHttpRequest(url, req_kind, function(obj) { + + var func = null; + + if (!h_get && item && ('_after_request' in item)) { + func = JSROOT.findFunction(item._after_request); + } else if (draw_handle && ('after_request' in draw_handle)) + func = draw_handle.after_request; + + if (typeof func == 'function') { + var res = func(pthis, item, obj, option, itemreq); + if ((res!=null) && (typeof res == "object")) obj = res; + } + + JSROOT.CallBack(callback, item, obj); + }); + + itemreq.send(null); + } + + JSROOT.Painter.OnlineHierarchy = function(node, obj) { + // central function for expand of all online items + + if (obj && node && ('_childs' in obj)) { + + for (var n=0;n<obj._childs.length;++n) + if (obj._childs[n]._more || obj._childs[n]._childs) + obj._childs[n]._expand = JSROOT.Painter.OnlineHierarchy; + + node._childs = obj._childs; + obj._childs = null; + return true; + } + + return false; + } + + HierarchyPainter.prototype.OpenOnline = function(server_address, user_callback) { + var painter = this; + + function AdoptHierarchy(result) { + painter.h = result; + if (painter.h == null) return; + + if (('_title' in painter.h) && (painter.h._title!='')) document.title = painter.h._title; + + result._isopen = true; + + // mark top hierarchy as online data and + painter.h._online = server_address; + + painter.h._get = function(item, itemname, callback, option) { + painter.GetOnlineItem(item, itemname, callback, option); + } + + painter.h._expand = JSROOT.Painter.OnlineHierarchy; + + var scripts = "", modules = ""; + painter.ForEach(function(item) { + if ('_childs' in item) item._expand = JSROOT.Painter.OnlineHierarchy; + + if ('_autoload' in item) { + var arr = item._autoload.split(";"); + for (var n = 0; n < arr.length; ++n) + if ((arr[n].length>3) && + ((arr[n].lastIndexOf(".js")==arr[n].length-3) || + (arr[n].lastIndexOf(".css")==arr[n].length-4))) { + if (scripts.indexOf(arr[n])<0) scripts+=arr[n]+";"; + } else { + if (modules.indexOf(arr[n])<0) modules+=arr[n]+";"; + } + } + }); + + if (scripts.length > 0) scripts = "user:" + scripts; + + // use AssertPrerequisites, while it protect us from race conditions + JSROOT.AssertPrerequisites(modules + scripts, function() { + + painter.ForEach(function(item) { + if (!('_drawfunc' in item) || !('_kind' in item)) return; + var typename = "kind:" + item._kind; + if (item._kind.indexOf('ROOT.')==0) typename = item._kind.slice(5); + var drawopt = item._drawopt; + if (!JSROOT.canDraw(typename) || (drawopt!=null)) + JSROOT.addDrawFunc({ name: typename, func: item._drawfunc, script: item._drawscript, opt: drawopt }); + }); + + JSROOT.CallBack(user_callback, painter); + }); + } + + if (!server_address) server_address = ""; + + if (typeof server_address == 'object') { + var h = server_address; + server_address = ""; + return AdoptHierarchy(h); + } + + JSROOT.NewHttpRequest(server_address + "h.json?compact=3", 'object', AdoptHierarchy).send(null); + } + + HierarchyPainter.prototype.GetOnlineProp = function(itemname) { + var item = this.Find(itemname); + if (!item) return null; + + var subname = item._name; + while (item._parent) { + item = item._parent; + + if ('_online' in item) { + return { + server : item._online, + itemname : subname + }; + } + subname = item._name + "/" + subname; + } + + return null; + } + + HierarchyPainter.prototype.FillOnlineMenu = function(menu, onlineprop, itemname) { + + var painter = this, + node = this.Find(itemname), + sett = JSROOT.getDrawSettings(node._kind, 'nosame;noinspect'), + handle = JSROOT.getDrawHandle(node._kind), + root_type = (typeof node._kind == 'string') ? node._kind.indexOf("ROOT.") == 0 : false; + + if (sett.opts && (node._can_draw !== false)) { + sett.opts.push('inspect'); + menu.addDrawMenu("Draw", sett.opts, function(arg) { painter.display(itemname, arg); }); + } + + if (!node._childs && (node._more !== false) && (node._more || root_type || sett.expand)) + menu.add("Expand", function() { painter.expand(itemname); }); + + if (handle && ('execute' in handle)) + menu.add("Execute", function() { painter.ExecuteCommand(itemname, menu.tree_node); }); + + var drawurl = onlineprop.server + onlineprop.itemname + "/draw.htm", separ = "?"; + if (this.IsMonitoring()) { + drawurl += separ + "monitoring=" + this.MonitoringInterval(); + separ = "&"; + } + + if (sett.opts && (node._can_draw !== false)) + menu.addDrawMenu("Draw in new window", sett.opts, function(arg) { window.open(drawurl+separ+"opt=" +arg); }); + + if (sett.opts && (sett.opts.length > 0) && root_type && (node._can_draw !== false)) + menu.addDrawMenu("Draw as png", sett.opts, function(arg) { + window.open(onlineprop.server + onlineprop.itemname + "/root.png?w=400&h=300&opt=" + arg); + }); + + if ('_player' in node) + menu.add("Player", function() { painter.player(itemname); }); + } + + HierarchyPainter.prototype.Adopt = function(h) { + this.h = h; + this.RefreshHtml(); + } + + HierarchyPainter.prototype.SetMonitoring = function(interval, flag) { + + if (interval!==undefined) { + this._monitoring_on = false; + this._monitoring_interval = 3000; + + interval = !interval ? 0 : parseInt(interval); + + if (!isNaN(interval) && (interval>0)) { + this._monitoring_on = true; + this._monitoring_interval = Math.max(100,interval); + } + } + + if (flag !== undefined) + this._monitoring_on = flag; + + // first clear old handle + if (this._monitoring_handle) clearInterval(this._monitoring_handle); + + // now set new interval (if necessary) + this._monitoring_handle = setInterval(this.updateAll.bind(this, "monitoring"), this._monitoring_interval); + } + + HierarchyPainter.prototype.MonitoringInterval = function(val) { + // returns interval + return ('_monitoring_interval' in this) ? this._monitoring_interval : 3000; + } + + HierarchyPainter.prototype.EnableMonitoring = function(on) { + this._monitoring_on = on; + } + + HierarchyPainter.prototype.IsMonitoring = function() { + return this._monitoring_on; + } + + HierarchyPainter.prototype.SetDisplay = function(layout, frameid) { + if (!frameid && (typeof layout == 'object')) { + this.disp = layout; + this.disp_kind = 'custom'; + this.disp_frameid = null; + } else { + this.disp_kind = layout; + this.disp_frameid = frameid; + } + + if (!this.register_resize) { + this.register_resize = true; + JSROOT.RegisterForResize(this); + } + } + + HierarchyPainter.prototype.GetLayout = function() { + return this.disp_kind; + } + + HierarchyPainter.prototype.ClearPainter = function(obj_painter) { + this.ForEach(function(item) { + if (item._painter === obj_painter) delete item._painter; + }); + } + + HierarchyPainter.prototype.clear = function(withbrowser) { + if (this.disp) { + this.disp.Reset(); + delete this.disp; + } + + var plainarr = []; + + this.ForEach(function(item) { + delete item._painter; // remove reference on the painter + // when only display cleared, try to clear all browser items + if (!withbrowser && (typeof item.clear=='function')) item.clear(); + if (withbrowser) plainarr.push(item); + }); + + if (withbrowser) { + + if (this._monitoring_handle) { + clearInterval(this._monitoring_handle); + delete this._monitoring_handle; + } + + // simplify work for javascript and delete all (ok, most of) cross-references + this.select_main().html(""); + plainarr.forEach(function(d) { delete d._parent; delete d._childs; delete d._obj; delete d._d3cont; }); + delete this.h; + } + } + + HierarchyPainter.prototype.GetDisplay = function() { + return ('disp' in this) ? this.disp : null; + } + + HierarchyPainter.prototype.CleanupFrame = function(divid) { + // hook to perform extra actions when frame is cleaned + + var lst = JSROOT.cleanup(divid); + + // we remove all painters references from items + if (lst && (lst.length>0)) + this.ForEach(function(item) { + if (item._painter && lst.indexOf(item._painter)>=0) delete item._painter; + }); + } + + /** \brief Creates configured JSROOT.MDIDisplay object + * + * @param callback - called when mdi object created + */ + HierarchyPainter.prototype.CreateDisplay = function(callback) { + + if ('disp' in this) { + if ((this.disp.NumDraw() > 0) || (this.disp_kind == "custom")) return JSROOT.CallBack(callback, this.disp); + this.disp.Reset(); + delete this.disp; + } + + // check that we can found frame where drawing should be done + if (document.getElementById(this.disp_frameid) == null) + return JSROOT.CallBack(callback, null); + + if ((this.disp_kind == "simple") || + ((this.disp_kind.indexOf("grid") == 0) && (this.disp_kind.indexOf("gridi") < 0))) + this.disp = new GridDisplay(this.disp_frameid, this.disp_kind); + else + return JSROOT.AssertPrerequisites('jq2d', this.CreateDisplay.bind(this, callback)); + + if (this.disp) + this.disp.CleanupFrame = this.CleanupFrame.bind(this); + + JSROOT.CallBack(callback, this.disp); + } + + /** \brief If possible, creates custom JSROOT.MDIDisplay for given item + * + * @param itemname - name of item, for which drawing is created + * @param custom_kind - display kind + * @param callback - callback function, called when mdi object created + */ + HierarchyPainter.prototype.CreateCustomDisplay = function(itemname, custom_kind, callback) { + + if (this.disp_kind != "simple") + return this.CreateDisplay(callback); + + this.disp_kind = custom_kind; + + // check if display can be erased + if (this.disp) { + var num = this.disp.NumDraw(); + if ((num>1) || ((num==1) && !this.disp.FindFrame(itemname))) + return this.CreateDisplay(callback); + this.disp.Reset(); + delete this.disp; + } + + this.CreateDisplay(callback); + } + + HierarchyPainter.prototype.updateOnOtherFrames = function(painter, obj) { + // function should update object drawings for other painters + var mdi = this.disp, handle = null, isany = false; + if (!mdi) return false; + + if (obj._typename) handle = JSROOT.getDrawHandle("ROOT." + obj._typename); + if (handle && handle.draw_field && obj[handle.draw_field]) + obj = obj[handle.draw_field]; + + mdi.ForEachPainter(function(p, frame) { + if ((p===painter) || (p.GetItemName() != painter.GetItemName())) return; + mdi.ActivateFrame(frame); + if (p.RedrawObject(obj)) isany = true; + }); + return isany; + } + + HierarchyPainter.prototype.CheckResize = function(size) { + if (this.disp) this.disp.CheckMDIResize(null, size); + } + + HierarchyPainter.prototype.StartGUI = function(gui_div, gui_call_back, url) { + + function GetOption(opt) { + var res = JSROOT.GetUrlOption(opt, url); + if (!res && gui_div && !gui_div.empty() && gui_div.node().hasAttribute(opt)) res = gui_div.attr(opt); + return res; + } + + function GetOptionAsArray(opt) { + var res = JSROOT.GetUrlOptionAsArray(opt, url); + if (res.length>0 || !gui_div || gui_div.empty()) return res; + while (opt.length>0) { + var separ = opt.indexOf(";"); + var part = separ>0 ? opt.substr(0, separ) : opt; + if (separ>0) opt = opt.substr(separ+1); else opt = ""; + + var canarray = true; + if (part[0]=='#') { part = part.substr(1); canarray = false; } + if (part==='files') continue; // special case for normal UI + + if (!gui_div.node().hasAttribute(part)) continue; + + var val = gui_div.attr(part); + + if (canarray) res = res.concat(JSROOT.ParseAsArray(val)); + else if (val!==null) res.push(val); + } + return res; + } + + var hpainter = this, + prereq = GetOption('prereq') || "", + filesdir = JSROOT.GetUrlOption("path", url) || "", // path used in normal gui + filesarr = GetOptionAsArray("#file;files"), + localfile = GetOption("localfile"), + jsonarr = GetOptionAsArray("#json;jsons"), + expanditems = GetOptionAsArray("expand"), + itemsarr = GetOptionAsArray("#item;items"), + optionsarr = GetOptionAsArray("#opt;opts"), + monitor = GetOption("monitoring"), + layout = GetOption("layout"), + style = GetOptionAsArray("#style"), + statush = 0, status = GetOption("status"), + browser_kind = GetOption("browser"), + browser_configured = !!browser_kind, + title = GetOption("title"); + + if (GetOption("float")!==null) { browser_kind='float'; browser_configured = true; } else + if (GetOption("fix")!==null) { browser_kind='fix'; browser_configured = true; } + + this.no_select = GetOption("noselect"); + + if (GetOption('files_monitoring')!==null) this.files_monitoring = true; + + if (title) document.title = title; + + var load = GetOption("load"); + if (load) prereq += ";io;2d;load:" + load; + + if (expanditems.length==0 && (GetOption("expand")==="")) expanditems.push(""); + + if (filesdir) { + for (var i=0;i<filesarr.length;++i) filesarr[i] = filesdir + filesarr[i]; + for (var i=0;i<jsonarr.length;++i) jsonarr[i] = filesdir + jsonarr[i]; + } + + if ((itemsarr.length==0) && GetOption("item")==="") itemsarr.push(""); + + if ((jsonarr.length==1) && (itemsarr.length==0) && (expanditems.length==0)) itemsarr.push(""); + + if (!this.disp_kind) { + if ((typeof layout == "string") && (layout.length>0)) + this.disp_kind = layout; + else + switch (itemsarr.length) { + case 0: + case 1: this.disp_kind = 'simple'; break; + case 2: this.disp_kind = 'vert2'; break; + case 3: this.disp_kind = 'vert21'; break; + case 4: this.disp_kind = 'vert22'; break; + case 5: this.disp_kind = 'vert32'; break; + case 6: this.disp_kind = 'vert222'; break; + case 7: this.disp_kind = 'vert322'; break; + case 8: this.disp_kind = 'vert332'; break; + case 9: this.disp_kind = 'vert333'; break; + default: this.disp_kind = 'flex'; + } + } + + if (status==="no") status = null; else + if (status==="off") { this.status_disabled = true; status = null; } else + if (status==="on") status = true; else + if (status!==null) { statush = parseInt(status); if (isNaN(statush) || (statush<5)) statush = 0; status = true; } + if (this.no_select==="") this.no_select = true; + + if (!browser_kind) browser_kind = "fix"; else + if (browser_kind==="no") browser_kind = ""; else + if (browser_kind==="off") { browser_kind = ""; status = null; this.exclude_browser = true; } + if (GetOption("nofloat")!==null) this.float_browser_disabled = true; + + if (this.start_without_browser) browser_kind = ""; + + if (status || browser_kind) prereq = "jq2d;" + prereq; + + this._topname = GetOption("topname"); + + function OpenAllFiles(res) { + if (browser_kind) { hpainter.CreateBrowser(browser_kind); browser_kind = ""; } + if (status!==null) { hpainter.CreateStatusLine(statush, status); status = null; } + if (jsonarr.length>0) + hpainter.OpenJsonFile(jsonarr.shift(), OpenAllFiles); + else if (filesarr.length>0) + hpainter.OpenRootFile(filesarr.shift(), OpenAllFiles); + else if ((localfile!==null) && (typeof hpainter.SelectLocalFile == 'function')) { + localfile = null; hpainter.SelectLocalFile(OpenAllFiles); + } else if (expanditems.length>0) + hpainter.expand(expanditems.shift(), OpenAllFiles); + else if (style.length>0) + hpainter.ApplyStyle(style.shift(), OpenAllFiles); + else + hpainter.displayAll(itemsarr, optionsarr, function() { + hpainter.RefreshHtml(); + hpainter.SetMonitoring(monitor); + JSROOT.CallBack(gui_call_back); + }); + } + + function AfterOnlineOpened() { + // check if server enables monitoring + + if (('_browser' in hpainter.h) && !browser_configured) { + browser_kind = hpainter.h._browser; + if (browser_kind==="off") { browser_kind = ""; status = null; hpainter.exclude_browser = true; } + } + + if (('_monitoring' in hpainter.h) && !monitor) + monitor = hpainter.h._monitoring; + + if (('_layout' in hpainter.h) && !layout) + hpainter.disp_kind = hpainter.h._layout; + + if (('_loadfile' in hpainter.h) && (filesarr.length==0)) + filesarr = JSROOT.ParseAsArray(hpainter.h._loadfile); + + if (('_drawitem' in hpainter.h) && (itemsarr.length==0)) { + itemsarr = JSROOT.ParseAsArray(hpainter.h._drawitem); + optionsarr = JSROOT.ParseAsArray(hpainter.h._drawopt); + } + + if (('_toptitle' in hpainter.h) && hpainter.exclude_browser && document) + document.title = hpainter.h._toptitle; + + if (gui_div) + hpainter.PrepareGuiDiv(gui_div, hpainter.disp_kind); + + OpenAllFiles(); + } + + var h0 = null; + if (this.is_online) { + if (typeof GetCachedHierarchy == 'function') h0 = GetCachedHierarchy(); + if (typeof h0 !== 'object') h0 = ""; + } + + if (h0!==null) + return this.OpenOnline(h0, AfterOnlineOpened); + + if (gui_div) + this.PrepareGuiDiv(gui_div, this.disp_kind); + + if (prereq.length>0) JSROOT.AssertPrerequisites(prereq, OpenAllFiles); + else OpenAllFiles(); + } + + HierarchyPainter.prototype.PrepareGuiDiv = function(myDiv, layout) { + + this.gui_div = myDiv.attr('id'); + + this.brlayout = new BrowserLayout(this.gui_div, this); + + this.brlayout.Create(!this.exclude_browser); + + if (!this.exclude_browser) { + var btns = this.brlayout.CreateBrowserBtns(); + + JSROOT.ToolbarIcons.CreateSVG(btns, JSROOT.ToolbarIcons.diamand, 15, "toggle fix-pos browser") + .style("margin","3px").on("click", this.CreateBrowser.bind(this, "fix", true)); + + if (!this.float_browser_disabled) + JSROOT.ToolbarIcons.CreateSVG(btns, JSROOT.ToolbarIcons.circle, 15, "toggle float browser") + .style("margin","3px").on("click", this.CreateBrowser.bind(this, "float", true)); + + if (!this.status_disabled) + JSROOT.ToolbarIcons.CreateSVG(btns, JSROOT.ToolbarIcons.three_circles, 15, "toggle status line") + .style("margin","3px").on("click", this.CreateStatusLine.bind(this, 0, "toggle")); + } + + this.SetDisplay(layout, this.brlayout.drawing_divid()); + } + + HierarchyPainter.prototype.CreateStatusLine = function(height, mode) { + if (this.status_disabled || !this.gui_div || !this.brlayout) return ''; + return this.brlayout.CreateStatusLine(height, mode); + } + + HierarchyPainter.prototype.CreateBrowser = function(browser_kind, update_html, call_back) { + if (!this.gui_div) return; + + var hpainter = this; + JSROOT.AssertPrerequisites('jq2d', function() { + hpainter.CreateBrowser(browser_kind, update_html, call_back); + }); + } + + // ====================================================================================== + + JSROOT.BuildNobrowserGUI = function() { + var myDiv = d3.select('#simpleGUI'), + online = false, drawing = false; + + if (myDiv.empty()) { + online = true; + myDiv = d3.select('#onlineGUI'); + if (myDiv.empty()) { myDiv = d3.select('#drawGUI'); drawing = true; } + if (myDiv.empty()) return alert('no div for simple nobrowser gui found'); + } + + if (myDiv.attr("ignoreurl") === "true") + JSROOT.gStyle.IgnoreUrlOptions = true; + + JSROOT.Painter.readStyleFromURL(); + + var guisize = JSROOT.GetUrlOption("divsize"); + if (guisize) { + guisize = guisize.split("x"); + if (guisize.length != 2) guisize = null; + } + + if (guisize) { + myDiv.style('position',"relative").style('width', guisize[0] + "px").style('height', guisize[1] + "px"); + } else { + d3.select('html').style('height','100%'); + d3.select('body').style('min-height','100%').style('margin',0).style('overflow',"hidden"); + myDiv.style('position',"absolute").style('left',0).style('top',0).style('bottom',0).style('right',0).style('padding',1); + } + + var hpainter = new JSROOT.HierarchyPainter('root', null); + + hpainter.is_online = online; + if (drawing) hpainter.exclude_browser = true; + + hpainter.start_without_browser = true; // indicate that browser not required at the beginning + + hpainter.StartGUI(myDiv, function() { + if (!drawing) return; + + var func = JSROOT.findFunction('GetCachedObject'); + var obj = (typeof func == 'function') ? JSROOT.JSONR_unref(func()) : null; + if (obj) hpainter._cached_draw_object = obj; + var opt = JSROOT.GetUrlOption("opt") || ""; + + if (JSROOT.GetUrlOption("websocket")!==null) opt+=";websocket"; + + hpainter.display("", opt); + }); + } + + JSROOT.Painter.drawStreamerInfo = function(divid, lst) { + var painter = new JSROOT.HierarchyPainter('sinfo', divid, 'white'); + + painter.h = { _name : "StreamerInfo", _childs : [] }; + + for ( var i = 0; i < lst.arr.length; ++i) { + var entry = lst.arr[i] + + if (entry._typename == "TList") continue; + + if (typeof (entry.fName) == 'undefined') { + JSROOT.console("strange element in StreamerInfo with type " + entry._typename); + continue; + } + + var item = { + _name : entry.fName + ";" + entry.fClassVersion, + _kind : "class " + entry.fName, + _title : "class:" + entry.fName + ' version:' + entry.fClassVersion + ' checksum:' + entry.fCheckSum, + _icon: "img_class", + _childs : [] + }; + + if (entry.fTitle != '') item._title += ' ' + entry.fTitle; + + painter.h._childs.push(item); + + if (typeof entry.fElements == 'undefined') continue; + for ( var l = 0; l < entry.fElements.arr.length; ++l) { + var elem = entry.fElements.arr[l]; + if (!elem || !elem.fName) continue; + var info = elem.fTypeName + " " + elem.fName, + title = elem.fTypeName + " type:" + elem.fType; + if (elem.fArrayDim===1) + info += "[" + elem.fArrayLength + "]"; + else + for (var dim=0;dim<elem.fArrayDim;++dim) + info+="[" + elem.fMaxIndex[dim] + "]"; + if (elem.fBaseVersion===4294967295) info += ":-1"; else + if (elem.fBaseVersion!==undefined) info += ":" + elem.fBaseVersion; + info += ";"; + if (elem.fTitle != '') info += " // " + elem.fTitle; + + item._childs.push({ _name : info, _title: title, _kind: elem.fTypeName, _icon: (elem.fTypeName == 'BASE') ? "img_class" : "img_member" }); + } + if (item._childs.length == 0) delete item._childs; + } + + // painter.select_main().style('overflow','auto'); + + painter.RefreshHtml(function() { + painter.SetDivId(divid); + painter.DrawingReady(); + }); + + return painter; + } + + // ====================================================================================== + + JSROOT.Painter.drawInspector = function(divid, obj) { + + JSROOT.cleanup(divid); + + var painter = new JSROOT.HierarchyPainter('inspector', divid, 'white'); + painter.default_by_click = "expand"; // default action + painter.with_icons = false; + painter.h = { _name: "Object", _title: "", _click_action: "expand", _nosimple: false, _do_context: true }; + if ((typeof obj.fTitle === 'string') && (obj.fTitle.length>0)) + painter.h._title = obj.fTitle; + + if (obj._typename) + painter.h._title += " type:" + obj._typename; + + if ((typeof obj.fName === 'string') && (obj.fName.length>0)) + painter.h._name = obj.fName; + + // painter.select_main().style('overflow','auto'); + + painter.fill_context = function(menu, hitem) { + var sett = JSROOT.getDrawSettings(hitem._kind, 'nosame'); + if (sett.opts) + menu.addDrawMenu("nosub:Draw", sett.opts, function(arg) { + if (!hitem || !hitem._obj) return; + var obj = hitem._obj, divid = this.divid; // need to remember while many references will be removed (including _obj) + JSROOT.cleanup(divid); + JSROOT.draw(divid, obj, arg); + }); + } + + if (JSROOT.IsRootCollection(obj)) { + painter.h._name = obj.name || obj._typename; + ListHierarchy(painter.h, obj); + } else { + ObjectHierarchy(painter.h, obj); + } + painter.RefreshHtml(function() { + painter.SetDivId(divid); + painter.DrawingReady(); + }); + + return painter; + } + + // ================================================================ + + // MDIDisplay - class to manage multiple document interface for drawings + + function MDIDisplay(frameid) { + JSROOT.TBasePainter.call(this); + this.frameid = frameid; + this.SetDivId(frameid); + this.select_main().property('mdi', this); + this.CleanupFrame = JSROOT.cleanup; // use standard cleanup function by default + this.active_frame_title = ""; // keep title of active frame + } + + MDIDisplay.prototype = Object.create(JSROOT.TBasePainter.prototype); + + MDIDisplay.prototype.BeforeCreateFrame = function(title) { + this.active_frame_title = title; + } + + MDIDisplay.prototype.ForEachFrame = function(userfunc, only_visible) { + // method dedicated to iterate over existing panels + // provided userfunc is called with arguments (frame) + + console.warn("ForEachFrame not implemented in MDIDisplay"); + } + + MDIDisplay.prototype.ForEachPainter = function(userfunc, only_visible) { + // method dedicated to iterate over existing panles + // provided userfunc is called with arguments (painter, frame) + + this.ForEachFrame(function(frame) { + var dummy = new JSROOT.TObjectPainter(); + dummy.SetDivId(frame, -1); + dummy.ForEachPainter(function(painter) { userfunc(painter, frame); }); + }, only_visible); + } + + MDIDisplay.prototype.NumDraw = function() { + var cnt = 0; + this.ForEachFrame(function() { ++cnt; }); + return cnt; + } + + MDIDisplay.prototype.FindFrame = function(searchtitle, force) { + var found_frame = null; + + this.ForEachFrame(function(frame) { + if (d3.select(frame).attr('frame_title') == searchtitle) + found_frame = frame; + }); + + if ((found_frame == null) && force) + found_frame = this.CreateFrame(searchtitle); + + return found_frame; + } + + MDIDisplay.prototype.ActivateFrame = function(frame) { + this.active_frame_title = d3.select(frame).attr('frame_title'); + } + + MDIDisplay.prototype.GetActiveFrame = function() { + return this.FindFrame(this.active_frame_title); + } + + MDIDisplay.prototype.CheckMDIResize = function(only_frame_id, size) { + // perform resize for each frame + var resized_frame = null; + + this.ForEachPainter(function(painter, frame) { + + if (only_frame_id && (d3.select(frame).attr('id') != only_frame_id)) return; + + if ((painter.GetItemName()!==null) && (typeof painter.CheckResize == 'function')) { + // do not call resize for many painters on the same frame + if (resized_frame === frame) return; + painter.CheckResize(size); + resized_frame = frame; + } + }); + } + + MDIDisplay.prototype.Reset = function() { + + this.active_frame_title = ""; + + this.ForEachFrame(this.CleanupFrame); + + this.select_main().html("").property('mdi', null); + } + + MDIDisplay.prototype.Draw = function(title, obj, drawopt) { + // draw object with specified options + if (!obj) return; + + if (!JSROOT.canDraw(obj._typename, drawopt)) return; + + var frame = this.FindFrame(title, true); + + this.ActivateFrame(frame); + + return JSROOT.redraw(frame, obj, drawopt); + } + + + // ================================================== + + function CustomDisplay() { + JSROOT.MDIDisplay.call(this, "dummy"); + this.frames = {}; // array of configured frames + } + + CustomDisplay.prototype = Object.create(MDIDisplay.prototype); + + CustomDisplay.prototype.AddFrame = function(divid, itemname) { + if (!(divid in this.frames)) this.frames[divid] = ""; + + this.frames[divid] += (itemname + ";"); + } + + CustomDisplay.prototype.ForEachFrame = function(userfunc, only_visible) { + var ks = Object.keys(this.frames); + for (var k = 0; k < ks.length; ++k) { + var node = d3.select("#"+ks[k]); + if (!node.empty()) + JSROOT.CallBack(userfunc, node.node()); + } + } + + CustomDisplay.prototype.CreateFrame = function(title) { + + this.BeforeCreateFrame(title); + + var ks = Object.keys(this.frames); + for (var k = 0; k < ks.length; ++k) { + var items = this.frames[ks[k]]; + if (items.indexOf(title+";")>=0) + return d3.select("#"+ks[k]).node(); + } + return null; + } + + CustomDisplay.prototype.Reset = function() { + MDIDisplay.prototype.Reset.call(this); + this.ForEachFrame(function(frame) { + d3.select(frame).html(""); + }); + } + + // ================================================ + + function GridDisplay(frameid, kind, kind2) { + // following kinds are supported + // vertical or horizontal - only first letter matters, defines basic orientation + // 'x' in the name disable interactive separators + // v4 or h4 - 4 equal elements in specified direction + // v231 - created 3 vertical elements, first divided on 2, second on 3 and third on 1 part + // v23_52 - create two vertical elements with 2 and 3 subitems, size ratio 5:2 + // gridNxM - normal grid layout without interactive separators + // gridiNxM - grid layout with interactive separators + // simple - no layout, full frame used for object drawings + + JSROOT.MDIDisplay.call(this, frameid); + + this.framecnt = 0; + this.getcnt = 0; + this.groups = []; + this.vertical = kind && (kind[0] == 'v'); + this.use_separarators = !kind || (kind.indexOf("x")<0); + this.simple_layout = false; + + this.select_main().style('overflow','hidden'); + + if (kind === "simple") { + this.simple_layout = true; + this.use_separarators = false; + this.framecnt = 1; + return; + } + + var num = 2, arr = undefined, sizes = undefined; + + if ((kind.indexOf("grid") == 0) || kind2) { + if (kind2) kind = kind + "x" + kind2; + else kind = kind.substr(4).trim(); + this.use_separarators = false; + if (kind[0]==="i") { + this.use_separarators = true; + kind = kind.substr(1); + } + + var separ = kind.indexOf("x"), sizex = 3, sizey = 3; + + if (separ > 0) { + sizey = parseInt(kind.substr(separ + 1)); + sizex = parseInt(kind.substr(0, separ)); + } else { + sizex = sizey = parseInt(kind); + } + + if (isNaN(sizex)) sizex = 3; + if (isNaN(sizey)) sizey = 3; + + if (sizey>1) { + this.vertical = true; + num = sizey; + if (sizex>1) { + arr = new Array(num); + for (var k=0;k<num;++k) arr[k] = sizex; + } + } else + if (sizex > 1) { + this.vertical = false; + num = sizex; + } else { + this.simple_layout = true; + this.use_separarators = false; + this.framecnt = 1; + return; + } + kind = ""; + } + + if (kind && kind.indexOf("_")>0) { + var arg = parseInt(kind.substr(kind.indexOf("_")+1), 10); + if (!isNaN(arg) && (arg>10)) { + kind = kind.substr(0, kind.indexOf("_")); + sizes = []; + while (arg>0) { + sizes.unshift(Math.max(arg % 10, 1)); + arg = Math.round((arg-sizes[0])/10); + if (sizes[0]===0) sizes[0]=1; + } + } + } + + kind = kind ? parseInt(kind.replace( /^\D+/g, ''), 10) : 0; + if (kind && (kind>1)) { + if (kind<10) { + num = kind; + } else { + arr = []; + while (kind>0) { + arr.unshift(kind % 10); + kind = Math.round((kind-arr[0])/10); + if (arr[0]==0) arr[0]=1; + } + num = arr.length; + } + } + + if (sizes && (sizes.length!==num)) sizes = undefined; + + if (!this.simple_layout) + this.CreateGroup(this, this.select_main(), num, arr, sizes); + } + + GridDisplay.prototype = Object.create(MDIDisplay.prototype); + + GridDisplay.prototype.CreateGroup = function(handle, main, num, childs, sizes) { + + if (!sizes) sizes = new Array(num); + var sum1 = 0, sum2 = 0; + for (var n=0;n<num;++n) sum1 += (sizes[n] || 1); + for (var n=0;n<num;++n) { + sizes[n] = Math.round(100 * (sizes[n] || 1) / sum1); + sum2 += sizes[n]; + if (n==num-1) sizes[n] += (100-sum2); // make 100% + } + + for (var cnt = 0; cnt<num; ++cnt) { + var group = { id: cnt, drawid: -1, position: 0, size: sizes[cnt] }; + if (cnt>0) group.position = handle.groups[cnt-1].position + handle.groups[cnt-1].size; + group.position0 = group.position; + + if (!childs || !childs[cnt] || childs[cnt]<2) group.drawid = this.framecnt++; + + handle.groups.push(group); + + var elem = main.append("div").attr('groupid', group.id); + + if (handle.vertical) + elem.style('float', 'bottom').style('height',group.size+'%').style('width','100%'); + else + elem.style('float', 'left').style('width',group.size+'%').style('height','100%'); + + if (group.drawid>=0) { + elem.classed('jsroot_newgrid', true); + if (typeof this.frameid === 'string') + elem.attr('id', this.frameid + "_" + group.drawid); + } else { + elem.style('display','flex').style('flex-direction', handle.vertical ? "row" : "column"); + } + + if (childs && (childs[cnt]>1)) { + group.vertical = !handle.vertical; + group.groups = []; + elem.style('overflow','hidden'); + this.CreateGroup(group, elem, childs[cnt]); + } + } + + if (this.use_separarators && this.CreateSeparator) + for (var cnt=1;cnt<num;++cnt) + this.CreateSeparator(handle, main, handle.groups[cnt]); + } + + GridDisplay.prototype.ForEachFrame = function(userfunc, only_visible) { + var main = this.select_main(); + + if (this.simple_layout) + userfunc(main.node()); + else + main.selectAll('.jsroot_newgrid').each(function() { + userfunc(d3.select(this).node()); + }); + } + + GridDisplay.prototype.GetActiveFrame = function() { + if (this.simple_layout) return this.select_main().node(); + + var found = MDIDisplay.prototype.GetActiveFrame.call(this); + if (found) return found; + + this.ForEachFrame(function(frame) { + if (!found) found = frame; + }, true); + + return found; + } + + GridDisplay.prototype.ActivateFrame = function(frame) { + this.active_frame_title = d3.select(frame).attr('frame_title'); + } + + GridDisplay.prototype.GetFrame = function(id) { + var main = this.select_main(); + if (this.simple_layout) return main.node(); + var res = null; + main.selectAll('.jsroot_newgrid').each(function() { + if (id-- === 0) res = this; + }); + return res; + } + + GridDisplay.prototype.NumGridFrames = function() { + return this.framecnt; + } + + GridDisplay.prototype.CreateFrame = function(title) { + this.BeforeCreateFrame(title); + + var frame = null, maxloop = this.framecnt || 2; + + while (!frame && maxloop--) { + frame = this.GetFrame(this.getcnt); + if (!this.simple_layout && this.framecnt) + this.getcnt = (this.getcnt+1) % this.framecnt; + + if (d3.select(frame).classed("jsroot_fixed_frame")) frame = null; + } + + if (frame) { + this.CleanupFrame(frame); + d3.select(frame).attr('frame_title', title); + } + + return frame; + } + + + // export all functions and classes + + JSROOT.Painter.drawList = drawList; + + JSROOT.Painter.FolderHierarchy = FolderHierarchy; + JSROOT.Painter.ObjectHierarchy = ObjectHierarchy; + JSROOT.Painter.TaskHierarchy = TaskHierarchy; + JSROOT.Painter.ListHierarchy = ListHierarchy; + JSROOT.Painter.KeysHierarchy = KeysHierarchy; + + JSROOT.BrowserLayout = BrowserLayout; + JSROOT.HierarchyPainter = HierarchyPainter; + + JSROOT.MDIDisplay = MDIDisplay; + JSROOT.CustomDisplay = CustomDisplay; + JSROOT.GridDisplay = GridDisplay; + + return JSROOT; + +})); diff --git a/js/scripts/JSRootPainter.hist.js b/js/scripts/JSRootPainter.hist.js new file mode 100644 index 00000000000..a961fa78dd4 --- /dev/null +++ b/js/scripts/JSRootPainter.hist.js @@ -0,0 +1,6882 @@ +/// @file JSRootPainter.hist.js +/// JavaScript ROOT graphics for histogram classes + +(function( factory ) { + if ( typeof define === "function" && define.amd ) { + define( ['JSRootPainter', 'd3'], factory ); + } else + if (typeof exports === 'object' && typeof module !== 'undefined') { + factory(require("./JSRootCore.js"), require("./d3.min.js")); + } else { + + if (typeof d3 != 'object') + throw new Error('This extension requires d3.js', 'JSRootPainter.hist.js'); + + if (typeof JSROOT == 'undefined') + throw new Error('JSROOT is not defined', 'JSRootPainter.hist.js'); + + if (typeof JSROOT.Painter != 'object') + throw new Error('JSROOT.Painter not defined', 'JSRootPainter.hist.js'); + + factory(JSROOT, d3); + } +} (function(JSROOT, d3) { + + "use strict"; + + JSROOT.sources.push("hist"); + + JSROOT.ToolbarIcons.th2color = { + recs: [{x:0,y:256,w:13,h:39,f:'rgb(38,62,168)'},{x:13,y:371,w:39,h:39},{y:294,h:39},{y:256,h:39},{y:218,h:39},{x:51,y:410,w:39,h:39},{y:371,h:39},{y:333,h:39},{y:294},{y:256,h:39},{y:218,h:39},{y:179,h:39},{y:141,h:39},{y:102,h:39},{y:64},{x:90,y:448,w:39,h:39},{y:410},{y:371,h:39},{y:333,h:39,f:'rgb(22,82,205)'},{y:294},{y:256,h:39,f:'rgb(16,100,220)'},{y:218,h:39},{y:179,h:39,f:'rgb(22,82,205)'},{y:141,h:39},{y:102,h:39,f:'rgb(38,62,168)'},{y:64},{y:0,h:27},{x:128,y:448,w:39,h:39},{y:410},{y:371,h:39},{y:333,h:39,f:'rgb(22,82,205)'},{y:294,f:'rgb(20,129,214)'},{y:256,h:39,f:'rgb(9,157,204)'},{y:218,h:39,f:'rgb(14,143,209)'},{y:179,h:39,f:'rgb(20,129,214)'},{y:141,h:39,f:'rgb(16,100,220)'},{y:102,h:39,f:'rgb(22,82,205)'},{y:64,f:'rgb(38,62,168)'},{y:26,h:39},{y:0,h:27},{x:166,y:486,h:14},{y:448,h:39},{y:410},{y:371,h:39,f:'rgb(22,82,205)'},{y:333,h:39,f:'rgb(20,129,214)'},{y:294,f:'rgb(82,186,146)'},{y:256,h:39,f:'rgb(179,189,101)'},{y:218,h:39,f:'rgb(116,189,129)'},{y:179,h:39,f:'rgb(82,186,146)'},{y:141,h:39,f:'rgb(14,143,209)'},{y:102,h:39,f:'rgb(16,100,220)'},{y:64,f:'rgb(38,62,168)'},{y:26,h:39},{x:205,y:486,w:39,h:14},{y:448,h:39},{y:410},{y:371,h:39,f:'rgb(16,100,220)'},{y:333,h:39,f:'rgb(9,157,204)'},{y:294,f:'rgb(149,190,113)'},{y:256,h:39,f:'rgb(244,198,59)'},{y:218,h:39},{y:179,h:39,f:'rgb(226,192,75)'},{y:141,h:39,f:'rgb(13,167,195)'},{y:102,h:39,f:'rgb(18,114,217)'},{y:64,f:'rgb(22,82,205)'},{y:26,h:39,f:'rgb(38,62,168)'},{x:243,y:448,w:39,h:39},{y:410},{y:371,h:39,f:'rgb(18,114,217)'},{y:333,h:39,f:'rgb(30,175,179)'},{y:294,f:'rgb(209,187,89)'},{y:256,h:39,f:'rgb(251,230,29)'},{y:218,h:39,f:'rgb(249,249,15)'},{y:179,h:39,f:'rgb(226,192,75)'},{y:141,h:39,f:'rgb(30,175,179)'},{y:102,h:39,f:'rgb(18,114,217)'},{y:64,f:'rgb(38,62,168)'},{y:26,h:39},{x:282,y:448,h:39},{y:410},{y:371,h:39,f:'rgb(18,114,217)'},{y:333,h:39,f:'rgb(14,143,209)'},{y:294,f:'rgb(149,190,113)'},{y:256,h:39,f:'rgb(226,192,75)'},{y:218,h:39,f:'rgb(244,198,59)'},{y:179,h:39,f:'rgb(149,190,113)'},{y:141,h:39,f:'rgb(9,157,204)'},{y:102,h:39,f:'rgb(18,114,217)'},{y:64,f:'rgb(38,62,168)'},{y:26,h:39},{x:320,y:448,w:39,h:39},{y:410},{y:371,h:39,f:'rgb(22,82,205)'},{y:333,h:39,f:'rgb(20,129,214)'},{y:294,f:'rgb(46,183,164)'},{y:256,h:39},{y:218,h:39,f:'rgb(82,186,146)'},{y:179,h:39,f:'rgb(9,157,204)'},{y:141,h:39,f:'rgb(20,129,214)'},{y:102,h:39,f:'rgb(16,100,220)'},{y:64,f:'rgb(38,62,168)'},{y:26,h:39},{x:358,y:448,h:39},{y:410},{y:371,h:39,f:'rgb(22,82,205)'},{y:333,h:39},{y:294,f:'rgb(16,100,220)'},{y:256,h:39,f:'rgb(20,129,214)'},{y:218,h:39,f:'rgb(14,143,209)'},{y:179,h:39,f:'rgb(18,114,217)'},{y:141,h:39,f:'rgb(22,82,205)'},{y:102,h:39,f:'rgb(38,62,168)'},{y:64},{y:26,h:39},{x:397,y:448,w:39,h:39},{y:371,h:39},{y:333,h:39},{y:294,f:'rgb(22,82,205)'},{y:256,h:39},{y:218,h:39},{y:179,h:39,f:'rgb(38,62,168)'},{y:141,h:39},{y:102,h:39},{y:64},{y:26,h:39},{x:435,y:410,h:39},{y:371,h:39},{y:333,h:39},{y:294},{y:256,h:39},{y:218,h:39},{y:179,h:39},{y:141,h:39},{y:102,h:39},{y:64},{x:474,y:256,h:39},{y:179,h:39}] + }; + + JSROOT.ToolbarIcons.th2colorz = { + recs: [{x:128,y:486,w:256,h:26,f:'rgb(38,62,168)'},{y:461,f:'rgb(22,82,205)'},{y:435,f:'rgb(16,100,220)'},{y:410,f:'rgb(18,114,217)'},{y:384,f:'rgb(20,129,214)'},{y:358,f:'rgb(14,143,209)'},{y:333,f:'rgb(9,157,204)'},{y:307,f:'rgb(13,167,195)'},{y:282,f:'rgb(30,175,179)'},{y:256,f:'rgb(46,183,164)'},{y:230,f:'rgb(82,186,146)'},{y:205,f:'rgb(116,189,129)'},{y:179,f:'rgb(149,190,113)'},{y:154,f:'rgb(179,189,101)'},{y:128,f:'rgb(209,187,89)'},{y:102,f:'rgb(226,192,75)'},{y:77,f:'rgb(244,198,59)'},{y:51,f:'rgb(253,210,43)'},{y:26,f:'rgb(251,230,29)'},{y:0,f:'rgb(249,249,15)'}] + }; + + JSROOT.ToolbarIcons.th2draw3d = { + path: "M172.768,0H51.726C23.202,0,0.002,23.194,0.002,51.712v89.918c0,28.512,23.2,51.718,51.724,51.718h121.042 c28.518,0,51.724-23.2,51.724-51.718V51.712C224.486,23.194,201.286,0,172.768,0z M177.512,141.63c0,2.611-2.124,4.745-4.75,4.745 H51.726c-2.626,0-4.751-2.134-4.751-4.745V51.712c0-2.614,2.125-4.739,4.751-4.739h121.042c2.62,0,4.75,2.125,4.75,4.739 L177.512,141.63L177.512,141.63z "+ + "M460.293,0H339.237c-28.521,0-51.721,23.194-51.721,51.712v89.918c0,28.512,23.2,51.718,51.721,51.718h121.045 c28.521,0,51.721-23.2,51.721-51.718V51.712C512.002,23.194,488.802,0,460.293,0z M465.03,141.63c0,2.611-2.122,4.745-4.748,4.745 H339.237c-2.614,0-4.747-2.128-4.747-4.745V51.712c0-2.614,2.133-4.739,4.747-4.739h121.045c2.626,0,4.748,2.125,4.748,4.739 V141.63z "+ + "M172.768,256.149H51.726c-28.524,0-51.724,23.205-51.724,51.726v89.915c0,28.504,23.2,51.715,51.724,51.715h121.042 c28.518,0,51.724-23.199,51.724-51.715v-89.915C224.486,279.354,201.286,256.149,172.768,256.149z M177.512,397.784 c0,2.615-2.124,4.736-4.75,4.736H51.726c-2.626-0.006-4.751-2.121-4.751-4.736v-89.909c0-2.626,2.125-4.753,4.751-4.753h121.042 c2.62,0,4.75,2.116,4.75,4.753L177.512,397.784L177.512,397.784z "+ + "M460.293,256.149H339.237c-28.521,0-51.721,23.199-51.721,51.726v89.915c0,28.504,23.2,51.715,51.721,51.715h121.045 c28.521,0,51.721-23.199,51.721-51.715v-89.915C512.002,279.354,488.802,256.149,460.293,256.149z M465.03,397.784 c0,2.615-2.122,4.736-4.748,4.736H339.237c-2.614,0-4.747-2.121-4.747-4.736v-89.909c0-2.626,2.121-4.753,4.747-4.753h121.045 c2.615,0,4.748,2.116,4.748,4.753V397.784z" + }; + + JSROOT.Painter.CreateDefaultPalette = function() { + + function HLStoRGB(h, l, s) { + var r, g, b; + if (s < 1e-100) { + r = g = b = l; // achromatic + } else { + function hue2rgb(p, q, t) { + if (t < 0) t += 1; + if (t > 1) t -= 1; + if (t < 1 / 6) return p + (q - p) * 6 * t; + if (t < 1 / 2) return q; + if (t < 2 / 3) return p + (q - p) * (2/3 - t) * 6; + return p; + } + var q = (l < 0.5) ? l * (1 + s) : l + s - l * s, + p = 2 * l - q; + r = hue2rgb(p, q, h + 1/3); + g = hue2rgb(p, q, h); + b = hue2rgb(p, q, h - 1/3); + } + return 'rgb(' + Math.round(r*255) + ',' + Math.round(g*255) + ',' + Math.round(b*255) + ')'; + } + + var palette = [], saturation = 1, lightness = 0.5, maxHue = 280, minHue = 0, maxPretty = 50; + for (var i = 0; i < maxPretty; ++i) { + var hue = (maxHue - (i + 1) * ((maxHue - minHue) / maxPretty)) / 360, + rgbval = HLStoRGB(hue, lightness, saturation); + palette.push(rgbval); + } + return new JSROOT.ColorPalette(palette); + } + + JSROOT.Painter.CreateGrayPalette = function() { + var palette = []; + for (var i = 0; i < 50; ++i) { + var code = Math.round((i+2)/60*255); + palette.push('rgb('+code+','+code+','+code+')'); + } + return new JSROOT.ColorPalette(palette); + } + + JSROOT.Painter.CreateGradientColorTable = function(Stops, Red, Green, Blue, NColors, alpha) { + // skip all checks + var palette = []; + + for (var g = 1; g < Stops.length; g++) { + // create the colors... + var nColorsGradient = parseInt(Math.floor(NColors*Stops[g]) - Math.floor(NColors*Stops[g-1])); + for (var c = 0; c < nColorsGradient; c++) { + var col = Math.round(Red[g-1] + c * (Red[g] - Red[g-1])/nColorsGradient) + "," + + Math.round(Green[g-1] + c * (Green[g] - Green[g-1])/ nColorsGradient) + "," + + Math.round(Blue[g-1] + c * (Blue[g] - Blue[g-1])/ nColorsGradient); + palette.push("rgb("+col+")"); + } + } + + return new JSROOT.ColorPalette(palette); + } + + JSROOT.Painter.GetColorPalette = function(col,alfa) { + col = col || JSROOT.gStyle.Palette; + if ((col>0) && (col<10)) return JSROOT.Painter.CreateGrayPalette(); + if (col < 51) return JSROOT.Painter.CreateDefaultPalette(); + if (col > 113) col = 57; + var red, green, blue, + stops = [ 0.0000, 0.1250, 0.2500, 0.3750, 0.5000, 0.6250, 0.7500, 0.8750, 1.0000 ]; + switch(col) { + + // Deep Sea + case 51: + red = [ 0, 9, 13, 17, 24, 32, 27, 25, 29]; + green = [ 0, 0, 0, 2, 37, 74, 113, 160, 221]; + blue = [ 28, 42, 59, 78, 98, 129, 154, 184, 221]; + break; + + // Grey Scale + case 52: + red = [ 0, 32, 64, 96, 128, 160, 192, 224, 255]; + green = [ 0, 32, 64, 96, 128, 160, 192, 224, 255]; + blue = [ 0, 32, 64, 96, 128, 160, 192, 224, 255]; + break; + + // Dark Body Radiator + case 53: + red = [ 0, 45, 99, 156, 212, 230, 237, 234, 242]; + green = [ 0, 0, 0, 45, 101, 168, 238, 238, 243]; + blue = [ 0, 1, 1, 3, 9, 8, 11, 95, 230]; + break; + + // Two-color hue (dark blue through neutral gray to bright yellow) + case 54: + red = [ 0, 22, 44, 68, 93, 124, 160, 192, 237]; + green = [ 0, 16, 41, 67, 93, 125, 162, 194, 241]; + blue = [ 97, 100, 99, 99, 93, 68, 44, 26, 74]; + break; + + // Rain Bow + case 55: + red = [ 0, 5, 15, 35, 102, 196, 208, 199, 110]; + green = [ 0, 48, 124, 192, 206, 226, 97, 16, 0]; + blue = [ 99, 142, 198, 201, 90, 22, 13, 8, 2]; + break; + + // Inverted Dark Body Radiator + case 56: + red = [ 242, 234, 237, 230, 212, 156, 99, 45, 0]; + green = [ 243, 238, 238, 168, 101, 45, 0, 0, 0]; + blue = [ 230, 95, 11, 8, 9, 3, 1, 1, 0]; + break; + + // Bird + case 57: + red = [ 0.2082*255, 0.0592*255, 0.0780*255, 0.0232*255, 0.1802*255, 0.5301*255, 0.8186*255, 0.9956*255, 0.9764*255]; + green = [ 0.1664*255, 0.3599*255, 0.5041*255, 0.6419*255, 0.7178*255, 0.7492*255, 0.7328*255, 0.7862*255, 0.9832*255]; + blue = [ 0.5293*255, 0.8684*255, 0.8385*255, 0.7914*255, 0.6425*255, 0.4662*255, 0.3499*255, 0.1968*255, 0.0539*255]; + break; + + // Cubehelix + case 58: + red = [ 0.0000, 0.0956*255, 0.0098*255, 0.2124*255, 0.6905*255, 0.9242*255, 0.7914*255, 0.7596*255, 1.0000*255]; + green = [ 0.0000, 0.1147*255, 0.3616*255, 0.5041*255, 0.4577*255, 0.4691*255, 0.6905*255, 0.9237*255, 1.0000*255]; + blue = [ 0.0000, 0.2669*255, 0.3121*255, 0.1318*255, 0.2236*255, 0.6741*255, 0.9882*255, 0.9593*255, 1.0000*255]; + break; + + // Green Red Violet + case 59: + red = [13, 23, 25, 63, 76, 104, 137, 161, 206]; + green = [95, 67, 37, 21, 0, 12, 35, 52, 79]; + blue = [ 4, 3, 2, 6, 11, 22, 49, 98, 208]; + break; + + // Blue Red Yellow + case 60: + red = [0, 61, 89, 122, 143, 160, 185, 204, 231]; + green = [0, 0, 0, 0, 14, 37, 72, 132, 235]; + blue = [0, 140, 224, 144, 4, 5, 6, 9, 13]; + break; + + // Ocean + case 61: + red = [ 14, 7, 2, 0, 5, 11, 55, 131, 229]; + green = [105, 56, 26, 1, 42, 74, 131, 171, 229]; + blue = [ 2, 21, 35, 60, 92, 113, 160, 185, 229]; + break; + + // Color Printable On Grey + case 62: + red = [ 0, 0, 0, 70, 148, 231, 235, 237, 244]; + green = [ 0, 0, 0, 0, 0, 69, 67, 216, 244]; + blue = [ 0, 102, 228, 231, 177, 124, 137, 20, 244]; + break; + + // Alpine + case 63: + red = [ 50, 56, 63, 68, 93, 121, 165, 192, 241]; + green = [ 66, 81, 91, 96, 111, 128, 155, 189, 241]; + blue = [ 97, 91, 75, 65, 77, 103, 143, 167, 217]; + break; + + // Aquamarine + case 64: + red = [ 145, 166, 167, 156, 131, 114, 101, 112, 132]; + green = [ 158, 178, 179, 181, 163, 154, 144, 152, 159]; + blue = [ 190, 199, 201, 192, 176, 169, 160, 166, 190]; + break; + + // Army + case 65: + red = [ 93, 91, 99, 108, 130, 125, 132, 155, 174]; + green = [ 126, 124, 128, 129, 131, 121, 119, 153, 173]; + blue = [ 103, 94, 87, 85, 80, 85, 107, 120, 146]; + break; + + // Atlantic + case 66: + red = [ 24, 40, 69, 90, 104, 114, 120, 132, 103]; + green = [ 29, 52, 94, 127, 150, 162, 159, 151, 101]; + blue = [ 29, 52, 96, 132, 162, 181, 184, 186, 131]; + break; + + // Aurora + case 67: + red = [ 46, 38, 61, 92, 113, 121, 132, 150, 191]; + green = [ 46, 36, 40, 69, 110, 135, 131, 92, 34]; + blue = [ 46, 80, 74, 70, 81, 105, 165, 211, 225]; + break; + + // Avocado + case 68: + red = [ 0, 4, 12, 30, 52, 101, 142, 190, 237]; + green = [ 0, 40, 86, 121, 140, 172, 187, 213, 240]; + blue = [ 0, 9, 14, 18, 21, 23, 27, 35, 101]; + break; + + // Beach + case 69: + red = [ 198, 206, 206, 211, 198, 181, 161, 171, 244]; + green = [ 103, 133, 150, 172, 178, 174, 163, 175, 244]; + blue = [ 49, 54, 55, 66, 91, 130, 184, 224, 244]; + break; + + // Black Body + case 70: + red = [ 243, 243, 240, 240, 241, 239, 186, 151, 129]; + green = [ 0, 46, 99, 149, 194, 220, 183, 166, 147]; + blue = [ 6, 8, 36, 91, 169, 235, 246, 240, 233]; + break; + + // Blue Green Yellow + case 71: + red = [ 22, 19, 19, 25, 35, 53, 88, 139, 210]; + green = [ 0, 32, 69, 108, 135, 159, 183, 198, 215]; + blue = [ 77, 96, 110, 116, 110, 100, 90, 78, 70]; + break; + + // Brown Cyan + case 72: + red = [ 68, 116, 165, 182, 189, 180, 145, 111, 71]; + green = [ 37, 82, 135, 178, 204, 225, 221, 202, 147]; + blue = [ 16, 55, 105, 147, 196, 226, 232, 224, 178]; + break; + + // CMYK + case 73: + red = [ 61, 99, 136, 181, 213, 225, 198, 136, 24]; + green = [ 149, 140, 96, 83, 132, 178, 190, 135, 22]; + blue = [ 214, 203, 168, 135, 110, 100, 111, 113, 22]; + break; + + // Candy + case 74: + red = [ 76, 120, 156, 183, 197, 180, 162, 154, 140]; + green = [ 34, 35, 42, 69, 102, 137, 164, 188, 197]; + blue = [ 64, 69, 78, 105, 142, 177, 205, 217, 198]; + break; + + // Cherry + case 75: + red = [ 37, 102, 157, 188, 196, 214, 223, 235, 251]; + green = [ 37, 29, 25, 37, 67, 91, 132, 185, 251]; + blue = [ 37, 32, 33, 45, 66, 98, 137, 187, 251]; + break; + + // Coffee + case 76: + red = [ 79, 100, 119, 137, 153, 172, 192, 205, 250]; + green = [ 63, 79, 93, 103, 115, 135, 167, 196, 250]; + blue = [ 51, 59, 66, 61, 62, 70, 110, 160, 250]; + break; + + // Dark Rain Bow + case 77: + red = [ 43, 44, 50, 66, 125, 172, 178, 155, 157]; + green = [ 63, 63, 85, 101, 138, 163, 122, 51, 39]; + blue = [ 121, 101, 58, 44, 47, 55, 57, 44, 43]; + break; + + // Dark Terrain + case 78: + red = [ 0, 41, 62, 79, 90, 87, 99, 140, 228]; + green = [ 0, 57, 81, 93, 85, 70, 71, 125, 228]; + blue = [ 95, 91, 91, 82, 60, 43, 44, 112, 228]; + break; + + // Fall + case 79: + red = [ 49, 59, 72, 88, 114, 141, 176, 205, 222]; + green = [ 78, 72, 66, 57, 59, 75, 106, 142, 173]; + blue = [ 78, 55, 46, 40, 39, 39, 40, 41, 47]; + break; + + // Fruit Punch + case 80: + red = [ 243, 222, 201, 185, 165, 158, 166, 187, 219]; + green = [ 94, 108, 132, 135, 125, 96, 68, 51, 61]; + blue = [ 7, 9, 12, 19, 45, 89, 118, 146, 118]; + break; + + // Fuchsia + case 81: + red = [ 19, 44, 74, 105, 137, 166, 194, 206, 220]; + green = [ 19, 28, 40, 55, 82, 110, 159, 181, 220]; + blue = [ 19, 42, 68, 96, 129, 157, 188, 203, 220]; + break; + + // Grey Yellow + case 82: + red = [ 33, 44, 70, 99, 140, 165, 199, 211, 216]; + green = [ 38, 50, 76, 105, 140, 165, 191, 189, 167]; + blue = [ 55, 67, 97, 124, 140, 166, 163, 129, 52]; + break; + + // Green Brown Terrain + case 83: + red = [ 0, 33, 73, 124, 136, 152, 159, 171, 223]; + green = [ 0, 43, 92, 124, 134, 126, 121, 144, 223]; + blue = [ 0, 43, 68, 76, 73, 64, 72, 114, 223]; + break; + + // Green Pink + case 84: + red = [ 5, 18, 45, 124, 193, 223, 205, 128, 49]; + green = [ 48, 134, 207, 230, 193, 113, 28, 0, 7]; + blue = [ 6, 15, 41, 121, 193, 226, 208, 130, 49]; + break; + + // Island + case 85: + red = [ 180, 106, 104, 135, 164, 188, 189, 165, 144]; + green = [ 72, 126, 154, 184, 198, 207, 205, 190, 179]; + blue = [ 41, 120, 158, 188, 194, 181, 145, 100, 62]; + break; + + // Lake + case 86: + red = [ 57, 72, 94, 117, 136, 154, 174, 192, 215]; + green = [ 0, 33, 68, 109, 140, 171, 192, 196, 209]; + blue = [ 116, 137, 173, 201, 200, 201, 203, 190, 187]; + break; + + // Light Temperature + case 87: + red = [ 31, 71, 123, 160, 210, 222, 214, 199, 183]; + green = [ 40, 117, 171, 211, 231, 220, 190, 132, 65]; + blue = [ 234, 214, 228, 222, 210, 160, 105, 60, 34]; + break; + + // Light Terrain + case 88: + red = [ 123, 108, 109, 126, 154, 172, 188, 196, 218]; + green = [ 184, 138, 130, 133, 154, 175, 188, 196, 218]; + blue = [ 208, 130, 109, 99, 110, 122, 150, 171, 218]; + break; + + // Mint + case 89: + red = [ 105, 106, 122, 143, 159, 172, 176, 181, 207]; + green = [ 252, 197, 194, 187, 174, 162, 153, 136, 125]; + blue = [ 146, 133, 144, 155, 163, 167, 166, 162, 174]; + break; + + // Neon + case 90: + red = [ 171, 141, 145, 152, 154, 159, 163, 158, 177]; + green = [ 236, 143, 100, 63, 53, 55, 44, 31, 6]; + blue = [ 59, 48, 46, 44, 42, 54, 82, 112, 179]; + break; + + // Pastel + case 91: + red = [ 180, 190, 209, 223, 204, 228, 205, 152, 91]; + green = [ 93, 125, 147, 172, 181, 224, 233, 198, 158]; + blue = [ 236, 218, 160, 133, 114, 132, 162, 220, 218]; + break; + + // Pearl + case 92: + red = [ 225, 183, 162, 135, 115, 111, 119, 145, 211]; + green = [ 205, 177, 166, 135, 124, 117, 117, 132, 172]; + blue = [ 186, 165, 155, 135, 126, 130, 150, 178, 226]; + break; + + // Pigeon + case 93: + red = [ 39, 43, 59, 63, 80, 116, 153, 177, 223]; + green = [ 39, 43, 59, 74, 91, 114, 139, 165, 223]; + blue = [ 39, 50, 59, 70, 85, 115, 151, 176, 223]; + break; + + // Plum + case 94: + red = [ 0, 38, 60, 76, 84, 89, 101, 128, 204]; + green = [ 0, 10, 15, 23, 35, 57, 83, 123, 199]; + blue = [ 0, 11, 22, 40, 63, 86, 97, 94, 85]; + break; + + // Red Blue + case 95: + red = [ 94, 112, 141, 165, 167, 140, 91, 49, 27]; + green = [ 27, 46, 88, 135, 166, 161, 135, 97, 58]; + blue = [ 42, 52, 81, 106, 139, 158, 155, 137, 116]; + break; + + // Rose + case 96: + red = [ 30, 49, 79, 117, 135, 151, 146, 138, 147]; + green = [ 63, 60, 72, 90, 94, 94, 68, 46, 16]; + blue = [ 18, 28, 41, 56, 62, 63, 50, 36, 21]; + break; + + // Rust + case 97: + red = [ 0, 30, 63, 101, 143, 152, 169, 187, 230]; + green = [ 0, 14, 28, 42, 58, 61, 67, 74, 91]; + blue = [ 39, 26, 21, 18, 15, 14, 14, 13, 13]; + break; + + // Sandy Terrain + case 98: + red = [ 149, 140, 164, 179, 182, 181, 131, 87, 61]; + green = [ 62, 70, 107, 136, 144, 138, 117, 87, 74]; + blue = [ 40, 38, 45, 49, 49, 49, 38, 32, 34]; + break; + + // Sienna + case 99: + red = [ 99, 112, 148, 165, 179, 182, 183, 183, 208]; + green = [ 39, 40, 57, 79, 104, 127, 148, 161, 198]; + blue = [ 15, 16, 18, 33, 51, 79, 103, 129, 177]; + break; + + // Solar + case 100: + red = [ 99, 116, 154, 174, 200, 196, 201, 201, 230]; + green = [ 0, 0, 8, 32, 58, 83, 119, 136, 173]; + blue = [ 5, 6, 7, 9, 9, 14, 17, 19, 24]; + break; + + // South West + case 101: + red = [ 82, 106, 126, 141, 155, 163, 142, 107, 66]; + green = [ 62, 44, 69, 107, 135, 152, 149, 132, 119]; + blue = [ 39, 25, 31, 60, 73, 68, 49, 72, 188]; + break; + + // Starry Night + case 102: + red = [ 18, 29, 44, 72, 116, 158, 184, 208, 221]; + green = [ 27, 46, 71, 105, 146, 177, 189, 190, 183]; + blue = [ 39, 55, 80, 108, 130, 133, 124, 100, 76]; + break; + + // Sunset + case 103: + red = [ 0, 48, 119, 173, 212, 224, 228, 228, 245]; + green = [ 0, 13, 30, 47, 79, 127, 167, 205, 245]; + blue = [ 0, 68, 75, 43, 16, 22, 55, 128, 245]; + break; + + // Temperature Map + case 104: + red = [ 34, 70, 129, 187, 225, 226, 216, 193, 179]; + green = [ 48, 91, 147, 194, 226, 229, 196, 110, 12]; + blue = [ 234, 212, 216, 224, 206, 110, 53, 40, 29]; + break; + + // Thermometer + case 105: + red = [ 30, 55, 103, 147, 174, 203, 188, 151, 105]; + green = [ 0, 65, 138, 182, 187, 175, 121, 53, 9]; + blue = [ 191, 202, 212, 208, 171, 140, 97, 57, 30]; + break; + + // Valentine + case 106: + red = [ 112, 97, 113, 125, 138, 159, 178, 188, 225]; + green = [ 16, 17, 24, 37, 56, 81, 110, 136, 189]; + blue = [ 38, 35, 46, 59, 78, 103, 130, 152, 201]; + break; + + // Visible Spectrum + case 107: + red = [ 18, 72, 5, 23, 29, 201, 200, 98, 29]; + green = [ 0, 0, 43, 167, 211, 117, 0, 0, 0]; + blue = [ 51, 203, 177, 26, 10, 9, 8, 3, 0]; + break; + + // Water Melon + case 108: + red = [ 19, 42, 64, 88, 118, 147, 175, 187, 205]; + green = [ 19, 55, 89, 125, 154, 169, 161, 129, 70]; + blue = [ 19, 32, 47, 70, 100, 128, 145, 130, 75]; + break; + + // Cool + case 109: + red = [ 33, 31, 42, 68, 86, 111, 141, 172, 227]; + green = [ 255, 175, 145, 106, 88, 55, 15, 0, 0]; + blue = [ 255, 205, 202, 203, 208, 205, 203, 206, 231]; + break; + + // Copper + case 110: + red = [ 0, 25, 50, 79, 110, 145, 181, 201, 254]; + green = [ 0, 16, 30, 46, 63, 82, 101, 124, 179]; + blue = [ 0, 12, 21, 29, 39, 49, 61, 74, 103]; + break; + + // Gist Earth + case 111: + red = [ 0, 13, 30, 44, 72, 120, 156, 200, 247]; + green = [ 0, 36, 84, 117, 141, 153, 151, 158, 247]; + blue = [ 0, 94, 100, 82, 56, 66, 76, 131, 247]; + break; + + // Viridis + case 112: + red = [ 26, 51, 43, 33, 28, 35, 74, 144, 246]; + green = [ 9, 24, 55, 87, 118, 150, 180, 200, 222]; + blue = [ 30, 96, 112, 114, 112, 101, 72, 35, 0]; + break; + + // Cividis + case 113: + red = [ 0, 5, 65, 97, 124, 156, 189, 224, 255 ]; + green = [ 32, 54, 77, 100, 123, 148, 175, 203, 234 ]; + blue = [ 77, 110, 107, 111, 120, 119, 111, 94, 70 ]; + break; + + default: + return JSROOT.Painter.CreateDefaultPalette(); + } + + return JSROOT.Painter.CreateGradientColorTable(stops, red, green, blue, 255, alfa); + } + + // ============================================================ + + // base class for all objects, derived from TPave + function TPavePainter(pave) { + JSROOT.TObjectPainter.call(this, pave); + this.Enabled = true; + this.UseContextMenu = true; + this.UseTextColor = false; // indicates if text color used, enabled menu entry + this.FirstRun = 1; // counter required to correctly complete drawing + this.AssignFinishPave(); + } + + TPavePainter.prototype = Object.create(JSROOT.TObjectPainter.prototype); + + TPavePainter.prototype.AssignFinishPave = function() { + function func() { + // function used to signal drawing ready, required when text drawing postponed due to mathjax + if (this.FirstRun <= 0) return; + this.FirstRun--; + if (this.FirstRun!==0) return; + delete this.FinishPave; // no need for that callback + this.DrawingReady(); + } + this.FinishPave = func.bind(this); + } + + TPavePainter.prototype.DrawPave = function(arg) { + // this draw only basic TPave + + this.UseTextColor = false; + + if (!this.Enabled) + return this.RemoveDrawG(); + + var pt = this.GetObject(), opt = pt.fOption.toUpperCase(); + + if (pt.fInit===0) { + this.stored = JSROOT.extend({}, pt); // store coordinates to use them when updating + pt.fInit = 1; + var pad = this.root_pad(); + + if (opt.indexOf("NDC")>=0) { + pt.fX1NDC = pt.fX1; pt.fX2NDC = pt.fX2; + pt.fY1NDC = pt.fY1; pt.fY2NDC = pt.fY2; + } else if (pad) { + if (pad.fLogx) { + if (pt.fX1 > 0) pt.fX1 = JSROOT.log10(pt.fX1); + if (pt.fX2 > 0) pt.fX2 = JSROOT.log10(pt.fX2); + } + if (pad.fLogy) { + if (pt.fY1 > 0) pt.fY1 = JSROOT.log10(pt.fY1); + if (pt.fY2 > 0) pt.fY2 = JSROOT.log10(pt.fY2); + } + pt.fX1NDC = (pt.fX1 - pad.fX1) / (pad.fX2 - pad.fX1); + pt.fY1NDC = (pt.fY1 - pad.fY1) / (pad.fY2 - pad.fY1); + pt.fX2NDC = (pt.fX2 - pad.fX1) / (pad.fX2 - pad.fX1); + pt.fY2NDC = (pt.fY2 - pad.fY1) / (pad.fY2 - pad.fY1); + } else { + pt.fX1NDC = pt.fY1NDC = 0.1; + pt.fX2NDC = pt.fY2NDC = 0.9; + } + + if ((pt.fX1NDC == pt.fX2NDC) && (pt.fY1NDC == pt.fY2NDC) && (pt._typename == "TLegend")) { + pt.fX1NDC = Math.max(pad ? pad.fLeftMargin : 0, pt.fX2NDC - 0.3); + pt.fX2NDC = Math.min(pt.fX1NDC + 0.3, pad ? 1-pad.fRightMargin : 1); + var h0 = Math.max(pt.fPrimitives ? pt.fPrimitives.arr.length*0.05 : 0, 0.2); + pt.fY2NDC = Math.min(pad ? 1-pad.fTopMargin : 1, pt.fY1NDC + h0); + pt.fY1NDC = Math.max(pt.fY2NDC - h0, pad ? pad.fBottomMargin : 0); + } + } + + var pos_x = Math.round(pt.fX1NDC * this.pad_width()), + pos_y = Math.round((1.0 - pt.fY2NDC) * this.pad_height()), + width = Math.round((pt.fX2NDC - pt.fX1NDC) * this.pad_width()), + height = Math.round((pt.fY2NDC - pt.fY1NDC) * this.pad_height()), + lwidth = pt.fBorderSize, + dx = (opt.indexOf("L")>=0) ? -1 : ((opt.indexOf("R")>=0) ? 1 : 0), + dy = (opt.indexOf("T")>=0) ? -1 : ((opt.indexOf("B")>=0) ? 1 : 0); + + // container used to recalculate coordinates + this.CreateG(); + + this.draw_g.attr("transform", "translate(" + pos_x + "," + pos_y + ")"); + + //if (!this.lineatt) + // this.lineatt = new JSROOT.TAttLineHandler(pt, lwidth>0 ? 1 : 0); + + this.createAttLine({ attr: pt, width: lwidth>0 ? 1 : 0 }); + + this.createAttFill({ attr: pt }); + + if (pt._typename == "TDiamond") { + var h2 = Math.round(height/2), w2 = Math.round(width/2), + dpath = "l"+w2+",-"+h2 + "l"+w2+","+h2 + "l-"+w2+","+h2+"z"; + + if ((lwidth > 1) && (pt.fShadowColor > 0) && (dx || dy)) + this.draw_g.append("svg:path") + .attr("d","M0,"+(h2+lwidth) + dpath) + .style("fill", this.get_color(pt.fShadowColor)) + .style("stroke", this.get_color(pt.fShadowColor)) + .style("stroke-width", "1px"); + + this.draw_g.append("svg:path") + .attr("d", "M0,"+h2 +dpath) + .call(this.fillatt.func) + .call(this.lineatt.func); + + var text_g = this.draw_g.append("svg:g") + .attr("transform", "translate(" + Math.round(width/4) + "," + Math.round(height/4) + ")"); + + this.DrawPaveText(w2, h2, arg, text_g); + + return; + } + + // add shadow decoration before main rect + if ((lwidth > 1) && (pt.fShadowColor > 0) && !pt.fNpaves && (dx || dy)) + this.draw_g.append("svg:path") + .attr("d","M"+(dx*lwidth)+","+(dy*lwidth) + "v"+height + "h"+width + "v-"+height + "z") + .style("fill", this.get_color(pt.fShadowColor)) + .style("stroke", this.get_color(pt.fShadowColor)) + .style("stroke-width", "1px"); + + if (pt.fNpaves) + for (var n = pt.fNpaves-1; n>0; --n) + this.draw_g.append("svg:path") + .attr("d", "M" + (dx*4*n) + ","+ (dy*4*n) + "h"+width + "v"+height + "h-"+width + "z") + .call(this.fillatt.func) + .call(this.lineatt.func); + + var rect = + this.draw_g.append("svg:path") + .attr("d", "M0,0h"+width + "v"+height + "h-"+width + "z") + .call(this.fillatt.func) + .call(this.lineatt.func); + + if ('PaveDrawFunc' in this) + this.PaveDrawFunc(width, height, arg); + + if (JSROOT.BatchMode || (pt._typename=="TPave")) return; + + // here all kind of interactive settings + + rect.style("pointer-events", "visibleFill") + .on("mouseenter", this.ShowObjectStatus.bind(this)) + + // position and size required only for drag functions + this.draw_g.attr("x", pos_x) + .attr("y", pos_y) + .attr("width", width) + .attr("height", height); + + this.AddDrag({ obj: pt, minwidth: 10, minheight: 20, canselect: true, + redraw: this.DrawPave.bind(this), + ctxmenu: JSROOT.touches && JSROOT.gStyle.ContextMenu && this.UseContextMenu }); + + if (this.UseContextMenu && JSROOT.gStyle.ContextMenu) + this.draw_g.on("contextmenu", this.ShowContextMenu.bind(this)); + } + + TPavePainter.prototype.DrawPaveLabel = function(_width, _height) { + this.UseTextColor = true; + + var pave = this.GetObject(); + + this.StartTextDrawing(pave.fTextFont, _height/1.2); + + this.DrawText({ align: pave.fTextAlign, width: _width, height: _height, text: pave.fLabel, color: this.get_color(pave.fTextColor) }); + + this.FinishTextDrawing(null, this.FinishPave); + } + + TPavePainter.prototype.DrawPaveStats = function(width, height, refill) { + + if (refill && this.IsStats()) this.FillStatistic(); + + var pt = this.GetObject(), lines = [], + tcolor = this.get_color(pt.fTextColor), + first_stat = 0, num_cols = 0, maxlen = 0; + + // now draw TLine and TBox objects + for (var j=0;j<pt.fLines.arr.length;++j) { + var entry = pt.fLines.arr[j]; + if ((entry._typename=="TText") || (entry._typename=="TLatex")) + lines.push(entry.fTitle); + } + + var nlines = lines.length; + + // adjust font size + for (var j = 0; j < nlines; ++j) { + var line = lines[j]; + if (j>0) maxlen = Math.max(maxlen, line.length); + if ((j == 0) || (line.indexOf('|') < 0)) continue; + if (first_stat === 0) first_stat = j; + var parts = line.split("|"); + if (parts.length > num_cols) + num_cols = parts.length; + } + + // for characters like 'p' or 'y' several more pixels required to stay in the box when drawn in last line + var stepy = height / nlines, has_head = false, margin_x = pt.fMargin * width; + + this.StartTextDrawing(pt.fTextFont, height/(nlines * 1.2)); + + this.UseTextColor = true; + + if (nlines == 1) { + this.DrawText({ align: pt.fTextAlign, width: width, height: height, text: lines[0], color: tcolor, latex: 1 }); + } else + for (var j = 0; j < nlines; ++j) { + var posy = j*stepy, jcolor = tcolor; + this.UseTextColor = true; + + if (first_stat && (j >= first_stat)) { + var parts = lines[j].split("|"); + for (var n = 0; n < parts.length; ++n) + this.DrawText({ align: "middle", x: width * n / num_cols, y: posy, latex: 0, + width: width/num_cols, height: stepy, text: parts[n], color: jcolor }); + } else if (lines[j].indexOf('=') < 0) { + if (j==0) { + has_head = true; + if (lines[j].length > maxlen + 5) + lines[j] = lines[j].substr(0,maxlen+2) + "..."; + } + this.DrawText({ align: (j == 0) ? "middle" : "start", x: margin_x, y: posy, + width: width-2*margin_x, height: stepy, text: lines[j], color: jcolor }); + } else { + var parts = lines[j].split("="), sumw = 0; + for (var n = 0; n < 2; ++n) + sumw += this.DrawText({ align: (n == 0) ? "start" : "end", x: margin_x, y: posy, + width: width-2*margin_x, height: stepy, text: parts[n], color: jcolor }); + this.TextScaleFactor(1.05*sumw/(width-2*margin_x), this.draw_g); + } + } + + var lpath = ""; + + if ((pt.fBorderSize > 0) && has_head) + lpath += "M0," + Math.round(stepy) + "h" + width; + + if ((first_stat > 0) && (num_cols > 1)) { + for (var nrow = first_stat; nrow < nlines; ++nrow) + lpath += "M0," + Math.round(nrow * stepy) + "h" + width; + for (var ncol = 0; ncol < num_cols - 1; ++ncol) + lpath += "M" + Math.round(width / num_cols * (ncol + 1)) + "," + Math.round(first_stat * stepy) + "V" + height; + } + + if (lpath) this.draw_g.append("svg:path").attr("d",lpath).call(this.lineatt.func); + + this.FinishTextDrawing(undefined, this.FinishPave); + + this.draw_g.classed("most_upper_primitives", true); // this primitive will remain on top of list + } + + TPavePainter.prototype.DrawPaveText = function(width, height, dummy_arg, text_g) { + + var pt = this.GetObject(), + tcolor = this.get_color(pt.fTextColor), + nlines = 0, lines = [], + can_height = this.pad_height(), + pp = this.pad_painter(), + individual_positioning = false, + draw_header = (pt.fLabel.length>0); + + if (draw_header) this.FirstRun++; // increment finish counter + + if (!text_g) text_g = this.draw_g; + + // first check how many text lines in the list + for (var j=0;j<pt.fLines.arr.length;++j) { + var entry = pt.fLines.arr[j]; + if ((entry._typename=="TText") || (entry._typename=="TLatex")) { + nlines++; // count lines + if ((entry.fX>0) || (entry.fY>0)) individual_positioning = true; + } + } + + var fast_draw = (nlines==1) && pp && pp._fast_drawing, nline = 0; + + // now draw TLine and TBox objects + for (var j=0;j<pt.fLines.arr.length;++j) { + var entry = pt.fLines.arr[j], + ytext = (nlines>0) ? Math.round((1-(nline-0.5)/nlines)*height) : 0; + switch (entry._typename) { + case "TText": + case "TLatex": + nline++; // just count line number + if (individual_positioning) { + // each line should be drawn and scaled separately + + var lx = entry.fX, ly = entry.fY; + + if ((lx>0) && (lx<1)) lx = Math.round(lx*width); else lx = pt.fMargin * width; + if ((ly>0) && (ly<1)) ly = Math.round((1-ly)*height); else ly = ytext; + + var jcolor = entry.fTextColor ? this.get_color(entry.fTextColor) : ""; + if (!jcolor) { + jcolor = tcolor; + this.UseTextColor = true; + } + + this.StartTextDrawing(pt.fTextFont, (entry.fTextSize || pt.fTextSize) * can_height, text_g); + + this.DrawText({ align: entry.fTextAlign || pt.fTextAlign, x: lx, y: ly, text: entry.fTitle, color: jcolor, + latex: (entry._typename == "TText") ? 0 : 1, draw_g: text_g, fast: fast_draw }); + + this.FinishTextDrawing(text_g, this.FinishPave); + + this.FirstRun++; + + } else { + lines.push(entry); // make as before + } + break; + case "TLine": + case "TBox": + var lx1 = entry.fX1, lx2 = entry.fX2, + ly1 = entry.fY1, ly2 = entry.fY2; + if (lx1!==0) lx1 = Math.round(lx1*width); + lx2 = lx2 ? Math.round(lx2*width) : width; + ly1 = ly1 ? Math.round((1-ly1)*height) : ytext; + ly2 = ly2 ? Math.round((1-ly2)*height) : ytext; + if (entry._typename == "TLine") { + var lineatt = new JSROOT.TAttLineHandler(entry); + text_g.append("svg:line") + .attr("x1", lx1) + .attr("y1", ly1) + .attr("x2", lx2) + .attr("y2", ly2) + .call(lineatt.func); + } else { + var fillatt = this.createAttFill(entry); + + text_g.append("svg:rect") + .attr("x", lx1) + .attr("y", ly2) + .attr("width", lx2-lx1) + .attr("height", ly1-ly2) + .call(fillatt.func); + } + break; + } + } + + if (individual_positioning) { + + // we should call FinishPave + if (this.FinishPave) this.FinishPave(); + + } else { + + // for characters like 'p' or 'y' several more pixels required to stay in the box when drawn in last line + var stepy = height / nlines, has_head = false, margin_x = pt.fMargin * width, max_font_size = 0; + + // for single line (typically title) limit font size + if ((nlines == 1) && (pt.fTextSize > 0)) { + max_font_size = Math.round(pt.fTextSize*can_height); + if (max_font_size < 3) max_font_size = 3; + } + + this.StartTextDrawing(pt.fTextFont, height/(nlines * 1.2), text_g, max_font_size); + + for (var j = 0; j < nlines; ++j) { + var arg = null, lj = lines[j]; + + if (nlines == 1) { + arg = { x:0, y:0, width: width, height: height }; + } else { + arg = { x: margin_x, y: j*stepy, width: width-2*margin_x, height: stepy }; + if (lj.fTextColor) arg.color = this.get_color(lj.fTextColor); + if (lj.fTextSize) arg.font_size = Math.round(lj.fTextSize*can_height); + } + + arg.align = pt.fTextAlign; + arg.draw_g = text_g; + arg.latex = (lj._typename == "TText" ? 0 : 1); + arg.text = lj.fTitle; + arg.fast = fast_draw; + if (!arg.color) { this.UseTextColor = true; arg.color = tcolor; } + + this.DrawText(arg); + } + + this.FinishTextDrawing(text_g, this.FinishPave); + } + + if (draw_header) { + var x = Math.round(width*0.25), + y = Math.round(-height*0.02), + w = Math.round(width*0.5), + h = Math.round(height*0.04), + lbl_g = text_g.append("svg:g"); + + lbl_g.append("svg:path") + .attr("d", "M"+x+","+y + "h"+w + "v"+h + "h-"+w + "z") + .call(this.fillatt.func) + .call(this.lineatt.func); + + this.StartTextDrawing(pt.fTextFont, h/1.5, lbl_g); + + this.DrawText({ align: 22, x: x, y: y, width: w, height: h, text: pt.fLabel, color: tcolor, draw_g: lbl_g }); + + this.FinishTextDrawing(lbl_g, this.FinishPave); + + this.UseTextColor = true; + } + } + + TPavePainter.prototype.Format = function(value, fmt) { + // method used to convert value to string according specified format + // format can be like 5.4g or 4.2e or 6.4f + if (!fmt) fmt = "stat"; + + var pave = this.GetObject(); + + switch(fmt) { + case "stat" : fmt = pave.fStatFormat || JSROOT.gStyle.fStatFormat; break; + case "fit": fmt = pave.fFitFormat || JSROOT.gStyle.fFitFormat; break; + case "entries": if ((Math.abs(value) < 1e9) && (Math.round(value) == value)) return value.toFixed(0); fmt = "14.7g"; break; + case "last": fmt = this.lastformat; break; + } + + delete this.lastformat; + + var res = JSROOT.FFormat(value, fmt || "6.4g"); + + this.lastformat = JSROOT.lastFFormat; + + return res; + } + + TPavePainter.prototype.DrawPaveLegend = function(w, h) { + + var legend = this.GetObject(), + nlines = legend.fPrimitives.arr.length, + ncols = legend.fNColumns, + nrows = nlines; + + if (ncols<2) ncols = 1; else { while ((nrows-1)*ncols >= nlines) nrows--; } + + function isEmpty(entry) { + return !entry.fObject && !entry.fOption && (!entry.fLabel || (entry.fLabel == " ")); + } + + if (ncols==1) { + for (var i=0;i<nlines;++i) + if (isEmpty(legend.fPrimitives.arr[i])) nrows--; + } + + if (nrows<1) nrows = 1; + + var tcolor = this.get_color(legend.fTextColor), + column_width = Math.round(w/ncols), + padding_x = Math.round(0.03*w/ncols), + padding_y = Math.round(0.03*h), + step_y = (h - 2*padding_y)/nrows, + font_size = 0.9*step_y, + max_font_size = 0, // not limited in the beggining + ph = this.pad_height(), + fsize, any_opt = false, i = -1; + + if (legend.fTextSize && (ph*legend.fTextSize > 2) && (ph*legend.fTextSize < font_size)) + font_size = max_font_size = Math.round(ph*legend.fTextSize); + + this.StartTextDrawing(legend.fTextFont, font_size, this.draw_g, max_font_size); + + for (var ii = 0; ii < nlines; ++ii) { + var leg = legend.fPrimitives.arr[ii]; + + if (isEmpty(leg)) continue; // let discard empty entry + + if (ncols==1) ++i; else i = ii; + + var lopt = leg.fOption.toLowerCase(), + icol = i % ncols, irow = (i - icol) / ncols, + x0 = icol * column_width, + tpos_x = x0 + Math.round(legend.fMargin*column_width), + pos_y = Math.round(padding_y + irow*step_y), // top corner + mid_y = Math.round(padding_y + (irow+0.5)*step_y), // center line + o_fill = leg, o_marker = leg, o_line = leg, + mo = leg.fObject, + painter = null, isany = false; + + if ((mo !== null) && (typeof mo == 'object')) { + if ('fLineColor' in mo) o_line = mo; + if ('fFillColor' in mo) o_fill = mo; + if ('fMarkerColor' in mo) o_marker = mo; + + painter = this.FindPainterFor(mo); + } + + // Draw fill pattern (in a box) + if (lopt.indexOf('f') != -1) { + var fillatt = (painter && painter.fillatt) ? painter.fillatt : this.createAttFill(o_fill); + // box total height is yspace*0.7 + // define x,y as the center of the symbol for this entry + this.draw_g.append("svg:rect") + .attr("x", x0 + padding_x) + .attr("y", Math.round(pos_y+step_y*0.1)) + .attr("width", tpos_x - 2*padding_x - x0) + .attr("height", Math.round(step_y*0.8)) + .call(fillatt.func); + if (!fillatt.empty()) isany = true; + } + + // Draw line + if (lopt.indexOf('l') != -1) { + var lineatt = (painter && painter.lineatt) ? painter.lineatt : new JSROOT.TAttLineHandler(o_line); + this.draw_g.append("svg:line") + .attr("x1", x0 + padding_x) + .attr("y1", mid_y) + .attr("x2", tpos_x - padding_x) + .attr("y2", mid_y) + .call(lineatt.func); + if (lineatt.color !== 'none') isany = true; + } + + // Draw error + if (lopt.indexOf('e') != -1 && (lopt.indexOf('l') == -1 || lopt.indexOf('f') != -1)) { + } + + // Draw Polymarker + if (lopt.indexOf('p') != -1) { + var marker = (painter && painter.markeratt) ? painter.markeratt : new JSROOT.TAttMarkerHandler(o_marker); + this.draw_g + .append("svg:path") + .attr("d", marker.create((x0 + tpos_x)/2, mid_y)) + .call(marker.func); + if (marker.color !== 'none') isany = true; + } + + // special case - nothing draw, try to show rect with line attributes + if (!isany && painter && painter.lineatt && (painter.lineatt.color !== 'none')) + this.draw_g.append("svg:rect") + .attr("x", x0 + padding_x) + .attr("y", Math.round(pos_y+step_y*0.1)) + .attr("width", tpos_x - 2*padding_x - x0) + .attr("height", Math.round(step_y*0.8)) + .attr("fill", "none") + .call(painter.lineatt.func); + + var pos_x = tpos_x; + if (lopt.length>0) any_opt = true; + else if (!any_opt) pos_x = x0 + padding_x; + + if (leg.fLabel) + this.DrawText({ align: "start", x: pos_x, y: pos_y, width: x0+column_width-pos_x-padding_x, height: step_y, text: leg.fLabel, color: tcolor }); + } + + // rescale after all entries are shown + this.FinishTextDrawing(this.draw_g, this.FinishPave); + } + + TPavePainter.prototype.FillContextMenu = function(menu) { + var pave = this.GetObject(); + + menu.add("header: " + pave._typename + "::" + pave.fName); + if (this.IsStats()) { + menu.add("Default position", function() { + pave.fX2NDC = JSROOT.gStyle.fStatX; + pave.fX1NDC = pave.fX2NDC - JSROOT.gStyle.fStatW; + pave.fY2NDC = JSROOT.gStyle.fStatY; + pave.fY1NDC = pave.fY2NDC - JSROOT.gStyle.fStatH; + pave.fInit = 1; + this.Redraw(); + }); + + menu.add("SetStatFormat", function() { + var fmt = prompt("Enter StatFormat", pave.fStatFormat); + if (fmt!=null) { + pave.fStatFormat = fmt; + this.Redraw(); + } + }); + menu.add("SetFitFormat", function() { + var fmt = prompt("Enter FitFormat", pave.fFitFormat); + if (fmt!=null) { + pave.fFitFormat = fmt; + this.Redraw(); + } + }); + menu.add("separator"); + menu.add("sub:SetOptStat", function() { + // todo - use jqury dialog here + var fmt = prompt("Enter OptStat", pave.fOptStat); + if (fmt!=null) { pave.fOptStat = parseInt(fmt); this.Redraw(); } + }); + function AddStatOpt(pos, name) { + var opt = (pos<10) ? pave.fOptStat : pave.fOptFit; + opt = parseInt(parseInt(opt) / parseInt(Math.pow(10,pos % 10))) % 10; + menu.addchk(opt, name, opt * 100 + pos, function(arg) { + var newopt = (arg % 100 < 10) ? pave.fOptStat : pave.fOptFit; + var oldopt = parseInt(arg / 100); + newopt -= (oldopt>0 ? oldopt : -1) * parseInt(Math.pow(10, arg % 10)); + if (arg % 100 < 10) pave.fOptStat = newopt; + else pave.fOptFit = newopt; + this.Redraw(); + }); + } + + AddStatOpt(0, "Histogram name"); + AddStatOpt(1, "Entries"); + AddStatOpt(2, "Mean"); + AddStatOpt(3, "Std Dev"); + AddStatOpt(4, "Underflow"); + AddStatOpt(5, "Overflow"); + AddStatOpt(6, "Integral"); + AddStatOpt(7, "Skewness"); + AddStatOpt(8, "Kurtosis"); + menu.add("endsub:"); + + menu.add("sub:SetOptFit", function() { + // todo - use jqury dialog here + var fmt = prompt("Enter OptStat", pave.fOptFit); + if (fmt!=null) { pave.fOptFit = parseInt(fmt); this.Redraw(); } + }); + AddStatOpt(10, "Fit parameters"); + AddStatOpt(11, "Par errors"); + AddStatOpt(12, "Chi square / NDF"); + AddStatOpt(13, "Probability"); + menu.add("endsub:"); + + menu.add("separator"); + } else + if (pave.fName === "title") + menu.add("Default position", function() { + pave.fX1NDC = 0.28; + pave.fY1NDC = 0.94; + pave.fX2NDC = 0.72; + pave.fY2NDC = 0.99; + pave.fInit = 1; + this.Redraw(); + }); + + if (this.UseTextColor) + this.TextAttContextMenu(menu); + + this.FillAttContextMenu(menu); + + return menu.size() > 0; + } + + TPavePainter.prototype.ShowContextMenu = function(evnt) { + if (!evnt) { + d3.event.stopPropagation(); // disable main context menu + d3.event.preventDefault(); // disable browser context menu + + // one need to copy event, while after call back event may be changed + evnt = d3.event; + } + + JSROOT.Painter.createMenu(this, function(menu) { + menu.painter.FillContextMenu(menu); + menu.show(evnt); + }); // end menu creation + } + + TPavePainter.prototype.IsStats = function() { + return this.MatchObjectType('TPaveStats'); + } + + TPavePainter.prototype.ClearPave = function() { + this.GetObject().Clear(); + } + + TPavePainter.prototype.AddText = function(txt) { + this.GetObject().AddText(txt); + } + + TPavePainter.prototype.FillFunctionStat = function(f1, dofit) { + if (!dofit || !f1) return false; + + var print_fval = dofit % 10, + print_ferrors = Math.floor(dofit/10) % 10, + print_fchi2 = Math.floor(dofit/100) % 10, + print_fprob = Math.floor(dofit/1000) % 10; + + if (print_fchi2 > 0) + this.AddText("#chi^2 / ndf = " + this.Format(f1.fChisquare,"fit") + " / " + f1.fNDF); + if (print_fprob > 0) + this.AddText("Prob = " + (('Math' in JSROOT) ? this.Format(JSROOT.Math.Prob(f1.fChisquare, f1.fNDF)) : "<not avail>")); + if (print_fval > 0) + for(var n=0;n<f1.GetNumPars();++n) { + var parname = f1.GetParName(n), parvalue = f1.GetParValue(n), parerr = f1.GetParError(n); + + parvalue = (parvalue===undefined) ? "<not avail>" : this.Format(Number(parvalue),"fit"); + if (parerr !== undefined) { + parerr = this.Format(parerr,"last"); + if ((Number(parerr)===0) && (f1.GetParError(n) != 0)) parerr = this.Format(f1.GetParError(n),"4.2g"); + } + + if ((print_ferrors > 0) && parerr) + this.AddText(parname + " = " + parvalue + " #pm " + parerr); + else + this.AddText(parname + " = " + parvalue); + } + + return true; + } + + TPavePainter.prototype.FillStatistic = function() { + + var pp = this.pad_painter(); + if (pp && pp._fast_drawing) return false; + + var pave = this.GetObject(), + main = pave.$main_painter || this.main_painter(); + + if (pave.fName !== "stats") return false; + if (!main || (typeof main.FillStatistic !== 'function')) return false; + + var dostat = parseInt(pave.fOptStat), dofit = parseInt(pave.fOptFit); + if (isNaN(dostat)) dostat = JSROOT.gStyle.fOptStat; + if (isNaN(dofit)) dofit = JSROOT.gStyle.fOptFit; + + // we take statistic from main painter + if (!main.FillStatistic(this, dostat, dofit)) return false; + + // adjust the size of the stats box with the number of lines + var nlines = pave.fLines.arr.length, + stath = nlines * JSROOT.gStyle.StatFontSize; + if ((stath <= 0) || (JSROOT.gStyle.StatFont % 10 === 3)) { + stath = 0.25 * nlines * JSROOT.gStyle.StatH; + pave.fY1NDC = pave.fY2NDC - stath; + } + + return true; + } + + TPavePainter.prototype.UpdateObject = function(obj) { + if (!this.MatchObjectType(obj)) return false; + + var pave = this.GetObject(); + + if (!pave.modified_NDC) { + // if position was not modified interactively, update from source object + + if (this.stored && !obj.fInit && (this.stored.fX1 == obj.fX1) + && (this.stored.fX2 == obj.fX2) && (this.stored.fY1 == obj.fY1) && (this.stored.fY2 == obj.fY2)) { + // case when source object not initialized and original coordinates are not changed + // take over only modified NDC coordinate, used in tutorials/graphics/canvas.C + if (this.stored.fX1NDC != obj.fX1NDC) pave.fX1NDC = obj.fX1NDC; + if (this.stored.fX2NDC != obj.fX2NDC) pave.fX2NDC = obj.fX2NDC; + if (this.stored.fY1NDC != obj.fY1NDC) pave.fY1NDC = obj.fY1NDC; + if (this.stored.fY2NDC != obj.fY2NDC) pave.fY2NDC = obj.fY2NDC; + } else { + pave.fOption = obj.fOption; + pave.fInit = obj.fInit; + pave.fX1 = obj.fX1; pave.fX2 = obj.fX2; + pave.fY1 = obj.fY1; pave.fY2 = obj.fY2; + pave.fX1NDC = obj.fX1NDC; pave.fX2NDC = obj.fX2NDC; + pave.fY1NDC = obj.fY1NDC; pave.fY2NDC = obj.fY2NDC; + } + + this.stored = JSROOT.extend({}, obj); // store latest coordiantes + } + + switch (obj._typename) { + case 'TPaveText': + pave.fLines = JSROOT.clone(obj.fLines); + return true; + case 'TPavesText': + pave.fLines = JSROOT.clone(obj.fLines); + pave.fNpaves = obj.fNpaves; + return true; + case 'TPaveLabel': + pave.fLabel = obj.fLabel; + return true; + case 'TPaveStats': + pave.fOptStat = obj.fOptStat; + pave.fOptFit = obj.fOptFit; + return true; + case 'TLegend': + var oldprim = pave.fPrimitives; + pave.fPrimitives = obj.fPrimitives; + pave.fNColumns = obj.fNColumns; + if (oldprim && oldprim.arr && pave.fPrimitives && pave.fPrimitives.arr && (oldprim.arr.length == pave.fPrimitives.arr.length)) { + // try to sync object reference, new object does not displayed automatically + // in ideal case one should use snapids in the entries + for (var k=0;k<oldprim.arr.length;++k) { + var oldobj = oldprim.arr[k].fObject, newobj = pave.fPrimitives.arr[k].fObject; + + if (oldobj && newobj && oldobj._typename == newobj._typename && oldobj.fName == newobj.fName) + pave.fPrimitives.arr[k].fObject = oldobj; + } + } + return true; + } + + return false; + } + + TPavePainter.prototype.Redraw = function() { + // if pavetext artificially disabled, do not redraw it + + this.DrawPave(true); + } + + function drawPave(divid, pave, opt) { + // one could force drawing of PaveText on specific sub-pad + var painter = new JSROOT.TPavePainter(pave); + painter.SetDivId(divid, 2, ((typeof opt == 'string') && (opt.indexOf("onpad:")==0)) ? opt.substr(6) : undefined); + + if ((pave.fName === "title") && (pave._typename === "TPaveText")) { + var tpainter = painter.FindPainterFor(null, "title"); + if (tpainter && (tpainter !== painter)) tpainter.DeleteThis(); + } + + switch (pave._typename) { + case "TPaveLabel": + painter.PaveDrawFunc = painter.DrawPaveLabel; + break; + case "TPaveStats": + painter.PaveDrawFunc = painter.DrawPaveStats; + painter.$secondary = true; // indicates that painter created from others + break; + case "TPaveText": + case "TPavesText": + case "TDiamond": + painter.PaveDrawFunc = painter.DrawPaveText; + break; + case "TLegend": + painter.PaveDrawFunc = painter.DrawPaveLegend; + break; + } + + painter.Redraw(); + + // drawing ready handled in special painters, if not exists - drawing is done + return painter.PaveDrawFunc ? painter : painter.DrawingReady(); + } + + function drawPaletteAxis(divid, palette, opt) { + + // disable draw of shadow element of TPave + palette.fBorderSize = 1; + palette.fShadowColor = 0; + + var painter = new JSROOT.TPavePainter(palette); + + painter.SetDivId(divid); + + painter.z_handle = new JSROOT.TAxisPainter(palette.fAxis, true); + painter.z_handle.SetDivId(divid, -1); + + painter.Cleanup = function() { + if (this.z_handle) { + this.z_handle.Cleanup(); + delete this.z_handle; + } + + JSROOT.TObjectPainter.prototype.Cleanup.call(this); + } + + painter.PaveDrawFunc = function(s_width, s_height, arg) { + + var pthis = this, + palette = this.GetObject(), + axis = palette.fAxis, + can_move = (typeof arg == 'string') && (arg.indexOf('canmove')>0), + postpone_draw = (typeof arg == 'string') && (arg.indexOf('postpone')>0), + nbr1 = axis.fNdiv % 100, + pos_x = parseInt(this.draw_g.attr("x")), // pave position + pos_y = parseInt(this.draw_g.attr("y")), + width = this.pad_width(), + height = this.pad_height(), + axisOffset = axis.fLabelOffset * width, + main = this.main_painter(), + framep = this.frame_painter(), + zmin = 0, zmax = 100, + contour = main.fContour; + + if (nbr1<=0) nbr1 = 8; + axis.fTickSize = 0.6 * s_width / width; // adjust axis ticks size + + if (contour && framep) { + zmin = Math.min(contour[0], framep.zmin); + zmax = Math.max(contour[contour.length-1], framep.zmax); + } else + if ((main.gmaxbin!==undefined) && (main.gminbin!==undefined)) { + // this is case of TH2 (needs only for size adjustment) + zmin = main.gminbin; zmax = main.gmaxbin; + } else + if ((main.hmin!==undefined) && (main.hmax!==undefined)) { + // this is case of TH1 + zmin = main.hmin; zmax = main.hmax; + } + + var z = null, z_kind = "normal"; + + if (this.root_pad().fLogz) { + z = d3.scaleLog(); + z_kind = "log"; + } else { + z = d3.scaleLinear(); + } + z.domain([zmin, zmax]).range([s_height,0]); + + this.draw_g.selectAll("rect").style("fill", 'white'); + + if (!contour || postpone_draw) + // we need such rect to correctly calculate size + this.draw_g.append("svg:rect") + .attr("x", 0) + .attr("y", 0) + .attr("width", s_width) + .attr("height", s_height) + .style("fill", 'white'); + else + for (var i=0;i<contour.length-1;++i) { + var z0 = z(contour[i]), + z1 = z(contour[i+1]), + col = main.getContourColor((contour[i]+contour[i+1])/2); + + var r = this.draw_g.append("svg:rect") + .attr("x", 0) + .attr("y", Math.round(z1)) + .attr("width", s_width) + .attr("height", Math.round(z0) - Math.round(z1)) + .style("fill", col) + .style("stroke", col) + .property("fill0", col) + .property("fill1", d3.rgb(col).darker(0.5).toString()) + + if (this.IsTooltipAllowed()) + r.on('mouseover', function() { + d3.select(this).transition().duration(100).style("fill", d3.select(this).property('fill1')); + }).on('mouseout', function() { + d3.select(this).transition().duration(100).style("fill", d3.select(this).property('fill0')); + }).append("svg:title").text(contour[i].toFixed(2) + " - " + contour[i+1].toFixed(2)); + + if (JSROOT.gStyle.Zooming) + r.on("dblclick", function() { pthis.frame_painter().Unzoom("z"); }); + } + + + this.z_handle.SetAxisConfig("zaxis", z_kind, z, zmin, zmax, zmin, zmax); + + this.z_handle.max_tick_size = Math.round(s_width*0.7); + + this.z_handle.DrawAxis(true, this.draw_g, s_width, s_height, "translate(" + s_width + ", 0)"); + + if (can_move && ('getBoundingClientRect' in this.draw_g.node())) { + var rect = this.draw_g.node().getBoundingClientRect(); + + var shift = (pos_x + parseInt(rect.width)) - Math.round(0.995*width) + 3; + + if (shift>0) { + this.draw_g.attr("x", pos_x - shift).attr("y", pos_y) + .attr("transform", "translate(" + (pos_x-shift) + ", " + pos_y + ")"); + palette.fX1NDC -= shift/width; + palette.fX2NDC -= shift/width; + } + } + + if (!JSROOT.gStyle.Zooming) return; + + var evnt = null, doing_zoom = false, sel1 = 0, sel2 = 0, zoom_rect = null; + + function moveRectSel() { + + if (!doing_zoom) return; + + d3.event.preventDefault(); + var m = d3.mouse(evnt); + + if (m[1] < sel1) sel1 = m[1]; else sel2 = m[1]; + + zoom_rect.attr("y", sel1) + .attr("height", Math.abs(sel2-sel1)); + } + + function endRectSel() { + if (!doing_zoom) return; + + d3.event.preventDefault(); + d3.select(window).on("mousemove.colzoomRect", null) + .on("mouseup.colzoomRect", null); + zoom_rect.remove(); + zoom_rect = null; + doing_zoom = false; + + var zmin = Math.min(z.invert(sel1), z.invert(sel2)), + zmax = Math.max(z.invert(sel1), z.invert(sel2)); + + pthis.frame_painter().Zoom("z", zmin, zmax); + } + + function startRectSel() { + // ignore when touch selection is activated + if (doing_zoom) return; + doing_zoom = true; + + d3.event.preventDefault(); + + evnt = this; + var origin = d3.mouse(evnt); + + sel1 = sel2 = origin[1]; + + zoom_rect = pthis.draw_g + .append("svg:rect") + .attr("class", "zoom") + .attr("id", "colzoomRect") + .attr("x", "0") + .attr("width", s_width) + .attr("y", sel1) + .attr("height", 5); + + d3.select(window).on("mousemove.colzoomRect", moveRectSel) + .on("mouseup.colzoomRect", endRectSel, true); + + d3.event.stopPropagation(); + } + + this.draw_g.select(".axis_zoom") + .on("mousedown", startRectSel) + .on("dblclick", function() { pthis.frame_painter().Unzoom("z"); }); + } + + painter.ShowContextMenu = function(evnt) { + this.frame_painter().ShowContextMenu("z", evnt, this.GetObject().fAxis); + } + + painter.UseContextMenu = true; + + painter.DrawPave(opt); + + return painter.DrawingReady(); + } + + /** @summary Produce and draw TLegend object for the specified divid + * @desc Should be called when all other objects are painted + * Invoked when item "$legend" specified in JSROOT URL string + * @private */ + function produceLegend(divid, opt) { + var main_painter = JSROOT.GetMainPainter(divid); + if (!main_painter) return; + + var pp = main_painter.pad_painter(), + pad = main_painter.root_pad(); + if (!pp || !pad) return; + + var leg = JSROOT.Create("TLegend"); + + for (var k=0;k<pp.painters.length;++k) { + var painter = pp.painters[k], + obj = painter.GetObject(); + + if (!obj) continue; + + var entry = JSROOT.Create("TLegendEntry"); + entry.fObject = obj; + entry.fLabel = (opt == "all") ? obj.fName : painter.GetItemName(); + entry.fOption = ""; + if (!entry.fLabel) continue; + + if (painter.lineatt && painter.lineatt.used) entry.fOption+="l"; + if (painter.fillatt && painter.fillatt.used) entry.fOption+="f"; + if (painter.markeratt && painter.markeratt.used) entry.fOption+="m"; + if (!entry.fOption) entry.fOption = "l"; + + leg.fPrimitives.Add(entry); + } + + // no entries - no need to draw legend + var szx = 0.4, szy = leg.fPrimitives.arr.length; + if (!szy) return; + if (szy>8) szy = 8; + szy *= 0.1; + + JSROOT.extend(leg, { + fX1NDC: szx*pad.fLeftMargin + (1-szx)*(1-pad.fRightMargin), + fY1NDC: (1-szy)*(1-pad.fTopMargin) + szy*pad.fBottomMargin, + fX2NDC: 0.99-pad.fRightMargin, + fY2NDC: 0.99-pad.fTopMargin + }); + leg.fFillStyle = 1001; + + return drawPave(divid, leg); + } + + // ============================================================================== + + function THistDrawOptions(opt) { + this.Reset(); + } + + THistDrawOptions.prototype.Reset = function() { + JSROOT.extend(this, + { Axis: 0, RevX: false, RevY: false, Bar: false, BarStyle: 0, Curve: false, + Hist: true, Line: false, Fill: false, + Error: false, ErrorKind: -1, errorX: JSROOT.gStyle.fErrorX, + Mark: false, Same: false, Scat: false, ScatCoef: 1., Func: true, + Arrow: false, Box: false, BoxStyle: 0, + Text: false, TextAngle: 0, TextKind: "", Char: 0, Color: false, Contour: 0, + Lego: 0, Surf: 0, Off: 0, Tri: 0, Proj: 0, AxisPos: 0, + Spec: false, Pie: false, List: false, Zscale: false, Candle: "", + GLBox: 0, GLColor: false, Project: "", + System: JSROOT.Painter.Coord.kCARTESIAN, + AutoColor: false, NoStat: false, ForceStat: false, AutoZoom: false, + HighRes: 0, Zero: true, Palette: 0, BaseLine: false, + Optimize: JSROOT.gStyle.OptimizeDraw, Mode3D: false, + FrontBox: true, BackBox: true, + _pmc: false, _plc: false, _pfc: false, need_fillcol: false, + minimum: -1111, maximum: -1111 }); + } + + THistDrawOptions.prototype.Decode = function(opt, hdim, histo, pad, painter) { + this.orginal = opt; + + var d = new JSROOT.DrawOptions(opt), check3dbox = ""; + + if ((hdim===1) && (histo.fSumw2.length > 0)) + for (var n=0;n<histo.fSumw2.length;++n) + if (histo.fSumw2[n] > 0) { this.Error = true; this.Hist = false; this.Zero = false; break; } + + this.ndim = hdim || 1; // keep dimensions, used for now in GED + + if (d.check('PAL', true)) this.Palette = d.partAsInt(); + if (d.check('MINIMUM:', true)) this.minimum = parseFloat(d.part); else this.minimum = histo.fMinimum; + if (d.check('MAXIMUM:', true)) this.maximum = parseFloat(d.part); else this.maximum = histo.fMaximum; + + if (d.check('NOOPTIMIZE')) this.Optimize = 0; + if (d.check('OPTIMIZE')) this.Optimize = 2; + + if (d.check('AUTOCOL')) this.AutoColor = true; + if (d.check('AUTOZOOM')) this.AutoZoom = true; + + if (d.check('OPTSTAT',true)) this.optstat = d.partAsInt(); + if (d.check('OPTFIT',true)) this.optfit = d.partAsInt(); + + if (d.check('NOSTAT')) this.NoStat = true; + if (d.check('STAT')) this.ForceStat = true; + + if (d.check('NOTOOLTIP') && painter) painter.SetTooltipAllowed(false); + if (d.check('TOOLTIP') && painter) painter.SetTooltipAllowed(true); + + if (d.check('LOGX') && pad) { pad.fLogx = 1; pad.fUxmin = 0; pad.fUxmax = 1; pad.fX1 = 0; pad.fX2 = 1; } + if (d.check('LOGY') && pad) { pad.fLogy = 1; pad.fUymin = 0; pad.fUymax = 1; pad.fY1 = 0; pad.fY2 = 1; } + if (d.check('LOGZ') && pad) pad.fLogz = 1; + if (d.check('GRIDXY') && pad) pad.fGridx = pad.fGridy = 1; + if (d.check('GRIDX') && pad) pad.fGridx = 1; + if (d.check('GRIDY') && pad) pad.fGridy = 1; + if (d.check('TICKXY') && pad) pad.fTickx = pad.fTicky = 1; + if (d.check('TICKX') && pad) pad.fTickx = 1; + if (d.check('TICKY') && pad) pad.fTicky = 1; + + if (d.check('FILL_', true)) { + if (d.partAsInt(1)>0) this.histoFillColor = d.partAsInt(); else + for (var col=0;col<8;++col) + if (JSROOT.Painter.root_colors[col].toUpperCase() === d.part) this.histoFillColor = col; + } + if (d.check('LINE_', true)) { + if (d.partAsInt(1)>0) this.histoLineColor = JSROOT.Painter.root_colors[d.partAsInt()]; else + for (var col=0;col<8;++col) + if (JSROOT.Painter.root_colors[col].toUpperCase() === d.part) this.histoLineColor = d.part; + } + + if (d.check('X+')) this.AxisPos = 10; + if (d.check('Y+')) this.AxisPos += 1; + + if (d.check('SAMES')) { this.Same = true; this.ForceStat = true; } + if (d.check('SAME')) { this.Same = true; this.Func = true; } + + if (d.check('SPEC')) this.Spec = true; // not used + + if (d.check('BASE0') || d.check('MIN0')) this.BaseLine = 0; else + if (JSROOT.gStyle.fHistMinimumZero) this.BaseLine = 0; + + if (d.check('PIE')) this.Pie = true; // not used + + if (d.check('CANDLE', true)) this.Candle = d.part; + + if (d.check('GLBOX',true)) this.GLBox = 10 + d.partAsInt(); + if (d.check('GLCOL')) this.GLColor = true; + + d.check('GL'); // suppress GL + + if (d.check('LEGO', true)) { + this.Lego = 1; + if (d.part.indexOf('0') >= 0) this.Zero = false; + if (d.part.indexOf('1') >= 0) this.Lego = 11; + if (d.part.indexOf('2') >= 0) this.Lego = 12; + if (d.part.indexOf('3') >= 0) this.Lego = 13; + if (d.part.indexOf('4') >= 0) this.Lego = 14; + check3dbox = d.part; + if (d.part.indexOf('Z') >= 0) this.Zscale = true; + } + + if (d.check('SURF', true)) { + this.Surf = d.partAsInt(10, 1); + check3dbox = d.part; + if (d.part.indexOf('Z')>=0) this.Zscale = true; + } + + if (d.check('TF3', true)) check3dbox = d.part; + + if (d.check('ISO', true)) check3dbox = d.part; + + if (d.check('LIST')) this.List = true; // not used + + if (d.check('CONT', true) && (hdim>1)) { + this.Contour = 1; + if (d.part.indexOf('Z') >= 0) this.Zscale = true; + if (d.part.indexOf('1') >= 0) this.Contour = 11; else + if (d.part.indexOf('2') >= 0) this.Contour = 12; else + if (d.part.indexOf('3') >= 0) this.Contour = 13; else + if (d.part.indexOf('4') >= 0) this.Contour = 14; + } + + // decode bar/hbar option + if (d.check('HBAR', true)) this.BarStyle = 20; else + if (d.check('BAR', true)) this.BarStyle = 10; + if (this.BarStyle > 0) { + this.Hist = false; + this.need_fillcol = true; + this.BarStyle += d.partAsInt(); + } + + if (d.check('ARR')) + this.Arrow = true; + + if (d.check('BOX',true)) + this.BoxStyle = 10 + d.partAsInt(); + + this.Box = this.BoxStyle > 0; + + if (d.check('COL')) this.Color = true; + if (d.check('CHAR')) this.Char = 1; + if (d.check('FUNC')) { this.Func = true; this.Hist = false; } + if (d.check('AXIS')) this.Axis = 1; + if (d.check('AXIG')) this.Axis = 2; + + if (d.check('TEXT', true)) { + this.Text = true; + this.Hist = false; + this.TextAngle = Math.min(d.partAsInt(), 90); + if (d.part.indexOf('N')>=0) this.TextKind = "N"; + if (d.part.indexOf('E')>=0) this.TextKind = "E"; + } + + if (d.check('SCAT=', true)) { + this.Scat = true; + this.ScatCoef = parseFloat(d.part); + if (isNaN(this.ScatCoef) || (this.ScatCoef<=0)) this.ScatCoef = 1.; + } + + if (d.check('SCAT')) this.Scat = true; + if (d.check('POL')) this.System = JSROOT.Painter.Coord.kPOLAR; + if (d.check('CYL')) this.System = JSROOT.Painter.Coord.kCYLINDRICAL; + if (d.check('SPH')) this.System = JSROOT.Painter.Coord.kSPHERICAL; + if (d.check('PSR')) this.System = JSROOT.Painter.Coord.kRAPIDITY; + + if (d.check('TRI', true)) { + this.Color = false; + this.Tri = 1; + check3dbox = d.part; + if (d.part.indexOf('ERR') >= 0) this.Error = true; + } + + if (d.check('AITOFF')) this.Proj = 1; + if (d.check('MERCATOR')) this.Proj = 2; + if (d.check('SINUSOIDAL')) this.Proj = 3; + if (d.check('PARABOLIC')) this.Proj = 4; + if (this.Proj > 0) this.Contour = 14; + + if (d.check('PROJX',true)) this.Project = "X" + d.partAsInt(0,1); + if (d.check('PROJY',true)) this.Project = "Y" + d.partAsInt(0,1); + + if (check3dbox) { + if (check3dbox.indexOf('FB') >= 0) this.FrontBox = false; + if (check3dbox.indexOf('BB') >= 0) this.BackBox = false; + } + + if ((hdim==3) && d.check('FB')) this.FrontBox = false; + if ((hdim==3) && d.check('BB')) this.BackBox = false; + + this._pfc = d.check("PFC"); + this._plc = d.check("PLC") || this.AutoColor; + this._pmc = d.check("PMC"); + + if (d.check('L')) { this.Line = true; this.Hist = false; this.Error = false; } + if (d.check('F')) { this.Fill = true; this.need_fillcol = true; } + + if (d.check('A')) this.Axis = -1; + if (this.Axis && d.check("RX")) this.RevX = true; + if (this.Axis && d.check("RY")) this.RevY = true; + + if (d.check('B1')) { this.BarStyle = 1; this.BaseLine = 0; this.Hist = false; this.need_fillcol = true; } + if (d.check('B')) { this.BarStyle = 1; this.Hist = false; this.need_fillcol = true; } + if (d.check('C')) { this.Curve = true; this.Hist = false; } + if (d.check('][')) { this.Off = 1; this.Hist = true; } + + if (d.check('HIST')) { this.Hist = true; this.Func = true; this.Error = false; } + + this.Bar = (this.BarStyle > 0); + + delete this.MarkStyle; // remove mark style if any + + if (d.check('P0')) { this.Mark = true; this.Hist = false; this.Zero = true; } + if (d.check('P')) { this.Mark = true; this.Hist = false; this.Zero = false; } + if (d.check('Z')) this.Zscale = true; + if (d.check('*')) { this.Mark = true; this.MarkStyle = 3; this.Hist = false; } + if (d.check('H')) this.Hist = true; + + if (d.check('E', true)) { + this.Error = true; + if (hdim == 1) { + this.Zero = false; // do not draw empty bins with erros + this.Hist = false; + if (!isNaN(parseInt(d.part[0]))) this.ErrorKind = parseInt(d.part[0]); + if ((this.ErrorKind === 3) || (this.ErrorKind === 4)) this.need_fillcol = true; + if (this.ErrorKind === 0) this.Zero = true; // enable drawing of empty bins + if (d.part.indexOf('X0')>=0) this.errorX = 0; + } + } + if (d.check('9')) this.HighRes = 1; + if (d.check('0')) this.Zero = false; + if (this.Color && d.check('1')) this.Zero = false; + + // flag identifies 3D drawing mode for histogram + if ((this.Lego > 0) || (hdim == 3) || + ((this.Surf > 0) || this.Error && (hdim == 2))) this.Mode3D = true; + + //if (this.Surf == 15) + // if (this.System == JSROOT.Painter.Coord.kPOLAR || this.System == JSROOT.Painter.Coord.kCARTESIAN) + // this.Surf = 13; + } + + // function should approx reconstruct draw options + THistDrawOptions.prototype.asString = function(painter) { + var fp = painter ? painter.frame_painter() : null; + + var res = ""; + if (this.Mode3D) { + + if (this.Lego) { + res = "LEGO"; + if (!this.Zero) res += "0"; + if (this.Lego > 10) res += (this.Lego-10); + if (this.Zscale) res+="Z"; + } else if (this.Surf) { + res = "SURF" + (this.Surf-10); + if (this.Zscale) res+="Z"; + } + if (!this.FrontBox) res+="FB"; + if (!this.BackBox) res+="BB"; + + } else { + if (this.Scat) { + res = "SCAT"; + } else if (this.Color) { + res = "COL"; + if (!this.Zero) res+="0"; + if (this.Zscale) res+="Z"; + if (this.Axis < 0) res+="A"; + } else if (this.Contour) { + res = "CONT"; + if (this.Contour > 10) res += (this.Contour-10); + if (this.Zscale) res+="Z"; + } else if (this.Bar) { + res = (this.BaseLine === false) ? "B" : "B1"; + } else if (this.Mark) { + res = this.Zero ? "P0" : "P"; // here invert logic with 0 + } else if (this.Scat) { + res = "SCAT"; + } else if (this.Error) { + res = "E"; + if (this.ErrorKind>=0) res += this.ErrorKind; + } else if (this.Line) { + res += "L"; + if (this.Fill) res += "F"; + } + + if (this.Text) { + res += "TEXT"; + if (this.TextAngle) res += this.TextAngle; + res += this.TextKind; + } + + } + return res; + } + + // ============================================================================== + + + /** + * @summary Basic painter for histogram classes + * + * @constructor + * @memberof JSROOT + * @augments JSROOT.TObjectPainter + * @param {object} histo - histogram object + */ + + function THistPainter(histo) { + JSROOT.TObjectPainter.call(this, histo); + this.histo = histo; + this.draw_content = true; + this.nbinsx = 0; + this.nbinsy = 0; + this.accept_drops = true; // indicate that one can drop other objects like doing Draw("same") + this.mode3d = false; + this.DecomposeTitle(); + } + + THistPainter.prototype = Object.create(JSROOT.TObjectPainter.prototype); + + THistPainter.prototype.GetHisto = function() { + return this.GetObject(); + } + + THistPainter.prototype.GetAxis = function(name) { + var histo = this.GetObject(); + if (histo) + switch(name) { + case "x": return histo.fXaxis; + case "y": return histo.fYaxis; + case "z": return histo.fZaxis; + } + return null; + } + + THistPainter.prototype.IsTProfile = function() { + return this.MatchObjectType('TProfile'); + } + + THistPainter.prototype.IsTH1K = function() { + return this.MatchObjectType('TH1K'); + } + + THistPainter.prototype.IsTH2Poly = function() { + return this.MatchObjectType(/^TH2Poly/) || this.MatchObjectType(/^TProfile2Poly/); + } + + THistPainter.prototype.Clear3DScene = function() { + var fp = this.frame_painter(); + if (fp && typeof fp.Create3DScene === 'function') + fp.Create3DScene(-1); + this.mode3d = false; + } + + THistPainter.prototype.Cleanup = function() { + + // clear all 3D buffers + this.Clear3DScene(); + + this.histo = null; // cleanup histogram reference + + delete this.fPalette; + delete this.fContour; + delete this.options; + + JSROOT.TObjectPainter.prototype.Cleanup.call(this); + } + + THistPainter.prototype.Dimension = function() { + var histo = this.GetHisto(); + if (!histo) return 0; + if (histo._typename.match(/^TH2/)) return 2; + if (histo._typename.match(/^TProfile2D/)) return 2; + if (histo._typename.match(/^TH3/)) return 3; + return 1; + } + + THistPainter.prototype.DecodeOptions = function(opt) { + /* decode string 'opt' and fill the option structure */ + var histo = this.GetHisto(), + hdim = this.Dimension(), + pad = this.root_pad(); + + if (!this.options) + this.options = new THistDrawOptions; + else + this.options.Reset(); + + this.options.Decode(opt || histo.fOption, hdim, histo, pad, this); + + this.OptionsStore(opt); // opt will be return as default draw option, used in webcanvas + } + + THistPainter.prototype.CopyOptionsFrom = function(src) { + if (src === this) return; + var o = this.options, o0 = src.options; + + o.Mode3D = o0.Mode3D; + o.Zero = o0.Zero; + if (o0.Mode3D) { + o.Lego = o0.Lego; + o.Surf = o0.Surf; + } else { + o.Color = o0.Color; + o.Contour = o0.Contour; + } + } + + /// copy draw options to all other histograms in the pad + THistPainter.prototype.CopyOptionsToOthers = function() { + var pthis = this; + + this.ForEachPainter(function(painter) { + if (painter === pthis) return; + if (typeof painter.CopyOptionsFrom == 'function') + painter.CopyOptionsFrom(pthis); + }, "objects"); + } + + THistPainter.prototype.ScanContent = function(when_axis_changed) { + // function will be called once new histogram or + // new histogram content is assigned + // one should find min,max,nbins, maxcontent values + // if when_axis_changed === true specified, content will be scanned after axis zoom changed + + alert("HistPainter.prototype.ScanContent not implemented"); + } + + THistPainter.prototype.CheckPadRange = function(use_pad) { + + // actual work will be done when frame will draw axes + if (this.is_main_painter()) + this.check_pad_range = use_pad ? "pad_range" : true; + } + + THistPainter.prototype.CheckHistDrawAttributes = function() { + + var histo = this.GetHisto(), + pp = this.pad_painter(); + + if (pp && (this.options._pfc || this.options._plc || this.options._pmc)) { + var icolor = pp.CreateAutoColor(); + if (this.options._pfc) { histo.fFillColor = icolor; delete this.fillatt; } + if (this.options._plc) { histo.fLineColor = icolor; delete this.lineatt; } + if (this.options._pmc) { histo.fMarkerColor = icolor; delete this.markeratt; } + this.options._pfc = this.options._plc = this.options._pmc = false; + } + + this.createAttFill({ attr: histo, color: this.options.histoFillColor, kind: 1 }); + + this.createAttLine({ attr: histo, color0: this.options.histoLineColor }); + } + + THistPainter.prototype.UpdateObject = function(obj, opt) { + + var histo = this.GetHisto(), + fp = this.frame_painter(); + + if (obj !== histo) { + + if (!this.MatchObjectType(obj)) return false; + + // TODO: simple replace of object does not help - one can have different + // complex relations between histo and stat box, histo and colz axis, + // one could have THStack or TMultiGraph object + // The only that could be done is update of content + + // this.histo = obj; + + // check only stats bit, later other settings can be monitored + if (histo.TestBit(JSROOT.TH1StatusBits.kNoStats) != obj.TestBit(JSROOT.TH1StatusBits.kNoStats)) { + histo.fBits = obj.fBits; + + var statpainter = this.FindPainterFor(this.FindStat()); + if (statpainter) statpainter.Enabled = !histo.TestBit(JSROOT.TH1StatusBits.kNoStats); + } + + // if (histo.TestBit(JSROOT.TH1StatusBits.kNoStats)) this.ToggleStat(); + + // special tratement for webcanvas - also name can be changed + if (this.snapid !== undefined) + histo.fName = obj.fName; + + histo.fFillColor = obj.fFillColor; + histo.fFillStyle = obj.fFillStyle; + histo.fLineColor = obj.fLineColor; + histo.fLineStyle = obj.fLineStyle; + histo.fLineWidth = obj.fLineWidth; + + histo.fEntries = obj.fEntries; + histo.fTsumw = obj.fTsumw; + histo.fTsumwx = obj.fTsumwx; + histo.fTsumwx2 = obj.fTsumwx2; + histo.fXaxis.fNbins = obj.fXaxis.fNbins; + if (this.Dimension() > 1) { + histo.fTsumwy = obj.fTsumwy; + histo.fTsumwy2 = obj.fTsumwy2; + histo.fTsumwxy = obj.fTsumwxy; + histo.fYaxis.fNbins = obj.fYaxis.fNbins; + if (this.Dimension() > 2) { + histo.fTsumwz = obj.fTsumwz; + histo.fTsumwz2 = obj.fTsumwz2; + histo.fTsumwxz = obj.fTsumwxz; + histo.fTsumwyz = obj.fTsumwyz; + histo.fZaxis.fNbins = obj.fZaxis.fNbins; + } + } + histo.fArray = obj.fArray; + histo.fNcells = obj.fNcells; + histo.fTitle = obj.fTitle; + histo.fMinimum = obj.fMinimum; + histo.fMaximum = obj.fMaximum; + function CopyAxis(tgt,src) { + tgt.fTitle = src.fTitle; + tgt.fLabels = src.fLabels; + tgt.fXmin = src.fXmin; + tgt.fXmax = src.fXmax; + tgt.fTimeDisplay = src.fTimeDisplay; + tgt.fTimeFormat = src.fTimeFormat; + // copy attributes + tgt.fAxisColor = src.fAxisColor; + tgt.fLabelColor = src.fLabelColor; + tgt.fLabelFont = src.fLabelFont; + tgt.fLabelOffset = src.fLabelOffset; + tgt.fLabelSize = src.fLabelSize; + tgt.fNdivisions = src.fNdivisions; + tgt.fTickLength = src.fTickLength; + tgt.fTitleColor = src.fTitleColor; + tgt.fTitleFont = src.fTitleFont; + tgt.fTitleOffset = src.fTitleOffset; + tgt.fTitleSize = src.fTitleSize; + } + CopyAxis(histo.fXaxis, obj.fXaxis); + CopyAxis(histo.fYaxis, obj.fYaxis); + CopyAxis(histo.fZaxis, obj.fZaxis); + if (!fp.zoom_changed_interactive) { + function CopyZoom(tgt,src) { + tgt.fFirst = src.fFirst; + tgt.fLast = src.fLast; + tgt.fBits = src.fBits; + } + CopyZoom(histo.fXaxis, obj.fXaxis); + CopyZoom(histo.fYaxis, obj.fYaxis); + CopyZoom(histo.fZaxis, obj.fZaxis); + } + histo.fSumw2 = obj.fSumw2; + + if (this.IsTProfile()) { + histo.fBinEntries = obj.fBinEntries; + } + if (this.IsTH1K()) { + histo.fNIn = obj.fNIn; + histo.fReady = false; + } + + this.DecomposeTitle(); + + if (obj.fFunctions && this.options.Func) { + for (var n=0;n<obj.fFunctions.arr.length;++n) { + var func = obj.fFunctions.arr[n]; + if (!func || !func._typename) continue; + var funcpainter = func.fName ? this.FindPainterFor(null, func.fName, func._typename) : null; + if (funcpainter) { + funcpainter.UpdateObject(func); + } else if ((func._typename != 'TPaletteAxis') && (func._typename != 'TPaveStats')) { + console.log('Get ' + func._typename + ' in histogram functions list, need to use?'); + // histo.fFunctions.Add(func,""); + } + } + } + + var changed_opt = (histo.fOption != obj.fOption); + histo.fOption = obj.fOption; + + if (((opt !== undefined) && (this.options.original !== opt)) || changed_opt) + this.DecodeOptions(opt || histo.fOption); + } + + // if (!fp.zoom_changed_interactive) this.CheckPadRange(); + + this.ScanContent(); + + this.histogram_updated = true; // indicate that object updated + + return true; + } + + THistPainter.prototype.CreateAxisFuncs = function(with_y_axis, with_z_axis) { + // here functions are defined to convert index to axis value and back + // introduced to support non-equidistant bins + + var histo = this.GetHisto(); + + function AssignFuncs(axis) { + if (axis.fXbins.length >= axis.fNbins) { + axis.regular = false; + axis.GetBinCoord = function(bin) { + var indx = Math.round(bin); + if (indx <= 0) return this.fXmin; + if (indx > this.fNbins) return this.fXmax; + if (indx==bin) return this.fXbins[indx]; + var indx2 = (bin < indx) ? indx - 1 : indx + 1; + return this.fXbins[indx] * Math.abs(bin-indx2) + this.fXbins[indx2] * Math.abs(bin-indx); + }; + axis.FindBin = function(x,add) { + for (var k = 1; k < this.fXbins.length; ++k) + if (x < this.fXbins[k]) return Math.floor(k-1+add); + return this.fNbins; + }; + } else { + axis.regular = true; + axis.binwidth = (axis.fXmax - axis.fXmin) / (axis.fNbins || 1); + axis.GetBinCoord = function(bin) { return this.fXmin + bin*this.binwidth; }; + axis.FindBin = function(x,add) { return Math.floor((x - this.fXmin) / this.binwidth + add); }; + } + } + + this.xmin = histo.fXaxis.fXmin; + this.xmax = histo.fXaxis.fXmax; + AssignFuncs(histo.fXaxis); + + this.ymin = histo.fYaxis.fXmin; + this.ymax = histo.fYaxis.fXmax; + + if (!with_y_axis || (this.nbinsy==0)) return; + + AssignFuncs(histo.fYaxis); + + if (!with_z_axis || (this.nbinsz==0)) return; + + AssignFuncs(histo.fZaxis); + } + + THistPainter.prototype.CreateXY = function() { + // Create x,y objects which maps user coordinates into pixels + // Now moved into TFramePainter + + if (!this.is_main_painter()) return; + + var histo = this.GetHisto(), + fp = this.frame_painter(); + + if (!fp) + return console.warn("histogram drawn without frame - not supported"); + + // artifically add y range to display axes + if (this.ymin === this.ymax) this.ymax += 1; + + fp.SetAxesRanges(histo.fXaxis, this.xmin, this.xmax, histo.fYaxis, this.ymin, this.ymax, histo.fZaxis, 0, 0); + fp.CreateXY({ ndim: this.Dimension(), + check_pad_range: this.check_pad_range, + create_canvas: this.create_canvas, + zoom_ymin: this.zoom_ymin, + zoom_ymax: this.zoom_ymax, + ymin_nz: this.ymin_nz, + swap_xy: (this.options.BarStyle >= 20), + reverse_x: this.options.RevX, + reverse_y: this.options.RevY, + Proj: this.options.Proj, + extra_y_space: this.options.Text && (this.options.BarStyle > 0) }); + delete this.check_pad_range; + } + + THistPainter.prototype.DrawBins = function() { + alert("HistPainter.DrawBins not implemented"); + } + + THistPainter.prototype.DrawAxes = function() { + // axes can be drawn only for main histogram + + if (!this.is_main_painter() || this.options.Same) return; + + var fp = this.frame_painter(); + if (!fp) return; + + fp.DrawAxes(false, this.options.Axis < 0, this.options.AxisPos, this.options.Zscale); + fp.DrawGrids(); + } + + THistPainter.prototype.ToggleTitle = function(arg) { + var histo = this.GetHisto(); + if (!this.is_main_painter() || !histo) return false; + if (arg==='only-check') return !histo.TestBit(JSROOT.TH1StatusBits.kNoTitle); + histo.InvertBit(JSROOT.TH1StatusBits.kNoTitle); + this.DrawTitle(); + } + + THistPainter.prototype.DecomposeTitle = function() { + // if histogram title includes ;, set axis title + + var histo = this.GetHisto(); + + if (!histo || !histo.fTitle) return; + + var arr = histo.fTitle.split(';'); + if (arr.length===3) { + histo.fTitle = arr[0]; + histo.fXaxis.fTitle = arr[1]; + histo.fYaxis.fTitle = arr[2]; + } + } + + THistPainter.prototype.DrawTitle = function() { + + // case when histogram drawn over other histogram (same option) + if (!this.is_main_painter() || this.options.Same) return; + + var histo = this.GetHisto(), st = JSROOT.gStyle, + tpainter = this.FindPainterFor(null, "title"), + pt = tpainter ? tpainter.GetObject() : null; + + if (!pt) pt = this.FindInPrimitives("title"); + if (pt && (pt._typename !== "TPaveText")) pt = null; + + var draw_title = !histo.TestBit(JSROOT.TH1StatusBits.kNoTitle) && (st.fOptTitle > 0); + + if (pt) { + pt.Clear(); + if (draw_title) pt.AddText(histo.fTitle); + if (tpainter) tpainter.Redraw(); + } else if (draw_title && !tpainter && histo.fTitle) { + pt = JSROOT.Create("TPaveText"); + + var fp = this.frame_painter(), midx = st.fTitleX, y2 = st.fTitleY, w = st.fTitleW, h = st.fTitleH; + if (!h && fp) h = (y2-fp.fY2NDC)*0.7; + if (!w && fp) w = fp.fX2NDC - fp.fX1NDC; + if (!h || isNaN(h) || (h<0)) h = 0.06; + if (!w || isNaN(w) || (w<0)) w = 0.44; + pt.fName = "title"; + pt.fX1NDC = midx - w/2; + pt.fY1NDC = y2 - h; + pt.fX2NDC = midx + w/2; + pt.fY2NDC = y2; + pt.fTextFont = st.fTitleFont; + pt.fTextSize = st.fTitleFontSize; + pt.fTextColor = st.fTitleTextColor; + pt.fTextAlign = st.fTitleAlign; + pt.fFillColor = st.fTitleColor; + pt.fFillStyle = st.fTitleStyle; + pt.fBorderSize = st.fTitleBorderSize; + + pt.AddText(histo.fTitle); + tpainter = JSROOT.Painter.drawPave(this.divid, pt); + if (tpainter) tpainter.$secondary = true; + } + } + + THistPainter.prototype.processTitleChange = function(arg) { + + var histo = this.GetHisto(), + tpainter = this.FindPainterFor(null, "title"); + + if (!histo || !tpainter) return null; + + if (arg==="check") + return (!this.is_main_painter() || this.options.Same) ? null : histo; + + var pt = tpainter.GetObject(); + pt.Clear(); + pt.AddText(histo.fTitle); + + tpainter.Redraw(); + } + + THistPainter.prototype.UpdateStatWebCanvas = function() { + if (!this.snapid) return; + + var stat = this.FindStat(), + statpainter = this.FindPainterFor(stat); + + if (statpainter && !statpainter.snapid) statpainter.Redraw(); + } + + THistPainter.prototype.ToggleStat = function(arg) { + + var stat = this.FindStat(), statpainter = null; + + if (!arg) arg = ""; + + if (stat == null) { + if (arg.indexOf('-check')>0) return false; + // when statbox created first time, one need to draw it + stat = this.CreateStat(true); + } else { + statpainter = this.FindPainterFor(stat); + } + + if (arg=='only-check') return statpainter ? statpainter.Enabled : false; + + if (arg=='fitpar-check') return stat ? stat.fOptFit : false; + + if (arg=='fitpar-toggle') { + if (!stat) return false; + stat.fOptFit = stat.fOptFit ? 0 : 1111; // for websocket command should be send to server + if (statpainter) statpainter.Redraw(); + return true; + } + + if (statpainter) { + statpainter.Enabled = !statpainter.Enabled; + // when stat box is drawn, it always can be drawn individually while it + // should be last for colz RedrawPad is used + statpainter.Redraw(); + return statpainter.Enabled; + } + + JSROOT.draw(this.divid, stat, "onpad:" + this.pad_name); + + return true; + } + + THistPainter.prototype.GetSelectIndex = function(axis, side, add) { + // be aware - here indexes starts from 0 + var indx = 0, + main = this.frame_painter(), + nbin = this['nbins'+axis] || 0, + taxis = this.GetAxis(axis), + min = main ? main['zoom_' + axis + 'min'] : 0, + max = main ? main['zoom_' + axis + 'max'] : 0; + + if ((min !== max) && taxis) { + if (side == "left") + indx = taxis.FindBin(min, add || 0); + else + indx = taxis.FindBin(max, (add || 0) + 0.5); + if (indx<0) indx = 0; else if (indx>nbin) indx = nbin; + } else { + indx = (side == "left") ? 0 : nbin; + } + + // TAxis object of histogram, where user range can be stored + if (taxis) { + if ((taxis.fFirst === taxis.fLast) || !taxis.TestBit(JSROOT.EAxisBits.kAxisRange) || + ((taxis.fFirst<=1) && (taxis.fLast>=nbin))) taxis = undefined; + } + + if (side == "left") { + if (indx < 0) indx = 0; + if (taxis && (taxis.fFirst>1) && (indx<taxis.fFirst)) indx = taxis.fFirst-1; + } else { + if (indx > nbin) indx = nbin; + if (taxis && (taxis.fLast <= nbin) && (indx>taxis.fLast)) indx = taxis.fLast; + } + + return indx; + } + + THistPainter.prototype.FindFunction = function(type_name, obj_name) { + var histo = this.GetObject(), + funcs = histo && histo.fFunctions ? histo.fFunctions.arr : null; + + if (!funcs) return null; + + for (var i = 0; i < funcs.length; ++i) { + if (obj_name && (funcs[i].fName !== obj_name)) continue; + if (funcs[i]._typename === type_name) return funcs[i]; + } + + return null; + } + + THistPainter.prototype.FindStat = function() { + return this.FindFunction('TPaveStats', 'stats'); + } + + THistPainter.prototype.IgnoreStatsFill = function() { + return !this.GetObject() || (!this.draw_content && !this.create_stats) || (this.options.Axis>0); + } + + THistPainter.prototype.CreateStat = function(force) { + + if (!force && !this.options.ForceStat) { + if (this.options.NoStat || this.histo.TestBit(JSROOT.TH1StatusBits.kNoStats) || !JSROOT.gStyle.AutoStat) return null; + + if (!this.draw_content || !this.is_main_painter()) return null; + } + + var stats = this.FindStat(), st = JSROOT.gStyle, + optstat = this.options.optstat, optfit = this.options.optfit; + + if (optstat !== undefined) { + if (stats) stats.fOptStat = optstat; + delete this.options.optstat; + } else { + optstat = this.histo.$custom_stat || st.fOptStat; + } + + if (optfit !== undefined) { + if (stats) stats.fOptFit = optfit; + delete this.options.optfit; + } else { + optfit = st.fOptFit; + } + + if (!stats && !optstat && !optfit) return null; + + this.create_stats = true; + + if (stats) return stats; + + stats = JSROOT.Create('TPaveStats'); + JSROOT.extend(stats, { fName: 'stats', + fOptStat: optstat, + fOptFit: optfit, + fBorderSize: 1 }); + + stats.fX1NDC = st.fStatX - st.fStatW; + stats.fY1NDC = st.fStatY - st.fStatH; + stats.fX2NDC = st.fStatX; + stats.fY2NDC = st.fStatY; + + stats.fFillColor = st.fStatColor; + stats.fFillStyle = st.fStatStyle; + + stats.fTextAngle = 0; + stats.fTextSize = st.fStatFontSize; // 9 ?? + stats.fTextAlign = 12; + stats.fTextColor = st.fStatTextColor; + stats.fTextFont = st.fStatFont; + +// st.fStatBorderSize : 1, + + if (this.histo._typename.match(/^TProfile/) || this.histo._typename.match(/^TH2/)) + stats.fY1NDC = 0.67; + + stats.AddText(this.histo.fName); + + this.AddFunction(stats); + + return stats; + } + + THistPainter.prototype.AddFunction = function(obj, asfirst) { + var histo = this.GetObject(); + if (!histo || !obj) return; + + if (!histo.fFunctions) + histo.fFunctions = JSROOT.Create("TList"); + + if (asfirst) + histo.fFunctions.AddFirst(obj); + else + histo.fFunctions.Add(obj); + } + + THistPainter.prototype.DrawNextFunction = function(indx, callback) { + // method draws next function from the functions list + + if (!this.options.Func || !this.histo.fFunctions || + (indx >= this.histo.fFunctions.arr.length)) return JSROOT.CallBack(callback); + + var func = this.histo.fFunctions.arr[indx], + opt = this.histo.fFunctions.opt[indx], + do_draw = false, + func_painter = this.FindPainterFor(func); + + // no need to do something if painter for object was already done + // object will be redraw automatically + if (func_painter === null) { + if (func._typename === 'TPaveText' || func._typename === 'TPaveStats') { + do_draw = !this.histo.TestBit(JSROOT.TH1StatusBits.kNoStats) && !this.options.NoStat; + } else if (func._typename === 'TF1') { + do_draw = !func.TestBit(JSROOT.BIT(9)); + } else + do_draw = (func._typename !== 'TPaletteAxis'); + } + + if (do_draw) + return JSROOT.draw(this.divid, func, opt, this.DrawNextFunction.bind(this, indx+1, callback)); + + this.DrawNextFunction(indx+1, callback); + } + + THistPainter.prototype.UnzoomUserRange = function(dox, doy, doz) { + + if (!this.histo) return false; + + var res = false, painter = this; + + function UnzoomTAxis(obj) { + if (!obj) return false; + if (!obj.TestBit(JSROOT.EAxisBits.kAxisRange)) return false; + if (obj.fFirst === obj.fLast) return false; + if ((obj.fFirst <= 1) && (obj.fLast >= obj.fNbins)) return false; + obj.InvertBit(JSROOT.EAxisBits.kAxisRange); + return true; + } + + function UzoomMinMax(ndim, hist) { + if (painter.Dimension()!==ndim) return false; + if ((painter.options.minimum===-1111) && (painter.options.maximum===-1111)) return false; + if (!painter.draw_content) return false; // if not drawing content, not change min/max + painter.options.minimum = painter.options.maximum = -1111; + painter.ScanContent(true); // to reset ymin/ymax + return true; + } + + if (dox && UnzoomTAxis(this.histo.fXaxis)) res = true; + if (doy && (UnzoomTAxis(this.histo.fYaxis) || UzoomMinMax(1, this.histo))) res = true; + if (doz && (UnzoomTAxis(this.histo.fZaxis) || UzoomMinMax(2, this.histo))) res = true; + + return res; + } + + THistPainter.prototype.AllowDefaultYZooming = function() { + // return true if default Y zooming should be enabled + // it is typically for 2-Dim histograms or + // when histogram not draw, defined by other painters + + if (this.Dimension()>1) return true; + if (this.draw_content) return false; + + var pad_painter = this.pad_painter(); + if (pad_painter && pad_painter.painters) + for (var k = 0; k < pad_painter.painters.length; ++k) { + var subpainter = pad_painter.painters[k]; + if ((subpainter!==this) && subpainter.wheel_zoomy!==undefined) + return subpainter.wheel_zoomy; + } + + return false; + } + + THistPainter.prototype.ShowAxisStatus = function(axis_name) { + // method called normally when mouse enter main object element + + var status_func = this.GetShowStatusFunc(); + + if (!status_func) return; + + var taxis = this.histo ? this.histo['f'+axis_name.toUpperCase()+"axis"] : null; + + var hint_name = axis_name, hint_title = "TAxis"; + + if (taxis) { hint_name = taxis.fName; hint_title = taxis.fTitle || "histogram TAxis object"; } + + var m = d3.mouse(this.svg_frame().node()); + + var id = (axis_name=="x") ? 0 : 1; + if (this.swap_xy) id = 1-id; + + var axis_value = (axis_name=="x") ? this.RevertX(m[id]) : this.RevertY(m[id]); + + status_func(hint_name, hint_title, axis_name + " : " + this.AxisAsText(axis_name, axis_value), + m[0].toFixed(0)+","+ m[1].toFixed(0)); + } + + THistPainter.prototype.AddInteractive = function() { + // only first painter in list allowed to add interactive functionality to the frame + + if (this.is_main_painter()) { + var fp = this.frame_painter(); + if (fp) fp.AddInteractive(); + } + } + + THistPainter.prototype.ShowContextMenu = function(kind, evnt, obj) { + + // this is for debug purposes only, when context menu is where, close is and show normal menu + //if (!evnt && !kind && document.getElementById('root_ctx_menu')) { + // var elem = document.getElementById('root_ctx_menu'); + // elem.parentNode.removeChild(elem); + // return; + //} + + var menu_painter = this, frame_corner = false, fp = null; // object used to show context menu + + if (!evnt) { + d3.event.preventDefault(); + d3.event.stopPropagation(); // disable main context menu + evnt = d3.event; + + if (kind === undefined) { + var ms = d3.mouse(this.svg_frame().node()), + tch = d3.touches(this.svg_frame().node()), + pp = this.pad_painter(), + pnt = null, sel = null; + + fp = this.frame_painter(); + + if (tch.length === 1) pnt = { x: tch[0][0], y: tch[0][1], touch: true }; else + if (ms.length === 2) pnt = { x: ms[0], y: ms[1], touch: false }; + + if ((pnt !== null) && (pp !== null)) { + pnt.painters = true; // assign painter for every tooltip + var hints = pp.GetTooltips(pnt), bestdist = 1000; + for (var n=0;n<hints.length;++n) + if (hints[n] && hints[n].menu) { + var dist = ('menu_dist' in hints[n]) ? hints[n].menu_dist : 7; + if (dist < bestdist) { sel = hints[n].painter; bestdist = dist; } + } + } + + if (sel!==null) menu_painter = sel; else + if (fp!==null) kind = "frame"; + + if (pnt!==null) frame_corner = (pnt.x>0) && (pnt.x<20) && (pnt.y>0) && (pnt.y<20); + + if (fp) fp.SetLastEventPos(pnt); + } + } + + // one need to copy event, while after call back event may be changed + menu_painter.ctx_menu_evnt = evnt; + + JSROOT.Painter.createMenu(menu_painter, function(menu) { + var domenu = menu.painter.FillContextMenu(menu, kind, obj); + + // fill frame menu by default - or append frame elements when activated in the frame corner + if (fp && (!domenu || (frame_corner && (kind!=="frame")))) + domenu = fp.FillContextMenu(menu); + + if (domenu) + menu.painter.FillObjectExecMenu(menu, kind, function() { + // suppress any running zooming + menu.painter.SwitchTooltip(false); + menu.show(menu.painter.ctx_menu_evnt, menu.painter.SwitchTooltip.bind(menu.painter, true)); + }); + + }); // end menu creation + } + + + THistPainter.prototype.ChangeUserRange = function(arg) { + var taxis = this.histo['f'+arg+"axis"]; + if (!taxis) return; + + var curr = "[1," + taxis.fNbins+"]"; + if (taxis.TestBit(JSROOT.EAxisBits.kAxisRange)) + curr = "[" +taxis.fFirst+"," + taxis.fLast+"]"; + + var res = prompt("Enter user range for axis " + arg + " like [1," + taxis.fNbins + "]", curr); + if (!res) return; + res = JSON.parse(res); + + if (!res || (res.length!=2) || isNaN(res[0]) || isNaN(res[1])) return; + taxis.fFirst = parseInt(res[0]); + taxis.fLast = parseInt(res[1]); + + var newflag = (taxis.fFirst < taxis.fLast) && (taxis.fFirst >= 1) && (taxis.fLast<=taxis.fNbins); + if (newflag != taxis.TestBit(JSROOT.EAxisBits.kAxisRange)) + taxis.InvertBit(JSROOT.EAxisBits.kAxisRange); + + this.Redraw(); + } + + THistPainter.prototype.FillContextMenu = function(menu) { + + var histo = this.GetHisto(), + fp = this.frame_painter(); + if (!histo) return; + + menu.add("header:"+ histo._typename + "::" + histo.fName); + + if (this.draw_content) { + menu.addchk(this.ToggleStat('only-check'), "Show statbox", function() { this.ToggleStat(); }); + if (this.Dimension() == 1) { + menu.add("User range X", "X", this.ChangeUserRange); + } else { + menu.add("sub:User ranges"); + menu.add("X", "X", this.ChangeUserRange); + menu.add("Y", "Y", this.ChangeUserRange); + if (this.Dimension() > 2) + menu.add("Z", "Z", this.ChangeUserRange); + menu.add("endsub:") + } + + if (typeof this.FillHistContextMenu == 'function') + this.FillHistContextMenu(menu); + } + + if (this.options.Mode3D) { + // menu for 3D drawings + + if (menu.size() > 0) + menu.add("separator"); + + var main = this.main_painter() || this; + + menu.addchk(main.IsTooltipAllowed(), 'Show tooltips', function() { + main.SetTooltipAllowed("toggle"); + }); + + menu.addchk(fp.enable_highlight, 'Highlight bins', function() { + fp.enable_highlight = !fp.enable_highlight; + if (!fp.enable_highlight && fp.BinHighlight3D && fp.mode3d) fp.BinHighlight3D(null); + }); + + if (fp && fp.Render3D) { + menu.addchk(main.options.FrontBox, 'Front box', function() { + main.options.FrontBox = !main.options.FrontBox; + fp.Render3D(); + }); + menu.addchk(main.options.BackBox, 'Back box', function() { + main.options.BackBox = !main.options.BackBox; + fp.Render3D(); + }); + } + + if (this.draw_content) { + menu.addchk(!this.options.Zero, 'Suppress zeros', function() { + this.options.Zero = !this.options.Zero; + this.InteractiveRedraw("pad"); + }); + + if ((this.options.Lego==12) || (this.options.Lego==14)) { + menu.addchk(this.options.Zscale, "Z scale", function() { + this.ToggleColz(); + }); + if (this.FillPaletteMenu) this.FillPaletteMenu(menu); + } + } + + if (main.control && typeof main.control.reset === 'function') + menu.add('Reset camera', function() { + main.control.reset(); + }); + } + + this.FillAttContextMenu(menu); + + if (this.histogram_updated && fp.zoom_changed_interactive) + menu.add('Let update zoom', function() { + fp.zoom_changed_interactive = 0; + }); + + return true; + } + + THistPainter.prototype.ButtonClick = function(funcname) { + // TODO: move to frame painter + + var fp = this.frame_painter(); + + if (!this.is_main_painter() || !fp) return false; + + switch(funcname) { + case "ToggleZoom": + if ((fp.zoom_xmin !== fp.zoom_xmax) || (fp.zoom_ymin !== fp.zoom_ymax) || (fp.zoom_zmin !== fp.zoom_zmax)) { + fp.Unzoom(); + return true; + } + if (this.draw_content && (typeof this.AutoZoom === 'function')) { + this.AutoZoom(); + return true; + } + break; + case "ToggleLogX": fp.ToggleLog("x"); break; + case "ToggleLogY": fp.ToggleLog("y"); break; + case "ToggleLogZ": fp.ToggleLog("z"); break; + case "ToggleStatBox": this.ToggleStat(); return true; break; + } + return false; + } + + THistPainter.prototype.FillToolbar = function(not_shown) { + var pp = this.pad_painter(); + if (!pp) return; + + pp.AddButton(JSROOT.ToolbarIcons.auto_zoom, 'Toggle between unzoom and autozoom-in', 'ToggleZoom', "Ctrl *"); + pp.AddButton(JSROOT.ToolbarIcons.arrow_right, "Toggle log x", "ToggleLogX", "PageDown"); + pp.AddButton(JSROOT.ToolbarIcons.arrow_up, "Toggle log y", "ToggleLogY", "PageUp"); + if (this.Dimension() > 1) + pp.AddButton(JSROOT.ToolbarIcons.arrow_diag, "Toggle log z", "ToggleLogZ"); + if (this.draw_content) + pp.AddButton(JSROOT.ToolbarIcons.statbox, 'Toggle stat box', "ToggleStatBox"); + if (!not_shown) pp.ShowButtons(); + } + + THistPainter.prototype.Get3DToolTip = function(indx) { + var tip = { bin: indx, name: this.GetObject().fName, title: this.GetObject().fTitle }; + switch (this.Dimension()) { + case 1: + tip.ix = indx; tip.iy = 1; + tip.value = this.histo.getBinContent(tip.ix); + tip.error = this.histo.getBinError(indx); + tip.lines = this.GetBinTips(indx-1); + break; + case 2: + tip.ix = indx % (this.nbinsx + 2); + tip.iy = (indx - tip.ix) / (this.nbinsx + 2); + tip.value = this.histo.getBinContent(tip.ix, tip.iy); + tip.error = this.histo.getBinError(indx); + tip.lines = this.GetBinTips(tip.ix-1, tip.iy-1); + break; + case 3: + tip.ix = indx % (this.nbinsx+2); + tip.iy = ((indx - tip.ix) / (this.nbinsx+2)) % (this.nbinsy+2); + tip.iz = (indx - tip.ix - tip.iy * (this.nbinsx+2)) / (this.nbinsx+2) / (this.nbinsy+2); + tip.value = this.GetObject().getBinContent(tip.ix, tip.iy, tip.iz); + tip.error = this.histo.getBinError(indx); + tip.lines = this.GetBinTips(tip.ix-1, tip.iy-1, tip.iz-1); + break; + } + + return tip; + } + + THistPainter.prototype.CreateContour = function(nlevels, zmin, zmax, zminpositive) { + + if (nlevels<1) nlevels = JSROOT.gStyle.fNumberContours; + this.fContour = []; + this.colzmin = zmin; + this.colzmax = zmax; + + if (this.root_pad().fLogz) { + if (this.colzmax <= 0) this.colzmax = 1.; + if (this.colzmin <= 0) + if ((zminpositive===undefined) || (zminpositive <= 0)) + this.colzmin = 0.0001*this.colzmax; + else + this.colzmin = ((zminpositive < 3) || (zminpositive>100)) ? 0.3*zminpositive : 1; + if (this.colzmin >= this.colzmax) this.colzmin = 0.0001*this.colzmax; + + var logmin = Math.log(this.colzmin)/Math.log(10), + logmax = Math.log(this.colzmax)/Math.log(10), + dz = (logmax-logmin)/nlevels; + this.fContour.push(this.colzmin); + for (var level=1; level<nlevels; level++) + this.fContour.push(Math.exp((logmin + dz*level)*Math.log(10))); + this.fContour.push(this.colzmax); + this.fCustomContour = true; + } else { + if ((this.colzmin === this.colzmax) && (this.colzmin !== 0)) { + this.colzmax += 0.01*Math.abs(this.colzmax); + this.colzmin -= 0.01*Math.abs(this.colzmin); + } + var dz = (this.colzmax-this.colzmin)/nlevels; + for (var level=0; level<=nlevels; level++) + this.fContour.push(this.colzmin + dz*level); + } + + var fp = this.frame_painter(); + if ((this.Dimension() < 3) && fp) { + fp.zmin = this.colzmin; + fp.zmax = this.colzmax; + } + + return this.fContour; + } + + THistPainter.prototype.GetContour = function() { + if (this.fContour) return this.fContour; + + var main = this.main_painter(), + fp = this.frame_painter(); + if ((main !== this) && main.fContour) { + this.fContour = main.fContour; + this.fCustomContour = main.fCustomContour; + this.colzmin = main.colzmin; + this.colzmax = main.colzmax; + return this.fContour; + } + + // if not initialized, first create contour array + // difference from ROOT - fContour includes also last element with maxbin, which makes easier to build logz + var histo = this.GetObject(), nlevels = JSROOT.gStyle.fNumberContours, + zmin = this.minbin, zmax = this.maxbin, zminpos = this.minposbin; + if (zmin === zmax) { zmin = this.gminbin; zmax = this.gmaxbin; zminpos = this.gminposbin } + if (histo.fContour) nlevels = histo.fContour.length; + if ((this.options.minimum !== -1111) && (this.options.maximum != -1111)) { + zmin = this.options.minimum; + zmax = this.options.maximum; + } + if (fp && (fp.zoom_zmin != fp.zoom_zmax)) { + zmin = fp.zoom_zmin; + zmax = fp.zoom_zmax; + } + + if (histo.fContour && (histo.fContour.length>1) && histo.TestBit(JSROOT.TH1StatusBits.kUserContour)) { + this.fContour = JSROOT.clone(histo.fContour); + this.fCustomContour = true; + this.colzmin = zmin; + this.colzmax = zmax; + if (zmax > this.fContour[this.fContour.length-1]) this.fContour.push(zmax); + if ((this.Dimension()<3) && fp) { + fp.zmin = this.colzmin; + fp.zmax = this.colzmax; + } + return this.fContour; + } + + this.fCustomContour = false; + + return this.CreateContour(nlevels, zmin, zmax, zminpos); + } + + /// return index from contours array, which corresponds to the content value **zc** + THistPainter.prototype.getContourIndex = function(zc) { + + var cntr = this.GetContour(); + + if (this.fCustomContour) { + var l = 0, r = cntr.length-1, mid; + if (zc < cntr[0]) return -1; + if (zc >= cntr[r]) return r; + while (l < r-1) { + mid = Math.round((l+r)/2); + if (cntr[mid] > zc) r = mid; else l = mid; + } + return l; + } + + // bins less than zmin not drawn + if (zc < this.colzmin) return this.options.Zero ? -1 : 0; + + // if bin content exactly zmin, draw it when col0 specified or when content is positive + if (zc===this.colzmin) return ((this.colzmin != 0) || !this.options.Zero || this.IsTH2Poly()) ? 0 : -1; + + return Math.floor(0.01+(zc-this.colzmin)*(cntr.length-1)/(this.colzmax-this.colzmin)); + } + + /// return color from the palette, which corresponds given controur value + /// optionally one can return color index of the palette + THistPainter.prototype.getContourColor = function(zc, asindx) { + var zindx = this.getContourIndex(zc); + if (zindx < 0) return null; + + var cntr = this.GetContour(), + palette = this.GetPalette(), + indx = palette.calcColorIndex(zindx, cntr.length); + + return asindx ? indx : palette.getColor(indx); + } + + THistPainter.prototype.GetPalette = function(force) { + if (!this.fPalette || force) + this.fPalette = this.get_palette(true, this.options.Palette); + return this.fPalette; + } + + THistPainter.prototype.FillPaletteMenu = function(menu) { + + var curr = this.options.Palette, hpainter = this; + if ((curr===null) || (curr===0)) curr = JSROOT.gStyle.Palette; + + function change(arg) { + hpainter.options.Palette = parseInt(arg); + hpainter.GetPalette(true); + hpainter.Redraw(); // redraw histogram + }; + + function add(id, name, more) { + menu.addchk((id===curr) || more, '<nobr>' + name + '</nobr>', id, change); + }; + + menu.add("sub:Palette"); + + add(50, "ROOT 5", (curr>=10) && (curr<51)); + add(51, "Deep Sea"); + add(52, "Grayscale", (curr>0) && (curr<10)); + add(53, "Dark body radiator"); + add(54, "Two-color hue"); + add(55, "Rainbow"); + add(56, "Inverted dark body radiator"); + add(57, "Bird", (curr>113)); + add(58, "Cubehelix"); + add(59, "Green Red Violet"); + add(60, "Blue Red Yellow"); + add(61, "Ocean"); + add(62, "Color Printable On Grey"); + add(63, "Alpine"); + add(64, "Aquamarine"); + add(65, "Army"); + add(66, "Atlantic"); + + menu.add("endsub:"); + } + + THistPainter.prototype.DrawColorPalette = function(enabled, postpone_draw, can_move) { + // only when create new palette, one could change frame size + + if (!this.is_main_painter()) return null; + + var pal = this.FindFunction('TPaletteAxis'), + pal_painter = this.FindPainterFor(pal); + + if (this._can_move_colz) { can_move = true; delete this._can_move_colz; } + + if (!pal_painter && !pal) { + pal_painter = this.FindPainterFor(undefined, undefined, "TPaletteAxis"); + if (pal_painter) { + pal = pal_painter.GetObject(); + // add to list of functions + this.AddFunction(pal, true); + } + } + + if (!enabled) { + if (pal_painter) { + pal_painter.Enabled = false; + pal_painter.RemoveDrawG(); // completely remove drawing without need to redraw complete pad + } + + return null; + } + + if (!pal) { + pal = JSROOT.Create('TPave'); + + JSROOT.extend(pal, { _typename: "TPaletteAxis", fName: "TPave", fH: null, fAxis: JSROOT.Create('TGaxis'), + fX1NDC: 0.91, fX2NDC: 0.95, fY1NDC: 0.1, fY2NDC: 0.9, fInit: 1 } ); + + var zaxis = this.GetHisto().fZaxis; + + JSROOT.extend(pal.fAxis, { fTitle: zaxis.fTitle, fTitleSize: zaxis.fTitleSize, fTextColor: zaxis.fTitleColor, fChopt: "+", + fLineColor: zaxis.fAxisColor, fLineSyle: 1, fLineWidth: 1, + fTextAngle: 0, fTextSize: zaxis.fLabelSize, fTextAlign: 11, fTextColor: zaxis.fLabelColor, fTextFont: zaxis.fLabelFont }); + + // place colz in the beginning, that stat box is always drawn on the top + this.AddFunction(pal, true); + + can_move = true; + } else if (pal.fAxis) { + // check some default values of TGaxis object + if (!pal.fAxis.fChopt) pal.fAxis.fChopt = "+"; + if (!pal.fAxis.fNdiv) pal.fAxis.fNdiv = 12; + if (!pal.fAxis.fLabelOffset) pal.fAxis.fLabelOffset = 0.005; + } + + var frame_painter = this.frame_painter(); + + // keep palette width + if (can_move && frame_painter) { + pal.fX2NDC = frame_painter.fX2NDC + 0.01 + (pal.fX2NDC - pal.fX1NDC); + pal.fX1NDC = frame_painter.fX2NDC + 0.01; + pal.fY1NDC = frame_painter.fY1NDC; + pal.fY2NDC = frame_painter.fY2NDC; + } + + var arg = ""; + if (postpone_draw) arg+=";postpone"; + if (can_move && !this.do_redraw_palette) arg+=";canmove" + + if (pal_painter === null) { + // when histogram drawn on sub pad, let draw new axis object on the same pad + var prev = this.CurrentPadName(this.pad_name); + // CAUTION!!! This is very special place where return value of JSROOT.draw is allowed + // while palette drawing is in same script. Normally callback should be used + pal_painter = JSROOT.draw(this.divid, pal, arg); + this.CurrentPadName(prev); + } else { + pal_painter.Enabled = true; + pal_painter.DrawPave(arg); + } + + // mark painter as secondary - not in list of TCanvas primitives + pal_painter.$secondary = true; + + // make dummy redraw, palette will be updated only from histogram painter + pal_painter.Redraw = function() {}; + + if (can_move && frame_painter && (pal.fX1NDC-0.005 < frame_painter.fX2NDC) && !this.do_redraw_palette) { + + this.do_redraw_palette = true; + + frame_painter.fX2NDC = pal.fX1NDC - 0.01; + frame_painter.Redraw(); + // here we should redraw main object + if (!postpone_draw) this.Redraw(); + + delete this.do_redraw_palette; + } + + return pal_painter; + } + + THistPainter.prototype.ToggleColz = function() { + var can_toggle = this.options.Mode3D ? (this.options.Lego === 12 || this.options.Lego === 14 || this.options.Surf === 11 || this.options.Surf === 12) : + this.options.Color || this.options.Contour; + + if (can_toggle) { + this.options.Zscale = !this.options.Zscale; + this.DrawColorPalette(this.options.Zscale, false, true); + } + } + + THistPainter.prototype.ToggleMode3D = function() { + this.options.Mode3D = !this.options.Mode3D; + + if (this.options.Mode3D) { + if (!this.options.Surf && !this.options.Lego && !this.options.Error) { + if ((this.nbinsx>=50) || (this.nbinsy>=50)) + this.options.Lego = this.options.Color ? 14 : 13; + else + this.options.Lego = this.options.Color ? 12 : 1; + + this.options.Zero = false; // do not show zeros by default + } + } + + this.CopyOptionsToOthers(); + this.InteractiveRedraw("pad","drawopt"); + } + + THistPainter.prototype.PrepareColorDraw = function(args) { + + if (!args) args = { rounding: true, extra: 0, middle: 0 }; + + if (args.extra === undefined) args.extra = 0; + if (args.middle === undefined) args.middle = 0; + + var histo = this.GetHisto(), + xaxis = histo.fXaxis, yaxis = histo.fYaxis, + pmain = this.frame_painter(), + hdim = this.Dimension(), + i, j, x, y, binz, binarea, + res = { + i1: this.GetSelectIndex("x", "left", 0 - args.extra), + i2: this.GetSelectIndex("x", "right", 1 + args.extra), + j1: (hdim===1) ? 0 : this.GetSelectIndex("y", "left", 0 - args.extra), + j2: (hdim===1) ? 1 : this.GetSelectIndex("y", "right", 1 + args.extra), + min: 0, max: 0, sumz: 0, xbar1: 0, xbar2: 1, ybar1: 0, ybar2: 1 + }; + + res.grx = new Float32Array(res.i2+1); + res.gry = new Float32Array(res.j2+1); + + if (typeof histo.fBarOffset == 'number' && typeof histo.fBarWidth == 'number' + && (histo.fBarOffset || histo.fBarWidth !== 1000)) { + if (histo.fBarOffset <= 1000) { + res.xbar1 = res.ybar1 = 0.001*histo.fBarOffset; + } else if (histo.fBarOffset <= 3000) { + res.xbar1 = 0.001*(histo.fBarOffset-2000); + } else if (histo.fBarOffset <= 5000) { + res.ybar1 = 0.001*(histo.fBarOffset-4000); + } + + if (histo.fBarWidth <= 1000) { + res.xbar2 = Math.min(1., res.xbar1 + 0.001*histo.fBarWidth); + res.ybar2 = Math.min(1., res.ybar1 + 0.001*histo.fBarWidth); + } else if (histo.fBarWidth <= 3000) { + res.xbar2 = Math.min(1., res.xbar1 + 0.001*(histo.fBarWidth-2000)); + // res.ybar2 = res.ybar1 + 1; + } else if (histo.fBarWidth <= 5000) { + // res.xbar2 = res.xbar1 + 1; + res.ybar2 = Math.min(1., res.ybar1 + 0.001*(histo.fBarWidth-4000)); + } + } + + if (args.original) { + res.original = true; + res.origx = new Float32Array(res.i2+1); + res.origy = new Float32Array(res.j2+1); + } + + if (args.pixel_density) args.rounding = true; + + if (!pmain) { + console.warn("cannot draw histogram without frame"); + return res; + } + + // calculate graphical coordinates in advance + for (i = res.i1; i <= res.i2; ++i) { + x = xaxis.GetBinCoord(i + args.middle); + if (pmain.logx && (x <= 0)) { res.i1 = i+1; continue; } + if (res.origx) res.origx[i] = x; + res.grx[i] = pmain.grx(x); + if (args.rounding) res.grx[i] = Math.round(res.grx[i]); + + if (args.use3d) { + if (res.grx[i] < -pmain.size_xy3d) { res.i1 = i; res.grx[i] = -pmain.size_xy3d; } + if (res.grx[i] > pmain.size_xy3d) { res.i2 = i; res.grx[i] = pmain.size_xy3d; } + } + } + + if (hdim===1) { + res.gry[0] = pmain.gry(0); + res.gry[1] = pmain.gry(1); + } else + for (j = res.j1; j <= res.j2; ++j) { + y = yaxis.GetBinCoord(j + args.middle); + if (pmain.logy && (y <= 0)) { res.j1 = j+1; continue; } + if (res.origy) res.origy[j] = y; + res.gry[j] = pmain.gry(y); + if (args.rounding) res.gry[j] = Math.round(res.gry[j]); + + if (args.use3d) { + if (res.gry[j] < -pmain.size_xy3d) { res.j1 = j; res.gry[j] = -pmain.size_xy3d; } + if (res.gry[j] > pmain.size_xy3d) { res.j2 = j; res.gry[j] = pmain.size_xy3d; } + } + } + + // find min/max values in selected range + + binz = histo.getBinContent(res.i1 + 1, res.j1 + 1); + this.maxbin = this.minbin = this.minposbin = null; + + for (i = res.i1; i < res.i2; ++i) { + for (j = res.j1; j < res.j2; ++j) { + binz = histo.getBinContent(i + 1, j + 1); + res.sumz += binz; + if (args.pixel_density) { + binarea = (res.grx[i+1]-res.grx[i])*(res.gry[j]-res.gry[j+1]); + if (binarea <= 0) continue; + res.max = Math.max(res.max, binz); + if ((binz>0) && ((binz<res.min) || (res.min===0))) res.min = binz; + binz = binz/binarea; + } + if (this.maxbin===null) { + this.maxbin = this.minbin = binz; + } else { + this.maxbin = Math.max(this.maxbin, binz); + this.minbin = Math.min(this.minbin, binz); + } + if (binz > 0) + if ((this.minposbin===null) || (binz<this.minposbin)) this.minposbin = binz; + } + } + + // force recalculation of z levels + this.fContour = null; + this.fCustomContour = false; + + return res; + } + + // ======================================================================== + + /** + * @summary Painter for TH1 classes + * + * @constructor + * @memberof JSROOT + * @augments JSROOT.THistPainter + * @param {object} histo - histogram object + */ + + function TH1Painter(histo) { + THistPainter.call(this, histo); + } + + TH1Painter.prototype = Object.create(THistPainter.prototype); + + TH1Painter.prototype.ConvertTH1K = function() { + var histo = this.GetObject(); + + if (histo.fReady) return; + + var arr = histo.fArray; // array of values + histo.fNcells = histo.fXaxis.fNbins + 2; + histo.fArray = new Float64Array(histo.fNcells); + for (var n=0;n<histo.fNcells;++n) histo.fArray[n] = 0; + for (var n=0;n<histo.fNIn;++n) histo.Fill(arr[n]); + histo.fReady = true; + } + + /** Scan content of 1-D histogram + * + * Detect min/max values for x and y axis + * @param when_axis_changed - true when only zooming was changed, some checks may be skipped + */ + + TH1Painter.prototype.ScanContent = function(when_axis_changed) { + // if when_axis_changed === true specified, content will be scanned after axis zoom changed + + if (when_axis_changed && !this.nbinsx) when_axis_changed = false; + + if (this.IsTH1K()) this.ConvertTH1K(); + + if (!when_axis_changed) { + this.nbinsx = this.histo.fXaxis.fNbins; + this.nbinsy = 0; + this.CreateAxisFuncs(false); + } + + var left = this.GetSelectIndex("x", "left"), + right = this.GetSelectIndex("x", "right"); + + if (when_axis_changed) { + if ((left === this.scan_xleft) && (right === this.scan_xright)) return; + } + + // Paint histogram axis only + this.draw_content = !(this.options.Axis > 0); + + this.scan_xleft = left; + this.scan_xright = right; + + var hmin = 0, hmin_nz = 0, hmax = 0, hsum = 0, first = true, + profile = this.IsTProfile(), value, err; + + for (var i = 0; i < this.nbinsx; ++i) { + value = this.histo.getBinContent(i + 1); + hsum += profile ? this.histo.fBinEntries[i + 1] : value; + + if ((i<left) || (i>=right)) continue; + + if ((value > 0) && ((hmin_nz == 0) || (value < hmin_nz))) hmin_nz = value; + + if (first) { + hmin = hmax = value; + first = false; + } + + err = this.options.Error ? this.histo.getBinError(i + 1) : 0; + + hmin = Math.min(hmin, value - err); + hmax = Math.max(hmax, value + err); + } + + // account overflow/underflow bins + if (profile) + hsum += this.histo.fBinEntries[0] + this.histo.fBinEntries[this.nbinsx + 1]; + else + hsum += this.histo.getBinContent(0) + this.histo.getBinContent(this.nbinsx + 1); + + this.stat_entries = hsum; + if (this.histo.fEntries>1) this.stat_entries = this.histo.fEntries; + + this.hmin = hmin; + this.hmax = hmax; + + this.ymin_nz = hmin_nz; // value can be used to show optimal log scale + + if ((this.nbinsx == 0) || ((Math.abs(hmin) < 1e-300 && Math.abs(hmax) < 1e-300))) { + this.draw_content = false; + hmin = this.ymin; + hmax = this.ymax; + } + + if (this.draw_content) { + if (hmin >= hmax) { + if (hmin == 0) { this.ymin = 0; this.ymax = 1; } + else if (hmin < 0) { this.ymin = 2 * hmin; this.ymax = 0; } + else { this.ymin = 0; this.ymax = hmin * 2; } + } else { + var dy = (hmax - hmin) * 0.05; + this.ymin = hmin - dy; + if ((this.ymin < 0) && (hmin >= 0)) this.ymin = 0; + this.ymax = hmax + dy; + } + } + + hmin = this.options.minimum; + hmax = this.options.maximum; + + if ((hmin === hmax) && (hmin !== -1111)) { + if (hmin < 0) { + hmin *= 2; hmax = 0; + } else { + hmin = 0; hmax*=2; if (!hmax) hmax = 1; + } + } + + var set_zoom = false; + if ((hmin != -1111) && (hmax != -1111) && !this.draw_content) { + this.ymin = hmin; + this.ymax = hmax; + } else { + if (hmin != -1111) { + if (hmin < this.ymin) this.ymin = hmin; else set_zoom = true; + } + if (hmax != -1111) { + if (hmax > this.ymax) this.ymax = hmax; else set_zoom = true; + } + } + + if (!when_axis_changed) { + if (set_zoom && this.draw_content) { + this.zoom_ymin = (hmin == -1111) ? this.ymin : hmin; + this.zoom_ymax = (hmax == -1111) ? this.ymax : hmax; + } else { + delete this.zoom_ymin; + delete this.zoom_ymax; + } + } + + // used in AllowDefaultYZooming + if (this.Dimension() > 1) this.wheel_zoomy = true; else + if (this.draw_content) this.wheel_zoomy = false; + } + + TH1Painter.prototype.CountStat = function(cond) { + var profile = this.IsTProfile(), + histo = this.GetHisto(), xaxis = histo.fXaxis, + left = this.GetSelectIndex("x", "left"), + right = this.GetSelectIndex("x", "right"), + stat_sumw = 0, stat_sumwx = 0, stat_sumwx2 = 0, stat_sumwy = 0, stat_sumwy2 = 0, + i, xx = 0, w = 0, xmax = null, wmax = null, + fp = this.frame_painter(), + res = { name: histo.fName, meanx: 0, meany: 0, rmsx: 0, rmsy: 0, integral: 0, entries: this.stat_entries, xmax:0, wmax:0 }; + + for (i = left; i < right; ++i) { + xx = xaxis.GetBinCoord(i + 0.5); + + if (cond && !cond(xx)) continue; + + if (profile) { + w = histo.fBinEntries[i + 1]; + stat_sumwy += histo.fArray[i + 1]; + stat_sumwy2 += histo.fSumw2[i + 1]; + } else { + w = histo.getBinContent(i + 1); + } + + if ((xmax===null) || (w>wmax)) { xmax = xx; wmax = w; } + + stat_sumw += w; + stat_sumwx += w * xx; + stat_sumwx2 += w * xx * xx; + } + + // when no range selection done, use original statistic from histogram + if (!fp.IsAxisZoomed("x") && (histo.fTsumw>0)) { + stat_sumw = histo.fTsumw; + stat_sumwx = histo.fTsumwx; + stat_sumwx2 = histo.fTsumwx2; + } + + res.integral = stat_sumw; + + if (stat_sumw > 0) { + res.meanx = stat_sumwx / stat_sumw; + res.meany = stat_sumwy / stat_sumw; + res.rmsx = Math.sqrt(Math.abs(stat_sumwx2 / stat_sumw - res.meanx * res.meanx)); + res.rmsy = Math.sqrt(Math.abs(stat_sumwy2 / stat_sumw - res.meany * res.meany)); + } + + if (xmax!==null) { + res.xmax = xmax; + res.wmax = wmax; + } + + return res; + } + + TH1Painter.prototype.FillStatistic = function(stat, dostat, dofit) { + + // no need to refill statistic if histogram is dummy + if (this.IgnoreStatsFill()) return false; + + var data = this.CountStat(), + print_name = dostat % 10, + print_entries = Math.floor(dostat / 10) % 10, + print_mean = Math.floor(dostat / 100) % 10, + print_rms = Math.floor(dostat / 1000) % 10, + print_under = Math.floor(dostat / 10000) % 10, + print_over = Math.floor(dostat / 100000) % 10, + print_integral = Math.floor(dostat / 1000000) % 10, + print_skew = Math.floor(dostat / 10000000) % 10, + print_kurt = Math.floor(dostat / 100000000) % 10; + + // make empty at the beginning + stat.ClearPave(); + + if (print_name > 0) + stat.AddText(data.name); + + if (this.IsTProfile()) { + + if (print_entries > 0) + stat.AddText("Entries = " + stat.Format(data.entries,"entries")); + + if (print_mean > 0) { + stat.AddText("Mean = " + stat.Format(data.meanx)); + stat.AddText("Mean y = " + stat.Format(data.meany)); + } + + if (print_rms > 0) { + stat.AddText("Std Dev = " + stat.Format(data.rmsx)); + stat.AddText("Std Dev y = " + stat.Format(data.rmsy)); + } + + } else { + + if (print_entries > 0) + stat.AddText("Entries = " + stat.Format(data.entries,"entries")); + + if (print_mean > 0) + stat.AddText("Mean = " + stat.Format(data.meanx)); + + if (print_rms > 0) + stat.AddText("Std Dev = " + stat.Format(data.rmsx)); + + if (print_under > 0) + stat.AddText("Underflow = " + stat.Format((this.histo.fArray.length > 0) ? this.histo.fArray[0] : 0,"entries")); + + if (print_over > 0) + stat.AddText("Overflow = " + stat.Format((this.histo.fArray.length > 0) ? this.histo.fArray[this.histo.fArray.length - 1] : 0,"entries")); + + if (print_integral > 0) + stat.AddText("Integral = " + stat.Format(data.integral,"entries")); + + if (print_skew > 0) + stat.AddText("Skew = <not avail>"); + + if (print_kurt > 0) + stat.AddText("Kurt = <not avail>"); + } + + if (dofit) stat.FillFunctionStat(this.FindFunction('TF1'), dofit); + + return true; + } + + TH1Painter.prototype.DrawBars = function(width, height) { + + this.CreateG(true); + + var left = this.GetSelectIndex("x", "left", -1), + right = this.GetSelectIndex("x", "right", 1), + pmain = this.frame_painter(), + pad = this.root_pad(), + histo = this.GetHisto(), xaxis = histo.fXaxis, + pthis = this, + show_text = this.options.Text, text_col, text_angle, text_size, + i, x1, x2, grx1, grx2, y, gry1, gry2, w, + bars = "", barsl = "", barsr = "", + side = (this.options.BarStyle > 10) ? this.options.BarStyle % 10 : 0; + + if (side>4) side = 4; + gry2 = pmain.swap_xy ? 0 : height; + if ((this.options.BaseLine !== false) && !isNaN(this.options.BaseLine)) + if (this.options.BaseLine >= pmain.scale_ymin) + gry2 = Math.round(pmain.gry(this.options.BaseLine)); + + if (show_text) { + text_col = this.get_color(histo.fMarkerColor); + text_angle = -1*this.options.TextAngle; + text_size = 20; + + if ((histo.fMarkerSize!==1) && text_angle) + text_size = 0.02*height*histo.fMarkerSize; + + this.StartTextDrawing(42, text_size, this.draw_g, text_size); + } + + + for (i = left; i < right; ++i) { + x1 = xaxis.GetBinLowEdge(i+1); + x2 = xaxis.GetBinLowEdge(i+2); + + if (pmain.logx && (x2 <= 0)) continue; + + grx1 = Math.round(pmain.grx(x1)); + grx2 = Math.round(pmain.grx(x2)); + + y = histo.getBinContent(i+1); + if (pmain.logy && (y < pmain.scale_ymin)) continue; + gry1 = Math.round(pmain.gry(y)); + + w = grx2 - grx1; + grx1 += Math.round(histo.fBarOffset/1000*w); + w = Math.round(histo.fBarWidth/1000*w); + + if (pmain.swap_xy) + bars += "M"+gry2+","+grx1 + "h"+(gry1-gry2) + "v"+w + "h"+(gry2-gry1) + "z"; + else + bars += "M"+grx1+","+gry1 + "h"+w + "v"+(gry2-gry1) + "h"+(-w)+ "z"; + + if (side > 0) { + grx2 = grx1 + w; + w = Math.round(w * side / 10); + if (pmain.swap_xy) { + barsl += "M"+gry2+","+grx1 + "h"+(gry1-gry2) + "v" + w + "h"+(gry2-gry1) + "z"; + barsr += "M"+gry2+","+grx2 + "h"+(gry1-gry2) + "v" + (-w) + "h"+(gry2-gry1) + "z"; + } else { + barsl += "M"+grx1+","+gry1 + "h"+w + "v"+(gry2-gry1) + "h"+(-w)+ "z"; + barsr += "M"+grx2+","+gry1 + "h"+(-w) + "v"+(gry2-gry1) + "h"+w + "z"; + } + } + + if (show_text && y) { + var lbl = (y === Math.round(y)) ? y.toString() : JSROOT.FFormat(y, JSROOT.gStyle.fPaintTextFormat); + + if (pmain.swap_xy) + this.DrawText({ align: 12, x: Math.round(gry1 + text_size/2), y: Math.round(grx1+0.1), height: Math.round(w*0.8), text: lbl, color: text_col, latex: 0 }); + else if (text_angle) + this.DrawText({ align: 12, x: grx1+w/2, y: Math.round(gry1 - 2 - text_size/5), width: 0, height: 0, rotate: text_angle, text: lbl, color: text_col, latex: 0 }); + else + this.DrawText({ align: 22, x: Math.round(grx1 + w*0.1), y: Math.round(gry1-2-text_size), width: Math.round(w*0.8), height: text_size, text: lbl, color: text_col, latex: 0 }); + } + } + + if (bars) + this.draw_g.append("svg:path") + .attr("d", bars) + .call(this.fillatt.func); + + if (barsl) + this.draw_g.append("svg:path") + .attr("d", barsl) + .call(this.fillatt.func) + .style("fill", d3.rgb(this.fillatt.color).brighter(0.5).toString()); + + if (barsr) + this.draw_g.append("svg:path") + .attr("d", barsr) + .call(this.fillatt.func) + .style("fill", d3.rgb(this.fillatt.color).darker(0.5).toString()); + + if (show_text) + this.FinishTextDrawing(this.draw_g); + } + + TH1Painter.prototype.DrawFilledErrors = function(width, height) { + this.CreateG(true); + + var left = this.GetSelectIndex("x", "left", -1), + right = this.GetSelectIndex("x", "right", 1), + pmain = this.frame_painter(), + histo = this.GetHisto(), xaxis = histo.fXaxis, + i, x, grx, y, yerr, gry1, gry2, + bins1 = [], bins2 = []; + + for (i = left; i < right; ++i) { + x = xaxis.GetBinCoord(i+0.5); + if (pmain.logx && (x <= 0)) continue; + grx = Math.round(pmain.grx(x)); + + y = histo.getBinContent(i+1); + yerr = histo.getBinError(i+1); + if (pmain.logy && (y-yerr < pmain.scale_ymin)) continue; + + gry1 = Math.round(pmain.gry(y + yerr)); + gry2 = Math.round(pmain.gry(y - yerr)); + + bins1.push({ grx:grx, gry: gry1 }); + bins2.unshift({ grx:grx, gry: gry2 }); + } + + var kind = (this.options.ErrorKind === 4) ? "bezier" : "line", + path1 = JSROOT.Painter.BuildSvgPath(kind, bins1), + path2 = JSROOT.Painter.BuildSvgPath("L"+kind, bins2); + + this.draw_g.append("svg:path") + .attr("d", path1.path + path2.path + "Z") + .style("stroke", "none") + .call(this.fillatt.func); + } + + TH1Painter.prototype.DrawBins = function() { + // new method, create svg:path expression ourself directly from histogram + // all points will be used, compress expression when too large + + this.CheckHistDrawAttributes(); + + var width = this.frame_width(), height = this.frame_height(); + + if (!this.draw_content || (width<=0) || (height<=0)) + return this.RemoveDrawG(); + + if (this.options.Bar) + return this.DrawBars(width, height); + + if ((this.options.ErrorKind === 3) || (this.options.ErrorKind === 4)) + return this.DrawFilledErrors(width, height); + + var left = this.GetSelectIndex("x", "left", -1), + right = this.GetSelectIndex("x", "right", 2), + pmain = this.frame_painter(), + pad = this.root_pad(), + histo = this.GetHisto(), + xaxis = histo.fXaxis, + pthis = this, + res = "", lastbin = false, + startx, currx, curry, x, grx, y, gry, curry_min, curry_max, prevy, prevx, i, bestimin, bestimax, + exclude_zero = !this.options.Zero, + show_errors = this.options.Error, + show_markers = this.options.Mark, + show_line = this.options.Line || this.options.Curve, + show_text = this.options.Text, + text_profile = show_text && (this.options.TextKind == "E") && this.IsTProfile() && histo.fBinEntries, + path_fill = null, path_err = null, path_marker = null, path_line = null, + do_marker = false, do_err = false, + endx = "", endy = "", dend = 0, my, yerr1, yerr2, bincont, binerr, mx1, mx2, midx, mmx1, mmx2, + mpath = "", text_col, text_angle, text_size; + + if (show_errors && !show_markers && (histo.fMarkerStyle > 1)) + show_markers = true; + + if (this.options.ErrorKind === 2) { + if (this.fillatt.empty()) show_markers = true; + else path_fill = ""; + } else if (this.options.Error) { + path_err = ""; + do_err = true; + } + + if (show_line) path_line = ""; + + if (show_markers) { + // draw markers also when e2 option was specified + this.createAttMarker({ attr: histo, style: this.options.MarkStyle }); // when style not configured, it will be ignored + if (this.markeratt.size > 0) { + // simply use relative move from point, can optimize in the future + path_marker = ""; + do_marker = true; + this.markeratt.reset_pos(); + } else { + show_markers = false; + } + } + + var draw_markers = show_errors || show_markers, + draw_any_but_hist = draw_markers || show_text || show_line, + draw_hist = this.options.Hist && (!this.lineatt.empty() || !this.fillatt.empty()); + + if (!draw_hist && !draw_any_but_hist) + return this.RemoveDrawG(); + + this.CreateG(true); + + if (show_text) { + text_col = this.get_color(histo.fMarkerColor); + text_angle = -1*this.options.TextAngle; + text_size = 20; + + if ((histo.fMarkerSize!==1) && text_angle) + text_size = 0.02*height*histo.fMarkerSize; + + if (!text_angle && !this.options.TextKind) { + var space = width / (right - left + 1); + if (space < 3 * text_size) { + text_angle = 270; + text_size = Math.round(space*0.7); + } + } + + this.StartTextDrawing(42, text_size, this.draw_g, text_size); + } + + // if there are too many points, exclude many vertical drawings at the same X position + // instead define min and max value and made min-max drawing + var use_minmax = ((right-left) > 3*width); + + if (this.options.ErrorKind === 1) { + var lw = this.lineatt.width + JSROOT.gStyle.fEndErrorSize; + endx = "m0," + lw + "v-" + 2*lw + "m0," + lw; + endy = "m" + lw + ",0h-" + 2*lw + "m" + lw + ",0"; + dend = Math.floor((this.lineatt.width-1)/2); + } + + if (draw_any_but_hist) use_minmax = true; + + // just to get correct values for the specified bin + function extract_bin(bin) { + bincont = histo.getBinContent(bin+1); + if (exclude_zero && (bincont===0)) return false; + mx1 = Math.round(pmain.grx(xaxis.GetBinLowEdge(bin+1))); + mx2 = Math.round(pmain.grx(xaxis.GetBinLowEdge(bin+2))); + midx = Math.round((mx1+mx2)/2); + my = Math.round(pmain.gry(bincont)); + yerr1 = yerr2 = 20; + if (show_errors) { + binerr = histo.getBinError(bin+1); + yerr1 = Math.round(my - pmain.gry(bincont + binerr)); // up + yerr2 = Math.round(pmain.gry(bincont - binerr) - my); // down + } + return true; + } + + function draw_errbin(bin) { + if (pthis.options.errorX > 0) { + mmx1 = Math.round(midx - (mx2-mx1)*pthis.options.errorX); + mmx2 = Math.round(midx + (mx2-mx1)*pthis.options.errorX); + path_err += "M" + (mmx1+dend) +","+ my + endx + "h" + (mmx2-mmx1-2*dend) + endx; + } + path_err += "M" + midx +"," + (my-yerr1+dend) + endy + "v" + (yerr1+yerr2-2*dend) + endy; + } + + function draw_bin(bin) { + if (extract_bin(bin)) { + if (show_text) { + var cont = text_profile ? histo.fBinEntries[bin+1] : bincont; + + if (cont!==0) { + var lbl = (cont === Math.round(cont)) ? cont.toString() : JSROOT.FFormat(cont, JSROOT.gStyle.fPaintTextFormat); + + if (text_angle) + pthis.DrawText({ align: 12, x: midx, y: Math.round(my - 2 - text_size/5), width: 0, height: 0, rotate: text_angle, text: lbl, color: text_col, latex: 0 }); + else + pthis.DrawText({ align: 22, x: Math.round(mx1 + (mx2-mx1)*0.1), y: Math.round(my-2-text_size), width: Math.round((mx2-mx1)*0.8), height: text_size, text: lbl, color: text_col, latex: 0 }); + } + } + + if (show_line && (path_line !== null)) + path_line += ((path_line.length===0) ? "M" : "L") + midx + "," + my; + + if (draw_markers) { + if ((my >= -yerr1) && (my <= height + yerr2)) { + if (path_fill !== null) + path_fill += "M" + mx1 +","+(my-yerr1) + + "h" + (mx2-mx1) + "v" + (yerr1+yerr2+1) + "h-" + (mx2-mx1) + "z"; + if ((path_marker !== null) && do_marker) + path_marker += pthis.markeratt.create(midx, my); + if ((path_err !== null) && do_err) + draw_errbin(bin); + } + } + } + } + + // check if we should draw markers or error marks directly, skipping optimization + if (do_marker || do_err) + if (!JSROOT.gStyle.OptimizeDraw || ((right-left<50000) && (JSROOT.gStyle.OptimizeDraw==1))) { + for (i = left; i < right; ++i) { + if (extract_bin(i)) { + if (path_marker !== null) + path_marker += pthis.markeratt.create(midx, my); + if (path_err !== null) + draw_errbin(i); + } + } + do_err = do_marker = false; + } + + + for (i = left; i <= right; ++i) { + + x = xaxis.GetBinLowEdge(i+1); + + if (this.logx && (x <= 0)) continue; + + grx = Math.round(pmain.grx(x)); + + lastbin = (i === right); + + if (lastbin && (left<right)) { + gry = curry; + } else { + y = histo.getBinContent(i+1); + gry = Math.round(pmain.gry(y)); + } + + if (res.length === 0) { + bestimin = bestimax = i; + prevx = startx = currx = grx; + prevy = curry_min = curry_max = curry = gry; + res = "M"+currx+","+curry; + } else if (use_minmax) { + if ((grx === currx) && !lastbin) { + if (gry < curry_min) bestimax = i; else + if (gry > curry_max) bestimin = i; + + curry_min = Math.min(curry_min, gry); + curry_max = Math.max(curry_max, gry); + curry = gry; + } else { + + if (draw_any_but_hist) { + if (bestimin === bestimax) { draw_bin(bestimin); } else + if (bestimin < bestimax) { draw_bin(bestimin); draw_bin(bestimax); } else { + draw_bin(bestimax); draw_bin(bestimin); + } + } + + // when several points at same X differs, need complete logic + if (draw_hist && ((curry_min !== curry_max) || (prevy !== curry_min))) { + + if (prevx !== currx) + res += "h"+(currx-prevx); + + if (curry === curry_min) { + if (curry_max !== prevy) + res += "v" + (curry_max - prevy); + if (curry_min !== curry_max) + res += "v" + (curry_min - curry_max); + } else { + if (curry_min !== prevy) + res += "v" + (curry_min - prevy); + if (curry_max !== curry_min) + res += "v" + (curry_max - curry_min); + if (curry !== curry_max) + res += "v" + (curry - curry_max); + } + + prevx = currx; + prevy = curry; + } + + if (lastbin && (prevx !== grx)) + res += "h"+(grx-prevx); + + bestimin = bestimax = i; + curry_min = curry_max = curry = gry; + currx = grx; + } + // end of use_minmax + } else if ((gry !== curry) || lastbin) { + if (grx !== currx) res += "h"+(grx-currx); + if (gry !== curry) res += "v"+(gry-curry); + curry = gry; + currx = grx; + } + } + + var close_path = ""; + if (!this.fillatt.empty()) { + var h0 = height + 3, gry0 = Math.round(pmain.gry(0)); + if (gry0 <= 0) h0 = -3; else if (gry0 < height) h0 = gry0; + close_path = "L"+currx+","+h0 + "L"+startx+","+h0 + "Z"; + if (res.length>0) res += close_path; + } + + if (draw_markers || show_line) { + if ((path_fill !== null) && (path_fill.length > 0)) + this.draw_g.append("svg:path") + .attr("d", path_fill) + .call(this.fillatt.func); + + if ((path_err !== null) && (path_err.length > 0)) + this.draw_g.append("svg:path") + .attr("d", path_err) + .call(this.lineatt.func); + + if ((path_line !== null) && (path_line.length > 0)) { + if (!this.fillatt.empty()) + this.draw_g.append("svg:path") + .attr("d", this.options.Fill ? (path_line + close_path) : res) + .attr("stroke", "none") + .call(this.fillatt.func); + + this.draw_g.append("svg:path") + .attr("d", path_line) + .attr("fill", "none") + .call(this.lineatt.func); + } + + if ((path_marker !== null) && (path_marker.length > 0)) + this.draw_g.append("svg:path") + .attr("d", path_marker) + .call(this.markeratt.func); + + } + + if ((res.length > 0) && draw_hist) { + this.draw_g.append("svg:path") + .attr("d", res) + .style("stroke-linejoin","miter") + .call(this.lineatt.func) + .call(this.fillatt.func); + } + + if (show_text) + this.FinishTextDrawing(this.draw_g); + + } + + TH1Painter.prototype.GetBinTips = function(bin) { + var tips = [], + name = this.GetTipName(), + pmain = this.frame_painter(), + histo = this.GetHisto(), + x1 = histo.fXaxis.GetBinLowEdge(bin+1), + x2 = histo.fXaxis.GetBinLowEdge(bin+2), + cont = histo.getBinContent(bin+1), + xlbl = "", xnormal = false; + + if (name.length>0) tips.push(name); + + if (pmain.x_kind === 'labels') xlbl = pmain.AxisAsText("x", x1); else + if (pmain.x_kind === 'time') xlbl = pmain.AxisAsText("x", (x1+x2)/2); else + { xnormal = true; xlbl = "[" + pmain.AxisAsText("x", x1) + ", " + pmain.AxisAsText("x", x2) + ")"; } + + if (this.options.Error || this.options.Mark) { + tips.push("x = " + xlbl); + tips.push("y = " + pmain.AxisAsText("y", cont)); + if (this.options.Error) { + if (xnormal) tips.push("error x = " + ((x2 - x1) / 2).toPrecision(4)); + tips.push("error y = " + histo.getBinError(bin + 1).toPrecision(4)); + } + } else { + tips.push("bin = " + (bin+1)); + tips.push("x = " + xlbl); + if (histo['$baseh']) cont -= histo['$baseh'].getBinContent(bin+1); + if (cont === Math.round(cont)) + tips.push("entries = " + cont); + else + tips.push("entries = " + JSROOT.FFormat(cont, JSROOT.gStyle.fStatFormat)); + } + + return tips; + } + + TH1Painter.prototype.ProcessTooltip = function(pnt) { + if ((pnt === null) || !this.draw_content || !this.draw_g || this.options.Mode3D) { + if (this.draw_g !== null) + this.draw_g.select(".tooltip_bin").remove(); + return null; + } + + var width = this.frame_width(), + height = this.frame_height(), + pmain = this.frame_painter(), + pad = this.root_pad(), + painter = this, + histo = this.GetHisto(), + findbin = null, show_rect = true, + grx1, midx, grx2, gry1, midy, gry2, gapx = 2, + left = this.GetSelectIndex("x", "left", -1), + right = this.GetSelectIndex("x", "right", 2), + l = left, r = right, pnt_x = pnt.x, pnt_y = pnt.y; + + function GetBinGrX(i) { + var xx = histo.fXaxis.GetBinLowEdge(i+1); + return (pmain.logx && (xx<=0)) ? null : pmain.grx(xx); + } + + function GetBinGrY(i) { + var yy = histo.getBinContent(i + 1); + if (pmain.logy && (yy < pmain.scale_ymin)) + return pmain.swap_xy ? -1000 : 10*height; + return Math.round(pmain.gry(yy)); + } + + if (pmain.swap_xy) { + var d = pnt.x; pnt_x = pnt_y; pnt_y = d; + d = height; height = width; width = d; + } + + while (l < r-1) { + var m = Math.round((l+r)*0.5), xx = GetBinGrX(m); + if ((xx === null) || (xx < pnt_x - 0.5)) { + if (pmain.swap_xy) r = m; else l = m; + } else if (xx > pnt_x + 0.5) { + if (pmain.swap_xy) l = m; else r = m; + } else { l++; r--; } + } + + findbin = r = l; + grx1 = GetBinGrX(findbin); + + if (pmain.swap_xy) { + while ((l>left) && (GetBinGrX(l-1) < grx1 + 2)) --l; + while ((r<right) && (GetBinGrX(r+1) > grx1 - 2)) ++r; + } else { + while ((l>left) && (GetBinGrX(l-1) > grx1 - 2)) --l; + while ((r<right) && (GetBinGrX(r+1) < grx1 + 2)) ++r; + } + + if (l < r) { + // many points can be assigned with the same cursor position + // first try point around mouse y + var best = height; + for (var m=l;m<=r;m++) { + var dist = Math.abs(GetBinGrY(m) - pnt_y); + if (dist < best) { best = dist; findbin = m; } + } + + // if best distance still too far from mouse position, just take from between + if (best > height/10) + findbin = Math.round(l + (r-l) / height * pnt_y); + + grx1 = GetBinGrX(findbin); + } + + grx1 = Math.round(grx1); + grx2 = Math.round(GetBinGrX(findbin+1)); + + if (this.options.Bar) { + var w = grx2 - grx1; + grx1 += Math.round(histo.fBarOffset/1000*w); + grx2 = grx1 + Math.round(histo.fBarWidth/1000*w); + } + + if (grx1 > grx2) { var d = grx1; grx1 = grx2; grx2 = d; } + + midx = Math.round((grx1+grx2)/2); + + midy = gry1 = gry2 = GetBinGrY(findbin); + + if (this.options.Bar) { + show_rect = true; + + gapx = 0; + + gry1 = Math.round(pmain.gry(((this.options.BaseLine!==false) && (this.options.BaseLine > pmain.scale_ymin)) ? this.options.BaseLine : pmain.scale_ymin)); + + if (gry1 > gry2) { var d = gry1; gry1 = gry2; gry2 = d; } + + if (!pnt.touch && (pnt.nproc === 1)) + if ((pnt_y<gry1) || (pnt_y>gry2)) findbin = null; + + } else if (this.options.Error || this.options.Mark || this.options.Line || this.options.Curve) { + + show_rect = true; + + var msize = 3; + if (this.markeratt) msize = Math.max(msize, this.markeratt.GetFullSize()); + + if (this.options.Error) { + var cont = histo.getBinContent(findbin+1), + binerr = histo.getBinError(findbin+1); + + gry1 = Math.round(pmain.gry(cont + binerr)); // up + gry2 = Math.round(pmain.gry(cont - binerr)); // down + + if ((cont==0) && this.IsTProfile()) findbin = null; + + var dx = (grx2-grx1)*this.options.errorX; + grx1 = Math.round(midx - dx); + grx2 = Math.round(midx + dx); + } + + // show at least 6 pixels as tooltip rect + if (grx2 - grx1 < 2*msize) { grx1 = midx-msize; grx2 = midx+msize; } + + gry1 = Math.min(gry1, midy - msize); + gry2 = Math.max(gry2, midy + msize); + + if (!pnt.touch && (pnt.nproc === 1)) + if ((pnt_y<gry1) || (pnt_y>gry2)) findbin = null; + + } else { + + // if histogram alone, use old-style with rects + // if there are too many points at pixel, use circle + show_rect = (pnt.nproc === 1) && (right-left < width); + + if (show_rect) { + gry2 = height; + + if (!this.fillatt.empty()) { + gry2 = Math.round(pmain.gry(0)); + if (gry2 < 0) gry2 = 0; else if (gry2 > height) gry2 = height; + if (gry2 < gry1) { var d = gry1; gry1 = gry2; gry2 = d; } + } + + // for mouse events pointer should be between y1 and y2 + if (((pnt.y < gry1) || (pnt.y > gry2)) && !pnt.touch) findbin = null; + } + } + + if (findbin!==null) { + // if bin on boundary found, check that x position is ok + if ((findbin === left) && (grx1 > pnt_x + gapx)) findbin = null; else + if ((findbin === right-1) && (grx2 < pnt_x - gapx)) findbin = null; else + // if bars option used check that bar is not match + if ((pnt_x < grx1 - gapx) || (pnt_x > grx2 + gapx)) findbin = null; else + // exclude empty bin if empty bins suppressed + if (!this.options.Zero && (this.histo.getBinContent(findbin+1)===0)) findbin = null; + } + + var ttrect = this.draw_g.select(".tooltip_bin"); + + if ((findbin === null) || ((gry2 <= 0) || (gry1 >= height))) { + ttrect.remove(); + return null; + } + + var res = { name: histo.fName, title: histo.fTitle, + x: midx, y: midy, exact: true, + color1: this.lineatt ? this.lineatt.color : 'green', + color2: this.fillatt ? this.fillatt.fillcoloralt('blue') : 'blue', + lines: this.GetBinTips(findbin) }; + + if (pnt.disabled) { + // case when tooltip should not highlight bin + + ttrect.remove(); + res.changed = true; + } else + if (show_rect) { + + if (ttrect.empty()) + ttrect = this.draw_g.append("svg:rect") + .attr("class","tooltip_bin h1bin") + .style("pointer-events","none"); + + res.changed = ttrect.property("current_bin") !== findbin; + + if (res.changed) + ttrect.attr("x", pmain.swap_xy ? gry1 : grx1) + .attr("width", pmain.swap_xy ? gry2-gry1 : grx2-grx1) + .attr("y", pmain.swap_xy ? grx1 : gry1) + .attr("height", pmain.swap_xy ? grx2-grx1 : gry2-gry1) + .style("opacity", "0.3") + .property("current_bin", findbin); + + res.exact = (Math.abs(midy - pnt_y) <= 5) || ((pnt_y>=gry1) && (pnt_y<=gry2)); + + res.menu = true; // one could show context menu + // distance to middle point, use to decide which menu to activate + res.menu_dist = Math.sqrt((midx-pnt_x)*(midx-pnt_x) + (midy-pnt_y)*(midy-pnt_y)); + + } else { + var radius = this.lineatt.width + 3; + + if (ttrect.empty()) + ttrect = this.draw_g.append("svg:circle") + .attr("class","tooltip_bin") + .style("pointer-events","none") + .attr("r", radius) + .call(this.lineatt.func) + .call(this.fillatt.func); + + res.exact = (Math.abs(midx - pnt.x) <= radius) && (Math.abs(midy - pnt.y) <= radius); + + res.menu = res.exact; // show menu only when mouse pointer exactly over the histogram + res.menu_dist = Math.sqrt((midx-pnt.x)*(midx-pnt.x) + (midy-pnt.y)*(midy-pnt.y)); + + res.changed = ttrect.property("current_bin") !== findbin; + + if (res.changed) + ttrect.attr("cx", midx) + .attr("cy", midy) + .property("current_bin", findbin); + } + + if (res.changed) + res.user_info = { obj: this.histo, name: this.histo.fName, + bin: findbin, cont: this.histo.getBinContent(findbin+1), + grx: midx, gry: midy }; + + return res; + } + + + TH1Painter.prototype.FillHistContextMenu = function(menu) { + + menu.add("Auto zoom-in", this.AutoZoom); + + var sett = JSROOT.getDrawSettings("ROOT." + this.GetObject()._typename, 'nosame'); + + menu.addDrawMenu("Draw with", sett.opts, function(arg) { + if (arg==='inspect') + return JSROOT.draw(this.divid, this.GetObject(), arg); + + this.DecodeOptions(arg); + + if (this.options.need_fillcol && this.fillatt && this.fillatt.empty()) + this.fillatt.Change(5,1001); + + // redraw all objects in pad, inform dependent objects + this.InteractiveRedraw("pad", "drawopt"); + }); + } + + TH1Painter.prototype.AutoZoom = function() { + var left = this.GetSelectIndex("x", "left", -1), + right = this.GetSelectIndex("x", "right", 1), + dist = right - left, histo = this.GetHisto(); + + if ((dist == 0) || !histo) return; + + // first find minimum + var min = histo.getBinContent(left + 1); + for (var indx = left; indx < right; ++indx) + min = Math.min(min, histo.getBinContent(indx+1)); + if (min > 0) return; // if all points positive, no chance for autoscale + + while ((left < right) && (histo.getBinContent(left+1) <= min)) ++left; + while ((left < right) && (histo.getBinContent(right) <= min)) --right; + + // if singular bin + if ((left === right-1) && (left > 2) && (right < this.nbinsx-2)) { + --left; ++right; + } + + if ((right - left < dist) && (left < right)) + this.frame_painter().Zoom(histo.fXaxis.GetBinLowEdge(left+1), histo.fXaxis.GetBinLowEdge(right+1)); + } + + TH1Painter.prototype.CanZoomIn = function(axis,min,max) { + var histo = this.GetHisto(); + + if ((axis=="x") && histo && (histo.fXaxis.FindBin(max,0.5) - histo.fXaxis.FindBin(min,0) > 1)) return true; + + if ((axis=="y") && (Math.abs(max-min) > Math.abs(this.ymax-this.ymin)*1e-6)) return true; + + // check if it makes sense to zoom inside specified axis range + return false; + } + + TH1Painter.prototype.CallDrawFunc = function(callback, resize) { + + var main = this.main_painter(), + fp = this.frame_painter(); + + if ((main!==this) && fp && (fp.mode3d !== this.options.Mode3D)) + this.CopyOptionsFrom(main); + + var funcname = this.options.Mode3D ? "Draw3D" : "Draw2D"; + + this[funcname](callback, resize); + } + + TH1Painter.prototype.Draw2D = function(call_back) { + this.Clear3DScene(); + this.mode3d = false; + + this.ScanContent(true); + + this.CreateXY(); + + if (typeof this.DrawColorPalette === 'function') + this.DrawColorPalette(false); + + this.DrawAxes(); + this.DrawBins(); + this.DrawTitle(); + this.UpdateStatWebCanvas(); + this.AddInteractive(); + JSROOT.CallBack(call_back); + } + + TH1Painter.prototype.Draw3D = function(call_back, resize) { + this.mode3d = true; + JSROOT.AssertPrerequisites('hist3d', function() { + this.Draw3D(call_back, resize); + }.bind(this)); + } + + TH1Painter.prototype.Redraw = function(resize) { + this.CallDrawFunc(null, resize); + } + + function drawHistogram1D(divid, histo, opt) { + // create painter and add it to canvas + var painter = new TH1Painter(histo); + + painter.SetDivId(divid, 1); + + // here we deciding how histogram will look like and how will be shown + painter.DecodeOptions(opt); + + painter.CheckPadRange(!painter.options.Mode3D); + + painter.ScanContent(); + + painter.CreateStat(); // only when required + + painter.CallDrawFunc(function() { + painter.DrawNextFunction(0, function() { + if (!painter.options.Mode3D && painter.options.AutoZoom) painter.AutoZoom(); + painter.FillToolbar(); + painter.DrawingReady(); + }); + }); + + return painter; + } + + // ======================================================================== + + /** + * @summary Painter for TH2 classes + * + * @constructor + * @memberof JSROOT + * @augments JSROOT.THistPainter + * @param {object} histo - histogram object + */ + + function TH2Painter(histo) { + THistPainter.call(this, histo); + this.fContour = null; // contour levels + this.fCustomContour = false; // are this user-defined levels (can be irregular) + this.fPalette = null; + this.wheel_zoomy = true; + } + + TH2Painter.prototype = Object.create(THistPainter.prototype); + + TH2Painter.prototype.Cleanup = function() { + delete this.fCustomContour; + delete this.tt_handle; + + THistPainter.prototype.Cleanup.call(this); + } + + TH2Painter.prototype.ToggleProjection = function(kind, width) { + + if (kind=="Projections") kind = ""; + + if ((typeof kind == 'string') && (kind.length>1)) { + width = parseInt(kind.substr(1)); + kind = kind[0]; + } + + if (!width) width = 1; + + if (kind && (this.is_projection==kind)) { + if (this.projection_width === width) { + kind = ""; + } else { + this.projection_width = width; + return; + } + } + + delete this.proj_hist; + + this.is_projection = (this.is_projection === kind) ? "" : kind; + this.projection_width = width; + + var canp = this.canv_painter(); + if (canp) canp.ToggleProjection(this.is_projection, this.RedrawProjection.bind(this)); + } + + TH2Painter.prototype.RedrawProjection = function(ii1, ii2, jj1, jj2) { + + if (!this.is_projection) return; + + if (jj2 == undefined) { + if (!this.tt_handle) return; + ii1 = Math.round((this.tt_handle.i1 + this.tt_handle.i2)/2); ii2 = ii1+1; + jj1 = Math.round((this.tt_handle.j1 + this.tt_handle.j2)/2); jj2 = jj1+1; + } + + var canp = this.canv_painter(); + + if (canp && (this.snapid !== undefined)) { + // this is when projection should be created on the server side + var exec = "EXECANDSEND:D" + this.is_projection + "PROJ:" + this.snapid + ":"; + if (this.is_projection == "X") + exec += 'ProjectionX("_projx",' + (jj1+1) + ',' + jj2 + ',"")'; + else + exec += 'ProjectionY("_projy",' + (ii1+1) + ',' + ii2 + ',"")'; + canp.SendWebsocket(exec); + return; + } + + if (!this.proj_hist) { + if (this.is_projection == "X") { + this.proj_hist = JSROOT.CreateHistogram("TH1D", this.nbinsx); + JSROOT.extend(this.proj_hist.fXaxis, this.histo.fXaxis); + this.proj_hist.fName = "xproj"; + this.proj_hist.fTitle = "X projection"; + } else { + this.proj_hist = JSROOT.CreateHistogram("TH1D", this.nbinsy); + JSROOT.extend(this.proj_hist.fXaxis, this.histo.fYaxis); + this.proj_hist.fName = "yproj"; + this.proj_hist.fTitle = "Y projection"; + } + } + + if (this.is_projection == "X") { + for (var i=0;i<this.nbinsx;++i) { + var sum=0; + for (var j=jj1;j<jj2;++j) sum+=this.histo.getBinContent(i+1,j+1); + this.proj_hist.setBinContent(i+1, sum); + } + } else { + for (var j=0;j<this.nbinsy;++j) { + var sum = 0; + for (var i=ii1;i<ii2;++i) sum += this.histo.getBinContent(i+1,j+1); + this.proj_hist.setBinContent(j+1, sum); + } + } + + return canp.DrawProjection(this.is_projection, this.proj_hist); + } + + TH2Painter.prototype.ExecuteMenuCommand = function(method, args) { + if (THistPainter.prototype.ExecuteMenuCommand.call(this,method, args)) return true; + + if ((method.fName == 'SetShowProjectionX') || (method.fName == 'SetShowProjectionY')) { + this.ToggleProjection(method.fName[17], args && parseInt(args) ? parseInt(args) : 1); + return true; + } + + return false; + } + + TH2Painter.prototype.FillHistContextMenu = function(menu) { + // painter automatically bind to menu callbacks + + menu.add("sub:Projections", this.ToggleProjection); + var kind = this.is_projection || ""; + if (kind) kind += this.projection_width; + var kinds = ["X1", "X2", "X3", "X5", "X10", "Y1", "Y2", "Y3", "Y5", "Y10"]; + for (var k=0;k<kinds.length;++k) + menu.addchk(kind==kinds[k], kinds[k], kinds[k], this.ToggleProjection); + menu.add("endsub:"); + + menu.add("Auto zoom-in", this.AutoZoom); + + var sett = JSROOT.getDrawSettings("ROOT." + this.GetObject()._typename, 'nosame'); + + menu.addDrawMenu("Draw with", sett.opts, function(arg) { + if (arg==='inspect') + return JSROOT.draw(this.divid, this.GetObject(), arg); + this.DecodeOptions(arg); + this.InteractiveRedraw("pad", "drawopt"); + }); + + if (this.options.Color) + this.FillPaletteMenu(menu); + } + + TH2Painter.prototype.ButtonClick = function(funcname) { + if (THistPainter.prototype.ButtonClick.call(this, funcname)) return true; + + if (this !== this.main_painter()) return false; + + switch(funcname) { + case "ToggleColor": this.ToggleColor(); break; + case "ToggleColorZ": this.ToggleColz(); break; + case "Toggle3D": this.ToggleMode3D(); break; + default: return false; + } + + // all methods here should not be processed further + return true; + } + + TH2Painter.prototype.FillToolbar = function() { + THistPainter.prototype.FillToolbar.call(this, true); + + var pp = this.pad_painter(); + if (!pp) return; + + if (!this.IsTH2Poly()) + pp.AddButton(JSROOT.ToolbarIcons.th2color, "Toggle color", "ToggleColor"); + pp.AddButton(JSROOT.ToolbarIcons.th2colorz, "Toggle color palette", "ToggleColorZ"); + pp.AddButton(JSROOT.ToolbarIcons.th2draw3d, "Toggle 3D mode", "Toggle3D"); + pp.ShowButtons(); + } + + TH2Painter.prototype.ToggleColor = function() { + + if (this.options.Mode3D) { + this.options.Mode3D = false; + this.options.Color = true; + } else { + this.options.Color = !this.options.Color; + } + + this._can_move_colz = true; // indicate that next redraw can move Z scale + + this.CopyOptionsToOthers(); + + this.RedrawPad(); + + // this.DrawColorPalette(this.options.Color && this.options.Zscale); + } + + TH2Painter.prototype.AutoZoom = function() { + if (this.IsTH2Poly()) return; // not implemented + + var i1 = this.GetSelectIndex("x", "left", -1), + i2 = this.GetSelectIndex("x", "right", 1), + j1 = this.GetSelectIndex("y", "left", -1), + j2 = this.GetSelectIndex("y", "right", 1), + i,j, histo = this.GetObject(); + + if ((i1 == i2) || (j1 == j2)) return; + + // first find minimum + var min = histo.getBinContent(i1 + 1, j1 + 1); + for (i = i1; i < i2; ++i) + for (j = j1; j < j2; ++j) + min = Math.min(min, histo.getBinContent(i+1, j+1)); + if (min > 0) return; // if all points positive, no chance for autoscale + + var ileft = i2, iright = i1, jleft = j2, jright = j1; + + for (i = i1; i < i2; ++i) + for (j = j1; j < j2; ++j) + if (histo.getBinContent(i + 1, j + 1) > min) { + if (i < ileft) ileft = i; + if (i >= iright) iright = i + 1; + if (j < jleft) jleft = j; + if (j >= jright) jright = j + 1; + } + + var xmin, xmax, ymin, ymax, isany = false; + + if ((ileft === iright-1) && (ileft > i1+1) && (iright < i2-1)) { ileft--; iright++; } + if ((jleft === jright-1) && (jleft > j1+1) && (jright < j2-1)) { jleft--; jright++; } + + if ((ileft > i1 || iright < i2) && (ileft < iright - 1)) { + xmin = histo.fXaxis.GetBinLowEdge(ileft+1); + xmax = histo.fXaxis.GetBinLowEdge(iright+1); + isany = true; + } + + if ((jleft > j1 || jright < j2) && (jleft < jright - 1)) { + ymin = histo.fYaxis.GetBinLowEdge(jleft+1); + ymax = histo.fYaxis.GetBinLowEdge(jright+1); + isany = true; + } + + if (isany) + this.frame_painter().Zoom(xmin, xmax, ymin, ymax); + } + + TH2Painter.prototype.ScanContent = function(when_axis_changed) { + + // no need to rescan histogram while result does not depend from axis selection + if (when_axis_changed && this.nbinsx && this.nbinsy) return; + + var i, j, histo = this.GetObject(); + + this.nbinsx = histo.fXaxis.fNbins; + this.nbinsy = histo.fYaxis.fNbins; + + // used in CreateXY method + + this.CreateAxisFuncs(true); + + if (this.IsTH2Poly()) { + this.gminposbin = null; + this.gminbin = this.gmaxbin = 0; + + for (var n=0, len=histo.fBins.arr.length; n<len; ++n) { + var bin_content = histo.fBins.arr[n].fContent; + if (n===0) this.gminbin = this.gmaxbin = bin_content; + + if (bin_content < this.gminbin) this.gminbin = bin_content; else + if (bin_content > this.gmaxbin) this.gmaxbin = bin_content; + + if (bin_content > 0) + if ((this.gminposbin===null) || (this.gminposbin > bin_content)) this.gminposbin = bin_content; + } + } else { + // global min/max, used at the moment in 3D drawing + this.gminbin = this.gmaxbin = histo.getBinContent(1, 1); + this.gminposbin = null; + for (i = 0; i < this.nbinsx; ++i) { + for (j = 0; j < this.nbinsy; ++j) { + var bin_content = histo.getBinContent(i+1, j+1); + if (bin_content < this.gminbin) this.gminbin = bin_content; else + if (bin_content > this.gmaxbin) this.gmaxbin = bin_content; + if (bin_content > 0) + if ((this.gminposbin===null) || (this.gminposbin > bin_content)) this.gminposbin = bin_content; + } + } + } + + // this value used for logz scale drawing + if (this.gminposbin === null) this.gminposbin = this.gmaxbin*1e-4; + + if (this.options.Axis > 0) { // Paint histogram axis only + this.draw_content = false; + } else { + this.draw_content = (this.gmaxbin > 0); + if (!this.draw_content && this.options.Zero && this.IsTH2Poly()) { + this.draw_content = true; + this.options.Line = 1; + } + } + } + + TH2Painter.prototype.CountStat = function(cond) { + var histo = this.GetHisto(), xaxis = histo.fXaxis, yaxis = histo.fYaxis, + stat_sum0 = 0, stat_sumx1 = 0, stat_sumy1 = 0, + stat_sumx2 = 0, stat_sumy2 = 0, stat_sumxy = 0, + xside, yside, xx, yy, zz, + fp = this.frame_painter(), + res = { name: histo.fName, entries: 0, integral: 0, meanx: 0, meany: 0, rmsx: 0, rmsy: 0, matrix: [0,0,0,0,0,0,0,0,0], xmax: 0, ymax:0, wmax: null }; + + if (this.IsTH2Poly()) { + + var len = histo.fBins.arr.length, i, bin, n, gr, ngr, numgraphs, numpoints, + pmain = this.frame_painter(); + + for (i=0;i<len;++i) { + bin = histo.fBins.arr[i]; + + xside = 1; yside = 1; + + if (bin.fXmin > pmain.scale_xmax) xside = 2; else + if (bin.fXmax < pmain.scale_xmin) xside = 0; + if (bin.fYmin > pmain.scale_ymax) yside = 2; else + if (bin.fYmax < pmain.scale_ymin) yside = 0; + + xx = yy = numpoints = 0; + gr = bin.fPoly; numgraphs = 1; + if (gr._typename === 'TMultiGraph') { numgraphs = bin.fPoly.fGraphs.arr.length; gr = null; } + + for (ngr=0;ngr<numgraphs;++ngr) { + if (!gr || (ngr>0)) gr = bin.fPoly.fGraphs.arr[ngr]; + + for (n=0;n<gr.fNpoints;++n) { + ++numpoints; + xx += gr.fX[n]; + yy += gr.fY[n]; + } + } + + if (numpoints > 1) { + xx = xx / numpoints; + yy = yy / numpoints; + } + + zz = bin.fContent; + + res.entries += zz; + + res.matrix[yside * 3 + xside] += zz; + + if ((xside != 1) || (yside != 1)) continue; + + if (cond && !cond(xx,yy)) continue; + + if ((res.wmax===null) || (zz>res.wmax)) { res.wmax = zz; res.xmax = xx; res.ymax = yy; } + + stat_sum0 += zz; + stat_sumx1 += xx * zz; + stat_sumy1 += yy * zz; + stat_sumx2 += xx * xx * zz; + stat_sumy2 += yy * yy * zz; + stat_sumxy += xx * yy * zz; + } + } else { + var xleft = this.GetSelectIndex("x", "left"), + xright = this.GetSelectIndex("x", "right"), + yleft = this.GetSelectIndex("y", "left"), + yright = this.GetSelectIndex("y", "right"), + xi, yi; + + for (xi = 0; xi <= this.nbinsx + 1; ++xi) { + xside = (xi <= xleft) ? 0 : (xi > xright ? 2 : 1); + xx = xaxis.GetBinCoord(xi - 0.5); + + for (yi = 0; yi <= this.nbinsy + 1; ++yi) { + yside = (yi <= yleft) ? 0 : (yi > yright ? 2 : 1); + yy = yaxis.GetBinCoord(yi - 0.5); + + zz = histo.getBinContent(xi, yi); + + res.entries += zz; + + res.matrix[yside * 3 + xside] += zz; + + if ((xside != 1) || (yside != 1)) continue; + + if ((cond!=null) && !cond(xx,yy)) continue; + + if ((res.wmax===null) || (zz>res.wmax)) { res.wmax = zz; res.xmax = xx; res.ymax = yy; } + + stat_sum0 += zz; + stat_sumx1 += xx * zz; + stat_sumy1 += yy * zz; + stat_sumx2 += xx * xx * zz; + stat_sumy2 += yy * yy * zz; + stat_sumxy += xx * yy * zz; + } + } + } + + if (!fp.IsAxisZoomed("x") && !fp.IsAxisZoomed("y") && (histo.fTsumw > 0)) { + stat_sum0 = histo.fTsumw; + stat_sumx1 = histo.fTsumwx; + stat_sumx2 = histo.fTsumwx2; + stat_sumy1 = histo.fTsumwy; + stat_sumy2 = histo.fTsumwy2; + stat_sumxy = histo.fTsumwxy; + } + + if (stat_sum0 > 0) { + res.meanx = stat_sumx1 / stat_sum0; + res.meany = stat_sumy1 / stat_sum0; + res.rmsx = Math.sqrt(Math.abs(stat_sumx2 / stat_sum0 - res.meanx * res.meanx)); + res.rmsy = Math.sqrt(Math.abs(stat_sumy2 / stat_sum0 - res.meany * res.meany)); + } + + if (res.wmax===null) res.wmax = 0; + res.integral = stat_sum0; + + if (histo.fEntries > 1) res.entries = histo.fEntries; + + return res; + } + + TH2Painter.prototype.FillStatistic = function(stat, dostat, dofit) { + + // no need to refill statistic if histogram is dummy + if (this.IgnoreStatsFill()) return false; + + var data = this.CountStat(), + print_name = Math.floor(dostat % 10), + print_entries = Math.floor(dostat / 10) % 10, + print_mean = Math.floor(dostat / 100) % 10, + print_rms = Math.floor(dostat / 1000) % 10, + print_under = Math.floor(dostat / 10000) % 10, + print_over = Math.floor(dostat / 100000) % 10, + print_integral = Math.floor(dostat / 1000000) % 10, + print_skew = Math.floor(dostat / 10000000) % 10, + print_kurt = Math.floor(dostat / 100000000) % 10; + + stat.ClearPave(); + + if (print_name > 0) + stat.AddText(data.name); + + if (print_entries > 0) + stat.AddText("Entries = " + stat.Format(data.entries,"entries")); + + if (print_mean > 0) { + stat.AddText("Mean x = " + stat.Format(data.meanx)); + stat.AddText("Mean y = " + stat.Format(data.meany)); + } + + if (print_rms > 0) { + stat.AddText("Std Dev x = " + stat.Format(data.rmsx)); + stat.AddText("Std Dev y = " + stat.Format(data.rmsy)); + } + + if (print_integral > 0) + stat.AddText("Integral = " + stat.Format(data.matrix[4],"entries")); + + if (print_skew > 0) { + stat.AddText("Skewness x = <undef>"); + stat.AddText("Skewness y = <undef>"); + } + + if (print_kurt > 0) + stat.AddText("Kurt = <undef>"); + + if ((print_under > 0) || (print_over > 0)) { + var m = data.matrix; + + stat.AddText("" + m[6].toFixed(0) + " | " + m[7].toFixed(0) + " | " + m[7].toFixed(0)); + stat.AddText("" + m[3].toFixed(0) + " | " + m[4].toFixed(0) + " | " + m[5].toFixed(0)); + stat.AddText("" + m[0].toFixed(0) + " | " + m[1].toFixed(0) + " | " + m[2].toFixed(0)); + } + + if (dofit) stat.FillFunctionStat(this.FindFunction('TF1'), dofit); + + return true; + } + + TH2Painter.prototype.DrawBinsColor = function(w,h) { + var histo = this.GetHisto(), + handle = this.PrepareColorDraw(), + colPaths = [], currx = [], curry = [], + colindx, cmd1, cmd2, i, j, binz, x1, dx, y2, dy; + + // now start build + for (i = handle.i1; i < handle.i2; ++i) { + + dx = handle.grx[i+1] - handle.grx[i]; + x1 = Math.round(handle.grx[i] + dx*handle.xbar1); + dx = Math.round(dx*(handle.xbar2-handle.xbar1)); + + for (j = handle.j1; j < handle.j2; ++j) { + binz = histo.getBinContent(i + 1, j + 1); + colindx = this.getContourColor(binz, true); + if (binz===0) { + if (!this.options.Zero) continue; + if ((colindx === null) && this._show_empty_bins) colindx = 0; + } + if (colindx === null) continue; + + dy = handle.gry[j]-handle.gry[j+1]; + y2 = Math.round(handle.gry[j+1] + dy*handle.ybar1); + dy = Math.round(dy*(handle.ybar2-handle.ybar1)); + + cmd1 = "M"+x1+","+y2; + if (colPaths[colindx] === undefined) { + colPaths[colindx] = cmd1; + } else{ + cmd2 = "m" + (x1-currx[colindx]) + "," + (y2-curry[colindx]); + colPaths[colindx] += (cmd2.length < cmd1.length) ? cmd2 : cmd1; + } + + currx[colindx] = x1; + curry[colindx] = y2; + + colPaths[colindx] += "v"+dy + "h"+dx + "v"+(-dy) + "z"; + } + } + + for (colindx=0;colindx<colPaths.length;++colindx) + if (colPaths[colindx] !== undefined) + this.draw_g + .append("svg:path") + .attr("palette-index", colindx) + .attr("fill", this.fPalette.getColor(colindx)) + .attr("d", colPaths[colindx]); + + return handle; + } + + TH2Painter.prototype.BuildContour = function(handle, levels, palette, contour_func) { + var histo = this.GetObject(), ddd = 0, + painter = this, + kMAXCONTOUR = 2004, + kMAXCOUNT = 2000, + // arguments used in the PaintContourLine + xarr = new Float32Array(2*kMAXCONTOUR), + yarr = new Float32Array(2*kMAXCONTOUR), + itarr = new Int32Array(2*kMAXCONTOUR), + lj = 0, ipoly, poly, polys = [], np, npmax = 0, + x = [0.,0.,0.,0.], y = [0.,0.,0.,0.], zc = [0.,0.,0.,0.], ir = [0,0,0,0], + i, j, k, n, m, ix, ljfill, count, + xsave, ysave, itars, ix, jx; + + function BinarySearch(zc) { + for (var kk=0;kk<levels.length;++kk) + if (zc<levels[kk]) return kk-1; + return levels.length-1; + } + + function PaintContourLine(elev1, icont1, x1, y1, elev2, icont2, x2, y2) { + /* Double_t *xarr, Double_t *yarr, Int_t *itarr, Double_t *levels */ + var vert = (x1 === x2), + tlen = vert ? (y2 - y1) : (x2 - x1), + n = icont1 +1, + tdif = elev2 - elev1, + ii = lj-1, + maxii = kMAXCONTOUR/2 -3 + lj, + icount = 0, + xlen, pdif, diff, elev; + + while (n <= icont2 && ii <= maxii) { +// elev = fH->GetContourLevel(n); + elev = levels[n]; + diff = elev - elev1; + pdif = diff/tdif; + xlen = tlen*pdif; + if (vert) { + xarr[ii] = x1; + yarr[ii] = y1 + xlen; + } else { + xarr[ii] = x1 + xlen; + yarr[ii] = y1; + } + itarr[ii] = n; + icount++; + ii +=2; + n++; + } + return icount; + } + + var arrx = handle.original ? handle.origx : handle.grx, + arry = handle.original ? handle.origy : handle.gry; + + for (j = handle.j1; j < handle.j2-1; ++j) { + + y[1] = y[0] = (arry[j] + arry[j+1])/2; + y[3] = y[2] = (arry[j+1] + arry[j+2])/2; + + for (i = handle.i1; i < handle.i2-1; ++i) { + + zc[0] = histo.getBinContent(i+1, j+1); + zc[1] = histo.getBinContent(i+2, j+1); + zc[2] = histo.getBinContent(i+2, j+2); + zc[3] = histo.getBinContent(i+1, j+2); + + for (k=0;k<4;k++) + ir[k] = BinarySearch(zc[k]); + + if ((ir[0] !== ir[1]) || (ir[1] !== ir[2]) || (ir[2] !== ir[3]) || (ir[3] !== ir[0])) { + x[3] = x[0] = (arrx[i] + arrx[i+1])/2; + x[2] = x[1] = (arrx[i+1] + arrx[i+2])/2; + + if (zc[0] <= zc[1]) n = 0; else n = 1; + if (zc[2] <= zc[3]) m = 2; else m = 3; + if (zc[n] > zc[m]) n = m; + n++; + lj=1; + for (ix=1;ix<=4;ix++) { + m = n%4 + 1; + ljfill = PaintContourLine(zc[n-1],ir[n-1],x[n-1],y[n-1], + zc[m-1],ir[m-1],x[m-1],y[m-1]); + lj += 2*ljfill; + n = m; + } + + if (zc[0] <= zc[1]) n = 0; else n = 1; + if (zc[2] <= zc[3]) m = 2; else m = 3; + if (zc[n] > zc[m]) n = m; + n++; + lj=2; + for (ix=1;ix<=4;ix++) { + if (n == 1) m = 4; + else m = n-1; + ljfill = PaintContourLine(zc[n-1],ir[n-1],x[n-1],y[n-1], + zc[m-1],ir[m-1],x[m-1],y[m-1]); + lj += 2*ljfill; + n = m; + } + // Re-order endpoints + + count = 0; + for (ix=1; ix<=lj-5; ix +=2) { + //count = 0; + while (itarr[ix-1] != itarr[ix]) { + xsave = xarr[ix]; + ysave = yarr[ix]; + itars = itarr[ix]; + for (jx=ix; jx<=lj-5; jx +=2) { + xarr[jx] = xarr[jx+2]; + yarr[jx] = yarr[jx+2]; + itarr[jx] = itarr[jx+2]; + } + xarr[lj-3] = xsave; + yarr[lj-3] = ysave; + itarr[lj-3] = itars; + if (count > kMAXCOUNT) break; + count++; + } + } + + if (count > kMAXCOUNT) continue; + + for (ix=1; ix<=lj-2; ix +=2) { + + ipoly = itarr[ix-1]; + + if ((ipoly >= 0) && (ipoly < levels.length)) { + poly = polys[ipoly]; + if (!poly) + poly = polys[ipoly] = JSROOT.CreateTPolyLine(kMAXCONTOUR*4, true); + + np = poly.fLastPoint; + if (np < poly.fN-2) { + poly.fX[np+1] = Math.round(xarr[ix-1]); poly.fY[np+1] = Math.round(yarr[ix-1]); + poly.fX[np+2] = Math.round(xarr[ix]); poly.fY[np+2] = Math.round(yarr[ix]); + poly.fLastPoint = np+2; + npmax = Math.max(npmax, poly.fLastPoint+1); + } else { + // console.log('reject point??', poly.fLastPoint); + } + } + } + } // end of if (ir[0] + } // end of j + } // end of i + + var polysort = new Int32Array(levels.length), first = 0; + //find first positive contour + for (ipoly=0;ipoly<levels.length;ipoly++) { + if (levels[ipoly] >= 0) { first = ipoly; break; } + } + //store negative contours from 0 to minimum, then all positive contours + k = 0; + for (ipoly=first-1;ipoly>=0;ipoly--) {polysort[k] = ipoly; k++;} + for (ipoly=first;ipoly<levels.length;ipoly++) { polysort[k] = ipoly; k++;} + + var xp = new Float32Array(2*npmax), + yp = new Float32Array(2*npmax); + + for (k=0;k<levels.length;++k) { + + ipoly = polysort[k]; + poly = polys[ipoly]; + if (!poly) continue; + + var colindx = palette.calcColorIndex(ipoly, levels.length), + xx = poly.fX, yy = poly.fY, np = poly.fLastPoint+1, + istart = 0, iminus, iplus, xmin = 0, ymin = 0, nadd; + + while (true) { + + iminus = npmax; + iplus = iminus+1; + xp[iminus]= xx[istart]; yp[iminus] = yy[istart]; + xp[iplus] = xx[istart+1]; yp[iplus] = yy[istart+1]; + xx[istart] = xx[istart+1] = xmin; + yy[istart] = yy[istart+1] = ymin; + while (true) { + nadd = 0; + for (i=2;i<np;i+=2) { + if ((iplus < 2*npmax-1) && (xx[i] === xp[iplus]) && (yy[i] === yp[iplus])) { + iplus++; + xp[iplus] = xx[i+1]; yp[iplus] = yy[i+1]; + xx[i] = xx[i+1] = xmin; + yy[i] = yy[i+1] = ymin; + nadd++; + } + if ((iminus > 0) && (xx[i+1] === xp[iminus]) && (yy[i+1] === yp[iminus])) { + iminus--; + xp[iminus] = xx[i]; yp[iminus] = yy[i]; + xx[i] = xx[i+1] = xmin; + yy[i] = yy[i+1] = ymin; + nadd++; + } + } + if (nadd == 0) break; + } + + if ((iminus+1 < iplus) && (iminus>=0)) + contour_func(colindx, xp, yp, iminus, iplus, ipoly); + + istart = 0; + for (i=2;i<np;i+=2) { + if (xx[i] !== xmin && yy[i] !== ymin) { + istart = i; + break; + } + } + + if (istart === 0) break; + } + } + } + + TH2Painter.prototype.DrawBinsContour = function(frame_w,frame_h) { + var handle = this.PrepareColorDraw({ rounding: false, extra: 100, original: this.options.Proj != 0 }); + + // get levels + var levels = this.GetContour(), + palette = this.GetPalette(), + painter = this, main = this.frame_painter(); + + function BuildPath(xp,yp,iminus,iplus) { + var cmd = "", last = null, pnt = null, i; + for (i=iminus;i<=iplus;++i) { + pnt = null; + switch (main.projection) { + case 1: pnt = main.ProjectAitoff2xy(xp[i], yp[i]); break; + case 2: pnt = main.ProjectMercator2xy(xp[i], yp[i]); break; + case 3: pnt = main.ProjectSinusoidal2xy(xp[i], yp[i]); break; + case 4: pnt = main.ProjectParabolic2xy(xp[i], yp[i]); break; + } + if (pnt) { + pnt.x = main.grx(pnt.x); + pnt.y = main.gry(pnt.y); + } else { + pnt = { x: xp[i], y: yp[i] }; + } + pnt.x = Math.round(pnt.x); + pnt.y = Math.round(pnt.y); + if (!cmd) cmd = "M" + pnt.x + "," + pnt.y; + else if ((pnt.x != last.x) && (pnt.y != last.y)) cmd += "l" + (pnt.x - last.x) + "," + (pnt.y - last.y); + else if (pnt.x != last.x) cmd += "h" + (pnt.x - last.x); + else if (pnt.y != last.y) cmd += "v" + (pnt.y - last.y); + last = pnt; + } + return cmd; + } + + if (this.options.Contour===14) { + var dd = "M0,0h"+frame_w+"v"+frame_h+"h-"+frame_w; + if (this.options.Proj) { + var sz = handle.j2 - handle.j1, xd = new Float32Array(sz*2), yd = new Float32Array(sz*2); + for (var i=0;i<sz;++i) { + xd[i] = handle.origx[handle.i1]; + yd[i] = (handle.origy[handle.j1]*(i+0.5) + handle.origy[handle.j2]*(sz-0.5-i))/sz; + xd[i+sz] = handle.origx[handle.i2]; + yd[i+sz] = (handle.origy[handle.j2]*(i+0.5) + handle.origy[handle.j1]*(sz-0.5-i))/sz; + } + dd = BuildPath(xd,yd,0,2*sz-1); + } + + this.draw_g + .append("svg:path") + .attr("d", dd + "z") + .style('stroke','none') + .style("fill", palette.calcColor(0, levels.length)); + } + + this.BuildContour(handle, levels, palette, + function(colindx,xp,yp,iminus,iplus) { + var icol = palette.getColor(colindx), + fillcolor = icol, lineatt = null; + + switch (painter.options.Contour) { + case 1: break; + case 11: fillcolor = 'none'; lineatt = new JSROOT.TAttLineHandler({ color: icol } ); break; + case 12: fillcolor = 'none'; lineatt = new JSROOT.TAttLineHandler({ color: 1, style: (colindx%5 + 1), width: 1 }); break; + case 13: fillcolor = 'none'; lineatt = painter.lineatt; break; + case 14: break; + } + + var elem = painter.draw_g + .append("svg:path") + .attr("class","th2_contour") + .attr("d", BuildPath(xp,yp,iminus,iplus) + (fillcolor == 'none' ? "" : "z")) + .style("fill", fillcolor); + + if (lineatt!==null) + elem.call(lineatt.func); + else + elem.style('stroke','none'); + } + ); + + handle.hide_only_zeros = true; // text drawing suppress only zeros + + return handle; + } + + TH2Painter.prototype.CreatePolyBin = function(pmain, bin) { + var cmd = "", ngr, ngraphs = 1, gr = null; + + if (bin.fPoly._typename=='TMultiGraph') + ngraphs = bin.fPoly.fGraphs.arr.length; + else + gr = bin.fPoly; + + for (ngr = 0; ngr < ngraphs; ++ ngr) { + if (!gr || (ngr>0)) gr = bin.fPoly.fGraphs.arr[ngr]; + + var npnts = gr.fNpoints, n, + x = gr.fX, y = gr.fY, + grx = Math.round(pmain.grx(x[0])), + gry = Math.round(pmain.gry(y[0])), + nextx, nexty; + + if ((npnts>2) && (x[0]==x[npnts-1]) && (y[0]==y[npnts-1])) npnts--; + + cmd += "M"+grx+","+gry; + + for (n=1;n<npnts;++n) { + nextx = Math.round(pmain.grx(x[n])); + nexty = Math.round(pmain.gry(y[n])); + if ((grx!==nextx) || (gry!==nexty)) { + if (grx===nextx) cmd += "v" + (nexty - gry); else + if (gry===nexty) cmd += "h" + (nextx - grx); else + cmd += "l" + (nextx - grx) + "," + (nexty - gry); + } + grx = nextx; gry = nexty; + } + + cmd += "z"; + } + + return cmd; + } + + TH2Painter.prototype.DrawPolyBinsColor = function(w,h) { + var histo = this.GetObject(), + pmain = this.frame_painter(), + colPaths = [], textbins = [], + colindx, cmd, bin, item, + i, len = histo.fBins.arr.length; + + // force recalculations of contours + this.fContour = null; + this.fCustomContour = false; + + // use global coordinates + this.maxbin = this.gmaxbin; + this.minbin = this.gminbin; + this.minposbin = this.gminposbin; + + for (i = 0; i < len; ++ i) { + bin = histo.fBins.arr[i]; + colindx = this.getContourColor(bin.fContent, true); + if (colindx === null) continue; + if (bin.fContent === 0) { + if (!this.options.Zero || !this.options.Line) continue; + colindx = 0; // make dummy fill color to draw only line + } + + // check if bin outside visible range + if ((bin.fXmin > pmain.scale_xmax) || (bin.fXmax < pmain.scale_xmin) || + (bin.fYmin > pmain.scale_ymax) || (bin.fYmax < pmain.scale_ymin)) continue; + + cmd = this.CreatePolyBin(pmain, bin); + + if (colPaths[colindx] === undefined) + colPaths[colindx] = cmd; + else + colPaths[colindx] += cmd; + + if (this.options.Text && bin.fContent) textbins.push(bin); + } + + for (colindx=0;colindx<colPaths.length;++colindx) + if (colPaths[colindx]) { + item = this.draw_g + .append("svg:path") + .attr("palette-index", colindx) + .attr("fill", colindx ? this.fPalette.getColor(colindx) : 'none') + .attr("d", colPaths[colindx]); + if (this.options.Line) + item.call(this.lineatt.func); + } + + if (textbins.length > 0) { + var text_col = this.get_color(histo.fMarkerColor), + text_angle = -1*this.options.TextAngle, + text_g = this.draw_g.append("svg:g").attr("class","th2poly_text"), + text_size = 12; + + if ((histo.fMarkerSize!==1) && text_angle) + text_size = Math.round(0.02*h*histo.fMarkerSize); + + this.StartTextDrawing(42, text_size, text_g, text_size); + + for (i = 0; i < textbins.length; ++ i) { + bin = textbins[i]; + + var posx = Math.round(pmain.x((bin.fXmin + bin.fXmax)/2)), + posy = Math.round(pmain.y((bin.fYmin + bin.fYmax)/2)), + lbl = ""; + + if (!this.options.TextKind) { + lbl = (Math.round(bin.fContent) === bin.fContent) ? bin.fContent.toString() : + JSROOT.FFormat(bin.fContent, JSROOT.gStyle.fPaintTextFormat); + } else { + if (bin.fPoly) lbl = bin.fPoly.fName; + if (lbl === "Graph") lbl = ""; + if (!lbl) lbl = bin.fNumber; + } + + this.DrawText({ align: 22, x: posx, y: posy, rotate: text_angle, text: lbl, color: text_col, latex: 0, draw_g: text_g }); + } + + this.FinishTextDrawing(text_g, null); + } + + return { poly: true }; + } + + TH2Painter.prototype.DrawBinsText = function(w, h, handle) { + var histo = this.GetObject(), + i,j,binz,colindx,binw,binh,lbl,posx,posy,sizex,sizey, + text_col = this.get_color(histo.fMarkerColor), + text_angle = -1*this.options.TextAngle, + text_g = this.draw_g.append("svg:g").attr("class","th2_text"), + text_size = 20, text_offset = 0, + profile2d = (this.options.TextKind == "E") && this.MatchObjectType('TProfile2D') && (typeof histo.getBinEntries=='function'); + + if (handle===null) handle = this.PrepareColorDraw({ rounding: false }); + + if ((histo.fMarkerSize!==1) && text_angle) + text_size = Math.round(0.02*h*histo.fMarkerSize); + + if (histo.fBarOffset!==0) text_offset = histo.fBarOffset*1e-3; + + this.StartTextDrawing(42, text_size, text_g, text_size); + + for (i = handle.i1; i < handle.i2; ++i) + for (j = handle.j1; j < handle.j2; ++j) { + binz = histo.getBinContent(i+1, j+1); + if ((binz === 0) && !this._show_empty_bins) continue; + + binw = handle.grx[i+1] - handle.grx[i]; + binh = handle.gry[j] - handle.gry[j+1]; + + if (profile2d) + binz = histo.getBinEntries(i+1, j+1); + + lbl = (binz === Math.round(binz)) ? binz.toString() : + JSROOT.FFormat(binz, JSROOT.gStyle.fPaintTextFormat); + + if (text_angle /*|| (histo.fMarkerSize!==1)*/) { + posx = Math.round(handle.grx[i] + binw*0.5); + posy = Math.round(handle.gry[j+1] + binh*(0.5 + text_offset)); + sizex = 0; + sizey = 0; + } else { + posx = Math.round(handle.grx[i] + binw*0.1); + posy = Math.round(handle.gry[j+1] + binh*(0.1 + text_offset)); + sizex = Math.round(binw*0.8); + sizey = Math.round(binh*0.8); + } + + this.DrawText({ align: 22, x: posx, y: posy, width: sizex, height: sizey, rotate: text_angle, text: lbl, color: text_col, latex: 0, draw_g: text_g }); + } + + this.FinishTextDrawing(text_g, null); + + handle.hide_only_zeros = true; // text drawing suppress only zeros + + return handle; + } + + TH2Painter.prototype.DrawBinsArrow = function(w, h) { + var histo = this.GetObject(), cmd = "", + i,j,binz,colindx,binw,binh,lbl, loop, dn = 1e-30, dx, dy, xc,yc, + dxn,dyn,x1,x2,y1,y2, anr,si,co, + handle = this.PrepareColorDraw({ rounding: false }), + scale_x = (handle.grx[handle.i2] - handle.grx[handle.i1])/(handle.i2 - handle.i1 + 1-0.03)/2, + scale_y = (handle.gry[handle.j2] - handle.gry[handle.j1])/(handle.j2 - handle.j1 + 1-0.03)/2; + + for (var loop=0;loop<2;++loop) + for (i = handle.i1; i < handle.i2; ++i) + for (j = handle.j1; j < handle.j2; ++j) { + + if (i === handle.i1) { + dx = histo.getBinContent(i+2, j+1) - histo.getBinContent(i+1, j+1); + } else if (i === handle.i2-1) { + dx = histo.getBinContent(i+1, j+1) - histo.getBinContent(i, j+1); + } else { + dx = 0.5*(histo.getBinContent(i+2, j+1) - histo.getBinContent(i, j+1)); + } + if (j === handle.j1) { + dy = histo.getBinContent(i+1, j+2) - histo.getBinContent(i+1, j+1); + } else if (j === handle.j2-1) { + dy = histo.getBinContent(i+1, j+1) - histo.getBinContent(i+1, j); + } else { + dy = 0.5*(histo.getBinContent(i+1, j+2) - histo.getBinContent(i+1, j)); + } + + if (loop===0) { + dn = Math.max(dn, Math.abs(dx), Math.abs(dy)); + } else { + xc = (handle.grx[i] + handle.grx[i+1])/2; + yc = (handle.gry[j] + handle.gry[j+1])/2; + dxn = scale_x*dx/dn; + dyn = scale_y*dy/dn; + x1 = xc - dxn; + x2 = xc + dxn; + y1 = yc - dyn; + y2 = yc + dyn; + dx = Math.round(x2-x1); + dy = Math.round(y2-y1); + + if ((dx!==0) || (dy!==0)) { + cmd += "M"+Math.round(x1)+","+Math.round(y1)+"l"+dx+","+dy; + + if (Math.abs(dx) > 5 || Math.abs(dy) > 5) { + anr = Math.sqrt(2/(dx*dx + dy*dy)); + si = Math.round(anr*(dx + dy)); + co = Math.round(anr*(dx - dy)); + if ((si!==0) && (co!==0)) + cmd+="l"+(-si)+","+co + "m"+si+","+(-co) + "l"+(-co)+","+(-si); + } + } + } + } + + this.draw_g + .append("svg:path") + .attr("class","th2_arrows") + .attr("d", cmd) + .style("fill", "none") + .call(this.lineatt.func); + + return handle; + } + + + TH2Painter.prototype.DrawBinsBox = function(w,h) { + + var histo = this.GetObject(), + handle = this.PrepareColorDraw({ rounding: false }), + main = this.main_painter(); + + if (main===this) { + if (main.maxbin === main.minbin) { + main.maxbin = main.gmaxbin; + main.minbin = main.gminbin; + main.minposbin = main.gminposbin; + } + if (main.maxbin === main.minbin) + main.minbin = Math.min(0, main.maxbin-1); + } + + var absmax = Math.max(Math.abs(main.maxbin), Math.abs(main.minbin)), + absmin = Math.max(0, main.minbin), + i, j, binz, absz, res = "", cross = "", btn1 = "", btn2 = "", + colindx, zdiff, dgrx, dgry, xx, yy, ww, hh, cmd1, cmd2, + xyfactor = 1, uselogz = false, logmin = 0, logmax = 1; + + if (this.root_pad().fLogz && (absmax>0)) { + uselogz = true; + logmax = Math.log(absmax); + if (absmin>0) logmin = Math.log(absmin); else + if ((main.minposbin>=1) && (main.minposbin<100)) logmin = Math.log(0.7); else + logmin = (main.minposbin > 0) ? Math.log(0.7*main.minposbin) : logmax - 10; + if (logmin >= logmax) logmin = logmax - 10; + xyfactor = 1. / (logmax - logmin); + } else { + xyfactor = 1. / (absmax - absmin); + } + + // now start build + for (i = handle.i1; i < handle.i2; ++i) { + for (j = handle.j1; j < handle.j2; ++j) { + binz = histo.getBinContent(i + 1, j + 1); + absz = Math.abs(binz); + if ((absz === 0) || (absz < absmin)) continue; + + zdiff = uselogz ? ((absz>0) ? Math.log(absz) - logmin : 0) : (absz - absmin); + // area of the box should be proportional to absolute bin content + zdiff = 0.5 * ((zdiff < 0) ? 1 : (1 - Math.sqrt(zdiff * xyfactor))); + // avoid oversized bins + if (zdiff < 0) zdiff = 0; + + ww = handle.grx[i+1] - handle.grx[i]; + hh = handle.gry[j] - handle.gry[j+1]; + + dgrx = zdiff * ww; + dgry = zdiff * hh; + + xx = Math.round(handle.grx[i] + dgrx); + yy = Math.round(handle.gry[j+1] + dgry); + + ww = Math.max(Math.round(ww - 2*dgrx), 1); + hh = Math.max(Math.round(hh - 2*dgry), 1); + + res += "M"+xx+","+yy + "v"+hh + "h"+ww + "v-"+hh + "z"; + + if ((binz<0) && (this.options.BoxStyle === 10)) + cross += "M"+xx+","+yy + "l"+ww+","+hh + "M"+(xx+ww)+","+yy + "l-"+ww+","+hh; + + if ((this.options.BoxStyle === 11) && (ww>5) && (hh>5)) { + var pww = Math.round(ww*0.1), + phh = Math.round(hh*0.1), + side1 = "M"+xx+","+yy + "h"+ww + "l"+(-pww)+","+phh + "h"+(2*pww-ww) + + "v"+(hh-2*phh)+ "l"+(-pww)+","+phh + "z", + side2 = "M"+(xx+ww)+","+(yy+hh) + "v"+(-hh) + "l"+(-pww)+","+phh + "v"+(hh-2*phh)+ + "h"+(2*pww-ww) + "l"+(-pww)+","+phh + "z"; + if (binz<0) { btn2+=side1; btn1+=side2; } + else { btn1+=side1; btn2+=side2; } + } + } + } + + if (res.length > 0) { + var elem = this.draw_g.append("svg:path") + .attr("d", res) + .call(this.fillatt.func); + if ((this.options.BoxStyle === 11) || !this.fillatt.empty()) + elem.style('stroke','none'); + else + elem.call(this.lineatt.func); + } + + if ((btn1.length>0) && (this.fillatt.color !== 'none')) + this.draw_g.append("svg:path") + .attr("d", btn1) + .style("stroke","none") + .call(this.fillatt.func) + .style("fill", d3.rgb(this.fillatt.color).brighter(0.5).toString()); + + if (btn2.length>0) + this.draw_g.append("svg:path") + .attr("d", btn2) + .style("stroke","none") + .call(this.fillatt.func) + .style("fill", this.fillatt.color === 'none' ? 'red' : d3.rgb(this.fillatt.color).darker(0.5).toString()); + + if (cross.length > 0) { + var elem = this.draw_g.append("svg:path") + .attr("d", cross) + .style("fill", "none"); + if (this.lineatt.color !== 'none') + elem.call(this.lineatt.func); + else + elem.style('stroke','black'); + } + + return handle; + } + + TH2Painter.prototype.DrawCandle = function(w,h) { + var histo = this.GetHisto(), + handle = this.PrepareColorDraw(), + pmain = this.frame_painter(), // used for axis values conversions + i, j, y, sum0, sum1, sum2, cont, center, counter, integral, w, pnt, + bars = "", markers = "", posy; + + if (histo.fMarkerColor === 1) histo.fMarkerColor = histo.fLineColor; + + // create attribute only when necessary + this.createAttMarker({ attr: histo, style: 5 }); + + // reset absolution position for markers + this.markeratt.reset_pos(); + + handle.candle = []; // array of drawn points + + // loop over visible x-bins + for (i = handle.i1; i < handle.i2; ++i) { + sum1 = 0; + //estimate integral + integral = 0; + counter = 0; + for (j = 0; j < this.nbinsy; ++j) { + integral += histo.getBinContent(i+1,j+1); + } + pnt = { bin:i, meany:0, m25y:0, p25y:0, median:0, iqr:0, whiskerp:0, whiskerm:0}; + //estimate quantiles... simple function... not so nice as GetQuantiles + for (j = 0; j < this.nbinsy; ++j) { + cont = histo.getBinContent(i+1,j+1); + posy = histo.fYaxis.GetBinCenter(j+1); + if (counter/integral < 0.001 && (counter + cont)/integral >=0.001) pnt.whiskerm = posy; // Lower whisker + if (counter/integral < 0.25 && (counter + cont)/integral >=0.25) pnt.m25y = posy; // Lower edge of box + if (counter/integral < 0.5 && (counter + cont)/integral >=0.5) pnt.median = posy; //Median + if (counter/integral < 0.75 && (counter + cont)/integral >=0.75) pnt.p25y = posy; //Upper edge of box + if (counter/integral < 0.999 && (counter + cont)/integral >=0.999) pnt.whiskerp = posy; // Upper whisker + counter += cont; + y = posy; // center of y bin coordinate + sum1 += cont*y; + } + if (counter > 0) { + pnt.meany = sum1/counter; + } + pnt.iqr = pnt.p25y-pnt.m25y; + + //Whiskers cannot exceed 1.5*iqr from box + if ((pnt.m25y-1.5*pnt.iqr) > pnt.whsikerm) { + pnt.whiskerm = pnt.m25y-1.5*pnt.iqr; + } + if ((pnt.p25y+1.5*pnt.iqr) < pnt.whiskerp) { + pnt.whiskerp = pnt.p25y+1.5*pnt.iqr; + } + + // exclude points with negative y when log scale is specified + if (pmain.logy && (pnt.whiskerm<=0)) continue; + + w = handle.grx[i+1] - handle.grx[i]; + w *= 0.66; + center = (handle.grx[i+1] + handle.grx[i]) / 2 + histo.fBarOffset/1000*w; + if (histo.fBarWidth>0) w = w * histo.fBarWidth / 1000; + + pnt.x1 = Math.round(center - w/2); + pnt.x2 = Math.round(center + w/2); + center = Math.round(center); + + pnt.y0 = Math.round(pmain.gry(pnt.median)); + // mean line + bars += "M" + pnt.x1 + "," + pnt.y0 + "h" + (pnt.x2-pnt.x1); + + pnt.y1 = Math.round(pmain.gry(pnt.p25y)); + pnt.y2 = Math.round(pmain.gry(pnt.m25y)); + + // rectangle + bars += "M" + pnt.x1 + "," + pnt.y1 + + "v" + (pnt.y2-pnt.y1) + "h" + (pnt.x2-pnt.x1) + "v-" + (pnt.y2-pnt.y1) + "z"; + + pnt.yy1 = Math.round(pmain.gry(pnt.whiskerp)); + pnt.yy2 = Math.round(pmain.gry(pnt.whiskerm)); + + // upper part + bars += "M" + center + "," + pnt.y1 + "v" + (pnt.yy1-pnt.y1); + bars += "M" + pnt.x1 + "," + pnt.yy1 + "h" + (pnt.x2-pnt.x1); + + // lower part + bars += "M" + center + "," + pnt.y2 + "v" + (pnt.yy2-pnt.y2); + bars += "M" + pnt.x1 + "," + pnt.yy2 + "h" + (pnt.x2-pnt.x1); + + //estimate outliers + for (j = 0; j < this.nbinsy; ++j) { + cont = histo.getBinContent(i+1,j+1); + posy = histo.fYaxis.GetBinCenter(j+1); + if (cont > 0 && posy < pnt.whiskerm) markers += this.markeratt.create(center, posy); + if (cont > 0 && posy > pnt.whiskerp) markers += this.markeratt.create(center, posy); + } + + handle.candle.push(pnt); // keep point for the tooltip + } + + if (bars.length > 0) + this.draw_g.append("svg:path") + .attr("d", bars) + .call(this.lineatt.func) + .call(this.fillatt.func); + + if (markers.length > 0) + this.draw_g.append("svg:path") + .attr("d", markers) + .call(this.markeratt.func); + + return handle; + } + + TH2Painter.prototype.DrawBinsScatter = function(w,h) { + var histo = this.GetObject(), + handle = this.PrepareColorDraw({ rounding: true, pixel_density: true }), + colPaths = [], currx = [], curry = [], cell_w = [], cell_h = [], + colindx, cmd1, cmd2, i, j, binz, cw, ch, factor = 1., + scale = this.options.ScatCoef * ((this.gmaxbin) > 2000 ? 2000. / this.gmaxbin : 1.); + + JSROOT.seed(handle.sumz); + + if (scale*handle.sumz < 1e5) { + // one can use direct drawing of scatter plot without any patterns + + this.createAttMarker({ attr: histo }); + + this.markeratt.reset_pos(); + + var path = "", k, npix; + for (i = handle.i1; i < handle.i2; ++i) { + cw = handle.grx[i+1] - handle.grx[i]; + for (j = handle.j1; j < handle.j2; ++j) { + ch = handle.gry[j] - handle.gry[j+1]; + binz = histo.getBinContent(i + 1, j + 1); + + npix = Math.round(scale*binz); + if (npix<=0) continue; + + for (k=0;k<npix;++k) + path += this.markeratt.create( + Math.round(handle.grx[i] + cw * JSROOT.random()), + Math.round(handle.gry[j+1] + ch * JSROOT.random())); + } + } + + this.draw_g + .append("svg:path") + .attr("d", path) + .call(this.markeratt.func); + + return handle; + } + + // limit filling factor, do not try to produce as many points as filled area; + if (this.maxbin > 0.7) factor = 0.7/this.maxbin; + + var nlevels = Math.round(handle.max - handle.min); + this.CreateContour((nlevels > 50) ? 50 : nlevels, this.minposbin, this.maxbin, this.minposbin); + + // now start build + for (i = handle.i1; i < handle.i2; ++i) { + for (j = handle.j1; j < handle.j2; ++j) { + binz = histo.getBinContent(i + 1, j + 1); + if ((binz <= 0) || (binz < this.minbin)) continue; + + cw = handle.grx[i+1] - handle.grx[i]; + ch = handle.gry[j] - handle.gry[j+1]; + if (cw*ch <= 0) continue; + + colindx = this.getContourIndex(binz/cw/ch); + if (colindx < 0) continue; + + cmd1 = "M"+handle.grx[i]+","+handle.gry[j+1]; + if (colPaths[colindx] === undefined) { + colPaths[colindx] = cmd1; + cell_w[colindx] = cw; + cell_h[colindx] = ch; + } else{ + cmd2 = "m" + (handle.grx[i]-currx[colindx]) + "," + (handle.gry[j+1] - curry[colindx]); + colPaths[colindx] += (cmd2.length < cmd1.length) ? cmd2 : cmd1; + cell_w[colindx] = Math.max(cell_w[colindx], cw); + cell_h[colindx] = Math.max(cell_h[colindx], ch); + } + + currx[colindx] = handle.grx[i]; + curry[colindx] = handle.gry[j+1]; + + colPaths[colindx] += "v"+ch+"h"+cw+"v-"+ch+"z"; + } + } + + var layer = this.svg_frame().select('.main_layer'), + defs = layer.select("defs"); + if (defs.empty() && (colPaths.length>0)) + defs = layer.insert("svg:defs",":first-child"); + + this.createAttMarker({ attr: histo }); + + for (colindx=0;colindx<colPaths.length;++colindx) + if ((colPaths[colindx] !== undefined) && (colindx<this.fContour.length)) { + var pattern_class = "scatter_" + colindx, + pattern = defs.select('.' + pattern_class); + if (pattern.empty()) + pattern = defs.append('svg:pattern') + .attr("class", pattern_class) + .attr("id", "jsroot_scatter_pattern_" + JSROOT.id_counter++) + .attr("patternUnits","userSpaceOnUse"); + else + pattern.selectAll("*").remove(); + + var npix = Math.round(factor*this.fContour[colindx]*cell_w[colindx]*cell_h[colindx]); + if (npix<1) npix = 1; + + var arrx = new Float32Array(npix), arry = new Float32Array(npix); + + if (npix===1) { + arrx[0] = arry[0] = 0.5; + } else { + for (var n=0;n<npix;++n) { + arrx[n] = JSROOT.random(); + arry[n] = JSROOT.random(); + } + } + + // arrx.sort(); + + this.markeratt.reset_pos(); + + var path = ""; + + for (var n=0;n<npix;++n) + path += this.markeratt.create(arrx[n] * cell_w[colindx], arry[n] * cell_h[colindx]); + + pattern.attr("width", cell_w[colindx]) + .attr("height", cell_h[colindx]) + .append("svg:path") + .attr("d",path) + .call(this.markeratt.func); + + this.draw_g + .append("svg:path") + .attr("scatter-index", colindx) + .attr("fill", 'url(#' + pattern.attr("id") + ')') + .attr("d", colPaths[colindx]); + } + + return handle; + } + + TH2Painter.prototype.DrawBins = function() { + + if (!this.draw_content) + return this.RemoveDrawG(); + + this.CheckHistDrawAttributes(); + + this.CreateG(true); + + var w = this.frame_width(), + h = this.frame_height(), + handle = null; + + if (this.IsTH2Poly()) + handle = this.DrawPolyBinsColor(w, h); + else if (this.options.Scat) + handle = this.DrawBinsScatter(w, h); + else if (this.options.Color) + handle = this.DrawBinsColor(w, h); + else if (this.options.Box) + handle = this.DrawBinsBox(w, h); + else if (this.options.Arrow) + handle = this.DrawBinsArrow(w, h); + else if (this.options.Contour) + handle = this.DrawBinsContour(w, h); + else if (this.options.Candle) + handle = this.DrawCandle(w, h); + + if (this.options.Text) + handle = this.DrawBinsText(w, h, handle); + + if (!handle) + handle = this.DrawBinsScatter(w, h); + + this.tt_handle = handle; + } + + TH2Painter.prototype.GetBinTips = function (i, j) { + var lines = [], pmain = this.frame_painter(), + histo = this.GetHisto(), + binz = histo.getBinContent(i+1,j+1) + + lines.push(this.GetTipName()); + + if (pmain.x_kind == 'labels') + lines.push("x = " + pmain.AxisAsText("x", histo.fXaxis.GetBinLowEdge(i+1))); + else + lines.push("x = [" + pmain.AxisAsText("x", histo.fXaxis.GetBinLowEdge(i+1)) + ", " + pmain.AxisAsText("x", histo.fXaxis.GetBinLowEdge(i+2)) + ")"); + + if (pmain.y_kind == 'labels') + lines.push("y = " + pmain.AxisAsText("y", histo.fYaxis.GetBinLowEdge(j+1))); + else + lines.push("y = [" + pmain.AxisAsText("y", histo.fYaxis.GetBinLowEdge(j+1)) + ", " + pmain.AxisAsText("y", histo.fYaxis.GetBinLowEdge(j+2)) + ")"); + + lines.push("bin = " + i + ", " + j); + + if (histo.$baseh) binz -= histo.$baseh.getBinContent(i+1,j+1); + + if (binz === Math.round(binz)) + lines.push("entries = " + binz); + else + lines.push("entries = " + JSROOT.FFormat(binz, JSROOT.gStyle.fStatFormat)); + + return lines; + } + + TH2Painter.prototype.GetCandleTips = function(p) { + var lines = [], main = this.frame_painter(), histo = this.GetHisto(); + + lines.push(this.GetTipName()); + + lines.push("x = " + main.AxisAsText("x", histo.fXaxis.GetBinLowEdge(p.bin+1))); + + lines.push('mean y = ' + JSROOT.FFormat(p.meany, JSROOT.gStyle.fStatFormat)) + lines.push('m25 = ' + JSROOT.FFormat(p.m25y, JSROOT.gStyle.fStatFormat)) + lines.push('p25 = ' + JSROOT.FFormat(p.p25y, JSROOT.gStyle.fStatFormat)) + + return lines; + } + + TH2Painter.prototype.ProvidePolyBinHints = function(binindx, realx, realy) { + + var histo = this.GetHisto(), + bin = histo.fBins.arr[binindx], + pmain = this.frame_painter(), + binname = bin.fPoly.fName, + lines = [], numpoints = 0; + + if (binname === "Graph") binname = ""; + if (binname.length === 0) binname = bin.fNumber; + + if ((realx===undefined) && (realy===undefined)) { + realx = realy = 0; + var gr = bin.fPoly, numgraphs = 1; + if (gr._typename === 'TMultiGraph') { numgraphs = bin.fPoly.fGraphs.arr.length; gr = null; } + + for (var ngr=0;ngr<numgraphs;++ngr) { + if (!gr || (ngr>0)) gr = bin.fPoly.fGraphs.arr[ngr]; + + for (var n=0;n<gr.fNpoints;++n) { + ++numpoints; + realx += gr.fX[n]; + realy += gr.fY[n]; + } + } + + if (numpoints > 1) { + realx = realx / numpoints; + realy = realy / numpoints; + } + } + + lines.push(this.GetTipName()); + lines.push("x = " + pmain.AxisAsText("x", realx)); + lines.push("y = " + pmain.AxisAsText("y", realy)); + if (numpoints > 0) lines.push("npnts = " + numpoints); + lines.push("bin = " + binname); + if (bin.fContent === Math.round(bin.fContent)) + lines.push("content = " + bin.fContent); + else + lines.push("content = " + JSROOT.FFormat(bin.fContent, JSROOT.gStyle.fStatFormat)); + return lines; + } + + TH2Painter.prototype.ProcessTooltip = function(pnt) { + if (!pnt || !this.draw_content || !this.draw_g || !this.tt_handle || this.options.Proj) { + if (this.draw_g !== null) + this.draw_g.select(".tooltip_bin").remove(); + return null; + } + + var histo = this.GetHisto(), + h = this.tt_handle, + ttrect = this.draw_g.select(".tooltip_bin"); + + if (h.poly) { + // process tooltips from TH2Poly + + var pmain = this.frame_painter(), + realx, realy, foundindx = -1; + + if (pmain.grx === pmain.x) realx = pmain.x.invert(pnt.x); + if (pmain.gry === pmain.y) realy = pmain.y.invert(pnt.y); + + if ((realx!==undefined) && (realy!==undefined)) { + var i, len = histo.fBins.arr.length, bin; + + for (i = 0; (i < len) && (foundindx < 0); ++ i) { + bin = histo.fBins.arr[i]; + + // found potential bins candidate + if ((realx < bin.fXmin) || (realx > bin.fXmax) || + (realy < bin.fYmin) || (realy > bin.fYmax)) continue; + + // ignore empty bins with col0 option + if ((bin.fContent === 0) && !this.options.Zero) continue; + + var gr = bin.fPoly, numgraphs = 1; + if (gr._typename === 'TMultiGraph') { numgraphs = bin.fPoly.fGraphs.arr.length; gr = null; } + + for (var ngr=0;ngr<numgraphs;++ngr) { + if (!gr || (ngr>0)) gr = bin.fPoly.fGraphs.arr[ngr]; + if (gr.IsInside(realx,realy)) { + foundindx = i; + break; + } + } + } + } + + if (foundindx < 0) { + ttrect.remove(); + return null; + } + + var res = { name: histo.fName, title: histo.fTitle, + x: pnt.x, y: pnt.y, + color1: this.lineatt ? this.lineatt.color : 'green', + color2: this.fillatt ? this.fillatt.fillcoloralt('blue') : "blue", + exact: true, menu: true, + lines: this.ProvidePolyBinHints(foundindx, realx, realy) }; + + if (pnt.disabled) { + ttrect.remove(); + res.changed = true; + } else { + + if (ttrect.empty()) + ttrect = this.draw_g.append("svg:path") + .attr("class","tooltip_bin h1bin") + .style("pointer-events","none"); + + res.changed = ttrect.property("current_bin") !== foundindx; + + if (res.changed) + ttrect.attr("d", this.CreatePolyBin(pmain, bin)) + .style("opacity", "0.7") + .property("current_bin", foundindx); + } + + if (res.changed) + res.user_info = { obj: histo, name: histo.fName, + bin: foundindx, + cont: bin.fContent, + grx: pnt.x, gry: pnt.y }; + + return res; + + } else if (h.candle) { + // process tooltips for candle + + var p, i; + + for (i=0;i<h.candle.length;++i) { + p = h.candle[i]; + if ((p.x1 <= pnt.x) && (pnt.x <= p.x2) && (p.yy1 <= pnt.y) && (pnt.y <= p.yy2)) break; + } + + if (i>=h.candle.length) { + ttrect.remove(); + return null; + } + + var res = { name: histo.fName, title: histo.fTitle, + x: pnt.x, y: pnt.y, + color1: this.lineatt ? this.lineatt.color : 'green', + color2: this.fillatt ? this.fillatt.fillcoloralt('blue') : "blue", + lines: this.GetCandleTips(p), exact: true, menu: true }; + + if (pnt.disabled) { + ttrect.remove(); + res.changed = true; + } else { + + if (ttrect.empty()) + ttrect = this.draw_g.append("svg:rect") + .attr("class","tooltip_bin h1bin") + .style("pointer-events","none"); + + res.changed = ttrect.property("current_bin") !== i; + + if (res.changed) + ttrect.attr("x", p.x1) + .attr("width", p.x2-p.x1) + .attr("y", p.yy1) + .attr("height", p.yy2- p.yy1) + .style("opacity", "0.7") + .property("current_bin", i); + } + + if (res.changed) + res.user_info = { obj: histo, name: histo.fName, + bin: i+1, cont: p.median, binx: i+1, biny: 1, + grx: pnt.x, gry: pnt.y }; + + return res; + } + + var i, j, binz = 0, colindx = null, + i1, i2, j1, j2, x1, x2, y1, y2; + + // search bins position + for (i = h.i1; i < h.i2; ++i) + if ((pnt.x>=h.grx[i]) && (pnt.x<=h.grx[i+1])) break; + + for (j = h.j1; j < h.j2; ++j) + if ((pnt.y>=h.gry[j+1]) && (pnt.y<=h.gry[j])) break; + + if ((i < h.i2) && (j < h.j2)) { + + i1 = i; i2 = i+1; j1 = j; j2 = j+1; + x1 = h.grx[i1]; x2 = h.grx[i2]; + y1 = h.gry[j2]; y2 = h.gry[j1]; + + var match = true; + + if (this.options.Color) { + // take into account bar settings + var dx = x2 - x1, dy = y2 - y1; + x2 = Math.round(x1 + dx*h.xbar2); + x1 = Math.round(x1 + dx*h.xbar1); + y2 = Math.round(y1 + dy*h.ybar2); + y1 = Math.round(y1 + dy*h.ybar1); + if ((pnt.x<x1) || (pnt.x>=x2) || (pnt.y<y1) || (pnt.y>=y2)) match = false; + } + + binz = histo.getBinContent(i+1,j+1); + if (this.is_projection) { + colindx = 0; // just to avoid hide + } else if (!match) { + colindx = null; + } else if (h.hide_only_zeros) { + colindx = (binz === 0) && !this._show_empty_bins ? null : 0; + } else { + colindx = this.getContourColor(binz, true); + if ((colindx === null) && (binz === 0) && this._show_empty_bins) colindx = 0; + } + } + + if (colindx === null) { + ttrect.remove(); + return null; + } + + var res = { name: histo.fName, title: histo.fTitle, + x: pnt.x, y: pnt.y, + color1: this.lineatt ? this.lineatt.color : 'green', + color2: this.fillatt ? this.fillatt.fillcoloralt('blue') : "blue", + lines: this.GetBinTips(i, j), exact: true, menu: true }; + + if (this.options.Color) res.color2 = this.GetPalette().getColor(colindx); + + if (pnt.disabled && !this.is_projection) { + ttrect.remove(); + res.changed = true; + } else { + if (ttrect.empty()) + ttrect = this.draw_g.append("svg:rect") + .attr("class","tooltip_bin h1bin") + .style("pointer-events","none"); + + var binid = i*10000 + j; + + if (this.is_projection == "X") { + x1 = 0; x2 = this.frame_width(); + if (this.projection_width > 1) { + var dd = (this.projection_width-1)/2; + if (j2+dd >= h.j2) { j2 = Math.min(Math.round(j2+dd), h.j2); j1 = Math.max(j2 - this.projection_width, h.j1); } + else { j1 = Math.max(Math.round(j1-dd), h.j1); j2 = Math.min(j1 + this.projection_width, h.j2); } + } + y1 = h.gry[j2]; y2 = h.gry[j1]; + binid = j1*777 + j2*333; + } else if (this.is_projection == "Y") { + y1 = 0; y2 = this.frame_height(); + if (this.projection_width > 1) { + var dd = (this.projection_width-1)/2; + if (i2+dd >= h.i2) { i2 = Math.min(Math.round(i2+dd), h.i2); i1 = Math.max(i2 - this.projection_width, h.i1); } + else { i1 = Math.max(Math.round(i1-dd), h.i1); i2 = Math.min(i1 + this.projection_width, h.i2); } + } + x1 = h.grx[i1], x2 = h.grx[i2], + binid = i1*777 + i2*333; + } + + res.changed = ttrect.property("current_bin") !== binid; + + if (res.changed) + ttrect.attr("x", x1) + .attr("width", x2 - x1) + .attr("y", y1) + .attr("height", y2 - y1) + .style("opacity", "0.7") + .property("current_bin", binid); + + if (this.is_projection && res.changed) + this.RedrawProjection(i1, i2, j1, j2); + } + + if (res.changed) + res.user_info = { obj: histo, name: histo.fName, + bin: histo.getBin(i+1, j+1), cont: binz, binx: i+1, biny: j+1, + grx: pnt.x, gry: pnt.y }; + + return res; + } + + TH2Painter.prototype.CanZoomIn = function(axis,min,max) { + // check if it makes sense to zoom inside specified axis range + if (axis=="z") return true; + + var obj = this.GetHisto(); + if (obj) obj = (axis=="y") ? obj.fYaxis : obj.fXaxis; + + return !obj || (obj.FindBin(max,0.5) - obj.FindBin(min,0) > 1); + } + + TH2Painter.prototype.Draw2D = function(call_back, resize) { + + this.Clear3DScene(); + this.mode3d = false; + + this.CreateXY(); + + // draw new palette, resize frame if required + var pp = this.DrawColorPalette(this.options.Zscale && (this.options.Color || this.options.Contour), true); + + this.DrawAxes(); + + this.DrawBins(); + + // redraw palette till the end when contours are available + if (pp) pp.DrawPave(); + + this.DrawTitle(); + + this.UpdateStatWebCanvas(); + + this.AddInteractive(); + + JSROOT.CallBack(call_back); + } + + TH2Painter.prototype.Draw3D = function(call_back, resize) { + this.mode3d = true; + JSROOT.AssertPrerequisites('hist3d', function() { + this.Draw3D(call_back, resize); + }.bind(this)); + } + + TH2Painter.prototype.CallDrawFunc = function(callback, resize) { + + var main = this.main_painter(), + fp = this.frame_painter(); + + if ((main!==this) && fp && (fp.mode3d !== this.options.Mode3D)) + this.CopyOptionsFrom(main); + + var funcname = this.options.Mode3D ? "Draw3D" : "Draw2D"; + this[funcname](callback, resize); + } + + TH2Painter.prototype.Redraw = function(resize) { + this.CallDrawFunc(null, resize); + } + + function drawHistogram2D(divid, histo, opt) { + // create painter and add it to canvas + var painter = new JSROOT.TH2Painter(histo); + + painter.SetDivId(divid, 1); + + // here we deciding how histogram will look like and how will be shown + painter.DecodeOptions(opt); + + if (painter.IsTH2Poly()) { + if (painter.options.Mode3D) painter.options.Lego = 12; // lego always 12 + else if (!painter.options.Color) painter.options.Color = true; // default is color + } + + painter._show_empty_bins = false; + + painter._can_move_colz = true; + + // special case for root 3D drawings - pad range is wired + painter.CheckPadRange(!painter.options.Mode3D && (painter.options.Contour != 14)); + + painter.ScanContent(); + + painter.CreateStat(); // only when required + + painter.CallDrawFunc(function() { + this.DrawNextFunction(0, function() { + if (!this.Mode3D && this.options.AutoZoom) this.AutoZoom(); + this.FillToolbar(); + if (this.options.Project && !this.mode3d) + this.ToggleProjection(this.options.Project); + this.DrawingReady(); + }.bind(this)); + }.bind(painter)); + + return painter; + } + + // ================================================================================= + + + function createTF2Histogram(func, nosave, hist) { + var nsave = 0, npx = 0, npy = 0; + if (!nosave) { + nsave = func.fSave.length; + npx = Math.round(func.fSave[nsave-2]); + npy = Math.round(func.fSave[nsave-1]); + if (nsave !== (npx+1)*(npy+1) + 6) nsave = 0; + } + + if (nsave > 6) { + var dx = (func.fSave[nsave-5] - func.fSave[nsave-6]) / npx / 2, + dy = (func.fSave[nsave-3] - func.fSave[nsave-4]) / npy / 2; + + if (!hist) hist = JSROOT.CreateHistogram("TH2F", npx+1, npy+1); + + hist.fXaxis.fXmin = func.fSave[nsave-6] - dx; + hist.fXaxis.fXmax = func.fSave[nsave-5] + dx; + + hist.fYaxis.fXmin = func.fSave[nsave-4] - dy; + hist.fYaxis.fXmax = func.fSave[nsave-3] + dy; + + for (var k=0,j=0;j<=npy;++j) + for (var i=0;i<=npx;++i) + hist.setBinContent(hist.getBin(i+1,j+1), func.fSave[k++]); + + } else { + npx = Math.max(func.fNpx, 2); + npy = Math.max(func.fNpy, 2); + + if (!hist) hist = JSROOT.CreateHistogram("TH2F", npx, npy); + + hist.fXaxis.fXmin = func.fXmin; + hist.fXaxis.fXmax = func.fXmax; + + hist.fYaxis.fXmin = func.fYmin; + hist.fYaxis.fXmax = func.fYmax; + + for (var j=0;j<npy;++j) + for (var i=0;i<npx;++i) { + var x = func.fXmin + (i + 0.5) * (func.fXmax - func.fXmin) / npx, + y = func.fYmin + (j + 0.5) * (func.fYmax - func.fYmin) / npy; + + hist.setBinContent(hist.getBin(i+1,j+1), func.evalPar(x,y)); + } + } + + hist.fName = "Func"; + hist.fTitle = func.fTitle; + hist.fMinimum = func.fMinimum; + hist.fMaximum = func.fMaximum; + //fHistogram->SetContour(fContour.fN, levels); + hist.fLineColor = func.fLineColor; + hist.fLineStyle = func.fLineStyle; + hist.fLineWidth = func.fLineWidth; + hist.fFillColor = func.fFillColor; + hist.fFillStyle = func.fFillStyle; + hist.fMarkerColor = func.fMarkerColor; + hist.fMarkerStyle = func.fMarkerStyle; + hist.fMarkerSize = func.fMarkerSize; + + hist.fBits |= JSROOT.TH1StatusBits.kNoStats; + + // only for testing - unfortunately, axis settings are not stored with TF2 + // hist.fXaxis.fTitle = "axis X"; + // hist.fXaxis.InvertBit(JSROOT.EAxisBits.kCenterTitle); + // hist.fYaxis.fTitle = "axis Y"; + // hist.fYaxis.InvertBit(JSROOT.EAxisBits.kCenterTitle); + // hist.fZaxis.fTitle = "axis Z"; + // hist.fZaxis.InvertBit(JSROOT.EAxisBits.kCenterTitle); + + return hist; + } + + // TF2 always drawn via temporary TH2 object, + // therefore there is no special painter class + + function drawTF2(divid, func, opt) { + + var d = new JSROOT.DrawOptions(opt); + + var hist = createTF2Histogram(func, d.check('NOSAVE')); + + if (d.empty()) opt = "cont3"; else + if (d.opt === "SAME") opt = "cont2 same"; + else opt = d.opt; + + var hpainter = drawHistogram2D(divid, hist, opt); + + hpainter.tf2_typename = func._typename; + hpainter.tf2_nosave = d.check('NOSAVE'); + + hpainter.UpdateObject = function(obj, opt) { + if (!obj || (this.tf2_typename != obj._typename)) return false; + + createTF2Histogram(obj, this.tf2_nosave, this.GetHisto()); + + return true; + } + + return hpainter; + } + + // ==================================================================== + + function THStackPainter(stack, opt) { + JSROOT.TObjectPainter.call(this, stack, opt); + + this.firstpainter = null; + this.painters = []; // keep painters to be able update objects + } + + THStackPainter.prototype = Object.create(JSROOT.TObjectPainter.prototype); + + THStackPainter.prototype.Cleanup = function() { + var pp = this.pad_painter(); + if (pp) pp.CleanPrimitives(this.Selector.bind(this, true)); + delete this.firstpainter; + delete this.painters; + JSROOT.TObjectPainter.prototype.Cleanup.call(this); + } + + THStackPainter.prototype.HasErrors = function(hist) { + if (hist.fSumw2 && (hist.fSumw2.length > 0)) + for (var n=0;n<hist.fSumw2.length;++n) + if (hist.fSumw2[n] > 0) return true; + return false; + } + + THStackPainter.prototype.BuildStack = function(stack) { + // build sum of all histograms + // Build a separate list fStack containing the running sum of all histograms + + if (!stack.fHists) return false; + var nhists = stack.fHists.arr.length; + if (nhists <= 0) return false; + var lst = JSROOT.Create("TList"); + lst.Add(JSROOT.clone(stack.fHists.arr[0]), stack.fHists.opt[0]); + for (var i=1;i<nhists;++i) { + var hnext = JSROOT.clone(stack.fHists.arr[i]), + hnextopt = stack.fHists.opt[i], + hprev = lst.arr[i-1]; + + if ((hnext.fNbins != hprev.fNbins) || + (hnext.fXaxis.fXmin != hprev.fXaxis.fXmin) || + (hnext.fXaxis.fXmax != hprev.fXaxis.fXmax)) { + JSROOT.console("When drawing THStack, cannot sum-up histograms " + hnext.fName + " and " + hprev.fName); + lst.Clear(); + return false; + } + + // trivial sum of histograms + for (var n = 0; n < hnext.fArray.length; ++n) + hnext.fArray[n] += hprev.fArray[n]; + + lst.Add(hnext, hnextopt); + } + stack.fStack = lst; + return true; + } + + THStackPainter.prototype.GetHistMinMax = function(hist, witherr) { + var res = { min : 0, max : 0 }, + domin = true, domax = true; + if (hist.fMinimum !== -1111) { + res.min = hist.fMinimum; + domin = false; + } + if (hist.fMaximum !== -1111) { + res.max = hist.fMaximum; + domax = false; + } + + if (!domin && !domax) return res; + + var i1 = 1, i2 = hist.fXaxis.fNbins, j1 = 1, j2 = 1, first = true; + + if (hist.fXaxis.TestBit(JSROOT.EAxisBits.kAxisRange)) { + i1 = hist.fXaxis.fFirst; + i2 = hist.fXaxis.fLast; + } + + if (hist._typename.indexOf("TH2")===0) { + j2 = hist.fYaxis.fNbins; + if (hist.fYaxis.TestBit(JSROOT.EAxisBits.kAxisRange)) { + j1 = hist.fYaxis.fFirst; + j2 = hist.fYaxis.fLast; + } + } + for (var j=j1; j<=j2;++j) + for (var i=i1; i<=i2;++i) { + var val = hist.getBinContent(i, j), + err = witherr ? hist.getBinError(hist.getBin(i,j)) : 0; + if (domin && (first || (val-err < res.min))) res.min = val-err; + if (domax && (first || (val+err > res.max))) res.max = val+err; + first = false; + } + + return res; + } + + THStackPainter.prototype.GetMinMax = function(iserr, pad) { + var res = { min: 0, max: 0 }, + stack = this.GetObject(); + + if (this.options.nostack) { + for (var i = 0; i < stack.fHists.arr.length; ++i) { + var resh = this.GetHistMinMax(stack.fHists.arr[i], iserr); + if (i==0) { + res = resh; + } else { + res.min = Math.min(res.min, resh.min); + res.max = Math.max(res.max, resh.max); + } + } + } else { + res.min = this.GetHistMinMax(stack.fStack.arr[0], iserr).min; + res.max = this.GetHistMinMax(stack.fStack.arr[stack.fStack.arr.length-1], iserr).max; + } + + if (stack.fMaximum != -1111) res.max = stack.fMaximum; + res.max *= 1.05; + if (stack.fMinimum != -1111) res.min = stack.fMinimum; + + if (pad && (this.options.ndim == 1 ? pad.fLogy : pad.fLogz)) { + if (res.max<=0) res.max = 1; + if (res.min<=0) res.min = 1e-4*res.max; + var kmin = 1/(1 + 0.5*JSROOT.log10(res.max / res.min)), + kmax = 1 + 0.2*JSROOT.log10(res.max / res.min); + res.min *= kmin; + res.max *= kmax; + } else { + if ((res.min>0) && (res.min < 0.05*res.max)) res.min = 0; + } + + return res; + } + + THStackPainter.prototype.DrawNextHisto = function(indx, mm, subp, reenter) { + if (mm === "callback") { + mm = null; // just misuse min/max argument to indicate callback + if (indx<0) this.firstpainter = subp; + else this.painters.push(subp); + indx++; + } + + var stack = this.GetObject(), + hist = stack.fHistogram, hopt = "", + hlst = this.options.nostack ? stack.fHists : stack.fStack, + nhists = (hlst && hlst.arr) ? hlst.arr.length : 0, rindx = 0; + + if (indx>=nhists) return this.DrawingReady(); + + if ((indx % 500 === 499) && !reenter) + return setTimeout(this.DrawNextHisto.bind(this, indx, mm, subp, true), 0); + + if (indx>=0) { + rindx = this.options.horder ? indx : nhists-indx-1; + hist = hlst.arr[rindx]; + hopt = hlst.opt[rindx] || hist.fOption || this.options.hopt; + if (hopt.toUpperCase().indexOf(this.options.hopt)<0) hopt += this.options.hopt; + if (this.options.draw_errors && !hopt) hopt = "E"; + hopt += " same nostat"; + + // if there is auto colors assignment, try to provide it + if (this.options._pfc || this.options._plc || this.options._pmc) { + if (!this.pallette && JSROOT.Painter.GetColorPalette) + this.palette = JSROOT.Painter.GetColorPalette(); + if (this.palette) { + var color = this.palette.calcColor(rindx, nhists+1); + var icolor = this.add_color(color); + + if (this.options._pfc) hist.fFillColor = icolor; + if (this.options._plc) hist.fLineColor = icolor; + if (this.options._pmc) hist.fMarkerColor = icolor; + } + } + + } else { + hopt = this.options.hopt + " axis"; + // if (mm && (!this.options.nostack || (hist.fMinimum==-1111 && hist.fMaximum==-1111))) hopt += ";minimum:" + mm.min + ";maximum:" + mm.max; + if (mm) hopt += ";minimum:" + mm.min + ";maximum:" + mm.max; + } + + // special handling of stacked histograms - set $baseh object for correct drawing + // also used to provide tooltips + if ((rindx > 0) && !this.options.nostack) hist.$baseh = hlst.arr[rindx - 1]; + + JSROOT.draw(this.divid, hist, hopt, this.DrawNextHisto.bind(this, indx, "callback")); + } + + THStackPainter.prototype.DecodeOptions = function(opt) { + if (!this.options) this.options = {}; + JSROOT.extend(this.options, { ndim: 1, nostack: false, same: false, horder: true, has_errors: false, draw_errors: false, hopt: "" }); + + var stack = this.GetObject(), + hist = stack.fHistogram || (stack.fHists ? stack.fHists.arr[0] : null) || (stack.fStack ? stack.fStack.arr[0] : null); + + if (hist && (hist._typename.indexOf("TH2")==0)) this.options.ndim = 2; + + if ((this.options.ndim==2) && !opt) opt = "lego1"; + + if (stack.fHists && !this.options.nostack) { + for (var k=0;k<stack.fHists.arr.length;++k) + this.options.has_errors = this.options.has_errors || this.HasErrors(stack.fHists.arr[k]); + } + + var d = new JSROOT.DrawOptions(opt); + + this.options.nostack = d.check("NOSTACK"); + if (d.check("STACK")) this.options.nostack = false; + this.options.same = d.check("SAME"); + + this.options._pfc = d.check("PFC"); + this.options._plc = d.check("PLC"); + this.options._pmc = d.check("PMC"); + + this.options.hopt = d.remain(); // use remaining draw options for histogram draw + + var dolego = d.check("LEGO"); + + this.options.errors = d.check("E"); + + // if any histogram appears with pre-calculated errors, use E for all histograms + if (!this.options.nostack && this.options.has_errors && !dolego && !d.check("HIST") && (this.options.hopt.indexOf("E")<0)) this.options.draw_errors = true; + + this.options.horder = this.options.nostack || dolego; + } + + THStackPainter.prototype.CreateHistogram = function(stack) { + var histos = stack.fHists, + numhistos = histos ? histos.arr.length : 0; + + if (!numhistos) { + var histo = JSROOT.CreateHistogram("TH1I", 100); + histo.fTitle = stack.fTitle; + return histo; + } + + var h0 = histos.arr[0]; + var histo = JSROOT.CreateHistogram((this.options.ndim==1) ? "TH1I" : "TH2I", h0.fXaxis.fNbins, h0.fYaxis.fNbins); + histo.fName = "axis_hist"; + JSROOT.extend(histo.fXaxis, h0.fXaxis); + if (this.options.ndim==2) + JSROOT.extend(histo.fYaxis, h0.fYaxis); + + // this code is not exists in ROOT painter, can be skipped? + for (var n=1;n<numhistos;++n) { + var h = histos.arr[n]; + + if (!histo.fXaxis.fLabels) { + histo.fXaxis.fXmin = Math.min(histo.fXaxis.fXmin, h.fXaxis.fXmin); + histo.fXaxis.fXmax = Math.max(histo.fXaxis.fXmax, h.fXaxis.fXmax); + } + + if ((this.options.ndim==2) && !histo.fYaxis.fLabels) { + histo.fYaxis.fXmin = Math.min(histo.fYaxis.fXmin, h.fYaxis.fXmin); + histo.fYaxis.fXmax = Math.max(histo.fYaxis.fXmax, h.fYaxis.fXmax); + } + } + + histo.fTitle = stack.fTitle; + + return histo; + } + + THStackPainter.prototype.drawStack = function() { + + var stack = this.GetObject(); + + // when building stack, one could fail to sum up histograms + if (!this.options.nostack) + this.options.nostack = ! this.BuildStack(stack); + + if (!stack.fHistogram && !this.options.same) + stack.fHistogram = this.CreateHistogram(stack); + + var mm = this.GetMinMax(this.options.errors || this.options.draw_errors, this.root_pad()); + + this.DrawNextHisto(this.options.same ? 0 : -1, mm); + return this; + } + + THStackPainter.prototype.UpdateObject = function(obj) { + if (!this.MatchObjectType(obj)) return false; + + var stack = this.GetObject(); + + stack.fHists = obj.fHists; + stack.fStack = obj.fStack; + + if (!this.options.nostack) { + this.options.nostack = !this.BuildStack(stack); + } + + var isany = false; + if (this.firstpainter) { + var src = obj.fHistogram; + if (!src) + src = stack.fHistogram = this.CreateHistogram(stack); + + this.firstpainter.UpdateObject(src); + + var mm = this.GetMinMax(this.options.errors || this.options.draw_errors, this.root_pad()); + + this.firstpainter.options.minimum = mm.min; + this.firstpainter.options.maximum = mm.max; + + if (this.options.ndim == 1) { + this.firstpainter.ymin = mm.min; + this.firstpainter.ymax = mm.max; + } + + isany = true; + } + + // try fully remove old histogram painters + var pp = this.pad_painter(); + if (pp) pp.CleanPrimitives(this.Selector.bind(this, false)); + this.painters = []; + + this.did_update = isany; + + return isany; + } + + /** @summary Returns true if painter belongs to stack, used in cleanup */ + THStackPainter.prototype.Selector = function(fullclear, painter) { + if (fullclear && (painter===this.firstpainter)) return true; + return this.painters.indexOf(painter) >= 0; + } + + /** @summary Redraw THStack, changes output only if Update was performed before */ + THStackPainter.prototype.Redraw = function() { + // do nothing in case of simple redraw + if (!this.did_update) return; + + // remove flag set in update + delete this.did_update; + + if (this.firstpainter) + this.firstpainter.Redraw(); + + this.DrawNextHisto(0, null); + } + + function drawHStack(divid, stack, opt) { + // paint the list of histograms + // By default, histograms are shown stacked. + // - the first histogram is paint + // - then the sum of the first and second, etc + + var painter = new THStackPainter(stack, opt); + painter.SetDivId(divid, -1); // it maybe no element to set divid + painter.DecodeOptions(opt); + + if (!stack.fHists || (stack.fHists.arr.length == 0)) return painter.DrawingReady(); + + painter.drawStack(); + + painter.SetDivId(divid); // only when first histogram drawn, we could assign divid + + return painter; + } + + // ================================================================================= + + // kept for backward compatibility, will be removed in future JSROOT versions + JSROOT.Painter.drawLegend = drawPave; + JSROOT.Painter.drawPaveText = drawPave; + + JSROOT.Painter.drawPave = drawPave; + JSROOT.Painter.produceLegend = produceLegend; + JSROOT.Painter.drawPaletteAxis = drawPaletteAxis; + JSROOT.Painter.drawHistogram1D = drawHistogram1D; + JSROOT.Painter.drawHistogram2D = drawHistogram2D; + JSROOT.Painter.drawTF2 = drawTF2; + JSROOT.Painter.drawHStack = drawHStack; + + JSROOT.TPavePainter = TPavePainter; + JSROOT.THistPainter = THistPainter; + JSROOT.TH1Painter = TH1Painter; + JSROOT.TH2Painter = TH2Painter; + JSROOT.THStackPainter = THStackPainter; + + return JSROOT; + +})); diff --git a/js/scripts/JSRootPainter.hist3d.js b/js/scripts/JSRootPainter.hist3d.js new file mode 100644 index 00000000000..0f40f318c80 --- /dev/null +++ b/js/scripts/JSRootPainter.hist3d.js @@ -0,0 +1,3511 @@ +/// @file JSRootPainter.hist3d.js +/// 3D histogram graphics + +(function( factory ) { + if ( typeof define === "function" && define.amd ) { + define( [ 'JSRootCore', 'd3', 'JSRootPainter.hist', 'threejs', 'threejs_all'], factory ); + } else + if (typeof exports === 'object' && typeof module !== 'undefined') { + var jsroot = require("./JSRootCore.js"); + factory(jsroot, require("./d3.min.js"), require("./JSRootPainter.hist.js"), require("./three.min.js"), require("./three.extra.min.js"), + jsroot.nodejs || (typeof document=='undefined') ? jsroot.nodejs_document : document); + } else { + + if (typeof JSROOT == 'undefined') + throw new Error('JSROOT is not defined', 'JSRootPainter.hist3d.js'); + + if (typeof d3 != 'object') + throw new Error('This extension requires d3.js', 'JSRootPainter.hist3d.js'); + + if (typeof THREE == 'undefined') + throw new Error('THREE is not defined', 'JSRoot3DPainter.js'); + + factory(JSROOT, d3, JSROOT, THREE, THREE); + } +} (function(JSROOT, d3, __DUMMY__, THREE, THREE_MORE, document) { + + "use strict"; + + JSROOT.sources.push("hist3d"); + + if ((typeof document=='undefined') && (typeof window=='object')) document = window.document; + + if (typeof JSROOT.THistPainter === 'undefined') + throw new Error('JSROOT.THistPainter is not defined', 'JSRootPainter.hist3d.js'); + + JSROOT.TFramePainter.prototype.SetCameraPosition = function(pad, first_time) { + var max3d = Math.max(0.75*this.size_xy3d, this.size_z3d); + + if (first_time) + this.camera.position.set(-1.6*max3d, -3.5*max3d, 1.4*this.size_z3d); + + if (pad && (first_time || !this.zoom_changed_interactive)) + if (!isNaN(pad.fTheta) && !isNaN(pad.fPhi) && ((pad.fTheta !== this.camera_Theta) || (pad.fPhi !== this.camera_Phi))) { + max3d = 3*Math.max(this.size_xy3d, this.size_z3d); + var phi = (-pad.fPhi-90)/180*Math.PI, theta = pad.fTheta/180*Math.PI; + + this.camera_Phi = pad.fPhi; + this.camera_Theta = pad.fTheta; + + this.camera.position.set(max3d*Math.cos(phi)*Math.cos(theta), + max3d*Math.sin(phi)*Math.cos(theta), + this.size_z3d + max3d*Math.sin(theta)); + + first_time = true; + } + + if (first_time) + this.camera.lookAt(this.lookat); + } + + JSROOT.TFramePainter.prototype.Create3DScene = function(arg) { + + if ((arg!==undefined) && (arg<0)) { + + if (!this.mode3d) return; + + //if (typeof this.TestAxisVisibility === 'function') + this.TestAxisVisibility(null, this.toplevel); + + this.clear_3d_canvas(); + + JSROOT.Painter.DisposeThreejsObject(this.scene); + if (this.control) this.control.Cleanup(); + + if (this.renderer) { + if (this.renderer.dispose) this.renderer.dispose(); + if (this.renderer.context) delete this.renderer.context; + } + + delete this.size_xy3d; + delete this.size_z3d; + delete this.tooltip_mesh; + delete this.scene; + delete this.toplevel; + delete this.camera; + delete this.pointLight; + delete this.renderer; + delete this.control; + if ('render_tmout' in this) { + clearTimeout(this.render_tmout); + delete this.render_tmout; + } + + this.mode3d = false; + + return; + } + + this.mode3d = true; // indicate 3d mode as hist painter does + + if ('toplevel' in this) { + // it is indication that all 3D object created, just replace it with empty + this.scene.remove(this.toplevel); + JSROOT.Painter.DisposeThreejsObject(this.toplevel); + delete this.tooltip_mesh; + delete this.toplevel; + if (this.control) this.control.HideTooltip(); + + var newtop = new THREE.Object3D(); + this.scene.add(newtop); + this.toplevel = newtop; + + this.Resize3D(); // set actual sizes + + this.SetCameraPosition(this.root_pad(), false); + + return; + } + + this.usesvg = JSROOT.Painter.UseSVGFor3D(); // SVG used in batch mode + //if (this.usesvg) this.usesvgimg = JSROOT.gStyle.ImageSVG; // use svg images to insert graphics + + var sz = this.size_for_3d(this.usesvg ? 3 : undefined); + + this.size_z3d = 100; + this.size_xy3d = (sz.height > 10) && (sz.width > 10) ? Math.round(sz.width/sz.height*this.size_z3d) : this.size_z3d; + + // three.js 3D drawing + this.scene = new THREE.Scene(); + //scene.fog = new THREE.Fog(0xffffff, 500, 3000); + + this.toplevel = new THREE.Object3D(); + this.scene.add(this.toplevel); + this.scene_width = sz.width; + this.scene_height = sz.height; + + this.camera = new THREE.PerspectiveCamera(45, this.scene_width / this.scene_height, 1, 40*this.size_z3d); + + this.camera_Phi = 30; + this.camera_Theta = 30; + + this.pointLight = new THREE.PointLight(0xffffff,1); + this.camera.add(this.pointLight); + this.pointLight.position.set(this.size_xy3d/2, this.size_xy3d/2, this.size_z3d/2); + this.lookat = new THREE.Vector3(0,0,0.8*this.size_z3d); + this.camera.up = new THREE.Vector3(0,0,1); + this.scene.add( this.camera ); + + this.SetCameraPosition(this.root_pad(), true); + + var res = JSROOT.Painter.Create3DRenderer(this.scene_width, this.scene_height, this.usesvg, (sz.can3d == 4)); + + this.renderer = res.renderer; + this.webgl = res.usewebgl; + this.add_3d_canvas(sz, res.dom); + + this.first_render_tm = 0; + this.enable_highlight = false; + + if (JSROOT.BatchMode) return; + + this.control = JSROOT.Painter.CreateOrbitControl(this, this.camera, this.scene, this.renderer, this.lookat); + + var axis_painter = this, obj_painter = this.main_painter(); + + this.control.ProcessMouseMove = function(intersects) { + var tip = null, mesh = null, zoom_mesh = null; + + for (var i = 0; i < intersects.length; ++i) { + if (intersects[i].object.tooltip) { + tip = intersects[i].object.tooltip(intersects[i]); + if (tip) { mesh = intersects[i].object; break; } + } else + if (intersects[i].object.zoom && !zoom_mesh) zoom_mesh = intersects[i].object; + } + + if (tip && !tip.use_itself) { + var delta_xy = 1e-4*axis_painter.size_xy3d, delta_z = 1e-4*axis_painter.size_z3d; + if ((tip.x1 > tip.x2) || (tip.y1 > tip.y2) || (tip.z1 > tip.z2)) console.warn('check 3D hints coordinates'); + tip.x1 -= delta_xy; tip.x2 += delta_xy; + tip.y1 -= delta_xy; tip.y2 += delta_xy; + tip.z1 -= delta_z; tip.z2 += delta_z; + } + + axis_painter.BinHighlight3D(tip, mesh); + + if (!tip && zoom_mesh && axis_painter.Get3DZoomCoord) { + var pnt = zoom_mesh.GlobalIntersect(this.raycaster), + axis_name = zoom_mesh.zoom, + axis_value = axis_painter.Get3DZoomCoord(pnt, axis_name); + + if ((axis_name==="z") && zoom_mesh.use_y_for_z) axis_name = "y"; + + var taxis = axis_painter.GetAxis(axis_name); + + var hint = { name: axis_name, + title: "TAxis", + line: "any info", + only_status: true }; + + if (taxis) { hint.name = taxis.fName; hint.title = taxis.fTitle || "histogram TAxis object"; } + + hint.line = axis_name + " : " + axis_painter.AxisAsText(axis_name, axis_value); + + return hint; + } + + return (tip && tip.lines) ? tip : ""; + } + + this.control.ProcessMouseLeave = function() { + axis_painter.BinHighlight3D(null); + } + + this.control.ContextMenu = function(pos, intersects) { + var kind = "hist", p = obj_painter; + if (intersects) + for (var n=0;n<intersects.length;++n) { + var mesh = intersects[n].object; + if (mesh.zoom) { kind = mesh.zoom; break; } + if (mesh.painter && typeof mesh.painter.ShowContextMenu === 'function') { + p = mesh.painter; break; + } + } + + p.ShowContextMenu(kind, pos); + } + } + + /** @brief Set frame activity flag + * @private */ + + JSROOT.TFramePainter.prototype.SetActive = function(on) { + if (this.control) + this.control.enableKeys = on; + } + + /** @brief call 3D rendering of the histogram drawing + * @desc tmout specified delay, after which actual rendering will be invoked + * Timeout used to avoid multiple rendering of the picture when several 3D drawings + * superimposed with each other. + * If tmeout<=0, rendering performed immediately + * Several special values are used: + * -1111 - immediate rendering with SVG renderer + * -2222 - rendering performed only if there were previous calls, which causes timeout activation + * @private */ + + JSROOT.TFramePainter.prototype.Render3D = function(tmout) { + + if (tmout === -1111) { + // special handling for direct SVG renderer + // probably, here one can use canvas renderer - after modifications + // var rrr = new THREE.SVGRenderer({ precision: 0, astext: true }); + var rrr = THREE.CreateSVGRenderer(false, 0, document); + rrr.setSize(this.scene_width, this.scene_height); + rrr.render(this.scene, this.camera); + if (rrr.makeOuterHTML) { + // use text mode, it is faster + var d = document.createElement('div'); + d.innerHTML = rrr.makeOuterHTML(); + return d.childNodes[0]; + } + return rrr.domElement; + } + + if (tmout === undefined) tmout = 5; // by default, rendering happens with timeout + + if ((tmout <= 0) || this.usesvg || JSROOT.BatchMode) { + if ('render_tmout' in this) { + clearTimeout(this.render_tmout); + } else { + if (tmout === -2222) return; // special case to check if rendering timeout was active + } + + if (this.renderer === undefined) return; + + var tm1 = new Date(); + + if (!this.opt3d) this.opt3d = { FrontBox: true, BackBox: true }; + + //if (typeof this.TestAxisVisibility === 'function') + this.TestAxisVisibility(this.camera, this.toplevel, this.opt3d.FrontBox, this.opt3d.BackBox); + + // do rendering, most consuming time + this.renderer.render(this.scene, this.camera); + + JSROOT.Painter.AfterRender3D(this.renderer); + + var tm2 = new Date(); + + delete this.render_tmout; + + if (this.first_render_tm === 0) { + this.first_render_tm = tm2.getTime() - tm1.getTime(); + this.enable_highlight = (this.first_render_tm < 1200) && this.IsTooltipAllowed(); + console.log('First render tm = ' + this.first_render_tm); + } + + return; + } + + // no need to shoot rendering once again + if ('render_tmout' in this) return; + + this.render_tmout = setTimeout(this.Render3D.bind(this,0), tmout); + } + + JSROOT.TFramePainter.prototype.Resize3D = function() { + + var sz = this.size_for_3d(this.access_3d_kind()); + + this.apply_3d_size(sz); + + if ((this.scene_width === sz.width) && (this.scene_height === sz.height)) return false; + + if ((sz.width<10) || (sz.height<10)) return false; + + // TODO: change xy/z ratio after canvas resize + // this.size_xy3d = Math.round(sz.width/sz.height*this.size_z3d); + + this.scene_width = sz.width; + this.scene_height = sz.height; + + this.camera.aspect = this.scene_width / this.scene_height; + this.camera.updateProjectionMatrix(); + + this.renderer.setSize( this.scene_width, this.scene_height ); + + return true; + } + + JSROOT.TFramePainter.prototype.BinHighlight3D = function(tip, selfmesh) { + + var changed = false, tooltip_mesh = null, changed_self = true, + want_remove = !tip || (tip.x1===undefined) || !this.enable_highlight; + + if (this.tooltip_selfmesh) { + changed_self = (this.tooltip_selfmesh !== selfmesh) + this.tooltip_selfmesh.material.color = this.tooltip_selfmesh.save_color; + delete this.tooltip_selfmesh; + changed = true; + } + + if (this.tooltip_mesh) { + tooltip_mesh = this.tooltip_mesh; + this.toplevel.remove(this.tooltip_mesh); + delete this.tooltip_mesh; + changed = true; + } + + if (want_remove) { + if (changed) this.Render3D(); + this.ProvideUserTooltip(null); + return; + } + + if (tip.use_itself) { + selfmesh.save_color = selfmesh.material.color; + selfmesh.material.color = new THREE.Color(tip.color); + this.tooltip_selfmesh = selfmesh; + changed = changed_self; + } else { + changed = true; + + var indicies = JSROOT.Painter.Box3D.Indexes, + normals = JSROOT.Painter.Box3D.Normals, + vertices = JSROOT.Painter.Box3D.Vertices, + pos, norm, + color = new THREE.Color(tip.color ? tip.color : 0xFF0000), + opacity = tip.opacity || 1; + + if (!tooltip_mesh) { + pos = new Float32Array(indicies.length*3); + norm = new Float32Array(indicies.length*3); + var geom = new THREE.BufferGeometry(); + geom.addAttribute( 'position', new THREE.BufferAttribute( pos, 3 ) ); + geom.addAttribute( 'normal', new THREE.BufferAttribute( norm, 3 ) ); + var mater = new THREE.MeshBasicMaterial( { color: color, opacity: opacity, flatShading: true } ); + tooltip_mesh = new THREE.Mesh(geom, mater); + } else { + pos = tooltip_mesh.geometry.attributes.position.array; + tooltip_mesh.geometry.attributes.position.needsUpdate = true; + tooltip_mesh.material.color = color; + tooltip_mesh.material.opacity = opacity; + } + + if (tip.x1 === tip.x2) console.warn('same tip X', tip.x1, tip.x2); + if (tip.y1 === tip.y2) console.warn('same tip Y', tip.y1, tip.y2); + if (tip.z1 === tip.z2) { tip.z2 = tip.z1 + 0.0001; } // avoid zero faces + + for (var k=0,nn=-3;k<indicies.length;++k) { + var vert = vertices[indicies[k]]; + pos[k*3] = tip.x1 + vert.x * (tip.x2 - tip.x1); + pos[k*3+1] = tip.y1 + vert.y * (tip.y2 - tip.y1); + pos[k*3+2] = tip.z1 + vert.z * (tip.z2 - tip.z1); + + if (norm) { + if (k%6===0) nn+=3; + norm[k*3] = normals[nn]; + norm[k*3+1] = normals[nn+1]; + norm[k*3+2] = normals[nn+2]; + } + } + this.tooltip_mesh = tooltip_mesh; + this.toplevel.add(tooltip_mesh); + } + + if (changed) this.Render3D(); + + if (this.GetObject()) + this.ProvideUserTooltip({ obj: this.GetObject(), name: this.GetObject().fName, + bin: tip.bin, cont: tip.value, + binx: tip.ix, biny: tip.iy, binz: tip.iz, + grx: (tip.x1+tip.x2)/2, gry: (tip.y1+tip.y2)/2, grz: (tip.z1+tip.z2)/2 }); + } + + JSROOT.TFramePainter.prototype.TestAxisVisibility = function(camera, toplevel, fb, bb) { + var top; + if (toplevel && toplevel.children) + for (var n=0;n<toplevel.children.length;++n) { + top = toplevel.children[n]; + if (top.axis_draw) break; + top = undefined; + } + + if (!top) return; + + if (!camera) { + // this is case when axis drawing want to be removed + toplevel.remove(top); + // delete this.TestAxisVisibility; + return; + } + + fb = fb ? true : false; + bb = bb ? true : false; + + var qudrant = 1, pos = camera.position; + if ((pos.x < 0) && (pos.y >= 0)) qudrant = 2; + if ((pos.x >= 0) && (pos.y >= 0)) qudrant = 3; + if ((pos.x >= 0) && (pos.y < 0)) qudrant = 4; + + function testvisible(id, range) { + if (id <= qudrant) id+=4; + return (id > qudrant) && (id < qudrant+range); + } + + for (var n=0;n<top.children.length;++n) { + var chld = top.children[n]; + if (chld.grid) chld.visible = bb && testvisible(chld.grid, 3); else + if (chld.zid) chld.visible = testvisible(chld.zid, 2); else + if (chld.xyid) chld.visible = testvisible(chld.xyid, 3); else + if (chld.xyboxid) { + var range = 5, shift = 0; + if (bb && !fb) { range = 3; shift = -2; } else + if (fb && !bb) range = 3; else + if (!fb && !bb) range = (chld.bottom ? 3 : 0); + chld.visible = testvisible(chld.xyboxid + shift, range); + if (!chld.visible && chld.bottom && bb) + chld.visible = testvisible(chld.xyboxid, 3); + } else + if (chld.zboxid) { + var range = 2, shift = 0; + if (fb && bb) range = 5; else + if (bb && !fb) range = 4; else + if (!bb && fb) { shift = -2; range = 4; } + chld.visible = testvisible(chld.zboxid + shift, range); + } + } + } + + JSROOT.TFramePainter.prototype.Set3DOptions = function(hopt) { + this.opt3d = hopt; + } + + JSROOT.TFramePainter.prototype.DrawXYZ = function(toplevel, opts) { + if (!opts) opts = {}; + + var grminx = -this.size_xy3d, grmaxx = this.size_xy3d, + grminy = -this.size_xy3d, grmaxy = this.size_xy3d, + grminz = 0, grmaxz = 2*this.size_z3d, + textsize = Math.round(this.size_z3d * 0.05), + pad = this.root_pad(), + xmin = this.xmin, xmax = this.xmax, + ymin = this.ymin, ymax = this.ymax, + zmin = this.zmin, zmax = this.zmax, + y_zoomed = false, z_zoomed = false; + + if (!this.size_z3d) { + grminx = this.xmin; grmaxx = this.xmax; + grminy = this.ymin; grmaxy = this.ymax; + grminz = this.zmin; grmaxz = this.zmax; + textsize = (grmaxz - grminz) * 0.05; + } + + if (('zoom_xmin' in this) && ('zoom_xmax' in this) && (this.zoom_xmin !== this.zoom_xmax)) { + xmin = this.zoom_xmin; xmax = this.zoom_xmax; + } + if (('zoom_ymin' in this) && ('zoom_ymax' in this) && (this.zoom_ymin !== this.zoom_ymax)) { + ymin = this.zoom_ymin; ymax = this.zoom_ymax; y_zoomed = true; + } + + if (('zoom_zmin' in this) && ('zoom_zmax' in this) && (this.zoom_zmin !== this.zoom_zmax)) { + zmin = this.zoom_zmin; zmax = this.zoom_zmax; z_zoomed = true; + } + + if (opts.use_y_for_z) { + this.zmin = this.ymin; this.zmax = this.ymax; + zmin = ymin; zmax = ymax; z_zoomed = y_zoomed; + // if (!z_zoomed && (this.hmin!==this.hmax)) { zmin = this.hmin; zmax = this.hmax; } + ymin = 0; ymax = 1; + } + + // z axis range used for lego plot + this.lego_zmin = zmin; this.lego_zmax = zmax; + + // factor 1.1 used in ROOT for lego plots + if ((opts.zmult !== undefined) && !z_zoomed) zmax *= opts.zmult; + + // this.TestAxisVisibility = HPainter_TestAxisVisibility; + + if (pad && pad.fLogx) { + if (xmax <= 0) xmax = 1.; + if ((xmin <= 0) && this.xaxis) + for (var i=0;i<this.xaxis.fNbins;++i) { + xmin = Math.max(xmin, this.xaxis.GetBinLowEdge(i+1)); + if (xmin>0) break; + } + if (xmin <= 0) xmin = 1e-4*xmax; + this.grx = d3.scaleLog(); + this.x_kind = "log"; + } else { + this.grx = d3.scaleLinear(); + if (this.xaxis && this.xaxis.fLabels) this.x_kind = "labels"; + else this.x_kind = "normal"; + } + + this.logx = (this.x_kind === "log"); + + this.grx.domain([ xmin, xmax ]).range([ grminx, grmaxx ]); + this.x_handle = new JSROOT.TAxisPainter(this.xaxis); + this.x_handle.SetAxisConfig("xaxis", this.x_kind, this.grx, this.xmin, this.xmax, xmin, xmax); + this.x_handle.CreateFormatFuncs(); + this.scale_xmin = xmin; this.scale_xmax = xmax; + + if (pad && pad.fLogy && !opts.use_y_for_z) { + if (ymax <= 0) ymax = 1.; + if ((ymin <= 0) && this.yaxis) + for (var i=0;i<this.yaxis.fNbins;++i) { + ymin = Math.max(ymin, this.yaxis.GetBinLowEdge(i+1)); + if (ymin>0) break; + } + + if (ymin <= 0) ymin = 1e-4*ymax; + this.gry = d3.scaleLog(); + this.y_kind = "log"; + } else { + this.gry = d3.scaleLinear(); + if (this.yaxis && this.yaxis.fLabels) this.y_kind = "labels"; + else this.y_kind = "normal"; + } + + this.logy = (this.y_kind === "log"); + + this.gry.domain([ ymin, ymax ]).range([ grminy, grmaxy ]); + this.y_handle = new JSROOT.TAxisPainter(this.yaxis); + this.y_handle.SetAxisConfig("yaxis", this.y_kind, this.gry, this.ymin, this.ymax, ymin, ymax); + this.y_handle.CreateFormatFuncs(); + this.scale_ymin = ymin; this.scale_ymax = ymax; + + if (pad && pad.fLogz) { + if (zmax <= 0) zmax = 1; + if (zmin <= 0) zmin = 1e-4*zmax; + this.grz = d3.scaleLog(); + this.z_kind = "log"; + } else { + this.grz = d3.scaleLinear(); + this.z_kind = "normal"; + if (this.zaxis && this.zaxis.fLabels && (opts.ndim === 3)) this.z_kind = "labels"; + } + + this.logz = (this.z_kind === "log"); + + this.grz.domain([ zmin, zmax ]).range([ grminz, grmaxz ]); + + this.SetRootPadRange(pad, true); // set some coordinates typical for 3D projections in ROOT + + this.z_handle = new JSROOT.TAxisPainter(this.zaxis); + this.z_handle.SetAxisConfig("zaxis", this.z_kind, this.grz, this.zmin, this.zmax, zmin, zmax); + this.z_handle.CreateFormatFuncs(); + this.scale_zmin = zmin; this.scale_zmax = zmax; + + this.x_handle.debug = true; + + var textMaterial = new THREE.MeshBasicMaterial({ color: 0x000000 }), + lineMaterial = new THREE.LineBasicMaterial({ color: 0x000000 }), + ticklen = textsize*0.5, text, tick, lbls = [], text_scale = 1, + xticks = this.x_handle.CreateTicks(false, true), + yticks = this.y_handle.CreateTicks(false, true), + zticks = this.z_handle.CreateTicks(false, true); + + // main element, where all axis elements are placed + var top = new THREE.Object3D(); + top.axis_draw = true; // mark element as axis drawing + toplevel.add(top); + + var ticks = [], maxtextheight = 0, xaxis = this.xaxis; + + while (xticks.next()) { + var grx = xticks.grpos, + is_major = (xticks.kind===1), + lbl = this.x_handle.format(xticks.tick, true, true); + if (xticks.last_major()) { if (!xaxis || !xaxis.fTitle) lbl = "x"; } else + if (lbl === null) { is_major = false; lbl = ""; } + + if (is_major && lbl && (lbl.length>0)) { + var text3d = new THREE.TextGeometry(lbl, { font: JSROOT.threejs_font_helvetiker_regular, size: textsize, height: 0, curveSegments: 5 }); + text3d.computeBoundingBox(); + var draw_width = text3d.boundingBox.max.x - text3d.boundingBox.min.x, + draw_height = text3d.boundingBox.max.y - text3d.boundingBox.min.y; + text3d.center = true; // place central + + // text3d.translate(-draw_width/2, 0, 0); + + maxtextheight = Math.max(maxtextheight, draw_height); + + text3d.grx = grx; + lbls.push(text3d); + + if (!xticks.last_major()) { + var space = (xticks.next_major_grpos() - grx); + if (draw_width > 0) + text_scale = Math.min(text_scale, 0.9*space/draw_width) + if (this.x_handle.IsCenterLabels()) text3d.grx += space/2; + } + } + + ticks.push(grx, 0, 0, grx, (is_major ? -ticklen : -ticklen * 0.6), 0); + } + + if (xaxis && xaxis.fTitle) { + var text3d = new THREE.TextGeometry(xaxis.fTitle, { font: JSROOT.threejs_font_helvetiker_regular, size: textsize, height: 0, curveSegments: 5 }); + text3d.computeBoundingBox(); + text3d.center = (xaxis.TestBit(JSROOT.EAxisBits.kCenterTitle)); + text3d.gry = 2; // factor 2 shift + text3d.grx = (grminx + grmaxx)/2; // default position for centered title + lbls.push(text3d); + } + + this.Get3DZoomCoord = function(point, kind) { + // return axis coordinate from intersection point with axis geometry + var pos = point[kind], min = this['scale_'+kind+'min'], max = this['scale_'+kind+'max']; + + if (kind==="z") pos = pos/2/this.size_z3d; + else pos = (pos+this.size_xy3d)/2/this.size_xy3d; + + if (this["log"+kind]) { + pos = Math.exp(Math.log(min) + pos*(Math.log(max)-Math.log(min))); + } else { + pos = min + pos*(max-min); + } + return pos; + } + + function CreateZoomMesh(kind, size_3d, use_y_for_z) { + var geom = new THREE.Geometry(); + + if (kind==="z") + geom.vertices.push( + new THREE.Vector3(0,0,0), + new THREE.Vector3(ticklen*4, 0, 0), + new THREE.Vector3(ticklen*4, 0, 2*size_3d), + new THREE.Vector3(0, 0, 2*size_3d)); + else + geom.vertices.push( + new THREE.Vector3(-size_3d,0,0), + new THREE.Vector3(size_3d,0,0), + new THREE.Vector3(size_3d,-ticklen*4,0), + new THREE.Vector3(-size_3d,-ticklen*4,0)); + + geom.faces.push(new THREE.Face3(0, 2, 1)); + geom.faces.push(new THREE.Face3(0, 3, 2)); + geom.computeFaceNormals(); + + var material = new THREE.MeshBasicMaterial({ transparent: true, + vertexColors: THREE.NoColors, // THREE.FaceColors, + side: THREE.DoubleSide, + opacity: 0 }); + + var mesh = new THREE.Mesh(geom, material); + mesh.zoom = kind; + mesh.size_3d = size_3d; + mesh.use_y_for_z = use_y_for_z; + if (kind=="y") mesh.rotateZ(Math.PI/2).rotateX(Math.PI); + + mesh.GlobalIntersect = function(raycaster) { + var plane = new THREE.Plane(), + geom = this.geometry; + + if (!geom || !geom.vertices) return undefined; + + plane.setFromCoplanarPoints(geom.vertices[0], geom.vertices[1], geom.vertices[2]); + plane.applyMatrix4(this.matrixWorld); + + var v1 = raycaster.ray.origin.clone(), + v2 = v1.clone().addScaledVector(raycaster.ray.direction, 1e10); + + var pnt = plane.intersectLine(new THREE.Line3(v1,v2), new THREE.Vector3()); + + if (!pnt) return undefined; + + var min = -this.size_3d, max = this.size_3d; + if (this.zoom==="z") { min = 0; max = 2*this.size_3d; } + + if (pnt[this.zoom] < min) pnt[this.zoom] = min; else + if (pnt[this.zoom] > max) pnt[this.zoom] = max; + + return pnt; + } + + mesh.ShowSelection = function(pnt1,pnt2) { + // used to show selection + + var tgtmesh = this.children ? this.children[0] : null, gg, kind = this.zoom; + if (!pnt1 || !pnt2) { + if (tgtmesh) { + this.remove(tgtmesh) + JSROOT.Painter.DisposeThreejsObject(tgtmesh); + } + return tgtmesh; + } + + if (!tgtmesh) { + gg = this.geometry.clone(); + if (kind==="z") gg.vertices[1].x = gg.vertices[2].x = ticklen; + else gg.vertices[2].y = gg.vertices[3].y = -ticklen; + tgtmesh = new THREE.Mesh(gg, new THREE.MeshBasicMaterial({ color: 0xFF00, side: THREE.DoubleSide })); + this.add(tgtmesh); + } else { + gg = tgtmesh.geometry; + } + + if (kind=="z") { + gg.vertices[0].z = gg.vertices[1].z = pnt1[kind]; + gg.vertices[2].z = gg.vertices[3].z = pnt2[kind]; + } else { + gg.vertices[0].x = gg.vertices[3].x = pnt1[kind]; + gg.vertices[1].x = gg.vertices[2].x = pnt2[kind]; + } + + gg.computeFaceNormals(); + + gg.verticesNeedUpdate = true; + gg.normalsNeedUpdate = true; + + return true; + } + + return mesh; + } + + var xcont = new THREE.Object3D(); + xcont.position.set(0, grminy, grminz) + xcont.rotation.x = 1/4*Math.PI; + xcont.xyid = 2; + var xtickslines = JSROOT.Painter.createLineSegments( ticks, lineMaterial ); + xcont.add(xtickslines); + + lbls.forEach(function(lbl) { + var w = lbl.boundingBox.max.x - lbl.boundingBox.min.x, + posx = lbl.center ? lbl.grx - w/2 : grmaxx - w, + m = new THREE.Matrix4(); + // matrix to swap y and z scales and shift along z to its position + m.set(text_scale, 0, 0, posx, + 0, text_scale, 0, (-maxtextheight*text_scale - 1.5*ticklen) * (lbl.gry || 1), + 0, 0, 1, 0, + 0, 0, 0, 1); + + var mesh = new THREE.Mesh(lbl, textMaterial); + mesh.applyMatrix(m); + xcont.add(mesh); + }); + + if (opts.zoom) xcont.add(CreateZoomMesh("x", this.size_xy3d)); + top.add(xcont); + + xcont = new THREE.Object3D(); + xcont.position.set(0, grmaxy, grminz); + xcont.rotation.x = 3/4*Math.PI; + xcont.add(new THREE.LineSegments(xtickslines.geometry, lineMaterial)); + lbls.forEach(function(lbl) { + + var w = lbl.boundingBox.max.x - lbl.boundingBox.min.x, + posx = lbl.center ? lbl.grx + w/2 : grmaxx, + m = new THREE.Matrix4(); + // matrix to swap y and z scales and shift along z to its position + m.set(-text_scale, 0, 0, posx, + 0, text_scale, 0, (-maxtextheight*text_scale - 1.5*ticklen) * (lbl.gry || 1), + 0, 0, -1, 0, + 0, 0, 0, 1); + var mesh = new THREE.Mesh(lbl, textMaterial); + mesh.applyMatrix(m); + xcont.add(mesh); + }); + + //xcont.add(new THREE.Mesh(ggg2, textMaterial)); + xcont.xyid = 4; + if (opts.zoom) xcont.add(CreateZoomMesh("x", this.size_xy3d)); + top.add(xcont); + + lbls = []; text_scale = 1; maxtextheight = 0; ticks = []; + + var yaxis = this.yaxis; + + while (yticks.next()) { + var gry = yticks.grpos, + is_major = (yticks.kind===1), + lbl = this.y_handle.format(yticks.tick, true, true); + if (yticks.last_major()) { if (!yaxis || !yaxis.fTitle) lbl = "y"; } else + if (lbl === null) { is_major = false; lbl = ""; } + + if (is_major) { + var text3d = new THREE.TextGeometry(lbl, { font: JSROOT.threejs_font_helvetiker_regular, size: textsize, height: 0, curveSegments: 5 }); + text3d.computeBoundingBox(); + var draw_width = text3d.boundingBox.max.x - text3d.boundingBox.min.x, + draw_height = text3d.boundingBox.max.y - text3d.boundingBox.min.y; + // text3d.translate(-draw_width/2, 0, 0); + text3d.center = true; + + maxtextheight = Math.max(maxtextheight, draw_height); + + text3d.gry = gry; + lbls.push(text3d); + + if (!yticks.last_major()) { + var space = (yticks.next_major_grpos() - gry); + if (draw_width > 0) + text_scale = Math.min(text_scale, 0.9*space/draw_width) + if (this.y_handle.IsCenterLabels()) text3d.gry += space/2; + } + } + ticks.push(0,gry,0, (is_major ? -ticklen : -ticklen*0.6), gry, 0); + } + + if (yaxis && yaxis.fTitle) { + var text3d = new THREE.TextGeometry(yaxis.fTitle, { font: JSROOT.threejs_font_helvetiker_regular, size: textsize, height: 0, curveSegments: 5 }); + text3d.computeBoundingBox(); + text3d.center = yaxis.TestBit(JSROOT.EAxisBits.kCenterTitle); + text3d.grx = 2; // factor 2 shift + text3d.gry = (grminy + grmaxy)/2; // default position for centered title + lbls.push(text3d); + } + + if (!opts.use_y_for_z) { + var yticksline = JSROOT.Painter.createLineSegments(ticks, lineMaterial), + ycont = new THREE.Object3D(); + ycont.position.set(grminx, 0, grminz); + ycont.rotation.y = -1/4*Math.PI; + ycont.add(yticksline); + //ycont.add(new THREE.Mesh(ggg1, textMaterial)); + + lbls.forEach(function(lbl) { + + var w = lbl.boundingBox.max.x - lbl.boundingBox.min.x, + posy = lbl.center ? lbl.gry + w/2 : grmaxy, + m = new THREE.Matrix4(); + // matrix to swap y and z scales and shift along z to its position + m.set(0, text_scale, 0, (-maxtextheight*text_scale - 1.5*ticklen)*(lbl.grx || 1), + -text_scale, 0, 0, posy, + 0, 0, 1, 0, + 0, 0, 0, 1); + + var mesh = new THREE.Mesh(lbl, textMaterial); + mesh.applyMatrix(m); + ycont.add(mesh); + }); + + ycont.xyid = 3; + if (opts.zoom) ycont.add(CreateZoomMesh("y", this.size_xy3d)); + top.add(ycont); + + ycont = new THREE.Object3D(); + ycont.position.set(grmaxx, 0, grminz); + ycont.rotation.y = -3/4*Math.PI; + ycont.add(new THREE.LineSegments(yticksline.geometry, lineMaterial)); + //ycont.add(new THREE.Mesh(ggg2, textMaterial)); + lbls.forEach(function(lbl) { + var w = lbl.boundingBox.max.x - lbl.boundingBox.min.x, + posy = lbl.center ? lbl.gry - w/2 : grmaxy - w, + m = new THREE.Matrix4(); + m.set(0, text_scale, 0, (-maxtextheight*text_scale - 1.5*ticklen)*(lbl.grx || 1), + text_scale, 0, 0, posy, + 0, 0, -1, 0, + 0, 0, 0, 1); + + var mesh = new THREE.Mesh(lbl, textMaterial); + mesh.applyMatrix(m); + ycont.add(mesh); + }); + ycont.xyid = 1; + if (opts.zoom) ycont.add(CreateZoomMesh("y", this.size_xy3d)); + top.add(ycont); + } + + + lbls = []; text_scale = 1; + + ticks = []; // just array, will be used for the buffer geometry + + var zgridx = null, zgridy = null, lastmajorz = null, + zaxis = this.zaxis, maxzlblwidth = 0; + + if (this.size_z3d) { + zgridx = []; zgridy = []; + } + + while (zticks.next()) { + var grz = zticks.grpos, + is_major = (zticks.kind == 1), + lbl = this.z_handle.format(zticks.tick, true, true); + if (lbl === null) { is_major = false; lbl = ""; } + + if (is_major && lbl) { + var text3d = new THREE.TextGeometry(lbl, { font: JSROOT.threejs_font_helvetiker_regular, size: textsize, height: 0, curveSegments: 5 }); + text3d.computeBoundingBox(); + var draw_width = text3d.boundingBox.max.x - text3d.boundingBox.min.x, + draw_height = text3d.boundingBox.max.y - text3d.boundingBox.min.y; + text3d.translate(-draw_width, -draw_height/2, 0); + text3d.grz = grz; + lbls.push(text3d); + + if ((lastmajorz !== null) && (draw_height>0)) + text_scale = Math.min(text_scale, 0.9*(grz - lastmajorz)/draw_height); + + maxzlblwidth = Math.max(maxzlblwidth, draw_width); + + lastmajorz = grz; + } + + // create grid + if (zgridx && is_major) + zgridx.push(grminx,0,grz, grmaxx,0,grz); + + if (zgridy && is_major) + zgridy.push(0,grminy,grz, 0,grmaxy,grz); + + ticks.push(0, 0, grz, (is_major ? ticklen : ticklen * 0.6), 0, grz); + } + + if (zgridx && (zgridx.length > 0)) { + + var material = new THREE.LineDashedMaterial({ color: 0x0, dashSize: 2, gapSize: 2 }); + + var lines1 = JSROOT.Painter.createLineSegments(zgridx, material); + lines1.position.set(0,grmaxy,0); + lines1.grid = 2; // mark as grid + lines1.visible = false; + top.add(lines1); + + var lines2 = new THREE.LineSegments(lines1.geometry, material); + lines2.position.set(0,grminy,0); + lines2.grid = 4; // mark as grid + lines2.visible = false; + top.add(lines2); + } + + if (zgridy && (zgridy.length > 0)) { + + var material = new THREE.LineDashedMaterial({ color: 0x0, dashSize: 2, gapSize: 2 }); + + var lines1 = JSROOT.Painter.createLineSegments(zgridy, material); + lines1.position.set(grmaxx,0, 0); + lines1.grid = 3; // mark as grid + lines1.visible = false; + top.add(lines1); + + var lines2 = new THREE.LineSegments(lines1.geometry, material); + lines2.position.set(grminx, 0, 0); + lines2.grid = 1; // mark as grid + lines2.visible = false; + top.add(lines2); + } + + var zcont = [], zticksline = JSROOT.Painter.createLineSegments( ticks, lineMaterial ); + for (var n=0;n<4;++n) { + zcont.push(new THREE.Object3D()); + + lbls.forEach(function(lbl) { + var m = new THREE.Matrix4(); + // matrix to swap y and z scales and shift along z to its position + m.set(-text_scale, 0, 0, 2*ticklen, + 0, 0, 1, 0, + 0, text_scale, 0, lbl.grz); + var mesh = new THREE.Mesh(lbl, textMaterial); + mesh.applyMatrix(m); + zcont[n].add(mesh); + }); + + if (zaxis && zaxis.fTitle) { + var text3d = new THREE.TextGeometry(zaxis.fTitle, { font: JSROOT.threejs_font_helvetiker_regular, size: textsize, height: 0, curveSegments: 5 }); + text3d.computeBoundingBox(); + var draw_width = text3d.boundingBox.max.x - text3d.boundingBox.min.x, + draw_height = text3d.boundingBox.max.y - text3d.boundingBox.min.y, + posz = zaxis.TestBit(JSROOT.EAxisBits.kCenterTitle) ? (grmaxz + grminz - draw_width)/2 : grmaxz - draw_width; + + text3d.rotateZ(Math.PI/2); + + var m = new THREE.Matrix4(); + m.set(-text_scale, 0, 0, 3*ticklen + maxzlblwidth, + 0, 0, 1, 0, + 0, text_scale, 0, posz); + var mesh = new THREE.Mesh(text3d, textMaterial); + mesh.applyMatrix(m); + zcont[n].add(mesh); + } + + zcont[n].add(n==0 ? zticksline : new THREE.LineSegments(zticksline.geometry, lineMaterial)); + if (opts.zoom) zcont[n].add(CreateZoomMesh("z", this.size_z3d, opts.use_y_for_z)); + + zcont[n].zid = n + 2; + top.add(zcont[n]); + } + + zcont[0].position.set(grminx,grmaxy,0); + zcont[0].rotation.z = 3/4*Math.PI; + + zcont[1].position.set(grmaxx,grmaxy,0); + zcont[1].rotation.z = 1/4*Math.PI; + + zcont[2].position.set(grmaxx,grminy,0); + zcont[2].rotation.z = -1/4*Math.PI; + + zcont[3].position.set(grminx,grminy,0); + zcont[3].rotation.z = -3/4*Math.PI; + + + // for TAxis3D do not show final cube + if (this.size_z3d === 0) return; + + var linex_geom = JSROOT.Painter.createLineSegments([grminx,0,0, grmaxx,0,0], lineMaterial, null, true); + for(var n=0;n<2;++n) { + var line = new THREE.LineSegments(linex_geom, lineMaterial); + line.position.set(0, grminy, (n===0) ? grminz : grmaxz); + line.xyboxid = 2; line.bottom = (n == 0); + top.add(line); + + line = new THREE.LineSegments(linex_geom, lineMaterial); + line.position.set(0, grmaxy, (n===0) ? grminz : grmaxz); + line.xyboxid = 4; line.bottom = (n == 0); + top.add(line); + } + + var liney_geom = JSROOT.Painter.createLineSegments([0,grminy,0, 0,grmaxy,0], lineMaterial, null, true); + for(var n=0;n<2;++n) { + var line = new THREE.LineSegments(liney_geom, lineMaterial); + line.position.set(grminx, 0, (n===0) ? grminz : grmaxz); + line.xyboxid = 3; line.bottom = (n == 0); + top.add(line); + + line = new THREE.LineSegments(liney_geom, lineMaterial); + line.position.set(grmaxx, 0, (n===0) ? grminz : grmaxz); + line.xyboxid = 1; line.bottom = (n == 0); + top.add(line); + } + + var linez_geom = JSROOT.Painter.createLineSegments([0,0,grminz, 0,0,grmaxz], lineMaterial, null, true); + for(var n=0;n<4;++n) { + var line = new THREE.LineSegments(linez_geom, lineMaterial); + line.zboxid = zcont[n].zid; + line.position.copy(zcont[n].position); + top.add(line); + } + } + + JSROOT.THistPainter.prototype.Draw3DBins = function() { + + if (!this.draw_content) return; + + if (this.IsTH2Poly() && this.DrawPolyLego) + return this.DrawPolyLego(); + + if ((this.Dimension()==2) && this.options.Contour && this.DrawContour3D) + return this.DrawContour3D(true); + + if ((this.Dimension()==2) && this.options.Surf && this.DrawSurf) + return this.DrawSurf(); + + if ((this.Dimension()==2) && this.options.Error && this.DrawError) + return this.DrawError(); + + // Perform TH1/TH2 lego plot with BufferGeometry + + var vertices = JSROOT.Painter.Box3D.Vertices, + indicies = JSROOT.Painter.Box3D.Indexes, + vnormals = JSROOT.Painter.Box3D.Normals, + segments = JSROOT.Painter.Box3D.Segments, + // reduced line segments + rsegments = [0, 1, 1, 2, 2, 3, 3, 0], + // reduced vertices + rvertices = [ new THREE.Vector3(0, 0, 0), new THREE.Vector3(0, 1, 0), new THREE.Vector3(1, 1, 0), new THREE.Vector3(1, 0, 0) ], + main = this.frame_painter(), + axis_zmin = main.grz.domain()[0], + axis_zmax = main.grz.domain()[1], + handle = this.PrepareColorDraw({ rounding: false, use3d: true, extra: 1 }), + i1 = handle.i1, i2 = handle.i2, j1 = handle.j1, j2 = handle.j2, + i, j, x1, x2, y1, y2, binz1, binz2, reduced, nobottom, notop, + pthis = this, + histo = this.GetHisto(), + basehisto = histo ? histo.$baseh : null, + split_faces = (this.options.Lego === 11) || (this.options.Lego === 13); // split each layer on two parts + + if ((i1 >= i2) || (j1 >= j2)) return; + + function GetBinContent(ii,jj, level) { + // return bin content in binz1, binz2, reduced flags + // return true if bin should be displayed + + binz2 = histo.getBinContent(ii+1, jj+1); + if (basehisto) + binz1 = basehisto.getBinContent(ii+1, jj+1); + else if (pthis.options.BaseLine !== false) + binz1 = pthis.options.BaseLine; + else + binz1 = pthis.options.Zero ? axis_zmin : 0; + if (binz2 < binz1) { var d = binz1; binz1 = binz2; binz2 = d; } + + if ((binz1 >= zmax) || (binz2 < zmin)) return false; + + reduced = (binz2 === zmin) || (binz1 >= binz2); + + if (!reduced || (level>0)) return true; + + if (histo['$baseh']) return false; // do not draw empty bins on top of other bins + + if (pthis.options.Zero || (axis_zmin>0)) return true; + + return pthis._show_empty_bins; + } + + // if bin ID fit into 16 bit, use smaller arrays for intersect indexes + var use16indx = (this.histo.getBin(i2, j2) < 0xFFFF), + levels = [ axis_zmin, axis_zmax ], palette = null, totalvertices = 0; + + // DRAW ALL CUBES + + if ((this.options.Lego === 12) || (this.options.Lego === 14)) { + // drawing colors levels, axis can not exceed palette + levels = this.CreateContour(histo.fContour ? histo.fContour.length : 20, main.lego_zmin, main.lego_zmax); + palette = this.GetPalette(); + //axis_zmin = levels[0]; + //axis_zmax = levels[levels.length-1]; + } + + for (var nlevel=0; nlevel<levels.length-1;++nlevel) { + + var zmin = levels[nlevel], zmax = levels[nlevel+1], + z1 = 0, z2 = 0, numvertices = 0, num2vertices = 0; + + // artifically extend last level of color pallette to maximial visible value + if (palette && (nlevel==levels.length-2) && zmax < axis_zmax) zmax = axis_zmax; + + var grzmin = main.grz(zmin), grzmax = main.grz(zmax); + + // now calculate size of buffer geometry for boxes + + for (i=i1;i<i2;++i) + for (j=j1;j<j2;++j) { + + if (!GetBinContent(i,j,nlevel)) continue; + + nobottom = !reduced && (nlevel>0); + notop = !reduced && (binz2 > zmax) && (nlevel < levels.length-2); + + numvertices += (reduced ? 12 : indicies.length); + if (nobottom) numvertices -= 6; + if (notop) numvertices -= 6; + + if (split_faces && !reduced) { + numvertices -= 12; + num2vertices += 12; + } + } + + totalvertices += numvertices + num2vertices; + + var positions = new Float32Array(numvertices*3), + normals = new Float32Array(numvertices*3), + face_to_bins_index = use16indx ? new Uint16Array(numvertices/3) : new Uint32Array(numvertices/3), + pos2 = null, norm2 = null, face_to_bins_indx2 = null, + v = 0, v2 = 0, vert, bin, k, nn; + + if (num2vertices > 0) { + pos2 = new Float32Array(num2vertices*3); + norm2 = new Float32Array(num2vertices*3); + face_to_bins_indx2 = use16indx ? new Uint16Array(num2vertices/3) : new Uint32Array(num2vertices/3); + } + + for (i=i1;i<i2;++i) { + x1 = handle.grx[i] + handle.xbar1*(handle.grx[i+1]-handle.grx[i]); + x2 = handle.grx[i] + handle.xbar2*(handle.grx[i+1]-handle.grx[i]); + for (j=j1;j<j2;++j) { + + if (!GetBinContent(i,j,nlevel)) continue; + + nobottom = !reduced && (nlevel>0); + notop = !reduced && (binz2 > zmax) && (nlevel < levels.length-2); + + y1 = handle.gry[j] + handle.ybar1*(handle.gry[j+1] - handle.gry[j]); + y2 = handle.gry[j] + handle.ybar2*(handle.gry[j+1] - handle.gry[j]); + + z1 = (binz1 <= zmin) ? grzmin : main.grz(binz1); + z2 = (binz2 > zmax) ? grzmax : main.grz(binz2); + + nn = 0; // counter over the normals, each normals correspond to 6 vertices + k = 0; // counter over vertices + + if (reduced) { + // we skip all side faces, keep only top and bottom + nn += 12; + k += 24; + } + + var size = indicies.length, bin_index = this.histo.getBin(i+1, j+1); + if (nobottom) size -= 6; + + // array over all vertices of the single bin + while(k < size) { + + vert = vertices[indicies[k]]; + + if (split_faces && (k < 12)) { + pos2[v2] = x1 + vert.x * (x2 - x1); + pos2[v2+1] = y1 + vert.y * (y2 - y1); + pos2[v2+2] = z1 + vert.z * (z2 - z1); + + norm2[v2] = vnormals[nn]; + norm2[v2+1] = vnormals[nn+1]; + norm2[v2+2] = vnormals[nn+2]; + if (v2%9===0) face_to_bins_indx2[v2/9] = bin_index; // remember which bin corresponds to the face + v2+=3; + } else { + positions[v] = x1 + vert.x * (x2 - x1); + positions[v+1] = y1 + vert.y * (y2 - y1); + positions[v+2] = z1 + vert.z * (z2 - z1); + + normals[v] = vnormals[nn]; + normals[v+1] = vnormals[nn+1]; + normals[v+2] = vnormals[nn+2]; + if (v%9===0) face_to_bins_index[v/9] = bin_index; // remember which bin corresponds to the face + v+=3; + } + + ++k; + + if (k%6 === 0) { + nn+=3; + if (notop && (k === indicies.length - 12)) { + k+=6; nn+=3; // jump over notop indexes + } + } + } + } + } + + var geometry = new THREE.BufferGeometry(); + geometry.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) ); + geometry.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ) ); + // geometry.computeVertexNormals(); + + var rootcolor = histo.fFillColor, + fcolor = this.get_color(rootcolor); + + if (palette) { + fcolor = palette.calcColor(nlevel, levels.length); + } else { + if ((this.options.Lego === 1) || (rootcolor < 2)) { + rootcolor = 1; + fcolor = 'white'; + } + } + + //var material = new THREE.MeshLambertMaterial( { color: fcolor } ); + var material = new THREE.MeshBasicMaterial( { color: fcolor, flatShading: true } ); + + var mesh = new THREE.Mesh(geometry, material); + + mesh.face_to_bins_index = face_to_bins_index; + mesh.painter = this; + mesh.zmin = axis_zmin; + mesh.zmax = axis_zmax; + mesh.baseline = (this.options.BaseLine===false) ? axis_zmin : this.options.BaseLine; + mesh.tip_color = (rootcolor===3) ? 0xFF0000 : 0x00FF00; + mesh.handle = handle; + + mesh.tooltip = function(intersect) { + if (isNaN(intersect.faceIndex)) { + console.error('faceIndex not provided, check three.js version', THREE.REVISION, 'expected r97'); + return null; + } + + if ((intersect.faceIndex < 0) || (intersect.faceIndex >= this.face_to_bins_index.length)) return null; + + var p = this.painter, + handle = this.handle, + main = p.frame_painter(), + histo = p.GetHisto(), + tip = p.Get3DToolTip( this.face_to_bins_index[intersect.faceIndex] ); + + tip.x1 = Math.max(-main.size_xy3d, handle.grx[tip.ix-1] + handle.xbar1*(handle.grx[tip.ix]-handle.grx[tip.ix-1])); + tip.x2 = Math.min(main.size_xy3d, handle.grx[tip.ix-1] + handle.xbar2*(handle.grx[tip.ix]-handle.grx[tip.ix-1])); + + tip.y1 = Math.max(-main.size_xy3d, handle.gry[tip.iy-1] + handle.ybar1*(handle.gry[tip.iy] - handle.gry[tip.iy-1])); + tip.y2 = Math.min(main.size_xy3d, handle.gry[tip.iy-1] + handle.ybar2*(handle.gry[tip.iy] - handle.gry[tip.iy-1])); + + var binz1 = this.baseline, binz2 = tip.value; + if (histo['$baseh']) binz1 = histo['$baseh'].getBinContent(tip.ix, tip.iy); + if (binz2<binz1) { var v = binz1; binz1 = binz2; binz2 = v; } + + tip.z1 = main.grz(Math.max(this.zmin,binz1)); + tip.z2 = main.grz(Math.min(this.zmax,binz2)); + + tip.color = this.tip_color; + + return tip; + } + + main.toplevel.add(mesh); + + if (num2vertices > 0) { + var geom2 = new THREE.BufferGeometry(); + geom2.addAttribute( 'position', new THREE.BufferAttribute( pos2, 3 ) ); + geom2.addAttribute( 'normal', new THREE.BufferAttribute( norm2, 3 ) ); + //geom2.computeVertexNormals(); + + //var material2 = new THREE.MeshLambertMaterial( { color: 0xFF0000 } ); + + var color2 = (rootcolor<2) ? new THREE.Color(0xFF0000) : + new THREE.Color(d3.rgb(fcolor).darker(0.5).toString()); + + var material2 = new THREE.MeshBasicMaterial( { color: color2, flatShading: true } ); + + var mesh2 = new THREE.Mesh(geom2, material2); + mesh2.face_to_bins_index = face_to_bins_indx2; + mesh2.painter = this; + mesh2.handle = mesh.handle; + mesh2.tooltip = mesh.tooltip; + mesh2.zmin = mesh.zmin; + mesh2.zmax = mesh.zmax; + mesh2.baseline = mesh.baseline; + mesh2.tip_color = mesh.tip_color; + + main.toplevel.add(mesh2); + } + } + + // lego3 or lego4 do not draw border lines + if (this.options.Lego > 12) return; + + // DRAW LINE BOXES + + var numlinevertices = 0, numsegments = 0, uselineindx = true, nskip = 0; + + zmax = axis_zmax; zmin = axis_zmin; + + for (i=i1;i<i2;++i) + for (j=j1;j<j2;++j) { + if (!GetBinContent(i,j,0)) { nskip++; continue; } + + // calculate required buffer size for line segments + numlinevertices += (reduced ? rvertices.length : vertices.length); + numsegments += (reduced ? rsegments.length : segments.length); + } + + // On some platforms vertex index required to be Uint16 array + // While we cannot use index for large vertex list + // skip index usage at all. It happens for relatively large histograms (100x100 bins) + if (numlinevertices > 0xFFF0) uselineindx = false; + + if (!uselineindx) numlinevertices = numsegments*3; + + var lpositions = new Float32Array( numlinevertices * 3 ), + lindicies = uselineindx ? new Uint16Array( numsegments ) : null, + grzmin = main.grz(axis_zmin), + grzmax = main.grz(axis_zmax), + z1 = 0, z2 = 0, ll = 0, ii = 0; + + for (i=i1;i<i2;++i) { + x1 = handle.grx[i] + handle.xbar1*(handle.grx[i+1]-handle.grx[i]); + x2 = handle.grx[i] + handle.xbar2*(handle.grx[i+1]-handle.grx[i]); + for (j=j1;j<j2;++j) { + + if (!GetBinContent(i,j,0)) continue; + + y1 = handle.gry[j] + handle.ybar1*(handle.gry[j+1] - handle.gry[j]); + y2 = handle.gry[j] + handle.ybar2*(handle.gry[j+1] - handle.gry[j]); + + z1 = (binz1 <= axis_zmin) ? grzmin : main.grz(binz1); + z2 = (binz2 > axis_zmax) ? grzmax : main.grz(binz2); + + var seg = reduced ? rsegments : segments, + vvv = reduced ? rvertices : vertices; + + if (uselineindx) { + // array of indicies for the lines, to avoid duplication of points + for (k=0; k < seg.length; ++k) { +// intersect_index[ii] = bin_index; + lindicies[ii++] = ll/3 + seg[k]; + } + + for (k=0; k < vvv.length; ++k) { + vert = vvv[k]; + lpositions[ll] = x1 + vert.x * (x2 - x1); + lpositions[ll+1] = y1 + vert.y * (y2 - y1); + lpositions[ll+2] = z1 + vert.z * (z2 - z1); + ll+=3; + } + } else { + // copy only vertex positions + for (k=0; k < seg.length; ++k) { + vert = vvv[seg[k]]; + lpositions[ll] = x1 + vert.x * (x2 - x1); + lpositions[ll+1] = y1 + vert.y * (y2 - y1); + lpositions[ll+2] = z1 + vert.z * (z2 - z1); +// intersect_index[ll/3] = bin_index; + ll+=3; + } + } + } + } + + // create boxes + var lcolor = this.get_color(histo.fLineColor); + material = new THREE.LineBasicMaterial({ color: new THREE.Color(lcolor) }); + if (!JSROOT.browser.isIE) material.linewidth = histo.fLineWidth; + + var line = JSROOT.Painter.createLineSegments(lpositions, material, uselineindx ? lindicies : null ); + + /* + line.painter = this; + line.intersect_index = intersect_index; + line.tooltip = function(intersect) { + if ((intersect.index<0) || (intersect.index >= this.intersect_index.length)) return null; + return this.painter.Get3DToolTip(this.intersect_index[intersect.index]); + } + */ + + main.toplevel.add(line); + } + + // =================================================================================== + + JSROOT.Painter.drawAxis3D = function(divid, axis, opt) { + + var painter = new JSROOT.TObjectPainter(axis); + + if (!('_main' in axis)) + painter.SetDivId(divid); + + painter.Draw3DAxis = function() { + var main = this.frame_painter(); + + if (!main || !main._toplevel) + return console.warn('no geo object found for 3D axis drawing'); + + var box = new THREE.Box3().setFromObject(main._toplevel); + + this.xmin = box.min.x; this.xmax = box.max.x; + this.ymin = box.min.y; this.ymax = box.max.y; + this.zmin = box.min.z; this.zmax = box.max.z; + + // use min/max values directly as graphical coordinates + this.size_xy3d = this.size_z3d = 0; + + this.DrawXYZ = JSROOT.TFramePainter.prototype.DrawXYZ; // just reuse axis drawing from frame painter + + this.DrawXYZ(main._toplevel); + + main.adjustCameraPosition(); + + main.Render3D(); + } + + painter.Draw3DAxis(); + + return painter.DrawingReady(); + } + + // ========================================================================================== + + JSROOT.TH1Painter.prototype.Draw3D = function(call_back, resize) { + // function called with this as painter + + this.mode3d = true; + + var main = this.frame_painter(), // who makes axis drawing + is_main = this.is_main_painter(), // is main histogram + histo = this.GetHisto(); + + if (resize) { + + if (is_main && main.Resize3D()) main.Render3D(); + + } else { + + this.DeleteAtt(); + + this.ScanContent(true); // may be required for axis drawings + + if (is_main) { + main.Create3DScene(); + main.SetAxesRanges(histo.fXaxis, this.xmin, this.xmax, histo.fYaxis, this.ymin, this.ymax, histo.fZaxis, 0, 0); + main.Set3DOptions(this.options); + main.DrawXYZ(main.toplevel, { use_y_for_z: true, zmult: 1.1, zoom: JSROOT.gStyle.Zooming, ndim: 1 }); + } + + this.Draw3DBins(); + + main.Render3D(); + + this.UpdateStatWebCanvas(); + + main.AddKeysHandler(); + } + + if (is_main) { + // (re)draw palette by resize while canvas may change dimension + this.DrawColorPalette(this.options.Zscale && ((this.options.Lego===12) || (this.options.Lego===14))); + + this.DrawTitle(); + } + + JSROOT.CallBack(call_back); + } + + // ========================================================================================== + + JSROOT.TH2Painter.prototype.Draw3D = function(call_back, resize) { + + this.mode3d = true; + + var main = this.frame_painter(), // who makes axis drawing + is_main = this.is_main_painter(), // is main histogram + histo = this.GetHisto(); + + if (resize) { + + if (is_main && main.Resize3D()) main.Render3D(); + + } else { + + var pad = this.root_pad(); + // if (pad && pad.fGridz === undefined) pad.fGridz = false; + + this.zmin = pad.fLogz ? this.gminposbin * 0.3 : this.gminbin; + this.zmax = this.gmaxbin; + + var zmult = 1.1; + + if (this.options.minimum !== -1111) this.zmin = this.options.minimum; + if (this.options.maximum !== -1111) { this.zmax = this.options.maximum; zmult = 1; } + + if (pad.fLogz && (this.zmin<=0)) this.zmin = this.zmax * 1e-5; + + this.DeleteAtt(); + + if (is_main) { + main.Create3DScene(); + main.SetAxesRanges(histo.fXaxis, this.xmin, this.xmax, histo.fYaxis, this.ymin, this.ymax, histo.fZaxis, this.zmin, this.zmax); + main.Set3DOptions(this.options); + main.DrawXYZ(main.toplevel, { zmult: zmult, zoom: JSROOT.gStyle.Zooming, ndim: 2 }); + } + + this.Draw3DBins(); + + main.Render3D(); + + this.UpdateStatWebCanvas(); + + main.AddKeysHandler(); + } + + if (is_main) { + + // (re)draw palette by resize while canvas may change dimension + this.DrawColorPalette(this.options.Zscale && ((this.options.Lego===12) || (this.options.Lego===14) || + (this.options.Surf===11) || (this.options.Surf===12))); + + this.DrawTitle(); + } + + JSROOT.CallBack(call_back); + } + + JSROOT.TH2Painter.prototype.DrawContour3D = function(realz) { + // for contour plots one requires handle with full range + var main = this.frame_painter(), + handle = this.PrepareColorDraw({rounding: false, use3d: true, extra: 100, middle: 0.0 }), + histo = this.GetHisto(), // get levels + levels = this.GetContour(), // init contour if not exists + palette = this.GetPalette(), + layerz = 2*main.size_z3d, pnts = []; + + this.BuildContour(handle, levels, palette, + function(colindx,xp,yp,iminus,iplus,ilevel) { + // ignore less than three points + if (iplus - iminus < 3) return; + + if (realz) { + layerz = main.grz(levels[ilevel]); + if ((layerz < 0) || (layerz > 2*main.size_z3d)) return; + } + + for (var i=iminus;i<iplus;++i) { + pnts.push(xp[i], yp[i], layerz); + pnts.push(xp[i+1], yp[i+1], layerz); + } + } + ); + + var lines = JSROOT.Painter.createLineSegments(pnts, JSROOT.Painter.Create3DLineMaterial(this, histo)); + main.toplevel.add(lines); + } + + JSROOT.TH2Painter.prototype.DrawSurf = function() { + var histo = this.GetHisto(), + main = this.frame_painter(), + handle = this.PrepareColorDraw({rounding: false, use3d: true, extra: 1, middle: 0.5 }), + i,j, x1, y1, x2, y2, z11, z12, z21, z22, + axis_zmin = main.grz.domain()[0], + axis_zmax = main.grz.domain()[1]; + + // first adjust ranges + + var main_grz = !main.logz ? main.grz : function(value) { return value < axis_zmin ? -0.1 : main.grz(value); } + + if ((handle.i2 - handle.i1 < 2) || (handle.j2 - handle.j1 < 2)) return; + + var ilevels = null, levels = null, dolines = true, dogrid = false, + donormals = false, palette = null; + + switch(this.options.Surf) { + case 11: ilevels = this.GetContour(); palette = this.GetPalette(); break; + case 12: + case 15: // make surf5 same as surf2 + case 17: ilevels = this.GetContour(); palette = this.GetPalette(); dolines = false; break; + case 14: dolines = false; donormals = true; break; + case 16: ilevels = this.GetContour(); dogrid = true; dolines = false; break; + default: ilevels = main.z_handle.CreateTicks(true); dogrid = true; break; + } + + if (ilevels) { + // recalculate levels into graphical coordinates + levels = new Float32Array(ilevels.length); + for (var ll=0;ll<ilevels.length;++ll) + levels[ll] = main_grz(ilevels[ll]); + } else { + levels = [0, 2*main.size_z3d]; // just cut top/bottom parts + } + + var loop, nfaces = [], pos = [], indx = [], // buffers for faces + nsegments = 0, lpos = null, lindx = 0, // buffer for lines + ngridsegments = 0, grid = null, gindx = 0, // buffer for grid lines segments + normindx = null; // buffer to remember place of vertex for each bin + + function CheckSide(z,level1, level2) { + if (z<level1) return -1; + if (z>level2) return 1; + return 0; + } + + function AddLineSegment(x1,y1,z1, x2,y2,z2) { + if (!dolines) return; + var side1 = CheckSide(z1,0,2*main.size_z3d), + side2 = CheckSide(z2,0,2*main.size_z3d); + if ((side1===side2) && (side1!==0)) return; + if (!loop) return ++nsegments; + + if (side1!==0) { + var diff = z2-z1; + z1 = (side1<0) ? 0 : 2*main.size_z3d; + x1 = x2 - (x2-x1)/diff*(z2-z1); + y1 = y2 - (y2-y1)/diff*(z2-z1); + } + if (side2!==0) { + var diff = z1-z2; + z2 = (side2<0) ? 0 : 2*main.size_z3d; + x2 = x1 - (x1-x2)/diff*(z1-z2); + y2 = y1 - (y1-y2)/diff*(z1-z2); + } + + lpos[lindx] = x1; lpos[lindx+1] = y1; lpos[lindx+2] = z1; lindx+=3; + lpos[lindx] = x2; lpos[lindx+1] = y2; lpos[lindx+2] = z2; lindx+=3; + } + + var pntbuf = new Float32Array(6*3), k = 0, lastpart = 0; // maximal 6 points + var gridpnts = new Float32Array(2*3), gridcnt = 0; + + function AddCrossingPoint(xx1,yy1,zz1, xx2,yy2,zz2, crossz, with_grid) { + if (k>=pntbuf.length) console.log('more than 6 points???'); + + var part = (crossz - zz1) / (zz2 - zz1), shift = 3; + if ((lastpart!==0) && (Math.abs(part) < Math.abs(lastpart))) { + // while second crossing point closer than first to original, move it in memory + pntbuf[k] = pntbuf[k-3]; + pntbuf[k+1] = pntbuf[k-2]; + pntbuf[k+2] = pntbuf[k-1]; + k-=3; shift = 6; + } + + pntbuf[k] = xx1 + part*(xx2-xx1); + pntbuf[k+1] = yy1 + part*(yy2-yy1); + pntbuf[k+2] = crossz; + + if (with_grid && grid) { + gridpnts[gridcnt] = pntbuf[k]; + gridpnts[gridcnt+1] = pntbuf[k+1]; + gridpnts[gridcnt+2] = pntbuf[k+2]; + gridcnt+=3; + } + + k += shift; + lastpart = part; + } + + function RememberVertex(indx, ii,jj) { + var bin = ((ii-handle.i1) * (handle.j2-handle.j1) + (jj-handle.j1))*8; + + if (normindx[bin]>=0) + return console.error('More than 8 vertexes for the bin'); + + var pos = bin+8+normindx[bin]; // position where write index + normindx[bin]--; + normindx[pos] = indx; // at this moment index can be overwritten, means all 8 position are there + } + + function RecalculateNormals(arr) { + for (var ii=handle.i1;ii<handle.i2;++ii) { + for (var jj=handle.j1;jj<handle.j2;++jj) { + var bin = ((ii-handle.i1) * (handle.j2-handle.j1) + (jj-handle.j1)) * 8; + + if (normindx[bin] === -1) continue; // nothing there + + var beg = (normindx[bin] >=0) ? bin : bin+9+normindx[bin], + end = bin+8, sumx=0, sumy = 0, sumz = 0; + + for (var kk=beg;kk<end;++kk) { + var indx = normindx[kk]; + if (indx<0) return console.error('FAILURE in NORMALS RECALCULATIONS'); + sumx+=arr[indx]; + sumy+=arr[indx+1]; + sumz+=arr[indx+2]; + } + + sumx = sumx/(end-beg); sumy = sumy/(end-beg); sumz = sumz/(end-beg); + + for (var kk=beg;kk<end;++kk) { + var indx = normindx[kk]; + arr[indx] = sumx; + arr[indx+1] = sumy; + arr[indx+2] = sumz; + } + } + } + } + + function AddMainTriangle(x1,y1,z1, x2,y2,z2, x3,y3,z3, is_first) { + + for (var lvl=1;lvl<levels.length;++lvl) { + + var side1 = CheckSide(z1, levels[lvl-1], levels[lvl]), + side2 = CheckSide(z2, levels[lvl-1], levels[lvl]), + side3 = CheckSide(z3, levels[lvl-1], levels[lvl]), + side_sum = side1 + side2 + side3; + + if (side_sum === 3) continue; + if (side_sum === -3) return; + + if (!loop) { + var npnts = Math.abs(side2-side1) + Math.abs(side3-side2) + Math.abs(side1-side3); + if (side1===0) ++npnts; + if (side2===0) ++npnts; + if (side3===0) ++npnts; + + if ((npnts===1) || (npnts===2)) console.error('FOND npnts', npnts); + + if (npnts>2) { + if (nfaces[lvl]===undefined) nfaces[lvl] = 0; + nfaces[lvl] += npnts-2; + } + + // check if any(contours for given level exists + if (((side1>0) || (side2>0) || (side3>0)) && + ((side1!==side2) || (side2!==side3) || (side3!==side1))) ++ngridsegments; + + continue; + } + + gridcnt = 0; + + k = 0; + if (side1 === 0) { pntbuf[k] = x1; pntbuf[k+1] = y1; pntbuf[k+2] = z1; k+=3; } + + if (side1!==side2) { + // order is important, should move from 1->2 point, checked via lastpart + lastpart = 0; + if ((side1<0) || (side2<0)) AddCrossingPoint(x1,y1,z1, x2,y2,z2, levels[lvl-1]); + if ((side1>0) || (side2>0)) AddCrossingPoint(x1,y1,z1, x2,y2,z2, levels[lvl], true); + } + + if (side2 === 0) { pntbuf[k] = x2; pntbuf[k+1] = y2; pntbuf[k+2] = z2; k+=3; } + + if (side2!==side3) { + // order is important, should move from 2->3 point, checked via lastpart + lastpart = 0; + if ((side2<0) || (side3<0)) AddCrossingPoint(x2,y2,z2, x3,y3,z3, levels[lvl-1]); + if ((side2>0) || (side3>0)) AddCrossingPoint(x2,y2,z2, x3,y3,z3, levels[lvl], true); + } + + if (side3 === 0) { pntbuf[k] = x3; pntbuf[k+1] = y3; pntbuf[k+2] = z3; k+=3; } + + if (side3!==side1) { + // order is important, should move from 3->1 point, checked via lastpart + lastpart = 0; + if ((side3<0) || (side1<0)) AddCrossingPoint(x3,y3,z3, x1,y1,z1, levels[lvl-1]); + if ((side3>0) || (side1>0)) AddCrossingPoint(x3,y3,z3, x1,y1,z1, levels[lvl], true); + } + + if (k===0) continue; + if (k<9) { console.log('found less than 3 points', k/3); continue; } + + if (grid && (gridcnt === 6)) { + for (var jj=0;jj < 6; ++jj) + grid[gindx+jj] = gridpnts[jj]; + gindx+=6; + } + + + // if three points and surf==14, remember vertex for each point + + var buf = pos[lvl], s = indx[lvl]; + if (donormals && (k===9)) { + RememberVertex(s, i, j); + RememberVertex(s+3, i+1, is_first ? j+1 : j); + RememberVertex(s+6, is_first ? i : i+1, j+1); + } + + for (var k1=3;k1<k-3;k1+=3) { + buf[s] = pntbuf[0]; buf[s+1] = pntbuf[1]; buf[s+2] = pntbuf[2]; s+=3; + buf[s] = pntbuf[k1]; buf[s+1] = pntbuf[k1+1]; buf[s+2] = pntbuf[k1+2]; s+=3; + buf[s] = pntbuf[k1+3]; buf[s+1] = pntbuf[k1+4]; buf[s+2] = pntbuf[k1+5]; s+=3; + } + indx[lvl] = s; + + } + } + + if (donormals) { + // for each bin maximal 8 points reserved + normindx = new Int32Array((handle.i2-handle.i1)*(handle.j2-handle.j1)*8); + for (var n=0;n<normindx.length;++n) normindx[n] = -1; + } + + for (loop=0;loop<2;++loop) { + if (loop) { + for (var lvl=1;lvl<levels.length;++lvl) + if (nfaces[lvl]) { + pos[lvl] = new Float32Array(nfaces[lvl] * 9); + indx[lvl] = 0; + } + if (dolines && (nsegments > 0)) + lpos = new Float32Array(nsegments * 6); + if (dogrid && (ngridsegments>0)) + grid = new Float32Array(ngridsegments * 6); + } + for (i=handle.i1;i<handle.i2-1;++i) { + x1 = handle.grx[i]; + x2 = handle.grx[i+1]; + for (j=handle.j1;j<handle.j2-1;++j) { + y1 = handle.gry[j]; + y2 = handle.gry[j+1]; + z11 = main_grz(histo.getBinContent(i+1, j+1)); + z12 = main_grz(histo.getBinContent(i+1, j+2)); + z21 = main_grz(histo.getBinContent(i+2, j+1)); + z22 = main_grz(histo.getBinContent(i+2, j+2)); + + AddMainTriangle(x1,y1,z11, x2,y2,z22, x1,y2,z12, true); + + AddMainTriangle(x1,y1,z11, x2,y1,z21, x2,y2,z22, false); + + AddLineSegment(x1,y2,z12, x1,y1,z11); + AddLineSegment(x1,y1,z11, x2,y1,z21); + + if (i===handle.i2-2) AddLineSegment(x2,y1,z21, x2,y2,z22); + if (j===handle.j2-2) AddLineSegment(x1,y2,z12, x2,y2,z22); + } + } + } + + for (var lvl=1;lvl<levels.length;++lvl) + if (pos[lvl]) { + if (indx[lvl] !== nfaces[lvl]*9) + console.error('SURF faces missmatch lvl', lvl, 'faces', nfaces[lvl], 'index', indx[lvl], 'check', nfaces[lvl]*9 - indx[lvl]); + var geometry = new THREE.BufferGeometry(); + geometry.addAttribute( 'position', new THREE.BufferAttribute( pos[lvl], 3 ) ); + geometry.computeVertexNormals(); + if (donormals && (lvl===1)) RecalculateNormals(geometry.getAttribute('normal').array); + + var fcolor, material; + if (palette) { + fcolor = palette.calcColor(lvl, levels.length); + } else { + fcolor = histo.fFillColor > 1 ? this.get_color(histo.fFillColor) : 'white'; + if ((this.options.Surf === 14) && (histo.fFillColor<2)) fcolor = this.get_color(48); + } + if (this.options.Surf === 14) + material = new THREE.MeshLambertMaterial( { color: fcolor, side: THREE.DoubleSide } ); + else + material = new THREE.MeshBasicMaterial( { color: fcolor, side: THREE.DoubleSide } ); + + var mesh = new THREE.Mesh(geometry, material); + + main.toplevel.add(mesh); + + mesh.painter = this; // to let use it with context menu + } + + + if (lpos) { + if (nsegments*6 !== lindx) + console.error('SURF lines mismmatch nsegm', nsegments, ' lindx', lindx, 'difference', nsegments*6 - lindx); + + var lcolor = this.get_color(histo.fLineColor), + material = new THREE.LineBasicMaterial({ color: new THREE.Color(lcolor) }); + if (!JSROOT.browser.isIE) material.linewidth = histo.fLineWidth; + var line = JSROOT.Painter.createLineSegments(lpos, material); + line.painter = this; + main.toplevel.add(line); + } + + if (grid) { + if (ngridsegments*6 !== gindx) + console.error('SURF grid draw mismatch ngridsegm', ngridsegments, 'gindx', gindx, 'diff', ngridsegments*6 - gindx); + + var material; + + if (this.options.Surf === 1) + material = new THREE.LineDashedMaterial( { color: 0x0, dashSize: 2, gapSize: 2 } ); + else + material = new THREE.LineBasicMaterial({ color: new THREE.Color(this.get_color(histo.fLineColor)) }); + + var line = JSROOT.Painter.createLineSegments(grid, material); + line.painter = this; + main.toplevel.add(line); + } + + if (this.options.Surf === 17) + this.DrawContour3D(); + + if (this.options.Surf === 13) { + + handle = this.PrepareColorDraw({rounding: false, use3d: true, extra: 100, middle: 0.0 }); + + // get levels + var levels = this.GetContour(), // init contour + palette = this.GetPalette(), + lastcolindx = -1, layerz = 2*main.size_z3d; + + this.BuildContour(handle, levels, palette, + function(colindx,xp,yp,iminus,iplus) { + // ignore less than three points + if (iplus - iminus < 3) return; + + var pnts = []; + + for (var i = iminus; i<=iplus; ++i) + if ((i === iminus) || (xp[i] !== xp[i-1]) || (yp[i] !== yp[i-1])) + pnts.push(new THREE.Vector2(xp[i], yp[i])); + + if (pnts.length < 3) return; + + var faces = THREE.ShapeUtils.triangulateShape(pnts , []); + + if (!faces || (faces.length === 0)) return; + + if ((lastcolindx < 0) || (lastcolindx !== colindx)) { + lastcolindx = colindx; + layerz+=0.0001*main.size_z3d; // change layers Z + } + + var pos = new Float32Array(faces.length*9), + norm = new Float32Array(faces.length*9), + indx = 0; + + for (var n=0;n<faces.length;++n) { + var face = faces[n]; + for (var v=0;v<3;++v) { + var pnt = pnts[face[v]]; + pos[indx] = pnt.x; + pos[indx+1] = pnt.y; + pos[indx+2] = layerz; + norm[indx] = 0; + norm[indx+1] = 0; + norm[indx+2] = 1; + + indx+=3; + } + } + + var geometry = new THREE.BufferGeometry(); + geometry.addAttribute( 'position', new THREE.BufferAttribute( pos, 3 ) ); + geometry.addAttribute( 'normal', new THREE.BufferAttribute( norm, 3 ) ); + + var fcolor = palette.getColor(colindx); + var material = new THREE.MeshBasicMaterial( { color: fcolor, flatShading: true, side: THREE.DoubleSide, opacity: 0.5 } ); + var mesh = new THREE.Mesh(geometry, material); + mesh.painter = this; + main.toplevel.add(mesh); + } + ); + } + } + + JSROOT.TH2Painter.prototype.DrawError = function() { + var pthis = this, + main = this.frame_painter(), + handle = this.PrepareColorDraw({ rounding: false, use3d: true, extra: 1 }), + zmin = main.grz.domain()[0], + zmax = main.grz.domain()[1], + i, j, bin, binz, binerr, x1, y1, x2, y2, z1, z2, + nsegments = 0, lpos = null, binindx = null, lindx = 0; + + function check_skip_min() { + // return true if minimal histogram value should be skipped + if (pthis.options.Zero || (zmin>0)) return false; + return !pthis._show_empty_bins; + } + + // loop over the points - first loop counts points, second fill arrays + for (var loop=0;loop<2;++loop) { + + for (i=handle.i1;i<handle.i2;++i) { + x1 = handle.grx[i]; + x2 = handle.grx[i+1]; + for (j=handle.j1;j<handle.j2;++j) { + binz = this.histo.getBinContent(i+1, j+1); + if ((binz < zmin) || (binz > zmax)) continue; + if ((binz===zmin) && check_skip_min()) continue; + + // just count number of segments + if (loop===0) { nsegments+=3; continue; } + + bin = this.histo.getBin(i+1,j+1); + binerr = this.histo.getBinError(bin); + binindx[lindx/18] = bin; + + y1 = handle.gry[j]; + y2 = handle.gry[j+1]; + + z1 = main.grz((binz - binerr < zmin) ? zmin : binz-binerr); + z2 = main.grz((binz + binerr > zmax) ? zmax : binz+binerr); + + lpos[lindx] = x1; lpos[lindx+3] = x2; + lpos[lindx+1] = lpos[lindx+4] = (y1+y2)/2; + lpos[lindx+2] = lpos[lindx+5] = (z1+z2)/2; + lindx+=6; + + lpos[lindx] = lpos[lindx+3] = (x1+x2)/2; + lpos[lindx+1] = y1; lpos[lindx+4] = y2; + lpos[lindx+2] = lpos[lindx+5] = (z1+z2)/2; + lindx+=6; + + lpos[lindx] = lpos[lindx+3] = (x1+x2)/2; + lpos[lindx+1] = lpos[lindx+4] = (y1+y2)/2; + lpos[lindx+2] = z1; lpos[lindx+5] = z2; + lindx+=6; + } + } + + if (loop===0) { + if (nsegments===0) return; + lpos = new Float32Array(nsegments*6); + binindx = new Int32Array(nsegments/3); + } + } + + // create lines + var lcolor = this.get_color(this.GetObject().fLineColor), + material = new THREE.LineBasicMaterial({ color: new THREE.Color(lcolor) }), + line = JSROOT.Painter.createLineSegments(lpos, material); + + if (!JSROOT.browser.isIE) material.linewidth = this.GetObject().fLineWidth; + + line.painter = this; + line.intersect_index = binindx; + line.zmin = zmin; + line.zmax = zmax; + line.tip_color = (this.GetObject().fLineColor===3) ? 0xFF0000 : 0x00FF00; + + line.tooltip = function(intersect) { + if (isNaN(intersect.index)) { + console.error('segment index not provided, check three.js version', THREE.REVISION, 'expected r97'); + return null; + } + + var pos = Math.floor(intersect.index / 6); + if ((pos<0) || (pos >= this.intersect_index.length)) return null; + var p = this.painter, + histo = p.GetHisto(), + main = p.frame_painter(), + tip = p.Get3DToolTip(this.intersect_index[pos]); + + tip.x1 = Math.max(-main.size_xy3d, main.grx(histo.fXaxis.GetBinLowEdge(tip.ix))); + tip.x2 = Math.min(main.size_xy3d, main.grx(histo.fXaxis.GetBinLowEdge(tip.ix+1))); + tip.y1 = Math.max(-main.size_xy3d, main.gry(histo.fYaxis.GetBinLowEdge(tip.iy))); + tip.y2 = Math.min(main.size_xy3d, main.gry(histo.fXaxis.GetBinLowEdge(tip.iy+1))); + + tip.z1 = main.grz(tip.value-tip.error < this.zmin ? this.zmin : tip.value-tip.error); + tip.z2 = main.grz(tip.value+tip.error > this.zmax ? this.zmax : tip.value+tip.error); + + tip.color = this.tip_color; + + return tip; + } + + main.toplevel.add(line); + } + + JSROOT.TH2Painter.prototype.DrawPolyLego = function() { + var histo = this.GetHisto(), + pmain = this.frame_painter(), + axis_zmin = pmain.grz.domain()[0], + axis_zmax = pmain.grz.domain()[1], + colindx, bin, i, len = histo.fBins.arr.length, cnt = 0, totalnfaces = 0, + z0 = pmain.grz(axis_zmin), z1 = z0; + + // force recalculations of contours + this.fContour = null; + this.fCustomContour = false; + + // use global coordinates + this.maxbin = this.gmaxbin; + this.minbin = this.gminbin; + this.minposbin = this.gminposbin; + + for (i = 0; i < len; ++ i) { + bin = histo.fBins.arr[i]; + if (bin.fContent < axis_zmin) continue; + + colindx = this.getContourColor(bin.fContent, true); + if (colindx === null) continue; + + // check if bin outside visible range + if ((bin.fXmin > pmain.scale_xmax) || (bin.fXmax < pmain.scale_xmin) || + (bin.fYmin > pmain.scale_ymax) || (bin.fYmax < pmain.scale_ymin)) continue; + + z1 = pmain.grz((bin.fContent > axis_zmax) ? axis_zmax : bin.fContent); + + var all_pnts = [], all_faces = [], + ngraphs = 1, gr = bin.fPoly, nfaces = 0; + + if (gr._typename=='TMultiGraph') { + ngraphs = bin.fPoly.fGraphs.arr.length; + gr = null; + } + + for (var ngr = 0; ngr < ngraphs; ++ngr) { + if (!gr || (ngr>0)) gr = bin.fPoly.fGraphs.arr[ngr]; + + var npnts = gr.fNpoints, x = gr.fX, y = gr.fY; + while ((npnts>2) && (x[0]===x[npnts-1]) && (y[0]===y[npnts-1])) --npnts; + + var pnts, faces; + + for (var ntry=0;ntry<2;++ntry) { + // run two loops - on the first try to compress data, on second - run as is (removing duplication) + + var lastx, lasty, currx, curry, + dist2 = pmain.size_xy3d*pmain.size_z3d, + dist2limit = (ntry>0) ? 0 : dist2/1e6; + + pnts = []; faces = null; + + for (var vert = 0; vert < npnts; ++vert) { + currx = pmain.grx(x[vert]); + curry = pmain.gry(y[vert]); + if (vert>0) + dist2 = (currx-lastx)*(currx-lastx) + (curry-lasty)*(curry-lasty); + if (dist2 > dist2limit) { + pnts.push(new THREE.Vector2(currx, curry)); + lastx = currx; + lasty = curry; + } + } + + try { + if (pnts.length > 2) + faces = THREE.ShapeUtils.triangulateShape(pnts , []); + } catch(e) { + faces = null; + } + + if (faces && (faces.length>pnts.length-3)) break; + } + + if (faces && faces.length && pnts) { + all_pnts.push(pnts); + all_faces.push(faces); + + nfaces += faces.length * 2; + if (z1>z0) nfaces += pnts.length*2; + } + } + + var pos = new Float32Array(nfaces*9), indx = 0; + + for (var ngr=0;ngr<all_pnts.length;++ngr) { + var pnts = all_pnts[ngr], faces = all_faces[ngr]; + + for (var layer=0;layer<2;++layer) { + for (var n=0;n<faces.length;++n) { + var face = faces[n], + pnt1 = pnts[face[0]], + pnt2 = pnts[face[(layer===0) ? 2 : 1]], + pnt3 = pnts[face[(layer===0) ? 1 : 2]]; + + pos[indx] = pnt1.x; + pos[indx+1] = pnt1.y; + pos[indx+2] = layer ? z1 : z0; + indx+=3; + + pos[indx] = pnt2.x; + pos[indx+1] = pnt2.y; + pos[indx+2] = layer ? z1 : z0; + indx+=3; + + pos[indx] = pnt3.x; + pos[indx+1] = pnt3.y; + pos[indx+2] = layer ? z1 : z0; + indx+=3; + } + } + + if (z1>z0) { + for (var n=0;n<pnts.length;++n) { + var pnt1 = pnts[n], + pnt2 = pnts[(n>0) ? n-1 : pnts.length-1]; + + pos[indx] = pnt1.x; + pos[indx+1] = pnt1.y; + pos[indx+2] = z0; + indx+=3; + + pos[indx] = pnt2.x; + pos[indx+1] = pnt2.y; + pos[indx+2] = z0; + indx+=3; + + pos[indx] = pnt2.x; + pos[indx+1] = pnt2.y; + pos[indx+2] = z1; + indx+=3; + + pos[indx] = pnt1.x; + pos[indx+1] = pnt1.y; + pos[indx+2] = z0; + indx+=3; + + pos[indx] = pnt2.x; + pos[indx+1] = pnt2.y; + pos[indx+2] = z1; + indx+=3; + + pos[indx] = pnt1.x; + pos[indx+1] = pnt1.y; + pos[indx+2] = z1; + indx+=3; + } + } + } + + var geometry = new THREE.BufferGeometry(); + geometry.addAttribute( 'position', new THREE.BufferAttribute( pos, 3 ) ); + geometry.computeVertexNormals(); + + var fcolor = this.fPalette.getColor(colindx); + var material = new THREE.MeshBasicMaterial( { color: fcolor, flatShading: true } ); + var mesh = new THREE.Mesh(geometry, material); + + pmain.toplevel.add(mesh); + + mesh.painter = this; + mesh.bins_index = i; + mesh.draw_z0 = z0; + mesh.draw_z1 = z1; + mesh.tip_color = 0x00FF00; + + mesh.tooltip = function(intersects) { + + var p = this.painter, main = p.frame_painter(), + bin = p.GetObject().fBins.arr[this.bins_index]; + + var tip = { + use_itself: true, // indicate that use mesh itself for highlighting + x1: main.grx(bin.fXmin), + x2: main.grx(bin.fXmax), + y1: main.gry(bin.fYmin), + y2: main.gry(bin.fYmax), + z1: this.draw_z0, + z2: this.draw_z1, + bin: this.bins_index, + value: bin.fContent, + color: this.tip_color, + lines: p.ProvidePolyBinHints(this.bins_index) + }; + + return tip; + }; + + totalnfaces += nfaces; + cnt++; + } + } + + // ============================================================================== + + function TH3Painter(histo) { + JSROOT.THistPainter.call(this, histo); + + this.mode3d = true; + } + + TH3Painter.prototype = Object.create(JSROOT.THistPainter.prototype); + + TH3Painter.prototype.ScanContent = function(when_axis_changed) { + + // no need to rescan histogram while result does not depend from axis selection + if (when_axis_changed && this.nbinsx && this.nbinsy && this.nbinsz) return; + + var histo = this.GetObject(); + + this.nbinsx = histo.fXaxis.fNbins; + this.nbinsy = histo.fYaxis.fNbins; + this.nbinsz = histo.fZaxis.fNbins; + + this.xmin = histo.fXaxis.fXmin; + this.xmax = histo.fXaxis.fXmax; + + this.ymin = histo.fYaxis.fXmin; + this.ymax = histo.fYaxis.fXmax; + + this.zmin = histo.fZaxis.fXmin; + this.zmax = histo.fZaxis.fXmax; + + // global min/max, used at the moment in 3D drawing + + this.gminbin = this.gmaxbin = histo.getBinContent(1,1,1); + + for (var i = 0; i < this.nbinsx; ++i) + for (var j = 0; j < this.nbinsy; ++j) + for (var k = 0; k < this.nbinsz; ++k) { + var bin_content = histo.getBinContent(i+1, j+1, k+1); + if (bin_content < this.gminbin) this.gminbin = bin_content; else + if (bin_content > this.gmaxbin) this.gmaxbin = bin_content; + } + + this.draw_content = this.gmaxbin > 0; + + this.CreateAxisFuncs(true, true); + } + + TH3Painter.prototype.CountStat = function() { + var histo = this.GetHisto(), xaxis = histo.fXaxis, yaxis = histo.fYaxis, zaxis = histo.fZaxis, + stat_sum0 = 0, stat_sumx1 = 0, stat_sumy1 = 0, + stat_sumz1 = 0, stat_sumx2 = 0, stat_sumy2 = 0, stat_sumz2 = 0, + i1 = this.GetSelectIndex("x", "left"), + i2 = this.GetSelectIndex("x", "right"), + j1 = this.GetSelectIndex("y", "left"), + j2 = this.GetSelectIndex("y", "right"), + k1 = this.GetSelectIndex("z", "left"), + k2 = this.GetSelectIndex("z", "right"), + fp = this.frame_painter(), + res = { name: histo.fName, entries: 0, integral: 0, meanx: 0, meany: 0, meanz: 0, rmsx: 0, rmsy: 0, rmsz: 0 }, + xi, yi, zi, xx, xside, yy, yside, zz, zside, cont; + + for (xi = 0; xi < this.nbinsx+2; ++xi) { + + xx = xaxis.GetBinCoord(xi - 0.5); + xside = (xi < i1) ? 0 : (xi > i2 ? 2 : 1); + + for (yi = 0; yi < this.nbinsy+2; ++yi) { + + yy = yaxis.GetBinCoord(yi - 0.5); + yside = (yi < j1) ? 0 : (yi > j2 ? 2 : 1); + + for (zi = 0; zi < this.nbinsz+2; ++zi) { + + zz = zaxis.GetBinCoord(zi - 0.5); + zside = (zi < k1) ? 0 : (zi > k2 ? 2 : 1); + + cont = histo.getBinContent(xi, yi, zi); + res.entries += cont; + + if ((xside==1) && (yside==1) && (zside==1)) { + stat_sum0 += cont; + stat_sumx1 += xx * cont; + stat_sumy1 += yy * cont; + stat_sumz1 += zz * cont; + stat_sumx2 += xx * xx * cont; + stat_sumy2 += yy * yy * cont; + stat_sumz2 += zz * zz * cont; + } + } + } + } + + if ((histo.fTsumw > 0) && !fp.IsAxisZoomed("x") && !fp.IsAxisZoomed("y") && !fp.IsAxisZoomed("z")) { + stat_sum0 = histo.fTsumw; + stat_sumx1 = histo.fTsumwx; + stat_sumx2 = histo.fTsumwx2; + stat_sumy1 = histo.fTsumwy; + stat_sumy2 = histo.fTsumwy2; + stat_sumz1 = histo.fTsumwz; + stat_sumz2 = histo.fTsumwz2; + } + + if (stat_sum0 > 0) { + res.meanx = stat_sumx1 / stat_sum0; + res.meany = stat_sumy1 / stat_sum0; + res.meanz = stat_sumz1 / stat_sum0; + res.rmsx = Math.sqrt(Math.abs(stat_sumx2 / stat_sum0 - res.meanx * res.meanx)); + res.rmsy = Math.sqrt(Math.abs(stat_sumy2 / stat_sum0 - res.meany * res.meany)); + res.rmsz = Math.sqrt(Math.abs(stat_sumz2 / stat_sum0 - res.meanz * res.meanz)); + } + + res.integral = stat_sum0; + + if (histo.fEntries > 1) res.entries = histo.fEntries; + + return res; + } + + TH3Painter.prototype.FillStatistic = function(stat, dostat, dofit) { + + // no need to refill statistic if histogram is dummy + if (this.IgnoreStatsFill()) return false; + + var data = this.CountStat(), + print_name = dostat % 10, + print_entries = Math.floor(dostat / 10) % 10, + print_mean = Math.floor(dostat / 100) % 10, + print_rms = Math.floor(dostat / 1000) % 10, + print_under = Math.floor(dostat / 10000) % 10, + print_over = Math.floor(dostat / 100000) % 10, + print_integral = Math.floor(dostat / 1000000) % 10; + //var print_skew = Math.floor(dostat / 10000000) % 10; + //var print_kurt = Math.floor(dostat / 100000000) % 10; + + stat.ClearPave(); + + if (print_name > 0) + stat.AddText(data.name); + + if (print_entries > 0) + stat.AddText("Entries = " + stat.Format(data.entries,"entries")); + + if (print_mean > 0) { + stat.AddText("Mean x = " + stat.Format(data.meanx)); + stat.AddText("Mean y = " + stat.Format(data.meany)); + stat.AddText("Mean z = " + stat.Format(data.meanz)); + } + + if (print_rms > 0) { + stat.AddText("Std Dev x = " + stat.Format(data.rmsx)); + stat.AddText("Std Dev y = " + stat.Format(data.rmsy)); + stat.AddText("Std Dev z = " + stat.Format(data.rmsz)); + } + + if (print_integral > 0) { + stat.AddText("Integral = " + stat.Format(data.integral,"entries")); + } + + if (dofit) stat.FillFunctionStat(this.FindFunction('TF1'), dofit); + + return true; + } + + TH3Painter.prototype.GetBinTips = function (ix, iy, iz) { + var lines = [], pmain = this.frame_painter(), histo = this.GetHisto(); + + lines.push(this.GetTipName()); + + if (pmain.x_kind == 'labels') + lines.push("x = " + pmain.AxisAsText("x", histo.fXaxis.GetBinLowEdge(ix+1)) + " xbin=" + (ix+1)); + else + lines.push("x = [" + pmain.AxisAsText("x", histo.fXaxis.GetBinLowEdge(ix+1)) + ", " + pmain.AxisAsText("x", histo.fXaxis.GetBinLowEdge(ix+2)) + ") xbin=" + (ix+1)); + + if (pmain.y_kind == 'labels') + lines.push("y = " + pmain.AxisAsText("y", histo.fYaxis.GetBinLowEdge(iy+1)) + " ybin=" + (iy+1)); + else + lines.push("y = [" + pmain.AxisAsText("y", histo.fYaxis.GetBinLowEdge(iy+1)) + ", " + pmain.AxisAsText("y", histo.fYaxis.GetBinLowEdge(iy+2)) + ") ybin=" + (iy+1)); + + if (pmain.z_kind == 'labels') + lines.push("z = " + pmain.AxisAsText("z", histo.fZaxis.GetBinLowEdge(iz+1)) + " zbin=" + (iz+1)); + else + lines.push("z = [" + pmain.AxisAsText("z", histo.fZaxis.GetBinLowEdge(iz+1)) + ", " + pmain.AxisAsText("z", histo.fZaxis.GetBinLowEdge(iz+2)) + ") zbin=" + (iz+1)); + + var binz = histo.getBinContent(ix+1, iy+1, iz+1); + if (binz === Math.round(binz)) + lines.push("entries = " + binz); + else + lines.push("entries = " + JSROOT.FFormat(binz, JSROOT.gStyle.fStatFormat)); + + return lines; + } + + TH3Painter.prototype.Draw3DScatter = function() { + // try to draw 3D histogram as scatter plot + // if too many points, box will be displayed + + var histo = this.GetObject(), + main = this.frame_painter(), + i1 = this.GetSelectIndex("x", "left", 0.5), + i2 = this.GetSelectIndex("x", "right", 0), + j1 = this.GetSelectIndex("y", "left", 0.5), + j2 = this.GetSelectIndex("y", "right", 0), + k1 = this.GetSelectIndex("z", "left", 0.5), + k2 = this.GetSelectIndex("z", "right", 0), + name = this.GetTipName("<br/>"), + i, j, k, bin_content; + + if ((i2<=i1) || (j2<=j1) || (k2<=k1)) return true; + + // scale down factor if too large values + var coef = (this.gmaxbin > 1000) ? 1000/this.gmaxbin : 1, + numpixels = 0, sumz = 0, content_lmt = Math.max(0, this.gminbin); + + for (i = i1; i < i2; ++i) { + for (j = j1; j < j2; ++j) { + for (k = k1; k < k2; ++k) { + bin_content = histo.getBinContent(i+1, j+1, k+1); + sumz += bin_content; + if (bin_content <= content_lmt) continue; + numpixels += Math.round(bin_content*coef); + } + } + } + + // too many pixels - use box drawing + if (numpixels > (main.webgl ? 100000 : 30000)) return false; + + JSROOT.seed(sumz); + + var pnts = new JSROOT.Painter.PointsCreator(numpixels, main.webgl, main.size_xy3d/200), + bins = new Int32Array(numpixels), nbin = 0; + + for (i = i1; i < i2; ++i) { + for (j = j1; j < j2; ++j) { + for (k = k1; k < k2; ++k) { + bin_content = histo.getBinContent(i+1, j+1, k+1); + if (bin_content <= content_lmt) continue; + var num = Math.round(bin_content*coef); + + for (var n=0;n<num;++n) { + var binx = histo.fXaxis.GetBinCoord(i+JSROOT.random()), + biny = histo.fYaxis.GetBinCoord(j+JSROOT.random()), + binz = histo.fZaxis.GetBinCoord(k+JSROOT.random()); + + // remember bin index for tooltip + bins[nbin++] = histo.getBin(i+1, j+1, k+1); + + pnts.AddPoint(main.grx(binx), main.gry(biny), main.grz(binz)); + } + } + } + } + + var mesh = pnts.CreatePoints(this.get_color(histo.fMarkerColor)); + main.toplevel.add(mesh); + + mesh.bins = bins; + mesh.painter = this; + mesh.tip_color = (histo.fMarkerColor===3) ? 0xFF0000 : 0x00FF00; + + mesh.tooltip = function(intersect) { + if (isNaN(intersect.index)) { + console.error('intersect.index not provided, check three.js version', THREE.REVISION, 'expected r97'); + return null; + } + + var indx = Math.floor(intersect.index / this.nvertex); + if ((indx<0) || (indx >= this.bins.length)) return null; + + var p = this.painter, histo = p.GetHisto(), + main = p.frame_painter(), + tip = p.Get3DToolTip(this.bins[indx]); + + tip.x1 = main.grx(histo.fXaxis.GetBinLowEdge(tip.ix)); + tip.x2 = main.grx(histo.fXaxis.GetBinLowEdge(tip.ix+1)); + tip.y1 = main.gry(histo.fYaxis.GetBinLowEdge(tip.iy)); + tip.y2 = main.gry(histo.fYaxis.GetBinLowEdge(tip.iy+1)); + tip.z1 = main.grz(histo.fZaxis.GetBinLowEdge(tip.iz)); + tip.z2 = main.grz(histo.fZaxis.GetBinLowEdge(tip.iz+1)); + tip.color = this.tip_color; + tip.opacity = 0.3; + + return tip; + } + + + return true; + } + + TH3Painter.prototype.Draw3DBins = function() { + + if (!this.draw_content) return; + + if (!this.options.Box && !this.options.GLBox && !this.options.GLColor && !this.options.Lego) + if (this.Draw3DScatter()) return; + + var rootcolor = this.GetObject().fFillColor, + fillcolor = this.get_color(rootcolor), + main = this.frame_painter(), + buffer_size = 0, use_lambert = false, + use_helper = false, use_colors = false, use_opacity = 1, use_scale = true, + single_bin_verts, single_bin_norms, + box_option = this.options.Box ? this.options.BoxStyle : 0, + tipscale = 0.5; + + if (!box_option && this.options.Lego) box_option = (this.options.Lego===1) ? 10 : this.options.Lego; + + if ((this.options.GLBox === 11) || (this.options.GLBox === 12)) { + + tipscale = 0.4; + use_lambert = true; + if (this.options.GLBox === 12) use_colors = true; + + var geom = JSROOT.Painter.TestWebGL() ? new THREE.SphereGeometry(0.5, 16, 12) : new THREE.SphereGeometry(0.5, 8, 6); + geom.applyMatrix( new THREE.Matrix4().makeRotationX( Math.PI / 2 ) ); + + buffer_size = geom.faces.length*9; + single_bin_verts = new Float32Array(buffer_size); + single_bin_norms = new Float32Array(buffer_size); + + // Fill a typed array with cube geometry that will be shared by all + // (This technically could be put into an InstancedBufferGeometry but + // performance gain is likely not huge ) + for (var face = 0; face < geom.faces.length; ++face) { + single_bin_verts[9*face ] = geom.vertices[geom.faces[face].a].x; + single_bin_verts[9*face+1] = geom.vertices[geom.faces[face].a].y; + single_bin_verts[9*face+2] = geom.vertices[geom.faces[face].a].z; + single_bin_verts[9*face+3] = geom.vertices[geom.faces[face].b].x; + single_bin_verts[9*face+4] = geom.vertices[geom.faces[face].b].y; + single_bin_verts[9*face+5] = geom.vertices[geom.faces[face].b].z; + single_bin_verts[9*face+6] = geom.vertices[geom.faces[face].c].x; + single_bin_verts[9*face+7] = geom.vertices[geom.faces[face].c].y; + single_bin_verts[9*face+8] = geom.vertices[geom.faces[face].c].z; + + single_bin_norms[9*face ] = geom.faces[face].vertexNormals[0].x; + single_bin_norms[9*face+1] = geom.faces[face].vertexNormals[0].y; + single_bin_norms[9*face+2] = geom.faces[face].vertexNormals[0].z; + single_bin_norms[9*face+3] = geom.faces[face].vertexNormals[1].x; + single_bin_norms[9*face+4] = geom.faces[face].vertexNormals[1].y; + single_bin_norms[9*face+5] = geom.faces[face].vertexNormals[1].z; + single_bin_norms[9*face+6] = geom.faces[face].vertexNormals[2].x; + single_bin_norms[9*face+7] = geom.faces[face].vertexNormals[2].y; + single_bin_norms[9*face+8] = geom.faces[face].vertexNormals[2].z; + } + + } else { + + var indicies = JSROOT.Painter.Box3D.Indexes, + normals = JSROOT.Painter.Box3D.Normals, + vertices = JSROOT.Painter.Box3D.Vertices; + + buffer_size = indicies.length*3; + single_bin_verts = new Float32Array(buffer_size); + single_bin_norms = new Float32Array(buffer_size); + + for (var k=0,nn=-3;k<indicies.length;++k) { + var vert = vertices[indicies[k]]; + single_bin_verts[k*3] = vert.x-0.5; + single_bin_verts[k*3+1] = vert.y-0.5; + single_bin_verts[k*3+2] = vert.z-0.5; + + if (k%6===0) nn+=3; + single_bin_norms[k*3] = normals[nn]; + single_bin_norms[k*3+1] = normals[nn+1]; + single_bin_norms[k*3+2] = normals[nn+2]; + } + use_helper = true; + + if (box_option===12) { use_colors = true; } else + if (box_option===13) { use_colors = true; use_helper = false; } else + if (this.options.GLColor) { use_colors = true; use_opacity = 0.5; use_scale = false; use_helper = false; use_lambert = true; } + } + + if (use_scale) + use_scale = (this.gminbin || this.gmaxbin) ? 1 / Math.max(Math.abs(this.gminbin), Math.abs(this.gmaxbin)) : 1; + + var histo = this.GetHisto(), + i1 = this.GetSelectIndex("x", "left", 0.5), + i2 = this.GetSelectIndex("x", "right", 0), + j1 = this.GetSelectIndex("y", "left", 0.5), + j2 = this.GetSelectIndex("y", "right", 0), + k1 = this.GetSelectIndex("z", "left", 0.5), + k2 = this.GetSelectIndex("z", "right", 0), + name = this.GetTipName("<br/>"); + + if ((i2<=i1) || (j2<=j1) || (k2<=k1)) return; + + var scalex = (main.grx(histo.fXaxis.GetBinLowEdge(i2+1)) - main.grx(histo.fXaxis.GetBinLowEdge(i1+1))) / (i2-i1), + scaley = (main.gry(histo.fYaxis.GetBinLowEdge(j2+1)) - main.gry(histo.fYaxis.GetBinLowEdge(j1+1))) / (j2-j1), + scalez = (main.grz(histo.fZaxis.GetBinLowEdge(k2+1)) - main.grz(histo.fZaxis.GetBinLowEdge(k1+1))) / (k2-k1); + + var nbins = 0, i, j, k, wei, bin_content, cols_size = [], num_colors = 0, cols_sequence = []; + + for (i = i1; i < i2; ++i) { + for (j = j1; j < j2; ++j) { + for (k = k1; k < k2; ++k) { + bin_content = histo.getBinContent(i+1, j+1, k+1); + if ((bin_content===0) || (bin_content < this.gminbin)) continue; + wei = use_scale ? Math.pow(Math.abs(bin_content*use_scale), 0.3333) : 1; + if (wei < 1e-3) continue; // do not draw empty or very small bins + + nbins++; + + if (!use_colors) continue; + + var colindx = this.getContourColor(bin_content, true); + if (colindx !== null) { + if (cols_size[colindx] === undefined) { + cols_size[colindx] = 0; + cols_sequence[colindx] = num_colors++; + } + cols_size[colindx]+=1; + } else { + console.error('not found color for', bin_content); + } + } + } + } + + if (!use_colors) { + cols_size.push(nbins); + num_colors = 1; + cols_sequence = [0]; + } + + var cols_nbins = new Array(num_colors), + bin_verts = new Array(num_colors), + bin_norms = new Array(num_colors), + bin_tooltips = new Array(num_colors), + helper_kind = new Array(num_colors), + helper_indexes = new Array(num_colors), // helper_kind == 1, use original vertices + helper_positions = new Array(num_colors); // helper_kind == 2, all vertices copied into separate buffer + + for(var ncol=0;ncol<cols_size.length;++ncol) { + if (!cols_size[ncol]) continue; // ignore dummy colors + + nbins = cols_size[ncol]; // how many bins with specified color + var nseq = cols_sequence[ncol]; + + cols_nbins[nseq] = 0; // counter for the filled bins + + helper_kind[nseq] = 0; + + // 1 - use same vertices to create helper, one can use maximal 64K vertices + // 2 - all vertices copied into separate buffer + if (use_helper) + helper_kind[nseq] = (nbins * buffer_size / 3 > 0xFFF0) ? 2 : 1; + + bin_verts[nseq] = new Float32Array(nbins * buffer_size); + bin_norms[nseq] = new Float32Array(nbins * buffer_size); + bin_tooltips[nseq] = new Int32Array(nbins); + + if (helper_kind[nseq]===1) + helper_indexes[nseq] = new Uint16Array(nbins * JSROOT.Painter.Box3D.MeshSegments.length); + + if (helper_kind[nseq]===2) + helper_positions[nseq] = new Float32Array(nbins * JSROOT.Painter.Box3D.Segments.length * 3); + } + + var binx, grx, biny, gry, binz, grz; + + for (i = i1; i < i2; ++i) { + binx = histo.fXaxis.GetBinCenter(i+1); grx = main.grx(binx); + for (j = j1; j < j2; ++j) { + biny = histo.fYaxis.GetBinCenter(j+1); gry = main.gry(biny); + for (k = k1; k < k2; ++k) { + bin_content = histo.getBinContent(i+1, j+1, k+1); + if ((bin_content===0) || (bin_content < this.gminbin)) continue; + + wei = use_scale ? Math.pow(Math.abs(bin_content*use_scale), 0.3333) : 1; + if (wei < 1e-3) continue; // do not show very small bins + + var nseq = 0; + if (use_colors) { + var colindx = this.getContourColor(bin_content, true); + if (colindx === null) continue; + nseq = cols_sequence[colindx]; + } + + nbins = cols_nbins[nseq]; + + binz = histo.fZaxis.GetBinCenter(k+1); grz = main.grz(binz); + + // remember bin index for tooltip + bin_tooltips[nseq][nbins] = histo.getBin(i+1, j+1, k+1); + + var vvv = nbins * buffer_size, bin_v = bin_verts[nseq], bin_n = bin_norms[nseq]; + + // Grab the coordinates and scale that are being assigned to each bin + for (var vi = 0; vi < buffer_size; vi+=3, vvv+=3) { + bin_v[vvv] = grx + single_bin_verts[vi]*scalex*wei; + bin_v[vvv+1] = gry + single_bin_verts[vi+1]*scaley*wei; + bin_v[vvv+2] = grz + single_bin_verts[vi+2]*scalez*wei; + + bin_n[vvv] = single_bin_norms[vi]; + bin_n[vvv+1] = single_bin_norms[vi+1]; + bin_n[vvv+2] = single_bin_norms[vi+2]; + } + + if (helper_kind[nseq]===1) { + // reuse vertices created for the mesh + var helper_segments = JSROOT.Painter.Box3D.MeshSegments; + vvv = nbins * helper_segments.length; + var shift = Math.round(nbins * buffer_size/3), + helper_i = helper_indexes[nseq]; + for (var n=0;n<helper_segments.length;++n) + helper_i[vvv+n] = shift + helper_segments[n]; + } + + if (helper_kind[nseq]===2) { + var helper_segments = JSROOT.Painter.Box3D.Segments, + helper_p = helper_positions[nseq]; + vvv = nbins * helper_segments.length * 3; + for (var n=0;n<helper_segments.length;++n, vvv+=3) { + var vert = JSROOT.Painter.Box3D.Vertices[helper_segments[n]]; + helper_p[vvv] = grx + (vert.x-0.5)*scalex*wei; + helper_p[vvv+1] = gry + (vert.y-0.5)*scaley*wei; + helper_p[vvv+2] = grz + (vert.z-0.5)*scalez*wei; + } + } + + cols_nbins[nseq] = nbins+1; + } + } + } + + for(var ncol=0;ncol<cols_size.length;++ncol) { + if (!cols_size[ncol]) continue; // ignore dummy colors + + nbins = cols_size[ncol]; // how many bins with specified color + var nseq = cols_sequence[ncol]; + + // BufferGeometries that store geometry of all bins + var all_bins_buffgeom = new THREE.BufferGeometry(); + + // Create mesh from bin buffergeometry + all_bins_buffgeom.addAttribute('position', new THREE.BufferAttribute( bin_verts[nseq], 3 ) ); + all_bins_buffgeom.addAttribute('normal', new THREE.BufferAttribute( bin_norms[nseq], 3 ) ); + + if (use_colors) fillcolor = this.fPalette.getColor(ncol); + + var material = use_lambert ? new THREE.MeshLambertMaterial({ color: fillcolor, opacity: use_opacity, transparent: (use_opacity<1) }) + : new THREE.MeshBasicMaterial({ color: fillcolor, opacity: use_opacity }); + + var combined_bins = new THREE.Mesh(all_bins_buffgeom, material); + + combined_bins.bins = bin_tooltips[nseq]; + combined_bins.bins_faces = buffer_size/9; + combined_bins.painter = this; + + combined_bins.scalex = tipscale*scalex; + combined_bins.scaley = tipscale*scaley; + combined_bins.scalez = tipscale*scalez; + combined_bins.tip_color = (rootcolor===3) ? 0xFF0000 : 0x00FF00; + combined_bins.use_scale = use_scale; + + combined_bins.tooltip = function(intersect) { + if (isNaN(intersect.faceIndex)) { + console.error('intersect.faceIndex not provided, check three.js version', THREE.REVISION, 'expected r97'); + return null; + } + var indx = Math.floor(intersect.faceIndex / this.bins_faces); + if ((indx<0) || (indx >= this.bins.length)) return null; + + var p = this.painter, + histo = p.GetHisto(), + main = p.frame_painter(), + tip = p.Get3DToolTip(this.bins[indx]), + grx = main.grx(histo.fXaxis.GetBinCoord(tip.ix-0.5)), + gry = main.gry(histo.fYaxis.GetBinCoord(tip.iy-0.5)), + grz = main.grz(histo.fZaxis.GetBinCoord(tip.iz-0.5)), + wei = this.use_scale ? Math.pow(Math.abs(tip.value*this.use_scale), 0.3333) : 1; + + tip.x1 = grx - this.scalex*wei; tip.x2 = grx + this.scalex*wei; + tip.y1 = gry - this.scaley*wei; tip.y2 = gry + this.scaley*wei; + tip.z1 = grz - this.scalez*wei; tip.z2 = grz + this.scalez*wei; + + tip.color = this.tip_color; + + return tip; + } + + main.toplevel.add(combined_bins); + + if (helper_kind[nseq] > 0) { + var lcolor = this.get_color(this.GetObject().fLineColor), + helper_material = new THREE.LineBasicMaterial( { color: lcolor } ), + lines = null; + + if (helper_kind[nseq] === 1) { + // reuse positions from the mesh - only special index was created + lines = JSROOT.Painter.createLineSegments( bin_verts[nseq], helper_material, helper_indexes[nseq] ); + } else { + lines = JSROOT.Painter.createLineSegments( helper_positions[nseq], helper_material ); + } + + main.toplevel.add(lines); + } + } + } + + TH3Painter.prototype.Redraw = function(resize) { + + var main = this.frame_painter(), // who makes axis and 3D drawing + histo = this.GetHisto(); + + if (resize) { + + if (main.Resize3D()) main.Render3D(); + + } else { + + main.Create3DScene(); + main.SetAxesRanges(histo.fXaxis, this.xmin, this.xmax, histo.fYaxis, this.ymin, this.ymax, histo.fZaxis, this.zmin, this.zmax); + main.Set3DOptions(this.options); + main.DrawXYZ(main.toplevel, { zoom: JSROOT.gStyle.Zooming, ndim: 3 }); + this.Draw3DBins(); + main.Render3D(); + this.UpdateStatWebCanvas(); + main.AddKeysHandler(); + } + + this.DrawTitle(); + } + + TH3Painter.prototype.FillToolbar = function() { + var pp = this.pad_painter(); + if (!pp) return; + + pp.AddButton(JSROOT.ToolbarIcons.auto_zoom, 'Unzoom all axes', 'ToggleZoom', "Ctrl *"); + if (this.draw_content) + pp.AddButton(JSROOT.ToolbarIcons.statbox, 'Toggle stat box', "ToggleStatBox"); + pp.ShowButtons(); + } + + TH3Painter.prototype.CanZoomIn = function(axis,min,max) { + // check if it makes sense to zoom inside specified axis range + var obj = this.GetHisto(); + if (obj) obj = obj["f"+axis.toUpperCase()+"axis"]; + return !obj || (obj.FindBin(max,0.5) - obj.FindBin(min,0) > 1); + } + + TH3Painter.prototype.AutoZoom = function() { + var i1 = this.GetSelectIndex("x", "left"), + i2 = this.GetSelectIndex("x", "right"), + j1 = this.GetSelectIndex("y", "left"), + j2 = this.GetSelectIndex("y", "right"), + k1 = this.GetSelectIndex("z", "left"), + k2 = this.GetSelectIndex("z", "right"), + i,j,k, histo = this.GetObject(); + + if ((i1 === i2) || (j1 === j2) || (k1 === k2)) return; + + // first find minimum + var min = histo.getBinContent(i1 + 1, j1 + 1, k1+1); + for (i = i1; i < i2; ++i) + for (j = j1; j < j2; ++j) + for (k = k1; k < k2; ++k) + min = Math.min(min, histo.getBinContent(i+1, j+1, k+1)); + + if (min>0) return; // if all points positive, no chance for autoscale + + var ileft = i2, iright = i1, jleft = j2, jright = j1, kleft = k2, kright = k1; + + for (i = i1; i < i2; ++i) + for (j = j1; j < j2; ++j) + for (k = k1; k < k2; ++k) + if (histo.getBinContent(i+1, j+1, k+1) > min) { + if (i < ileft) ileft = i; + if (i >= iright) iright = i + 1; + if (j < jleft) jleft = j; + if (j >= jright) jright = j + 1; + if (k < kleft) kleft = k; + if (k >= kright) kright = k + 1; + } + + var xmin, xmax, ymin, ymax, zmin, zmax, isany = false; + + if ((ileft === iright-1) && (ileft > i1+1) && (iright < i2-1)) { ileft--; iright++; } + if ((jleft === jright-1) && (jleft > j1+1) && (jright < j2-1)) { jleft--; jright++; } + if ((kleft === kright-1) && (kleft > k1+1) && (kright < k2-1)) { kleft--; kright++; } + + if ((ileft > i1 || iright < i2) && (ileft < iright - 1)) { + xmin = histo.fXaxis.GetBinLowEdge(ileft+1); + xmax = histo.fXaxis.GetBinLowEdge(iright+1); + isany = true; + } + + if ((jleft > j1 || jright < j2) && (jleft < jright - 1)) { + ymin = histo.fYaxis.GetBinLowEdge(jleft+1); + ymax = histo.fYaxis.GetBinLowEdge(jright+1); + isany = true; + } + + if ((kleft > k1 || kright < k2) && (kleft < kright - 1)) { + zmin = histo.fZaxis.GetBinLowEdge(kleft+1); + zmax = histo.fZaxis.GetBinLowEdge(kright+1); + isany = true; + } + + if (isany) this.frame_painter().Zoom(xmin, xmax, ymin, ymax, zmin, zmax); + } + + TH3Painter.prototype.FillHistContextMenu = function(menu) { + + var sett = JSROOT.getDrawSettings("ROOT." + this.GetObject()._typename, 'nosame'); + + menu.addDrawMenu("Draw with", sett.opts, function(arg) { + if (arg==='inspect') + return JSROOT.draw(this.divid, this.GetObject(),arg); + + this.DecodeOptions(arg); + this.Redraw(); + this.InteractiveRedraw(true,"drawopt"); + }); + } + + JSROOT.Painter.drawHistogram3D = function(divid, histo, opt) { + // create painter and add it to canvas + var painter = new JSROOT.TH3Painter(histo); + + painter.SetDivId(divid, 4); + + painter.DecodeOptions(opt); + + painter.CheckPadRange(); + + painter.ScanContent(); + + painter.Redraw(); + + var stats = painter.CreateStat(); // only when required + if (stats) JSROOT.draw(painter.divid, stats, ""); + + painter.FillToolbar(); + + return painter.DrawingReady(); + } + + // =========================================================================================== + + function TGraph2DPainter(graph) { + JSROOT.TObjectPainter.call(this, graph); + } + + TGraph2DPainter.prototype = Object.create(JSROOT.TObjectPainter.prototype); + + TGraph2DPainter.prototype.DecodeOptions = function(opt) { + var d = new JSROOT.DrawOptions(opt); + + if (!this.options) + this.options = {}; + + var res = this.options; + + res.Color = d.check("COL"); + res.Line = d.check("LINE"); + res.Error = d.check("ERR") && this.MatchObjectType("TGraph2DErrors"); + res.Circles = d.check("P0"); + res.Markers = d.check("P"); + + if (!res.Markers && !res.Error && !res.Circles && !res.Line) res.Markers = true; + if (!res.Markers) res.Color = false; + + this.OptionsStore(opt); + } + + TGraph2DPainter.prototype.CreateHistogram = function() { + var gr = this.GetObject(), + xmin = gr.fX[0], xmax = xmin, + ymin = gr.fY[0], ymax = ymin, + zmin = gr.fZ[0], zmax = zmin; + + for (var p = 0; p < gr.fNpoints;++p) { + + var x = gr.fX[p], y = gr.fY[p], z = gr.fZ[p], + errx = this.options.Error ? gr.fEX[p] : 0, + erry = this.options.Error ? gr.fEY[p] : 0, + errz = this.options.Error ? gr.fEZ[p] : 0; + + xmin = Math.min(xmin, x-errx); + xmax = Math.max(xmax, x+errx); + ymin = Math.min(ymin, y-erry); + ymax = Math.max(ymax, y+erry); + zmin = Math.min(zmin, z-errz); + zmax = Math.max(zmax, z+errz); + } + + if (xmin >= xmax) xmax = xmin+1; + if (ymin >= ymax) ymax = ymin+1; + if (zmin >= zmax) zmax = zmin+1; + var dx = (xmax-xmin)*0.02, dy = (ymax-ymin)*0.02, dz = (zmax-zmin)*0.02, + uxmin = xmin - dx, uxmax = xmax + dx, + uymin = ymin - dy, uymax = ymax + dy, + uzmin = zmin - dz, uzmax = zmax + dz; + + if ((uxmin<0) && (xmin>=0)) uxmin = xmin*0.98; + if ((uxmax>0) && (xmax<=0)) uxmax = 0; + + if ((uymin<0) && (ymin>=0)) uymin = ymin*0.98; + if ((uymax>0) && (ymax<=0)) uymax = 0; + + if ((uzmin<0) && (zmin>=0)) uzmin = zmin*0.98; + if ((uzmax>0) && (zmax<=0)) uzmax = 0; + + var graph = this.GetObject(); + + if (graph.fMinimum != -1111) uzmin = graph.fMinimum; + if (graph.fMaximum != -1111) uzmax = graph.fMaximum; + + var histo = JSROOT.CreateHistogram("TH2I", 10, 10); + histo.fName = graph.fName + "_h"; + histo.fTitle = graph.fTitle; + histo.fXaxis.fXmin = uxmin; + histo.fXaxis.fXmax = uxmax; + histo.fYaxis.fXmin = uymin; + histo.fYaxis.fXmax = uymax; + histo.fZaxis.fXmin = uzmin; + histo.fZaxis.fXmax = uzmax; + histo.fMinimum = uzmin; + histo.fMaximum = uzmax; + histo.fBits = histo.fBits | JSROOT.TH1StatusBits.kNoStats; + return histo; + } + + TGraph2DPainter.prototype.Graph2DTooltip = function(intersect) { + if (isNaN(intersect.index)) { + console.error('intersect.index not provided, check three.js version', THREE.REVISION, 'expected r97'); + return null; + } + + var indx = Math.floor(intersect.index / this.nvertex); + if ((indx<0) || (indx >= this.index.length)) return null; + + indx = this.index[indx]; + + var p = this.painter, + grx = p.grx(this.graph.fX[indx]), + gry = p.gry(this.graph.fY[indx]), + grz = p.grz(this.graph.fZ[indx]); + + if (this.check_next && indx+1<this.graph.fX.length) { + function sqr(v) { return v*v; } + var d = intersect.point, + grx1 = p.grx(this.graph.fX[indx+1]), + gry1 = p.gry(this.graph.fY[indx+1]), + grz1 = p.grz(this.graph.fZ[indx+1]); + if (sqr(d.x-grx1)+sqr(d.y-gry1)+sqr(d.z-grz1) < sqr(d.x-grx)+sqr(d.y-gry)+sqr(d.z-grz)) { + grx = grx1; gry = gry1; grz = grz1; indx++; + } + } + + return { + x1: grx - this.scale0, + x2: grx + this.scale0, + y1: gry - this.scale0, + y2: gry + this.scale0, + z1: grz - this.scale0, + z2: grz + this.scale0, + color: this.tip_color, + lines: [ this.tip_name, + "pnt: " + indx, + "x: " + p.AxisAsText("x", this.graph.fX[indx]), + "y: " + p.AxisAsText("y", this.graph.fY[indx]), + "z: " + p.AxisAsText("z", this.graph.fZ[indx]) + ] + } + } + + TGraph2DPainter.prototype.Redraw = function() { + + var main = this.main_painter(), + fp = this.frame_painter(), + graph = this.GetObject(), + step = 1; + + if (!graph || !main || !fp || !fp.mode3d) return; + + function CountSelected(zmin, zmax) { + var cnt = 0; + for (var i=0; i < graph.fNpoints; ++i) { + if ((graph.fX[i] < fp.scale_xmin) || (graph.fX[i] > fp.scale_xmax) || + (graph.fY[i] < fp.scale_ymin) || (graph.fY[i] > fp.scale_ymax) || + (graph.fZ[i] < zmin) || (graph.fZ[i] >= zmax)) continue; + + ++cnt; + } + return cnt; + } + + // try to define scale-down factor + if ((JSROOT.gStyle.OptimizeDraw > 0) && !fp.webgl) { + var numselected = CountSelected(fp.scale_zmin, fp.scale_zmax), + sizelimit = 50000; + + if (numselected > sizelimit) { + step = Math.floor(numselected / sizelimit); + if (step <= 2) step = 2; + } + } + + var markeratt = new JSROOT.TAttMarkerHandler(graph), + palette = null, + levels = [fp.scale_zmin, fp.scale_zmax], + scale = fp.size_xy3d / 100 * markeratt.GetFullSize(); + + if (this.options.Circles) scale = 0.06*fp.size_xy3d; + + if (fp.usesvg) scale*=0.3; + + if (this.options.Color) { + levels = main.GetContour(); + palette = main.GetPalette(); + } + + for (var lvl=0;lvl<levels.length-1;++lvl) { + + var lvl_zmin = Math.max(levels[lvl], fp.scale_zmin), + lvl_zmax = Math.min(levels[lvl+1], fp.scale_zmax); + + if (lvl_zmin >= lvl_zmax) continue; + + var size = Math.floor(CountSelected(lvl_zmin, lvl_zmax) / step), + pnts = null, select = 0, + index = new Int32Array(size), icnt = 0, + err = null, line = null, ierr = 0, iline = 0; + + if (this.options.Markers || this.options.Circles) + pnts = new JSROOT.Painter.PointsCreator(size, fp.webgl, scale/3); + + if (this.options.Error) + err = new Float32Array(size*6*3); + + if (this.options.Line) + line = new Float32Array((size-1)*6); + + for (var i=0; i < graph.fNpoints; ++i) { + if ((graph.fX[i] < fp.scale_xmin) || (graph.fX[i] > fp.scale_xmax) || + (graph.fY[i] < fp.scale_ymin) || (graph.fY[i] > fp.scale_ymax) || + (graph.fZ[i] < lvl_zmin) || (graph.fZ[i] >= lvl_zmax)) continue; + + if (step > 1) { + select = (select+1) % step; + if (select!==0) continue; + } + + index[icnt++] = i; // remember point index for tooltip + + var x = fp.grx(graph.fX[i]), + y = fp.gry(graph.fY[i]), + z = fp.grz(graph.fZ[i]); + + if (pnts) pnts.AddPoint(x,y,z); + + if (err) { + err[ierr] = fp.grx(graph.fX[i] - graph.fEX[i]); + err[ierr+1] = y; + err[ierr+2] = z; + err[ierr+3] = fp.grx(graph.fX[i] + graph.fEX[i]); + err[ierr+4] = y; + err[ierr+5] = z; + ierr+=6; + err[ierr] = x; + err[ierr+1] = fp.gry(graph.fY[i] - graph.fEY[i]); + err[ierr+2] = z; + err[ierr+3] = x; + err[ierr+4] = fp.gry(graph.fY[i] + graph.fEY[i]); + err[ierr+5] = z; + ierr+=6; + err[ierr] = x; + err[ierr+1] = y; + err[ierr+2] = fp.grz(graph.fZ[i] - graph.fEZ[i]); + err[ierr+3] = x; + err[ierr+4] = y; + err[ierr+5] = fp.grz(graph.fZ[i] + graph.fEZ[i]);; + ierr+=6; + } + + if (line) { + if (iline>=6) { + line[iline] = line[iline-3]; + line[iline+1] = line[iline-2]; + line[iline+2] = line[iline-1]; + iline+=3; + } + line[iline] = x; + line[iline+1] = y; + line[iline+2] = z; + iline+=3; + } + } + + if (line && (iline>3) && (line.length == iline)) { + var lcolor = this.get_color(this.GetObject().fLineColor), + material = new THREE.LineBasicMaterial({ color: new THREE.Color(lcolor) }); + if (!JSROOT.browser.isIE) material.linewidth = this.GetObject().fLineWidth; + var linemesh = JSROOT.Painter.createLineSegments(line, material); + fp.toplevel.add(linemesh); + + linemesh.graph = graph; + linemesh.index = index; + linemesh.painter = fp; + linemesh.scale0 = 0.7*scale; + linemesh.tip_name = this.GetTipName(); + linemesh.tip_color = (graph.fMarkerColor === 3) ? 0xFF0000 : 0x00FF00; + linemesh.nvertex = 2; + linemesh.check_next = true; + + linemesh.tooltip = this.Graph2DTooltip; + } + + if (err) { + var lcolor = this.get_color(this.GetObject().fLineColor), + material = new THREE.LineBasicMaterial({ color: new THREE.Color(lcolor) }); + if (!JSROOT.browser.isIE) material.linewidth = this.GetObject().fLineWidth; + var errmesh = JSROOT.Painter.createLineSegments(err, material); + fp.toplevel.add(errmesh); + + errmesh.graph = graph; + errmesh.index = index; + errmesh.painter = fp; + errmesh.scale0 = 0.7*scale; + errmesh.tip_name = this.GetTipName(); + errmesh.tip_color = (graph.fMarkerColor === 3) ? 0xFF0000 : 0x00FF00; + errmesh.nvertex = 6; + + errmesh.tooltip = this.Graph2DTooltip; + } + + if (pnts) { + + var fcolor = 'blue'; + + if (!this.options.Circles) + fcolor = palette ? palette.calcColor(lvl, levels.length) : + this.get_color(graph.fMarkerColor); + + var mesh = pnts.CreatePoints(fcolor); + + fp.toplevel.add(mesh); + + mesh.graph = graph; + mesh.index = index; + mesh.painter = fp; + mesh.scale0 = 0.3*scale; + mesh.tip_name = this.GetTipName(); + mesh.tip_color = (graph.fMarkerColor === 3) ? 0xFF0000 : 0x00FF00; + + mesh.tooltip = this.Graph2DTooltip; + } + } + + fp.Render3D(100); // set large timeout to be able draw other points + } + + JSROOT.Painter.drawGraph2D = function(divid, gr, opt) { + + var painter = new JSROOT.TGraph2DPainter(gr); + + painter.SetDivId(divid, -1); // just to get access to existing elements + + painter.DecodeOptions(opt); + + if (painter.main_painter()) { + painter.SetDivId(divid); + painter.Redraw(); + return painter.DrawingReady(); + } + + if (!gr.fHistogram) + gr.fHistogram = painter.CreateHistogram(); + + JSROOT.draw(divid, gr.fHistogram, "lego;axis", function(hpainter) { + painter.ownhisto = true; + painter.SetDivId(divid); + painter.Redraw(); + return painter.DrawingReady(); + }); + + return painter; + } + + // =================================================================== + + JSROOT.Painter.drawPolyMarker3D = function(divid, poly, opt) { + + var painter = new JSROOT.TObjectPainter(poly); + + painter.SetDivId(divid); + + painter.Redraw = function() { + + var fp = this.frame_painter(); + + if (!fp || !fp.mode3d) return; + + var step = 1, sizelimit = 50000, numselect = 0; + + for (var i=0;i<poly.fP.length;i+=3) { + if ((poly.fP[i] < fp.scale_xmin) || (poly.fP[i] > fp.scale_xmax) || + (poly.fP[i+1] < fp.scale_ymin) || (poly.fP[i+1] > fp.scale_ymax) || + (poly.fP[i+2] < fp.scale_zmin) || (poly.fP[i+2] > fp.scale_zmax)) continue; + ++numselect; + } + + if ((JSROOT.gStyle.OptimizeDraw > 0) && (numselect > sizelimit)) { + step = Math.floor(numselect/sizelimit); + if (step <= 2) step = 2; + } + + var size = Math.floor(numselect/step), + pnts = new JSROOT.Painter.PointsCreator(size, fp.webgl, fp.size_xy3d/100), + index = new Int32Array(size), + select = 0, icnt = 0; + + for (var i=0; i<poly.fP.length; i+=3) { + + if ((poly.fP[i] < fp.scale_xmin) || (poly.fP[i] > fp.scale_xmax) || + (poly.fP[i+1] < fp.scale_ymin) || (poly.fP[i+1] > fp.scale_ymax) || + (poly.fP[i+2] < fp.scale_zmin) || (poly.fP[i+2] > fp.scale_zmax)) continue; + + if (step > 1) { + select = (select+1) % step; + if (select!==0) continue; + } + + index[icnt++] = i; + + pnts.AddPoint(fp.grx(poly.fP[i]), fp.gry(poly.fP[i+1]), fp.grz(poly.fP[i+2])); + } + + var mesh = pnts.CreatePoints(this.get_color(poly.fMarkerColor)); + + fp.toplevel.add(mesh); + + mesh.tip_color = (poly.fMarkerColor === 3) ? 0xFF0000 : 0x00FF00; + mesh.tip_name = poly.fName || "Poly3D"; + mesh.poly = poly; + mesh.painter = fp; + mesh.scale0 = 0.7*pnts.scale; + mesh.index = index; + + mesh.tooltip = function(intersect) { + if (isNaN(intersect.index)) { + console.error('intersect.index not provided, check three.js version', THREE.REVISION, 'expected r97'); + return null; + } + var indx = Math.floor(intersect.index / this.nvertex); + if ((indx<0) || (indx >= this.index.length)) return null; + + indx = this.index[indx]; + + var p = this.painter, + grx = p.grx(this.poly.fP[indx]), + gry = p.gry(this.poly.fP[indx+1]), + grz = p.grz(this.poly.fP[indx+2]); + + return { + x1: grx - this.scale0, + x2: grx + this.scale0, + y1: gry - this.scale0, + y2: gry + this.scale0, + z1: grz - this.scale0, + z2: grz + this.scale0, + color: this.tip_color, + lines: [ this.tip_name, + "pnt: " + indx/3, + "x: " + p.AxisAsText("x", this.poly.fP[indx]), + "y: " + p.AxisAsText("y", this.poly.fP[indx+1]), + "z: " + p.AxisAsText("z", this.poly.fP[indx+2]) + ] + } + + } + + fp.Render3D(100); // set large timeout to be able draw other points + } + + painter.Redraw(); + + return painter.DrawingReady(); + } + + JSROOT.TH3Painter = TH3Painter; + JSROOT.TGraph2DPainter = TGraph2DPainter; + + return JSROOT; +})); diff --git a/js/scripts/JSRootPainter.jquery.js b/js/scripts/JSRootPainter.jquery.js new file mode 100644 index 00000000000..6f41acd24b2 --- /dev/null +++ b/js/scripts/JSRootPainter.jquery.js @@ -0,0 +1,2220 @@ +/// @file JSRootPainter.jquery.js +/// Part of JavaScript ROOT graphics, dependent from jQuery functionality + +(function( factory ) { + if ( typeof define === "function" && define.amd ) { + define( ['jquery', 'jquery-ui', 'd3', 'JSRootPainter', 'JSRootPainter.hierarchy'], factory ); + } else { + + if (typeof jQuery == 'undefined') + throw new Error('jQuery not defined', 'JSRootPainter.jquery.js'); + + if (typeof jQuery.ui == 'undefined') + throw new Error('jQuery-ui not defined','JSRootPainter.jquery.js'); + + if (typeof d3 != 'object') + throw new Error('This extension requires d3.v3.js', 'JSRootPainter.jquery.js'); + + if (typeof JSROOT == 'undefined') + throw new Error('JSROOT is not defined', 'JSRootPainter.jquery.js'); + + if (typeof JSROOT.Painter != 'object') + throw new Error('JSROOT.Painter not defined', 'JSRootPainter.jquery.js'); + + factory(jQuery, jQuery.ui, d3, JSROOT); + } +} (function($, myui, d3, JSROOT) { + + "use strict"; + + JSROOT.sources.push("jq2d"); + + if ( typeof define === "function" && define.amd ) + JSROOT.loadScript('$$$style/jquery-ui.css'); + + JSROOT.Painter.createMenu = function(painter, maincallback) { + var menuname = 'root_ctx_menu'; + + if (!maincallback && typeof painter==='function') { maincallback = painter; painter = null; } + + var menu = { painter: painter, element: null, code: "", cnt: 1, funcs: {}, separ: false }; + + menu.add = function(name, arg, func) { + if (name == "separator") { this.code += "<li>-</li>"; this.separ = true; return; } + + if (name.indexOf("header:")==0) { + this.code += "<li class='ui-widget-header' style='padding:3px; padding-left:5px;'>"+name.substr(7)+"</li>"; + return; + } + + if (name=="endsub:") { this.code += "</ul></li>"; return; } + var close_tag = "</li>", style = ""; + if (name.indexOf("sub:")==0) { name = name.substr(4); close_tag="<ul>"; /* style += ";padding-right:2em" */} + + if (typeof arg == 'function') { func = arg; arg = name; } + + var item = ""; + + if (name.indexOf("chk:")==0) { item = "<span class='ui-icon ui-icon-check' style='margin:1px'></span>"; name = name.substr(4); } else + if (name.indexOf("unk:")==0) { item = "<span class='ui-icon ui-icon-blank' style='margin:1px'></span>"; name = name.substr(4); } + + // special handling of first versions with menu support + if (($.ui.version.indexOf("1.10")==0) || ($.ui.version.indexOf("1.9")==0)) + item = '<a href="#">' + item + name + '</a>'; + else + if ($.ui.version.indexOf("1.11")==0) + item += name; + else + item = '<div>' + item + name + '</div>'; + + this.code += "<li cnt='" + this.cnt + "' arg='" + arg + "' style='" + style + "'>" + item + close_tag; + if (typeof func == 'function') this.funcs[this.cnt] = func; // keep call-back function + + this.cnt++; + } + + menu.addchk = function(flag, name, arg, func) { + return this.add((flag ? "chk:" : "unk:") + name, arg, func); + } + + menu.size = function() { return this.cnt-1; } + + menu.addDrawMenu = function(menu_name, opts, call_back) { + if (!opts) opts = []; + if (opts.length==0) opts.push(""); + + var without_sub = false; + if (menu_name.indexOf("nosub:")==0) { + without_sub = true; + menu_name = menu_name.substr(6); + } + + if (opts.length === 1) { + if (opts[0]==='inspect') menu_name = menu_name.replace("Draw", "Inspect"); + return this.add(menu_name, opts[0], call_back); + } + + if (!without_sub) this.add("sub:" + menu_name, opts[0], call_back); + + for (var i=0;i<opts.length;++i) { + var name = opts[i]; + if (name=="") name = '<dflt>'; + + var group = i+1; + if ((opts.length>5) && (name.length>0)) { + // check if there are similar options, which can be grouped once again + while ((group<opts.length) && (opts[group].indexOf(name)==0)) group++; + } + + if (without_sub) name = menu_name + " " + name; + + if (group < i+2) { + this.add(name, opts[i], call_back); + } else { + this.add("sub:" + name, opts[i], call_back); + for (var k=i+1;k<group;++k) + this.add(opts[k], opts[k], call_back); + this.add("endsub:"); + i = group-1; + } + } + if (!without_sub) this.add("endsub:"); + } + + menu.remove = function() { + if (this.element!==null) { + this.element.remove(); + if (this.close_callback) this.close_callback(); + document.body.removeEventListener('click', this.remove_bind); + } + this.element = null; + } + + menu.remove_bind = menu.remove.bind(menu); + + menu.show = function(event, close_callback) { + this.remove(); + + if (typeof close_callback == 'function') this.close_callback = close_callback; + + document.body.addEventListener('click', this.remove_bind); + + var oldmenu = document.getElementById(menuname); + if (oldmenu) oldmenu.parentNode.removeChild(oldmenu); + + $(document.body).append('<ul class="jsroot_ctxmenu">' + this.code + '</ul>'); + + this.element = $('.jsroot_ctxmenu'); + + var pthis = this; + + this.element + .attr('id', menuname) + .css('left', event.clientX + window.pageXOffset) + .css('top', event.clientY + window.pageYOffset) +// .css('font-size', '80%') + .css('position', 'absolute') // this overrides ui-menu-items class property + .menu({ + items: "> :not(.ui-widget-header)", + select: function( event, ui ) { + var arg = ui.item.attr('arg'), + cnt = ui.item.attr('cnt'), + func = cnt ? pthis.funcs[cnt] : null; + pthis.remove(); + if (typeof func == 'function') { + if ('painter' in menu) + func.bind(pthis.painter)(arg); // if 'painter' field set, returned as this to callback + else + func(arg); + } + } + }); + + var newx = null, newy = null; + + if (event.clientX + this.element.width() > $(window).width()) newx = $(window).width() - this.element.width() - 20; + if (event.clientY + this.element.height() > $(window).height()) newy = $(window).height() - this.element.height() - 20; + + if (newx!==null) this.element.css('left', (newx>0 ? newx : 0) + window.pageXOffset); + if (newy!==null) this.element.css('top', (newy>0 ? newy : 0) + window.pageYOffset); + } + + JSROOT.CallBack(maincallback, menu); + + return menu; + } + + // ================================================================================================= + + var BrowserLayout = JSROOT.BrowserLayout; + + /// set browser title text + /// Title also used for dragging of the float browser + BrowserLayout.prototype.SetBrowserTitle = function(title) { + var main = d3.select("#" + this.gui_div + " .jsroot_browser"); + if (!main.empty()) + main.select(".jsroot_browser_title").text(title); + } + + BrowserLayout.prototype.ToggleBrowserKind = function(kind) { + + if (!this.gui_div) return; + + if (!kind) { + if (!this.browser_kind) return; + kind = (this.browser_kind === "float") ? "fix" : "float"; + } + + var main = d3.select("#"+this.gui_div+" .jsroot_browser"), + jmain = $(main.node()), + area = jmain.find(".jsroot_browser_area"), + pthis = this; + + if (this.browser_kind === "float") { + area.css('bottom', '0px') + .css('top', '0px') + .css('width','').css('height','') + .toggleClass('jsroot_float_browser', false) + .resizable("destroy") + .draggable("destroy"); + } else if (this.browser_kind === "fix") { + main.select(".jsroot_v_separator").remove(); + area.css('left', '0px'); + d3.select("#"+this.gui_div+"_drawing").style('left','0px'); // reset size + main.select(".jsroot_h_separator").style('left','0px'); + d3.select("#"+this.gui_div+"_status").style('left','0px'); // reset left + pthis.CheckResize(); + } + + this.browser_kind = kind; + this.browser_visible = true; + + if (kind==="float") { + area.css('bottom', '40px') + .toggleClass('jsroot_float_browser', true) + .resizable({ + containment: "parent", + minWidth: 100, + resize: function( event, ui ) { + pthis.SetButtonsPosition(); + }, + stop: function( event, ui ) { + var bottom = $(this).parent().innerHeight() - ui.position.top - ui.size.height; + if (bottom<7) $(this).css('height', "").css('bottom', 0); + } + }) + .draggable({ + containment: "parent", + handle : $("#"+this.gui_div).find(".jsroot_browser_title"), + snap: true, + snapMode: "inner", + snapTolerance: 10, + drag: function( event, ui ) { + pthis.SetButtonsPosition(); + }, + stop: function( event, ui ) { + var bottom = $(this).parent().innerHeight() - $(this).offset().top - $(this).outerHeight(); + if (bottom<7) $(this).css('height', "").css('bottom', 0); + } + }); + this.AdjustBrowserSize(); + + } else { + + area.css('left',0).css('top',0).css('bottom',0).css('height',''); + + var vsepar = + main.append('div') + .classed("jsroot_separator", true).classed('jsroot_v_separator', true) + .style('position', 'absolute').style('top',0).style('bottom',0); + // creation of vertical separator + $(vsepar.node()).draggable({ + axis: "x" , cursor: "ew-resize", + containment: "parent", + helper : function() { return $(this).clone().css('background-color','grey'); }, + drag: function(event,ui) { + pthis.SetButtonsPosition(); + pthis.AdjustSeparator(ui.position.left, null); + }, + stop: function(event,ui) { + pthis.CheckResize(); + } + }); + + this.AdjustSeparator(250, null, true, true); + } + + this.SetButtonsPosition(); + } + + BrowserLayout.prototype.SetButtonsPosition = function() { + if (!this.gui_div) return; + + var jmain = $("#"+this.gui_div+" .jsroot_browser"), + btns = jmain.find(".jsroot_browser_btns"), + top = 7, left = 7; + + if (!btns.length) return; + + if (this.browser_visible) { + var area = jmain.find(".jsroot_browser_area"), + off0 = jmain.offset(), off1 = area.offset(); + top = off1.top - off0.top + 7; + left = off1.left - off0.left + area.innerWidth() - 27; + } + + btns.css('left', left+'px').css('top', top+'px'); + } + + BrowserLayout.prototype.AdjustBrowserSize = function(onlycheckmax) { + if (!this.gui_div || (this.browser_kind !== "float")) return; + + var jmain = $("#" + this.gui_div + " .jsroot_browser"); + if (!jmain.length) return; + + var area = jmain.find(".jsroot_browser_area"), + cont = jmain.find(".jsroot_browser_hierarchy"), + chld = cont.children(":first"); + + if (onlycheckmax) { + if (area.parent().innerHeight() - 10 < area.innerHeight()) + area.css('bottom', '0px').css('top','0px'); + return; + } + + if (!chld.length) return; + + var h1 = cont.innerHeight(), + h2 = chld.innerHeight(); + + if ((h2!==undefined) && (h2<h1*0.7)) area.css('bottom', ''); + } + + BrowserLayout.prototype.ToggleBrowserVisisbility = function(fast_close) { + if (!this.gui_div || (typeof this.browser_visible==='string')) return; + + var main = d3.select("#" + this.gui_div + " .jsroot_browser"), + area = main.select('.jsroot_browser_area'); + + if (area.empty()) return; + + var vsepar = main.select(".jsroot_v_separator"), + drawing = d3.select("#" + this.gui_div + "_drawing"), + tgt = area.property('last_left'), + tgt_separ = area.property('last_vsepar'), + tgt_drawing = area.property('last_drawing'); + + if (!this.browser_visible) { + if (fast_close) return; + area.property('last_left', null).property('last_vsepar',null).property('last_drawing', null); + } else { + area.property('last_left', area.style('left')); + if (!vsepar.empty()) { + area.property('last_vsepar', vsepar.style('left')); + area.property('last_drawing', drawing.style('left')); + } + tgt = (-$(area.node()).outerWidth(true)-10).toString() + "px"; + var mainw = $(main.node()).outerWidth(true); + + if (vsepar.empty() && ($(area.node()).offset().left > mainw/2)) tgt = (mainw+10) + "px"; + + tgt_separ = "-10px"; + tgt_drawing = "0px"; + } + + var pthis = this, visible_at_the_end = !this.browser_visible, _duration = fast_close ? 0 : 700; + + this.browser_visible = 'changing'; + + area.transition().style('left', tgt).duration(_duration).on("end", function() { + if (fast_close) return; + pthis.browser_visible = visible_at_the_end; + if (visible_at_the_end) pthis.SetButtonsPosition(); + }); + + if (!visible_at_the_end) + main.select(".jsroot_browser_btns").transition().style('left', '7px').style('top', '7px').duration(_duration); + + if (!vsepar.empty()) { + vsepar.transition().style('left', tgt_separ).duration(_duration); + drawing.transition().style('left', tgt_drawing).duration(_duration).on("end", this.CheckResize.bind(this)); + } + + if (this.status_layout && (this.browser_kind == 'fix')) { + main.select(".jsroot_h_separator").transition().style('left', tgt_drawing).duration(_duration); + main.select(".jsroot_status_area").transition().style('left', tgt_drawing).duration(_duration); + } + } + + /// used together with browser buttons + BrowserLayout.prototype.Toggle = function(browser_kind) { + if (this.browser_visible!=='changing') { + if (browser_kind === this.browser_kind) this.ToggleBrowserVisisbility(); + else this.ToggleBrowserKind(browser_kind); + } + } + + BrowserLayout.prototype.DeleteContent = function() { + var main = d3.select("#" + this.gui_div + " .jsroot_browser"); + if (main.empty()) return; + + this.CreateStatusLine("delete"); + var vsepar = main.select(".jsroot_v_separator"); + if (!vsepar.empty()) + $(vsepar.node()).draggable('destroy'); + + this.ToggleBrowserVisisbility(true); + + main.selectAll("*").remove(); + delete this.browser_visible; + delete this.browser_kind; + + this.CheckResize(); + } + + /// method creates status line + BrowserLayout.prototype.CreateStatusLine = function(height, mode) { + var main = d3.select("#"+this.gui_div+" .jsroot_browser"); + if (main.empty()) return ''; + + var id = this.gui_div + "_status", + line = d3.select("#"+id), skip_height_check = false, + is_visible = !line.empty(); + + if (mode==="toggle") { mode = !is_visible; skip_height_check = (height === this.last_hsepar_height); } else + if (height==="delete") { mode = false; height = 0; delete this.status_layout; } else + if (mode===undefined) { mode = true; this.status_layout = "app"; } + + if (is_visible) { + if ((mode === true) || (this.status_layout==="app")) return id; + + var hsepar = main.select(".jsroot_h_separator"); + + $(hsepar.node()).draggable("destroy"); + + hsepar.remove(); + line.remove(); + + delete this.status_layout; + + if (this.status_handler && (JSROOT.Painter.ShowStatus === this.status_handler)) { + delete JSROOT.Painter.ShowStatus; + delete this.status_handler; + } + + this.AdjustSeparator(null, 0, true); + return ""; + } + + if (mode === false) return ""; + + var left_pos = d3.select("#" + this.gui_div + "_drawing").style('left'); + + line = main.insert("div",".jsroot_browser_area").attr("id",id) + .classed("jsroot_status_area", true) + .style('position',"absolute").style('left',left_pos).style('height',"20px").style('bottom',0).style('right',0) + .style('margin',0).style('border',0); + + var hsepar = main.insert("div",".jsroot_browser_area") + .classed("jsroot_separator", true).classed("jsroot_h_separator", true) + .style('position','absolute').style('left',left_pos).style('right',0).style('bottom','20px').style('height','5px'); + + var pthis = this; + + $(hsepar.node()).draggable({ + axis: "y" , cursor: "ns-resize", containment: "parent", + helper: function() { return $(this).clone().css('background-color','grey'); }, + drag: function(event,ui) { + pthis.AdjustSeparator(null, -ui.position.top); + }, + stop: function(event,ui) { + pthis.CheckResize(); + } + }); + + if (!height || (typeof height === 'string')) height = this.last_hsepar_height || 20; + + this.AdjustSeparator(null, height, true); + + if (this.status_layout == "app") return id; + + this.status_layout = new JSROOT.GridDisplay(id, 'horizx4_1213'); + + var frame_titles = ['object name','object title','mouse coordinates','object info']; + for (var k=0;k<4;++k) + d3.select(this.status_layout.GetFrame(k)).attr('title', frame_titles[k]).style('overflow','hidden') + .append("label").attr("class","jsroot_status_label"); + + this.status_handler = this.ShowStatus.bind(this); + + JSROOT.Painter.ShowStatus = this.status_handler; + + return id; + } + + BrowserLayout.prototype.AdjustSeparator = function(vsepar, hsepar, redraw, first_time) { + + if (!this.gui_div) return; + + var main = d3.select("#" + this.gui_div + " .jsroot_browser"), w = 5; + + if ((hsepar===null) && first_time && !main.select(".jsroot_h_separator").empty()) { + // if separator set for the first time, check if status line present + hsepar = main.select(".jsroot_h_separator").style('bottom'); + if ((typeof hsepar=='string') && (hsepar.indexOf('px')==hsepar.length-2)) + hsepar = hsepar.substr(0,hsepar.length-2); + else + hsepar = null; + } + + if (hsepar!==null) { + hsepar = parseInt(hsepar); + var elem = main.select(".jsroot_h_separator"), hlimit = 0; + + if (!elem.empty()) { + if (hsepar<0) hsepar += ($(main.node()).outerHeight(true) - w); + if (hsepar<5) hsepar = 5; + this.last_hsepar_height = hsepar; + elem.style('bottom', hsepar+'px').style('height', w+'px'); + d3.select("#" + this.gui_div + "_status").style('height', hsepar+'px'); + hlimit = (hsepar+w) + 'px'; + } + + d3.select("#" + this.gui_div + "_drawing").style('bottom',hlimit); + } + + if (vsepar!==null) { + vsepar = parseInt(vsepar); + if (vsepar<50) vsepar = 50; + main.select(".jsroot_browser_area").style('width',(vsepar-5)+'px'); + d3.select("#" + this.gui_div + "_drawing").style('left',(vsepar+w)+'px'); + main.select(".jsroot_h_separator").style('left', (vsepar+w)+'px'); + d3.select("#" + this.gui_div + "_status").style('left',(vsepar+w)+'px'); + main.select(".jsroot_v_separator").style('left',vsepar+'px').style('width',w+"px"); + } + + if (redraw) this.CheckResize(); + } + + BrowserLayout.prototype.ShowStatus = function(name, title, info, coordinates) { + if (!this.status_layout) return; + + $(this.status_layout.GetFrame(0)).children('label').text(name || ""); + $(this.status_layout.GetFrame(1)).children('label').text(title || ""); + $(this.status_layout.GetFrame(2)).children('label').text(coordinates || ""); + $(this.status_layout.GetFrame(3)).children('label').text(info || ""); + + if (!this.status_layout.first_check) { + this.status_layout.first_check = true; + var maxh = 0; + for (var n=0;n<4;++n) + maxh = Math.max(maxh, $(this.status_layout.GetFrame(n)).children('label').outerHeight()); + if ((maxh>5) && ((maxh>this.last_hsepar_height) || (maxh<this.last_hsepar_height+5))) + this.AdjustSeparator(null, maxh, true); + } + } + + // ================================================================================================= + + var HierarchyPainter = JSROOT.HierarchyPainter; + + HierarchyPainter.prototype.isLastSibling = function(hitem) { + if (!hitem || !hitem._parent || !hitem._parent._childs) return false; + var chlds = hitem._parent._childs, indx = chlds.indexOf(hitem); + if (indx<0) return false; + while (++indx < chlds.length) + if (!('_hidden' in chlds[indx])) return false; + return true; + } + + HierarchyPainter.prototype.addItemHtml = function(hitem, d3prnt, arg) { + + if (!hitem || ('_hidden' in hitem)) return true; + + var isroot = (hitem === this.h), + has_childs = ('_childs' in hitem), + handle = JSROOT.getDrawHandle(hitem._kind), + img1 = "", img2 = "", can_click = false, break_list = false, + d3cont, itemname = this.itemFullName(hitem); + + if (handle !== null) { + if ('icon' in handle) img1 = handle.icon; + if ('icon2' in handle) img2 = handle.icon2; + if ((img1.length==0) && (typeof handle.icon_get == 'function')) + img1 = handle.icon_get(hitem, this); + if (('func' in handle) || ('execute' in handle) || ('aslink' in handle) || + (('expand' in handle) && (hitem._more !== false))) can_click = true; + } + + if ('_icon' in hitem) img1 = hitem._icon; + if ('_icon2' in hitem) img2 = hitem._icon2; + if ((img1.length==0) && ('_online' in hitem)) + hitem._icon = img1 = "img_globe"; + if ((img1.length==0) && isroot) + hitem._icon = img1 = "img_base"; + + if (hitem._more || ('_expand' in hitem) || ('_player' in hitem)) + can_click = true; + + var can_menu = can_click; + if (!can_menu && (typeof hitem._kind == 'string') && (hitem._kind.indexOf("ROOT.")==0)) + can_menu = can_click = true; + + if (img2.length==0) img2 = img1; + if (img1.length==0) img1 = (has_childs || hitem._more) ? "img_folder" : "img_page"; + if (img2.length==0) img2 = (has_childs || hitem._more) ? "img_folderopen" : "img_page"; + + if (arg === "update") { + d3prnt.selectAll("*").remove(); + d3cont = d3prnt; + } else { + d3cont = d3prnt.append("div"); + if (arg && (arg >= (hitem._parent._show_limit || JSROOT.gStyle.HierarchyLimit))) break_list = true; + } + + hitem._d3cont = d3cont.node(); // set for direct referencing + d3cont.attr("item", itemname); + + // line with all html elements for this item (excluding childs) + var d3line = d3cont.append("div").attr('class','h_line'); + + // build indent + var prnt = isroot ? null : hitem._parent; + while (prnt && (prnt !== this.h)) { + d3line.insert("div",":first-child") + .attr("class", this.isLastSibling(prnt) ? "img_empty" : "img_line"); + prnt = prnt._parent; + } + + var icon_class = "", plusminus = false; + + if (isroot) { + // for root node no extra code + } else + if (has_childs && !break_list) { + icon_class = hitem._isopen ? "img_minus" : "img_plus"; + plusminus = true; + } else + /*if (hitem._more) { + icon_class = "img_plus"; // should be special plus ??? + plusminus = true; + } else */ { + icon_class = "img_join"; + } + + var h = this; + + if (icon_class.length > 0) { + if (break_list || this.isLastSibling(hitem)) icon_class += "bottom"; + var d3icon = d3line.append("div").attr('class', icon_class); + if (plusminus) d3icon.style('cursor','pointer') + .on("click", function() { h.tree_click(this, "plusminus"); }); + } + + // make node icons + + if (this.with_icons && !break_list) { + var icon_name = hitem._isopen ? img2 : img1; + + var d3img; + + if (icon_name.indexOf("img_")==0) + d3img = d3line.append("div") + .attr("class", icon_name) + .attr("title", hitem._kind); + else + d3img = d3line.append("img") + .attr("src", icon_name) + .attr("alt","") + .attr("title", hitem._kind) + .style('vertical-align','top').style('width','18px').style('height','18px'); + + if (('_icon_click' in hitem) || (handle && ('icon_click' in handle))) + d3img.on("click", function() { h.tree_click(this, "icon"); }); + } + + var d3a = d3line.append("a"); + if (can_click || has_childs || break_list) + d3a.attr("class","h_item") + .on("click", function() { h.tree_click(this); }); + + if (break_list) { + hitem._break_point = true; // indicate that list was broken here + d3a.attr('title', 'there are ' + (hitem._parent._childs.length-arg) + ' more items') + .text("...more..."); + return false; + } + + if ('disp_kind' in h) { + if (JSROOT.gStyle.DragAndDrop && can_click) + this.enable_dragging(d3a.node(), itemname); + if (JSROOT.gStyle.ContextMenu && can_menu) + d3a.on('contextmenu', function() { h.tree_contextmenu(this); }); + + d3a.on("mouseover", function() { h.tree_mouseover(true, this); }) + .on("mouseleave", function() { h.tree_mouseover(false, this); }); + } else + if (hitem._direct_context && JSROOT.gStyle.ContextMenu) + d3a.on('contextmenu', function() { h.direct_contextmenu(this); }); + + var element_name = hitem._name, element_title = ""; + + if ('_realname' in hitem) + element_name = hitem._realname; + + if ('_title' in hitem) + element_title = hitem._title; + + if ('_fullname' in hitem) + element_title += " fullname: " + hitem._fullname; + + if (!element_title) + element_title = element_name; + + d3a.attr('title', element_title) + .text(element_name + ('_value' in hitem ? ":" : "")) + .style('background', hitem._background ? hitem._background : null); + + if ('_value' in hitem) { + var d3p = d3line.append("p"); + if ('_vclass' in hitem) d3p.attr('class', hitem._vclass); + if (!hitem._isopen) d3p.html(hitem._value); + } + + if (has_childs && (isroot || hitem._isopen)) { + var d3chlds = d3cont.append("div").attr("class", "h_childs"); + for (var i=0; i< hitem._childs.length; ++i) { + var chld = hitem._childs[i]; + chld._parent = hitem; + if (!this.addItemHtml(chld, d3chlds, i)) break; // if too many items, skip rest + } + } + + return true; + } + + HierarchyPainter.prototype.toggleOpenState = function(isopen, h) { + var hitem = h ? h : this.h; + + if (!('_childs' in hitem)) { + if (!isopen || this.with_icons || (!hitem._expand && (hitem._more !== true))) return false; + this.expand(this.itemFullName(hitem)); + if (hitem._childs) hitem._isopen = true; + return true; + } + + if ((hitem != this.h) && isopen && !hitem._isopen) { + // when there are childs and they are not see, simply show them + hitem._isopen = true; + return true; + } + + var change_child = false; + for (var i=0; i < hitem._childs.length; ++i) + if (this.toggleOpenState(isopen, hitem._childs[i])) change_child = true; + + if ((hitem != this.h) && !isopen && hitem._isopen && !change_child) { + // if none of the childs can be closed, than just close that item + delete hitem._isopen; + return true; + } + + if (!h) this.RefreshHtml(); + + return false; + } + + HierarchyPainter.prototype.RefreshHtml = function(callback) { + + if (!this.divid) return JSROOT.CallBack(callback); + + var d3elem = this.select_main(); + + d3elem.html("") + .style('overflow','hidden') // clear html - most simple way + .style('display','flex') + .style('flex-direction','column'); + + var h = this, factcmds = [], status_item = null; + this.ForEach(function(item) { + delete item._d3cont; // remove html container + if (('_fastcmd' in item) && (item._kind == 'Command')) factcmds.push(item); + if (('_status' in item) && !status_item) status_item = item; + }); + + if (!this.h || d3elem.empty()) + return JSROOT.CallBack(callback); + + if (factcmds.length) { + var fastbtns = d3elem.append("div").attr("class","jsroot"); + for (var n=0;n<factcmds.length;++n) { + var btn = fastbtns.append("button") + .text("") + .attr("class",'fast_command') + .attr("item", this.itemFullName(factcmds[n])) + .attr("title", factcmds[n]._title) + .on("click", function() { h.ExecuteCommand(d3.select(this).attr("item"), this); } ); + + if ('_icon' in factcmds[n]) + btn.append('img').attr("src", factcmds[n]._icon); + } + } + + var d3btns = d3elem.append("p").attr("class", "jsroot").style("margin-bottom","3px").style("margin-top",0); + d3btns.append("a").attr("class", "h_button").text("open all") + .attr("title","open all items in the browser").on("click", h.toggleOpenState.bind(h,true)); + d3btns.append("text").text(" | "); + d3btns.append("a").attr("class", "h_button").text("close all") + .attr("title","close all items in the browser").on("click", h.toggleOpenState.bind(h,false)); + + if ('_online' in this.h) { + d3btns.append("text").text(" | "); + d3btns.append("a").attr("class", "h_button").text("reload") + .attr("title","reload object list from the server").on("click", h.reload.bind(h)); + } + + if ('disp_kind' in this) { + d3btns.append("text").text(" | "); + d3btns.append("a").attr("class", "h_button").text("clear") + .attr("title","clear all drawn objects").on("click", h.clear.bind(h,false)); + } + + var maindiv = + d3elem.append("div") + .attr("class", "jsroot") + .style('font-size', this.with_icons ? "12px" : "15px") + .style("overflow","auto") + .style("flex","1"); + + if (this.background) // case of object inspector and streamer infos display + maindiv.style("background-color", this.background) + .style('margin', '2px').style('padding', '2px'); + + this.addItemHtml(this.h, maindiv.append("div").attr("class","h_tree")); + + if (status_item && !this.status_disabled && (JSROOT.GetUrlOption('nostatus')===null)) { + var func = JSROOT.findFunction(status_item._status); + var hdiv = (typeof func == 'function') ? this.CreateStatusLine() : null; + if (hdiv) func(hdiv, this.itemFullName(status_item)); + } + + JSROOT.CallBack(callback); + } + + HierarchyPainter.prototype.UpdateTreeNode = function(hitem, d3cont) { + if ((d3cont===undefined) || d3cont.empty()) { + d3cont = d3.select(hitem._d3cont ? hitem._d3cont : null); + var name = this.itemFullName(hitem); + if (d3cont.empty()) + d3cont = this.select_main().select("[item='" + name + "']"); + if (d3cont.empty() && ('_cycle' in hitem)) + d3cont = this.select_main().select("[item='" + name + ";" + hitem._cycle + "']"); + if (d3cont.empty()) return; + } + + this.addItemHtml(hitem, d3cont, "update"); + + if (this.brlayout) this.brlayout.AdjustBrowserSize(true); + } + + HierarchyPainter.prototype.UpdateBackground = function(hitem, scroll_into_view) { + + if (!hitem || !hitem._d3cont) return; + + var d3cont = d3.select(hitem._d3cont); + + if (d3cont.empty()) return; + + var d3a = d3cont.select(".h_item"); + + d3a.style('background', hitem._background ? hitem._background : null); + + if (scroll_into_view && hitem._background) + d3a.node().scrollIntoView(false); + } + + HierarchyPainter.prototype.tree_click = function(node, place) { + if (!node) return; + + var d3cont = d3.select(node.parentNode.parentNode); + var itemname = d3cont.attr('item'); + if (!itemname) return; + + var hitem = this.Find(itemname); + if (!hitem) return; + + if (hitem._break_point) { + // special case of more item + + delete hitem._break_point; + + // update item itself + this.addItemHtml(hitem, d3cont, "update"); + + var prnt = hitem._parent, indx = prnt._childs.indexOf(hitem), + d3chlds = d3.select(d3cont.node().parentNode); + + if (indx<0) return console.error('internal error'); + + prnt._show_limit = (prnt._show_limit || JSROOT.gStyle.HierarchyLimit) * 2; + + for (var n=indx+1;n<prnt._childs.length;++n) { + var chld = prnt._childs[n]; + chld._parent = prnt; + if (!this.addItemHtml(chld, d3chlds, n)) break; // if too many items, skip rest + } + + return; + } + + var prnt = hitem, dflt = undefined; + while (prnt) { + if ((dflt = prnt._click_action) !== undefined) break; + prnt = prnt._parent; + } + + if (!place || (place=="")) place = "item"; + + var sett = JSROOT.getDrawSettings(hitem._kind), handle = sett.handle; + + if (place == "icon") { + var func = null; + if (typeof hitem._icon_click == 'function') func = hitem._icon_click; else + if (handle && typeof handle.icon_click == 'function') func = handle.icon_click; + if (func && func(hitem,this)) + this.UpdateTreeNode(hitem, d3cont); + return; + } + + // special feature - all items with '_expand' function are not drawn by click + if ((place=="item") && ('_expand' in hitem) && !d3.event.ctrlKey && !d3.event.shiftKey) place = "plusminus"; + + // special case - one should expand item + if (((place == "plusminus") && !('_childs' in hitem) && hitem._more) || + ((place == "item") && (dflt === "expand"))) { + return this.expand(itemname, null, d3cont); + } + + if (place == "item") { + if ('_player' in hitem) + return this.player(itemname); + + if (handle && handle.aslink) + return window.open(itemname + "/"); + + if (handle && handle.execute) + return this.ExecuteCommand(itemname, node.parentNode); + + if (handle && handle.ignore_online && this.isOnlineItem(hitem)) return; + + var can_draw = hitem._can_draw, + can_expand = hitem._more, + dflt_expand = (this.default_by_click === "expand"), + drawopt = ""; + + if (d3.event.shiftKey) { + drawopt = (handle && handle.shift) ? handle.shift : "inspect"; + if ((drawopt==="inspect") && handle && handle.noinspect) drawopt = ""; + } + if (handle && handle.ctrl && d3.event.ctrlKey) drawopt = handle.ctrl; + + if (!drawopt) { + for (var pitem = hitem._parent; pitem; pitem = pitem._parent) { + if (pitem._painter) { can_draw = false; if (can_expand===undefined) can_expand = false; break; } + } + } + + if (hitem._childs) can_expand = false; + + if (can_draw === undefined) can_draw = sett.draw; + if (can_expand === undefined) can_expand = sett.expand; + + if (can_draw && can_expand && !drawopt) { + // if default action specified as expand, disable drawing + if (dflt_expand || (handle && (handle.dflt === 'expand'))) can_draw = false; else + if (this.isItemDisplayed(itemname)) can_draw = false; // if already displayed, try to expand + } + + if (can_draw) + return this.display(itemname, drawopt); + + if (can_expand || dflt_expand) + return this.expand(itemname, null, d3cont); + + // cannot draw, but can inspect ROOT objects + if ((typeof hitem._kind === "string") && (hitem._kind.indexOf("ROOT.")===0) && sett.inspect && (can_draw!==false)) + return this.display(itemname, "inspect"); + + if (!hitem._childs || (hitem === this.h)) return; + } + + if (hitem._isopen) + delete hitem._isopen; + else + hitem._isopen = true; + + this.UpdateTreeNode(hitem, d3cont); + } + + HierarchyPainter.prototype.tree_mouseover = function(on, elem) { + var itemname = d3.select(elem.parentNode.parentNode).attr('item'); + + var hitem = this.Find(itemname); + if (!hitem) return; + + var painter, prnt = hitem; + while (prnt && !painter) { + painter = prnt._painter; + prnt = prnt._parent; + } + + if (painter && typeof painter.MouseOverHierarchy === 'function') + painter.MouseOverHierarchy(on, itemname, hitem); + } + + HierarchyPainter.prototype.direct_contextmenu = function(elem) { + // this is alternative context menu, used in the object inspector + + d3.event.preventDefault(); + var itemname = d3.select(elem.parentNode.parentNode).attr('item'); + var hitem = this.Find(itemname); + if (!hitem) return; + + if (typeof this.fill_context !== 'function') return; + + JSROOT.Painter.createMenu(this, function(menu) { + + menu.painter.fill_context(menu, hitem); + + if (menu.size() > 0) { + menu.tree_node = elem.parentNode; + menu.show(d3.event); + } + }); + } + + HierarchyPainter.prototype.tree_contextmenu = function(elem) { + // this is handling of context menu request for the normal objects browser + + d3.event.preventDefault(); + + var itemname = d3.select(elem.parentNode.parentNode).attr('item'); + + var hitem = this.Find(itemname); + if (!hitem) return; + + var painter = this, + onlineprop = painter.GetOnlineProp(itemname), + fileprop = painter.GetFileProp(itemname); + + function qualifyURL(url) { + function escapeHTML(s) { + return s.split('&').join('&').split('<').join('<').split('"').join('"'); + } + var el = document.createElement('div'); + el.innerHTML = '<a href="' + escapeHTML(url) + '">x</a>'; + return el.firstChild.href; + } + + JSROOT.Painter.createMenu(painter, function(menu) { + + if ((itemname == "") && !('_jsonfile' in hitem)) { + var addr = "", cnt = 0; + function separ() { return cnt++ > 0 ? "&" : "?"; } + + var files = []; + painter.ForEachRootFile(function(item) { files.push(item._file.fFullURL); }); + + if (!painter.GetTopOnlineItem()) + addr = JSROOT.source_dir + "index.htm"; + + if (painter.IsMonitoring()) + addr += separ() + "monitoring=" + painter.MonitoringInterval(); + + if (files.length==1) + addr += separ() + "file=" + files[0]; + else + if (files.length>1) + addr += separ() + "files=" + JSON.stringify(files); + + if (painter['disp_kind']) + addr += separ() + "layout=" + painter.disp_kind.replace(/ /g, ""); + + var items = []; + + if (painter.disp) + painter.disp.ForEachPainter(function(p) { + if (p.GetItemName()!=null) + items.push(p.GetItemName()); + }); + + if (items.length == 1) { + addr += separ() + "item=" + items[0]; + } else if (items.length > 1) { + addr += separ() + "items=" + JSON.stringify(items); + } + + menu.add("Direct link", function() { window.open(addr); }); + menu.add("Only items", function() { window.open(addr + "&nobrowser"); }); + } else if (onlineprop) { + painter.FillOnlineMenu(menu, onlineprop, itemname); + } else { + var sett = JSROOT.getDrawSettings(hitem._kind, 'nosame'); + + // allow to draw item even if draw function is not defined + if (hitem._can_draw) { + if (!sett.opts) sett.opts = [""]; + if (sett.opts.indexOf("")<0) sett.opts.unshift(""); + } + + if (sett.opts) + menu.addDrawMenu("Draw", sett.opts, function(arg) { this.display(itemname, arg); }); + + if (fileprop && sett.opts && !fileprop.localfile) { + var filepath = qualifyURL(fileprop.fileurl); + if (filepath.indexOf(JSROOT.source_dir) == 0) + filepath = filepath.slice(JSROOT.source_dir.length); + filepath = fileprop.kind + "=" + filepath; + if (fileprop.itemname.length > 0) { + var name = fileprop.itemname; + if (name.search(/\+| |\,/)>=0) name = "\'" + name + "\'"; + filepath += "&item=" + name; + } + + menu.addDrawMenu("Draw in new tab", sett.opts, function(arg) { + window.open(JSROOT.source_dir + "index.htm?nobrowser&"+filepath +"&opt="+arg); + }); + } + + if (sett.expand && !('_childs' in hitem) && (hitem._more || !('_more' in hitem))) + menu.add("Expand", function() { painter.expand(itemname); }); + + if (hitem._kind === "ROOT.TStyle") + menu.add("Apply", function() { painter.ApplyStyle(itemname); }); + } + + if (typeof hitem._menu == 'function') + hitem._menu(menu, hitem, painter); + + if (menu.size() > 0) { + menu.tree_node = elem.parentNode; + if (menu.separ) menu.add("separator"); // add separator at the end + menu.add("Close"); + menu.show(d3.event); + } + + }); // end menu creation + + return false; + } + + /** \brief Creates configured JSROOT.MDIDisplay object + * + * @param callback - called when mdi object created + */ + + HierarchyPainter.prototype.CreateDisplay = function(callback) { + + if ('disp' in this) { + if (this.disp.NumDraw() > 0) return JSROOT.CallBack(callback, this.disp); + this.disp.Reset(); + delete this.disp; + } + + // check that we can found frame where drawing should be done + if (document.getElementById(this.disp_frameid) == null) + return JSROOT.CallBack(callback, null); + + if (this.disp_kind == "tabs") + this.disp = new TabsDisplay(this.disp_frameid); + else + if (this.disp_kind.indexOf("flex")==0) + this.disp = new FlexibleDisplay(this.disp_frameid); + else + if (this.disp_kind.indexOf("coll")==0) + this.disp = new CollapsibleDisplay(this.disp_frameid); + else + this.disp = new JSROOT.GridDisplay(this.disp_frameid, this.disp_kind); + + if (this.disp) + this.disp.CleanupFrame = this.CleanupFrame.bind(this); + + JSROOT.CallBack(callback, this.disp); + } + + HierarchyPainter.prototype.enable_dragging = function(element, itemname) { + $(element).draggable({ revert: "invalid", appendTo: "body", helper: "clone" }); + } + + HierarchyPainter.prototype.enable_dropping = function(frame, itemname) { + var h = this; + $(frame).droppable({ + hoverClass : "ui-state-active", + accept: function(ui) { + var dropname = ui.parent().parent().attr('item'); + if ((dropname == itemname) || !dropname) return false; + + var ditem = h.Find(dropname); + if (!ditem || (!('_kind' in ditem))) return false; + + return ditem._kind.indexOf("ROOT.")==0; + }, + drop: function(event, ui) { + var dropname = ui.draggable.parent().parent().attr('item'); + if (!dropname) return false; + return h.dropitem(dropname, $(this).attr("id")); + } + }); + } + + HierarchyPainter.prototype.CreateBrowser = function(browser_kind, update_html, call_back) { + + if (!this.gui_div || this.exclude_browser || !this.brlayout) return false; + + var main = d3.select("#" + this.gui_div + " .jsroot_browser"), + jmain = $(main.node()); + + // one requires top-level container + if (main.empty()) return false; + + if ((browser_kind==="float") && this.float_browser_disabled) browser_kind = "fix"; + + if (!main.select('.jsroot_browser_area').empty()) { + // this is case when browser created, + // if update_html specified, hidden state will be toggled + + if (update_html) this.brlayout.Toggle(browser_kind); + + JSROOT.CallBack(call_back); + + return true; + } + + var guiCode = "<p class='jsroot_browser_version'><a href='https://root.cern/js/'>JSROOT</a> version <span style='color:green'><b>" + JSROOT.version + "</b></span></p>"; + + if (this.is_online) { + guiCode +='<p> Hierarchy in <a href="h.json">json</a> and <a href="h.xml">xml</a> format</p>' + + '<div style="display:flex;flex-direction:row;">' + + '<label style="margin-right:5px; vertical-align:middle;">' + + '<input style="vertical-align:middle;" type="checkbox" name="monitoring" class="gui_monitoring"/>' + + 'Monitoring</label>'; + } else if (!this.no_select) { + var myDiv = d3.select("#"+this.gui_div), + files = myDiv.attr("files") || "../files/hsimple.root", + path = JSROOT.GetUrlOption("path") || myDiv.attr("path") || "", + arrFiles = files.split(';'); + + guiCode += + '<input type="text" value="" style="width:95%; margin:5px;border:2px;" class="gui_urlToLoad" title="input file name"/>' + +'<div style="display:flex;flex-direction:row;padding-top:5px">' + +'<select class="gui_selectFileName" style="flex:1;padding:2px;" title="select file name"' + +'<option value="" selected="selected"></option>'; + for (var i in arrFiles) + guiCode += '<option value = "' + path + arrFiles[i] + '">' + arrFiles[i] + '</option>'; + guiCode += '</select>' + +'<input type="file" class="gui_localFile" accept=".root" style="display:none"/><output id="list" style="display:none"></output>' + +'<input type="button" value="..." class="gui_fileBtn" style="min-width:3em;padding:3px;margin-left:5px;margin-right:5px;" title="select local file for reading"/><br/>' + +'</div>' + +'<p id="gui_fileCORS"><small><a href="https://github.com/root-project/jsroot/blob/master/docs/JSROOT.md#reading-root-files-from-other-servers">Read docu</a>' + +' how to open files from other servers.</small></p>' + +'<div style="display:flex;flex-direction:row">' + +'<input style="padding:3px;margin-right:5px;"' + +' class="gui_ReadFileBtn" type="button" title="Read the Selected File" value="Load"/>' + +'<input style="padding:3px;margin-right:5px;"' + +' class="gui_ResetUIBtn" type="button" title="Close all opened files and clear drawings" value="Reset"/>' + } else if (this.no_select == "file") { + guiCode += '<div style="display:flex;flex-direction:row">'; + } + + if (this.is_online || !this.no_select || this.no_select=="file") + guiCode += '<select style="padding:2px;margin-right:5px;" title="layout kind" class="gui_layout"></select>' + + '</div>'; + + guiCode += '<div id="' + this.gui_div+'_browser_hierarchy" class="jsroot_browser_hierarchy"></div>'; + + this.brlayout.SetBrowserContent(guiCode); + + this.brlayout.SetBrowserTitle(this.is_online ? 'ROOT online server' : 'Read a ROOT file'); + + var hpainter = this, localfile_read_callback = null; + + if (!this.is_online && !this.no_select) { + + this.ReadSelectedFile = function() { + var filename = main.select(".gui_urlToLoad").property('value').trim(); + if (!filename) return; + + if ((filename.toLowerCase().lastIndexOf(".json") == filename.length-5)) + this.OpenJsonFile(filename); + else + this.OpenRootFile(filename); + } + + jmain.find(".gui_selectFileName").val("").change(function() { + jmain.find(".gui_urlToLoad").val($(this).val()); + }); + jmain.find(".gui_fileBtn").button().click(function() { + jmain.find(".gui_localFile").click(); + }); + + jmain.find(".gui_ReadFileBtn").button().click(function(){ + hpainter.ReadSelectedFile(); + }); + + jmain.find(".gui_ResetUIBtn").button().click(function(){ + hpainter.clear(true); + }); + + jmain.find(".gui_urlToLoad").keyup(function(e) { + if (e.keyCode == 13) hpainter.ReadSelectedFile(); + }); + + jmain.find(".gui_localFile").change(function(evnt) { + var files = evnt.target.files; + + for (var n=0;n<files.length;++n) { + var f = files[n]; + main.select(".gui_urlToLoad").property('value', f.name); + if (hpainter) hpainter.OpenRootFile(f, localfile_read_callback); + } + + localfile_read_callback = null; + }); + + this.SelectLocalFile = function(read_callback) { + localfile_read_callback = read_callback; + $("#" + this.gui_div + " .jsroot_browser").find(".gui_localFile").click(); + } + } + + var jlayout = jmain.find(".gui_layout"); + if (jlayout.length) { + var lst = ['simple', 'vert2', 'vert3', 'vert231', 'horiz2', 'horiz32', 'flex', + 'grid 2x2', 'grid 1x3', 'grid 2x3', 'grid 3x3', 'grid 4x4', 'collapsible', 'tabs']; + + for (var k=0;k<lst.length;++k){ + var opt = document.createElement('option'); + opt.value = lst[k]; + opt.innerHTML = lst[k]; + jlayout.get(0).appendChild(opt); + } + + jlayout.change(function() { + hpainter.SetDisplay($(this).val() || 'collapsible', hpainter.gui_div + "_drawing"); + }); + } + + this.SetDivId(this.gui_div + '_browser_hierarchy'); + + if (update_html) { + this.RefreshHtml(); + this.InitializeBrowser(); + } + + this.brlayout.ToggleBrowserKind(browser_kind || "fix"); + + JSROOT.CallBack(call_back); + + return true; + } + + HierarchyPainter.prototype.InitializeBrowser = function() { + + var main = d3.select("#" + this.gui_div + " .jsroot_browser"); + if (main.empty() || !this.brlayout) return; + var jmain = $(main.node()), hpainter = this; + + if (this.brlayout) this.brlayout.AdjustBrowserSize(); + + var selects = main.select(".gui_layout").node(); + + if (selects) { + var found = false; + for (var i in selects.options) { + var s = selects.options[i].text; + if (typeof s !== 'string') continue; + if ((s == this.GetLayout()) || (s.replace(/ /g,"") == this.GetLayout())) { + selects.selectedIndex = i; found = true; + break; + } + } + if (!found) { + var opt = document.createElement('option'); + opt.innerHTML = opt.value = this.GetLayout(); + selects.appendChild(opt); + selects.selectedIndex = selects.options.length-1; + } + } + + if (this.is_online) { + if (this.h && this.h._toptitle) + this.brlayout.SetBrowserTitle(this.h._toptitle); + jmain.find(".gui_monitoring") + .prop('checked', this.IsMonitoring()) + .click(function() { + hpainter.EnableMonitoring(this.checked); + hpainter.updateAll(!this.checked); + }); + } else if (!this.no_select) { + var fname = ""; + this.ForEachRootFile(function(item) { if (!fname) fname = item._fullurl; }); + jmain.find(".gui_urlToLoad").val(fname); + } + } + + HierarchyPainter.prototype.EnableMonitoring = function(on) { + this._monitoring_on = on; + + var chkbox = d3.select("#" + this.gui_div + " .jsroot_browser .gui_monitoring"); + if (!chkbox.empty() && (chkbox.property('checked') !== on)) + chkbox.property('checked', on); + } + + HierarchyPainter.prototype.CreateStatusLine = function(height, mode) { + if (this.status_disabled || !this.gui_div || !this.brlayout) return ''; + return this.brlayout.CreateStatusLine(height, mode); + } + + JSROOT.BuildGUI = function() { + var myDiv = d3.select('#simpleGUI'), online = false; + + if (myDiv.empty()) { + myDiv = d3.select('#onlineGUI'); + if (myDiv.empty()) return alert('no div for gui found'); + online = true; + } + + if (myDiv.attr("ignoreurl") === "true") + JSROOT.gStyle.IgnoreUrlOptions = true; + + if ((JSROOT.GetUrlOption("nobrowser")!==null) || (myDiv.attr("nobrowser") && myDiv.attr("nobrowser")!=="false")) + return JSROOT.BuildNobrowserGUI(); + + JSROOT.Painter.readStyleFromURL(); + + var hpainter = new JSROOT.HierarchyPainter('root', null); + + hpainter.is_online = online; + + hpainter.StartGUI(myDiv, hpainter.InitializeBrowser.bind(hpainter)); + } + + // ================================================== + + function CollapsibleDisplay(frameid) { + JSROOT.MDIDisplay.call(this, frameid); + this.cnt = 0; // use to count newly created frames + } + + CollapsibleDisplay.prototype = Object.create(JSROOT.MDIDisplay.prototype); + + CollapsibleDisplay.prototype.ForEachFrame = function(userfunc, only_visible) { + var topid = this.frameid + '_collapsible'; + + if (document.getElementById(topid) == null) return; + + if (typeof userfunc != 'function') return; + + $('#' + topid + ' .collapsible_draw').each(function() { + + // check if only visible specified + if (only_visible && $(this).is(":hidden")) return; + + userfunc($(this).get(0)); + }); + } + + CollapsibleDisplay.prototype.GetActiveFrame = function() { + var found = JSROOT.MDIDisplay.prototype.GetActiveFrame.call(this); + if (found && !$(found).is(":hidden")) return found; + + found = null; + this.ForEachFrame(function(frame) { + if (!found) found = frame; + }, true); + + return found; + } + + CollapsibleDisplay.prototype.ActivateFrame = function(frame) { + if ($(frame).is(":hidden")) { + $(frame).prev().toggleClass("ui-accordion-header-active ui-state-active ui-state-default ui-corner-bottom") + .find("> .ui-icon").toggleClass("ui-icon-triangle-1-e ui-icon-triangle-1-s").end() + .next().toggleClass("ui-accordion-content-active").slideDown(0); + } + $(frame).prev()[0].scrollIntoView(); + // remember title + this.active_frame_title = d3.select(frame).attr('frame_title'); + } + + CollapsibleDisplay.prototype.CreateFrame = function(title) { + + this.BeforeCreateFrame(title); + + var topid = this.frameid + '_collapsible'; + + if (document.getElementById(topid) == null) + $("#"+this.frameid).append('<div id="'+ topid + '" class="jsroot ui-accordion ui-accordion-icons ui-widget ui-helper-reset" style="overflow:auto; overflow-y:scroll; height:100%; padding-left: 2px; padding-right: 2px"></div>'); + + var mdi = this, + hid = topid + "_sub" + this.cnt++, + uid = hid + "h", + entryInfo = "<h5 id=\"" + uid + "\">" + + "<span class='ui-icon ui-icon-triangle-1-e'></span>" + + "<a> " + title + "</a> " + + "<button type='button' class='jsroot_collaps_closebtn' style='float:right; width:1.4em' title='close canvas'/>" + + " </h5>\n" + + "<div class='collapsible_draw' id='" + hid + "'></div>\n"; + + $("#" + topid).append(entryInfo); + + $('#' + uid) + .addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-top ui-corner-bottom") + .hover(function() { $(this).toggleClass("ui-state-hover"); }) + .click( function() { + $(this).toggleClass("ui-accordion-header-active ui-state-active ui-state-default ui-corner-bottom") + .find("> .ui-icon").toggleClass("ui-icon-triangle-1-e ui-icon-triangle-1-s") + .end().next().toggleClass("ui-accordion-content-active").slideToggle(0); + var sub = $(this).next(), hide_drawing = sub.is(":hidden"); + sub.css('display', hide_drawing ? 'none' : ''); + if (!hide_drawing) JSROOT.resize(sub.get(0)); + }) + .next() + .addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom") + .hide(); + + $('#' + uid).find(" .jsroot_collaps_closebtn") + .button({ icons: { primary: "ui-icon-close" }, text: false }) + .click(function(){ + mdi.CleanupFrame($(this).parent().next().attr('id')); + $(this).parent().next().remove(); // remove drawing + $(this).parent().remove(); // remove header + }); + + $('#' + uid) + .toggleClass("ui-accordion-header-active ui-state-active ui-state-default ui-corner-bottom") + .find("> .ui-icon").toggleClass("ui-icon-triangle-1-e ui-icon-triangle-1-s").end().next() + .toggleClass("ui-accordion-content-active").slideToggle(0); + + return $("#" + hid).attr('frame_title', title).css('overflow','hidden') + .attr('can_resize','height') // inform JSROOT that it can resize height of the + .css('position','relative') // this required for correct positioning of 3D canvas in WebKit + .get(0); + } + + // ================================================ + + function TabsDisplay(frameid) { + JSROOT.MDIDisplay.call(this, frameid); + this.cnt = 0; + } + + TabsDisplay.prototype = Object.create(JSROOT.MDIDisplay.prototype); + + TabsDisplay.prototype.ForEachFrame = function(userfunc, only_visible) { + var topid = this.frameid + '_tabs'; + + if (document.getElementById(topid) == null) return; + + if (typeof userfunc != 'function') return; + + var cnt = -1; + var active = $('#' + topid).tabs("option", "active"); + + $('#' + topid + '> .tabs_draw').each(function() { + cnt++; + if (!only_visible || (cnt == active)) + userfunc($(this).get(0)); + }); + } + + TabsDisplay.prototype.GetActiveFrame = function() { + var found = null; + this.ForEachFrame(function(frame) { + if (!found) found = frame; + }, true); + + return found; + } + + TabsDisplay.prototype.ActivateFrame = function(frame) { + var cnt = 0, id = -1; + this.ForEachFrame(function(fr) { + if ($(fr).attr('id') == $(frame).attr('id')) id = cnt; + cnt++; + }); + $('#' + this.frameid + "_tabs").tabs("option", "active", id); + + this.active_frame_title = d3.select(frame).attr('frame_title'); + } + + TabsDisplay.prototype.CreateFrame = function(title) { + + this.BeforeCreateFrame(title); + + var mdi = this, + topid = this.frameid + '_tabs', + hid = topid + "_sub" + this.cnt++, + li = '<li><a href="#' + hid + '">' + title + + '</a><span class="ui-icon ui-icon-close" style="float: left; margin: 0.4em 0.2em 0 0; cursor: pointer;" role="presentation">Remove Tab</span></li>', + cont = '<div class="tabs_draw" id="' + hid + '"></div>'; + + if (document.getElementById(topid) == null) { + $("#" + this.frameid).append('<div id="' + topid + '" class="jsroot">' + ' <ul>' + li + ' </ul>' + cont + '</div>'); + + var tabs = $("#" + topid) + .css('overflow','hidden') + .tabs({ + heightStyle : "fill", + activate : function (event,ui) { + $(ui.newPanel).css('overflow', 'hidden'); + JSROOT.resize($(ui.newPanel).get(0)); + } + }); + + tabs.delegate("span.ui-icon-close", "click", function() { + var panelId = $(this).closest("li").remove().attr("aria-controls"); + mdi.CleanupFrame(panelId); + $("#" + panelId).remove(); + tabs.tabs("refresh"); + if ($('#' + topid + '> .tabs_draw').length == 0) + $("#" + topid).remove(); + + }); + } else { + $("#" + topid).find("> .ui-tabs-nav").append(li); + $("#" + topid).append(cont); + $("#" + topid).tabs("refresh"); + $("#" + topid).tabs("option", "active", -1); + } + $('#' + hid) + .empty() + .css('overflow', 'hidden') + .attr('frame_title', title); + + return $('#' + hid).get(0); + } + + TabsDisplay.prototype.CheckMDIResize = function(frame_id, size) { + $("#" + this.frameid + '_tabs').tabs("refresh"); + JSROOT.MDIDisplay.prototype.CheckMDIResize.call(this, frame_id, size); + } + + // ================================================== + + function FlexibleDisplay(frameid) { + JSROOT.MDIDisplay.call(this, frameid); + this.cnt = 0; // use to count newly created frames + } + + FlexibleDisplay.prototype = Object.create(JSROOT.MDIDisplay.prototype); + + FlexibleDisplay.prototype.ForEachFrame = function(userfunc, only_visible) { + var topid = this.frameid + '_flex'; + + if (document.getElementById(topid) == null) return; + if (typeof userfunc != 'function') return; + + $('#' + topid + ' .flex_draw').each(function() { + // check if only visible specified + if (only_visible && $(this).is(":hidden")) return; + + userfunc($(this).get(0)); + }); + } + + FlexibleDisplay.prototype.GetActiveFrame = function() { + var found = JSROOT.MDIDisplay.prototype.GetActiveFrame.call(this); + if (found && !$(found).is(":hidden")) return found; + + found = null; + this.ForEachFrame(function(frame) { + if (!found) found = frame; + }, true); + + return found; + } + + FlexibleDisplay.prototype.ActivateFrame = function(frame) { + this.active_frame_title = d3.select(frame).attr('frame_title'); + } + + FlexibleDisplay.prototype.CreateFrame = function(title) { + + this.BeforeCreateFrame(title); + + var topid = this.frameid + '_flex'; + + if (document.getElementById(topid) == null) + $("#" + this.frameid).append('<div id="'+ topid + '" class="jsroot" style="overflow:none; height:100%; width:100%"></div>'); + + var mdi = this, + top = $("#" + topid), + w = top.width(), + h = top.height(), + subid = topid + "_frame" + this.cnt; + + var entry ='<div id="' + subid + '" class="flex_frame" style="position:absolute">' + + '<div class="ui-widget-header flex_header">'+ + '<p>'+title+'</p>' + + '<button type="button" style="float:right; width:1.4em"/>' + + '<button type="button" style="float:right; width:1.4em"/>' + + '<button type="button" style="float:right; width:1.4em"/>' + + '</div>' + + '<div id="' + subid + '_cont" class="flex_draw"></div>' + + '</div>'; + + top.append(entry); + + function PopupWindow(div) { + if (div === 'first') { + div = null; + $('#' + topid + ' .flex_frame').each(function() { + if (!$(this).is(":hidden") && ($(this).prop('state') != "minimal")) div = $(this); + }); + if (!div) return; + } + + div.appendTo(div.parent()); + + if (div.prop('state') == "minimal") return; + + div = div.find(".flex_draw").get(0); + var dummy = new JSROOT.TObjectPainter(); + dummy.SetDivId(div, -1); + JSROOT.Painter.SelectActivePad({ pp: dummy.canv_painter(), active: true }); + + JSROOT.resize(div); + } + + function ChangeWindowState(main, state) { + var curr = main.prop('state'); + if (!curr) curr = "normal"; + main.prop('state', state); + if (state==curr) return; + + if (curr == "normal") { + main.prop('original_height', main.height()); + main.prop('original_width', main.width()); + main.prop('original_top', main.css('top')); + main.prop('original_left', main.css('left')); + } + + main.find(".jsroot_minbutton").find('.ui-icon') + .toggleClass("ui-icon-triangle-1-s", state!="minimal") + .toggleClass("ui-icon-triangle-2-n-s", state=="minimal"); + + main.find(".jsroot_maxbutton").find('.ui-icon') + .toggleClass("ui-icon-triangle-1-n", state!="maximal") + .toggleClass("ui-icon-triangle-2-n-s", state=="maximal"); + + switch (state) { + case "minimal": + main.height(main.find('.flex_header').height()).width("auto"); + main.find(".flex_draw").css("display","none"); + main.find(".ui-resizable-handle").css("display","none"); + break; + case "maximal": + main.height("100%").width("100%").css('left','').css('top',''); + main.find(".flex_draw").css("display",""); + main.find(".ui-resizable-handle").css("display","none"); + break; + default: + main.find(".flex_draw").css("display",""); + main.find(".ui-resizable-handle").css("display",""); + main.height(main.prop('original_height')) + .width(main.prop('original_width')); + if (curr!="minimal") + main.css('left', main.prop('original_left')) + .css('top', main.prop('original_top')); + } + + if (state !== "minimal") + PopupWindow(main); + else + PopupWindow("first"); + } + + $("#" + subid) + .css('left', parseInt(w * (this.cnt % 5)/10)) + .css('top', parseInt(h * (this.cnt % 5)/10)) + .width(Math.round(w * 0.58)) + .height(Math.round(h * 0.58)) + .resizable({ + helper: "jsroot-flex-resizable-helper", + start: function(event, ui) { + // bring element to front when start resizing + PopupWindow($(this)); + }, + stop: function(event, ui) { + var rect = { width : ui.size.width-1, height : ui.size.height - $(this).find(".flex_header").height()-1 }; + JSROOT.resize($(this).find(".flex_draw").get(0), rect); + } + }) + .draggable({ + containment: "parent", + start: function(event, ui) { + // bring element to front when start dragging + PopupWindow($(this)); + + var ddd = $(this).find(".flex_draw"); + + // block dragging when mouse below header + var elementMouseIsOver = document.elementFromPoint(event.clientX, event.clientY); + var isparent = false; + $(elementMouseIsOver).parents().map(function() { if ($(this).get(0) === ddd.get(0)) isparent = true; }); + if (isparent) return false; + } + }) + .click(function() { PopupWindow($(this)); }) + .find('.flex_header') + // .hover(function() { $(this).toggleClass("ui-state-hover"); }) + .click(function() { + PopupWindow($(this).parent()); + }) + .dblclick(function() { + var main = $(this).parent(); + if (main.prop('state') == "normal") + ChangeWindowState(main, "maximal"); + else + ChangeWindowState(main, "normal"); + }) + .find("button") + .first() + .attr('title','close canvas') + .button({ icons: { primary: "ui-icon-close" }, text: false }) + .click(function() { + var main = $(this).parent().parent(); + mdi.CleanupFrame(main.find(".flex_draw").get(0)); + main.remove(); + PopupWindow('first'); // set active as first window + }) + .next() + .attr('title','maximize canvas') + .addClass('jsroot_maxbutton') + .button({ icons: { primary: "ui-icon-triangle-1-n" }, text: false }) + .click(function() { + var main = $(this).parent().parent(); + var maximize = $(this).find('.ui-icon').hasClass("ui-icon-triangle-1-n"); + ChangeWindowState(main, maximize ? "maximal" : "normal"); + }) + .next() + .attr('title','minimize canvas') + .addClass('jsroot_minbutton') + .button({ icons: { primary: "ui-icon-triangle-1-s" }, text: false }) + .click(function() { + var main = $(this).parent().parent(); + var minimize = $(this).find('.ui-icon').hasClass("ui-icon-triangle-1-s"); + ChangeWindowState(main, minimize ? "minimal" : "normal"); + }); + + // set default z-index to avoid overlap of these special elements + $("#" + subid).find(".ui-resizable-handle").css('z-index', ''); + + this.cnt++; + + return $("#" + subid + "_cont").attr('frame_title', title).get(0); + } + + // ================== new grid with flexible boundaries ======== + + JSROOT.GridDisplay.prototype.CreateSeparator = function(handle, main, group) { + var separ = $(main.append("div").node()); + + separ.toggleClass('jsroot_separator', true) + .toggleClass(handle.vertical ? 'jsroot_hline' : 'jsroot_vline', true) + .prop('handle', handle) + .attr('separator-id', group.id) + .css('position','absolute') + .css(handle.vertical ? 'top' : 'left', "calc(" + group.position+"% - 2px)") + .css(handle.vertical ? 'width' : 'height', (handle.size || 100)+"%") + .css(handle.vertical ? 'height' : 'width', '5px') + .css('cursor', handle.vertical ? "ns-resize" : "ew-resize"); + + separ.bind('changePosition', function(e, drag_ui) { + var handle = $(this).prop('handle'), + id = parseInt($(this).attr('separator-id')), + pos = handle.groups[id].position; + + if (drag_ui === 'restore') { + pos = handle.groups[id].position0; + } else + if (drag_ui && drag_ui.offset) { + if (handle.vertical) + pos = Math.round((drag_ui.offset.top+2-$(this).parent().offset().top)/$(this).parent().innerHeight()*100); + else + pos = Math.round((drag_ui.offset.left+2-$(this).parent().offset().left)/$(this).parent().innerWidth()*100); + } + + var diff = handle.groups[id].position - pos; + + if (Math.abs(diff)<0.3) return; // if no significant change, do nothing + + // do not change if size too small + if (Math.min(handle.groups[id-1].size-diff, handle.groups[id].size+diff) < 5) return; + + handle.groups[id-1].size -= diff; + handle.groups[id].size += diff; + handle.groups[id].position = pos; + + function SetGroupSize(prnt, grid) { + var name = handle.vertical ? 'height' : 'width', + size = handle.groups[grid].size+'%'; + prnt.children("[groupid='"+grid+"']").css(name, size) + .children(".jsroot_separator").css(name, size); + } + + $(this).css(handle.vertical ? 'top' : 'left', "calc("+pos+"% - 2px)"); + + SetGroupSize($(this).parent(), id-1); + SetGroupSize($(this).parent(), id); + + if (drag_ui === 'restore') { + $(this).trigger('resizeGroup', id-1); + $(this).trigger('resizeGroup', id); + } + }); + + separ.bind('resizeGroup', function(e, grid) { + var sel = $(this).parent().children("[groupid='"+grid+"']"); + if (!sel.hasClass('jsroot_newgrid')) sel = sel.find(".jsroot_newgrid"); + sel.each(function() { JSROOT.resize($(this).get(0)); }); + }); + + separ.dblclick(function() { + $(this).trigger('changePosition', 'restore'); + }); + + separ.draggable({ + axis: handle.vertical ? "y" : "x", + cursor: handle.vertical ? "ns-resize" : "ew-resize", + containment: "parent", + helper : function() { return $(this).clone().css('background-color','grey'); }, + start: function(event,ui) { + // remember start position + var handle = $(this).prop('handle'), + id = parseInt($(this).attr('separator-id')); + handle.groups[id].startpos = handle.groups[id].position; + }, + drag: function(event,ui) { + $(this).trigger('changePosition', ui); + }, + stop: function(event,ui) { + // verify if start position was changed + var handle = $(this).prop('handle'), + id = parseInt($(this).attr('separator-id')); + if (Math.abs(handle.groups[id].startpos - handle.groups[id].position)<0.5) return; + + $(this).trigger('resizeGroup', id-1); + $(this).trigger('resizeGroup', id); + } + }); + } + + // ========== performs tree drawing on server ================== + + JSROOT.CreateTreePlayer = function(player) { + + player.draw_first = true; + + player.ConfigureOnline = function(itemname, url, askey, root_version, dflt_expr) { + this.SetItemName(itemname, "", this); + this.url = url; + this.root_version = root_version; + this.askey = askey; + this.dflt_expr = dflt_expr; + } + + player.ConfigureTree = function(tree) { + this.local_tree = tree; + } + + player.KeyUp = function(e) { + if (e.keyCode == 13) this.PerformDraw(); + } + + player.ShowExtraButtons = function(args) { + var main = $("#" + this.divid); + + main.find(".treedraw_buttons") + .append(" Cut: <input class='treedraw_cut ui-corner-all ui-widget' style='width:8em;margin-left:5px' title='cut expression'></input>"+ + " Opt: <input class='treedraw_opt ui-corner-all ui-widget' style='width:5em;margin-left:5px' title='histogram draw options'></input>"+ + " Num: <input class='treedraw_number' style='width:7em;margin-left:5px' title='number of entries to process (default all)'></input>" + + " First: <input class='treedraw_first' style='width:7em;margin-left:5px' title='first entry to process (default first)'></input>" + + " <button class='treedraw_clear' title='Clear drawing'>Clear</button>"); + + var page = 1000, numentries = undefined, p = this; + if (this.local_tree) numentries = this.local_tree.fEntries || 0; + + main.find(".treedraw_cut").val(args && args.parse_cut ? args.parse_cut : "").keyup(this.keyup); + main.find(".treedraw_opt").val(args && args.drawopt ? args.drawopt : "").keyup(this.keyup); + main.find(".treedraw_number").val(args && args.numentries ? args.numentries : "").spinner({ numberFormat: "n", min: 0, page: 1000, max: numentries }).keyup(this.keyup); + main.find(".treedraw_first").val(args && args.firstentry ? args.firstentry : "").spinner({ numberFormat: "n", min: 0, page: 1000, max: numentries }).keyup(this.keyup); + main.find(".treedraw_clear").button().click(function() { JSROOT.cleanup(p.drawid); }); + } + + player.Show = function(divid, args) { + this.drawid = divid + "_draw"; + + this.keyup = this.KeyUp.bind(this); + + var show_extra = args && (args.parse_cut || args.numentries || args.firstentry); + + var main =$("#" + divid); + + main.html("<div class='treedraw_buttons' style='padding-left:0.5em'>" + + "<button class='treedraw_exe' title='Execute draw expression'>Draw</button>" + + " Expr:<input class='treedraw_varexp ui-corner-all ui-widget' style='width:12em;margin-left:5px' title='draw expression'></input> " + + (show_extra ? "" : "<button class='treedraw_more'>More</button>") + + "</div>" + + "<hr/>" + + "<div id='" + this.drawid + "' style='width:100%'></div>"); + + // only when main html element created, one can set divid + this.SetDivId(divid); + + var p = this; + + if (this.local_tree) + main.find('.treedraw_buttons').attr('title', "Tree draw player for: " + this.local_tree.fName); + main.find('.treedraw_exe').button().click(function() { p.PerformDraw(); }); + main.find('.treedraw_varexp') + .val(args && args.parse_expr ? args.parse_expr : (this.dflt_expr || "px:py")) + .keyup(this.keyup); + + if (show_extra) { + this.ShowExtraButtons(args); + } else { + main.find('.treedraw_more').button().click(function() { + $(this).remove(); + p.ShowExtraButtons(); + }); + } + + this.CheckResize(); + } + + player.PerformLocalDraw = function() { + if (!this.local_tree) return; + + var frame = $(this.select_main().node()), + args = { expr: frame.find('.treedraw_varexp').val() }; + + if (frame.find('.treedraw_more').length==0) { + args.cut = frame.find('.treedraw_cut').val(); + if (!args.cut) delete args.cut; + + args.drawopt = frame.find('.treedraw_opt').val(); + if (args.drawopt === "dump") { args.dump = true; args.drawopt = ""; } + if (!args.drawopt) delete args.drawopt; + + args.numentries = parseInt(frame.find('.treedraw_number').val()); + if (isNaN(args.numentries)) delete args.numentries; + + args.firstentry = parseInt(frame.find('.treedraw_first').val()); + if (isNaN(args.firstentry)) delete args.firstentry; + } + + var p = this; + + if (args.drawopt) JSROOT.cleanup(p.drawid); + + p.local_tree.Draw(args, function(histo, hopt, intermediate) { + JSROOT.redraw(p.drawid, histo, hopt); + }); + } + + player.PerformDraw = function() { + + if (this.local_tree) return this.PerformLocalDraw(); + + var frame = $(this.select_main().node()), + url = this.url + '/exe.json.gz?compact=3&method=Draw', + expr = frame.find('.treedraw_varexp').val(), + hname = "h_tree_draw", option = "", + pos = expr.indexOf(">>"); + + if (pos<0) { + expr += ">>" + hname; + } else { + hname = expr.substr(pos+2); + if (hname[0]=='+') hname = hname.substr(1); + var pos2 = hname.indexOf("("); + if (pos2>0) hname = hname.substr(0, pos2); + } + + if (frame.find('.treedraw_more').length==0) { + var cut = frame.find('.treedraw_cut').val(), + nentries = frame.find('.treedraw_number').val(), + firstentry = frame.find('.treedraw_first').val(); + + option = frame.find('.treedraw_opt').val(); + + url += '&prototype="const char*,const char*,Option_t*,Long64_t,Long64_t"&varexp="' + expr + '"&selection="' + cut + '"'; + + // provide all optional arguments - default value kMaxEntries not works properly in ROOT6 + if (nentries=="") nentries = (this.root_version >= 394499) ? "TTree::kMaxEntries": "1000000000"; // kMaxEntries available since ROOT 6.05/03 + if (firstentry=="") firstentry = "0"; + url += '&option="' + option + '"&nentries=' + nentries + '&firstentry=' + firstentry; + } else { + url += '&prototype="Option_t*"&opt="' + expr + '"'; + } + url += '&_ret_object_=' + hname; + + var player = this; + + function SubmitDrawRequest() { + JSROOT.NewHttpRequest(url, 'object', function(res) { + if (!res) return; + JSROOT.cleanup(player.drawid); + JSROOT.draw(player.drawid, res, option); + }).send(); + } + + if (this.askey) { + // first let read tree from the file + this.askey = false; + JSROOT.NewHttpRequest(this.url + "/root.json", 'text', SubmitDrawRequest).send(); + } else { + SubmitDrawRequest(); + } + } + + player.CheckResize = function(arg) { + var main = $(this.select_main().node()); + + $("#" + this.drawid).width(main.width()); + var h = main.height(), + h0 = main.find(".treedraw_buttons").outerHeight(true), + h1 = main.find("hr").outerHeight(true); + + $("#" + this.drawid).height(h - h0 - h1 - 2); + + JSROOT.resize(this.drawid); + } + + return player; + } + + /// @private + /// function used with THttpServer to assign player for the TTree object + + JSROOT.drawTreePlayer = function(hpainter, itemname, askey, asleaf) { + + var item = hpainter.Find(itemname), + top = hpainter.GetTopOnlineItem(item), + draw_expr = "", leaf_cnt = 0; + if (!item || !top) return null; + + if (asleaf) { + draw_expr = item._name; + while (item && !item._ttree) item = item._parent; + if (!item) return null; + itemname = hpainter.itemFullName(item); + } + + var url = hpainter.GetOnlineItemUrl(itemname); + if (!url) return null; + + var root_version = top._root_version ? parseInt(top._root_version) : 396545; // by default use version number 6-13-01 + + var mdi = hpainter.GetDisplay(); + if (!mdi) return null; + + var frame = mdi.FindFrame(itemname, true); + if (!frame) return null; + + var divid = d3.select(frame).attr('id'), + player = new JSROOT.TBasePainter(); + + if (item._childs && !asleaf) + for (var n=0;n<item._childs.length;++n) { + var leaf = item._childs[n]; + if (leaf && leaf._kind && (leaf._kind.indexOf("ROOT.TLeaf")==0) && (leaf_cnt<2)) { + if (leaf_cnt++ > 0) draw_expr+=":"; + draw_expr+=leaf._name; + } + } + + JSROOT.CreateTreePlayer(player); + player.ConfigureOnline(itemname, url, askey, root_version, draw_expr); + player.Show(divid); + + return player; + } + + /// @private + /// function used with THttpServer when tree is not yet loaded + JSROOT.drawTreePlayerKey = function(hpainter, itemname) { + return JSROOT.drawTreePlayer(hpainter, itemname, true); + } + + /// @private + /// function used with THttpServer for when tree is not yet loaded + JSROOT.drawLeafPlayer = function(hpainter, itemname) { + return JSROOT.drawTreePlayer(hpainter, itemname, false, true); + } + + // ======================================================================= + + JSROOT.Painter.ConfigureVSeparator = function(handle) { + // FIXME: obsolete, will be removed + } + + JSROOT.Painter.AdjustLayout = function(left, height, firsttime) { + // FIXME: obsolete, will be removed + if (JSROOT.hpainter && JSROOT.hpainter.brlayout) + JSROOT.hpainter.brlayout.AdjustSeparator(left, height, true); + } + + JSROOT.Painter.ConfigureHSeparator = function(height) { + // FIXME: obsolete, will be removed + if (!JSROOT.hpainter) return ""; + + return JSROOT.hpainter.CreateStatusLine(height); + } + + return JSROOT; + +})); + diff --git a/js/scripts/JSRootPainter.js b/js/scripts/JSRootPainter.js new file mode 100644 index 00000000000..6ddd03838a9 --- /dev/null +++ b/js/scripts/JSRootPainter.js @@ -0,0 +1,6536 @@ +(function( factory ) { + if ( typeof define === "function" && define.amd ) { + define( ['JSRootCore', 'd3'], factory ); + } else + if (typeof exports === 'object' && typeof module !== 'undefined') { + var jsroot = require("./JSRootCore.js"); + factory(jsroot, require("./d3.min.js")); + if (jsroot.nodejs) jsroot.Painter.readStyleFromURL("?interactive=0&tooltip=0&nomenu&noprogress¬ouch&toolbar=0&webgl=0"); + } else { + + if (typeof JSROOT == 'undefined') + throw new Error('JSROOT is not defined', 'JSRootPainter.js'); + + if (typeof d3 != 'object') + throw new Error('d3 is not defined', 'JSRootPainter.js'); + + if (typeof JSROOT.Painter == 'object') + throw new Error('JSROOT.Painter already defined', 'JSRootPainter.js'); + + factory(JSROOT, d3); + } +} (function(JSROOT, d3) { + + "use strict"; + + JSROOT.sources.push("2d"); + + // do it here while require.js does not provide method to load css files + if ( typeof define === "function" && define.amd ) + JSROOT.loadScript('$$$style/JSRootPainter.css'); + + if (!JSROOT._test_d3_) { + if ((typeof d3 == 'object') && d3.version && (d3.version[0]==="5")) { + if (d3.version !== '5.7.0') + console.log('Reuse existing d3.js ' + d3.version + ", expected 5.7.0"); + JSROOT._test_d3_ = 5; + } else if ((typeof d3 == 'object') && d3.version && (d3.version[0]==="4")) { + if (d3.version !== '4.4.4') + console.warn('Try to use older d3.js ' + d3.version + ", expected 5.7.0"); + JSROOT._test_d3_ = 4; + } else if ((typeof d3 == 'object') && d3.version && (d3.version[0]==="3")) { + console.error("Very old d3.js " + d3.version + " found, please UPGRADE"); + d3.timeFormat = d3.time.format; + d3.scaleTime = d3.time.scale; + d3.scaleLog = d3.scale.log; + d3.scaleLinear = d3.scale.linear; + JSROOT._test_d3_ = 3; + } else { + console.error('Fail to identify d3.js version ' + (d3 ? d3.version : "???")); + } + } + + // list of user painters, called with arguments func(vis, obj, opt) + JSROOT.DrawFuncs = { lst:[], cache:{} }; + + /** @summary Register draw function for the class + * @desc List of supported draw options could be provided, separated with ';' + * Several different draw functions for the same class or kind could be specified + * @param {object} args - arguments + * @param {string} args.name - class name + * @param {string} [args.prereq] - prerequicities to load before search for the draw function + * @param {string} args.func - name of draw function for the class + * @param {string} [args.direct=false] - if true, function is just Redraw() method of TObjectPainter + * @param {string} args.opt - list of supported draw options (separated with semicolon) like "col;scat;" + * @param {string} [args.icon] - icon name shown for the class in hierarchy browser + */ + JSROOT.addDrawFunc = function(_name, _func, _opt) { + if ((arguments.length == 1) && (typeof arguments[0] == 'object')) { + JSROOT.DrawFuncs.lst.push(arguments[0]); + return arguments[0]; + } + var handle = { name:_name, func:_func, opt:_opt }; + JSROOT.DrawFuncs.lst.push(handle); + return handle; + } + + // icons taken from http://uxrepo.com/ + + JSROOT.ToolbarIcons = { + camera: { path: 'M 152.00,304.00c0.00,57.438, 46.562,104.00, 104.00,104.00s 104.00-46.562, 104.00-104.00s-46.562-104.00-104.00-104.00S 152.00,246.562, 152.00,304.00z M 480.00,128.00L 368.00,128.00 c-8.00-32.00-16.00-64.00-48.00-64.00L 192.00,64.00 c-32.00,0.00-40.00,32.00-48.00,64.00L 32.00,128.00 c-17.60,0.00-32.00,14.40-32.00,32.00l0.00,288.00 c0.00,17.60, 14.40,32.00, 32.00,32.00l 448.00,0.00 c 17.60,0.00, 32.00-14.40, 32.00-32.00L 512.00,160.00 C 512.00,142.40, 497.60,128.00, 480.00,128.00z M 256.00,446.00c-78.425,0.00-142.00-63.574-142.00-142.00c0.00-78.425, 63.575-142.00, 142.00-142.00c 78.426,0.00, 142.00,63.575, 142.00,142.00 C 398.00,382.426, 334.427,446.00, 256.00,446.00z M 480.00,224.00l-64.00,0.00 l0.00-32.00 l 64.00,0.00 L 480.00,224.00 z' }, + disk: { path: 'M384,0H128H32C14.336,0,0,14.336,0,32v448c0,17.656,14.336,32,32,32h448c17.656,0,32-14.344,32-32V96L416,0H384z M352,160 V32h32v128c0,17.664-14.344,32-32,32H160c-17.664,0-32-14.336-32-32V32h128v128H352z M96,288c0-17.656,14.336-32,32-32h256 c17.656,0,32,14.344,32,32v192H96V288z' }, + question: { path: 'M256,512c141.375,0,256-114.625,256-256S397.375,0,256,0S0,114.625,0,256S114.625,512,256,512z M256,64 c63.719,0,128,36.484,128,118.016c0,47.453-23.531,84.516-69.891,110.016C300.672,299.422,288,314.047,288,320 c0,17.656-14.344,32-32,32c-17.664,0-32-14.344-32-32c0-40.609,37.25-71.938,59.266-84.031 C315.625,218.109,320,198.656,320,182.016C320,135.008,279.906,128,256,128c-30.812,0-64,20.227-64,64.672 c0,17.664-14.336,32-32,32s-32-14.336-32-32C128,109.086,193.953,64,256,64z M256,449.406c-18.211,0-32.961-14.75-32.961-32.969 c0-18.188,14.75-32.953,32.961-32.953c18.219,0,32.969,14.766,32.969,32.953C288.969,434.656,274.219,449.406,256,449.406z' }, + undo: { path: 'M450.159,48.042c8.791,9.032,16.983,18.898,24.59,29.604c7.594,10.706,14.146,22.207,19.668,34.489 c5.509,12.296,9.82,25.269,12.92,38.938c3.113,13.669,4.663,27.834,4.663,42.499c0,14.256-1.511,28.863-4.532,43.822 c-3.009,14.952-7.997,30.217-14.953,45.795c-6.955,15.577-16.202,31.52-27.755,47.826s-25.88,32.9-42.942,49.807 c-5.51,5.444-11.787,11.67-18.834,18.651c-7.033,6.98-14.496,14.366-22.39,22.168c-7.88,7.802-15.955,15.825-24.187,24.069 c-8.258,8.231-16.333,16.203-24.252,23.888c-18.3,18.13-37.354,37.016-57.191,56.65l-56.84-57.445 c19.596-19.472,38.54-38.279,56.84-56.41c7.75-7.685,15.772-15.604,24.108-23.757s16.438-16.163,24.33-24.057 c7.894-7.893,15.356-15.33,22.402-22.312c7.034-6.98,13.312-13.193,18.821-18.651c22.351-22.402,39.165-44.648,50.471-66.738 c11.279-22.09,16.932-43.567,16.932-64.446c0-15.785-3.217-31.005-9.638-45.671c-6.422-14.665-16.229-28.504-29.437-41.529 c-3.282-3.282-7.358-6.395-12.217-9.325c-4.871-2.938-10.381-5.503-16.516-7.697c-6.121-2.201-12.815-3.992-20.058-5.373 c-7.242-1.374-14.9-2.064-23.002-2.064c-8.218,0-16.802,0.834-25.788,2.507c-8.961,1.674-18.053,4.429-27.222,8.271 c-9.189,3.842-18.456,8.869-27.808,15.089c-9.358,6.219-18.521,13.819-27.502,22.793l-59.92,60.271l93.797,94.058H0V40.91 l93.27,91.597l60.181-60.532c13.376-15.018,27.222-27.248,41.536-36.697c14.308-9.443,28.608-16.776,42.89-21.992 c14.288-5.223,28.505-8.74,42.623-10.557C294.645,0.905,308.189,0,321.162,0c13.429,0,26.389,1.185,38.84,3.562 c12.478,2.377,24.2,5.718,35.192,10.029c11.006,4.311,21.126,9.404,30.374,15.265C434.79,34.724,442.995,41.119,450.159,48.042z' }, + arrow_right : { path: 'M30.796,226.318h377.533L294.938,339.682c-11.899,11.906-11.899,31.184,0,43.084c11.887,11.899,31.19,11.893,43.077,0 l165.393-165.386c5.725-5.712,8.924-13.453,8.924-21.539c0-8.092-3.213-15.84-8.924-21.551L338.016,8.925 C332.065,2.975,324.278,0,316.478,0c-7.802,0-15.603,2.968-21.539,8.918c-11.899,11.906-11.899,31.184,0,43.084l113.391,113.384 H30.796c-16.822,0-30.463,13.645-30.463,30.463C0.333,212.674,13.974,226.318,30.796,226.318z' }, + arrow_up : { path: 'M295.505,629.446V135.957l148.193,148.206c15.555,15.559,40.753,15.559,56.308,0c15.555-15.538,15.546-40.767,0-56.304 L283.83,11.662C276.372,4.204,266.236,0,255.68,0c-10.568,0-20.705,4.204-28.172,11.662L11.333,227.859 c-7.777,7.777-11.666,17.965-11.666,28.158c0,10.192,3.88,20.385,11.657,28.158c15.563,15.555,40.762,15.555,56.317,0 l148.201-148.219v493.489c0,21.993,17.837,39.82,39.82,39.82C277.669,669.267,295.505,651.439,295.505,629.446z' }, + arrow_diag : { path: 'M279.875,511.994c-1.292,0-2.607-0.102-3.924-0.312c-10.944-1.771-19.333-10.676-20.457-21.71L233.97,278.348 L22.345,256.823c-11.029-1.119-19.928-9.51-21.698-20.461c-1.776-10.944,4.031-21.716,14.145-26.262L477.792,2.149 c9.282-4.163,20.167-2.165,27.355,5.024c7.201,7.189,9.199,18.086,5.024,27.356L302.22,497.527 C298.224,506.426,289.397,511.994,279.875,511.994z M118.277,217.332l140.534,14.294c11.567,1.178,20.718,10.335,21.878,21.896 l14.294,140.519l144.09-320.792L118.277,217.332z' }, + auto_zoom: { path: 'M505.441,242.47l-78.303-78.291c-9.18-9.177-24.048-9.171-33.216,0c-9.169,9.172-9.169,24.045,0.006,33.217l38.193,38.188 H280.088V80.194l38.188,38.199c4.587,4.584,10.596,6.881,16.605,6.881c6.003,0,12.018-2.297,16.605-6.875 c9.174-9.172,9.174-24.039,0.011-33.217L273.219,6.881C268.803,2.471,262.834,0,256.596,0c-6.229,0-12.202,2.471-16.605,6.881 l-78.296,78.302c-9.178,9.172-9.178,24.045,0,33.217c9.177,9.171,24.051,9.171,33.21,0l38.205-38.205v155.4H80.521l38.2-38.188 c9.177-9.171,9.177-24.039,0.005-33.216c-9.171-9.172-24.039-9.178-33.216,0L7.208,242.464c-4.404,4.403-6.881,10.381-6.881,16.611 c0,6.227,2.477,12.207,6.881,16.61l78.302,78.291c4.587,4.581,10.599,6.875,16.605,6.875c6.006,0,12.023-2.294,16.61-6.881 c9.172-9.174,9.172-24.036-0.005-33.211l-38.205-38.199h152.593v152.063l-38.199-38.211c-9.171-9.18-24.039-9.18-33.216-0.022 c-9.178,9.18-9.178,24.059-0.006,33.222l78.284,78.302c4.41,4.404,10.382,6.881,16.611,6.881c6.233,0,12.208-2.477,16.611-6.881 l78.302-78.296c9.181-9.18,9.181-24.048,0-33.205c-9.174-9.174-24.054-9.174-33.21,0l-38.199,38.188v-152.04h152.051l-38.205,38.199 c-9.18,9.175-9.18,24.037-0.005,33.211c4.587,4.587,10.596,6.881,16.604,6.881c6.01,0,12.024-2.294,16.605-6.875l78.303-78.285 c4.403-4.403,6.887-10.378,6.887-16.611C512.328,252.851,509.845,246.873,505.441,242.47z' }, + statbox : { + path : 'M28.782,56.902H483.88c15.707,0,28.451-12.74,28.451-28.451C512.331,12.741,499.599,0,483.885,0H28.782 C13.074,0,0.331,12.741,0.331,28.451C0.331,44.162,13.074,56.902,28.782,56.902z' + + 'M483.885,136.845H28.782c-15.708,0-28.451,12.741-28.451,28.451c0,15.711,12.744,28.451,28.451,28.451H483.88 c15.707,0,28.451-12.74,28.451-28.451C512.331,149.586,499.599,136.845,483.885,136.845z' + + 'M483.885,273.275H28.782c-15.708,0-28.451,12.731-28.451,28.452c0,15.707,12.744,28.451,28.451,28.451H483.88 c15.707,0,28.451-12.744,28.451-28.451C512.337,286.007,499.599,273.275,483.885,273.275z' + + 'M256.065,409.704H30.492c-15.708,0-28.451,12.731-28.451,28.451c0,15.707,12.744,28.451,28.451,28.451h225.585 c15.707,0,28.451-12.744,28.451-28.451C284.516,422.436,271.785,409.704,256.065,409.704z' + }, + circle: { path: "M256,256 m-150,0 a150,150 0 1,0 300,0 a150,150 0 1,0 -300,0" }, + three_circles: { path: "M256,85 m-70,0 a70,70 0 1,0 140,0 a70,70 0 1,0 -140,0 M256,255 m-70,0 a70,70 0 1,0 140,0 a70,70 0 1,0 -140,0 M256,425 m-70,0 a70,70 0 1,0 140,0 a70,70 0 1,0 -140,0 " }, + diamand: { path: "M256,0L384,256L256,511L128,256z" }, + rect: { path: "M80,80h352v352h-352z" }, + cross: { path: "M80,40l176,176l176,-176l40,40l-176,176l176,176l-40,40l-176,-176l-176,176l-40,-40l176,-176l-176,-176z" }, + vrgoggles: { size: "245.82 141.73", path: 'M175.56,111.37c-22.52,0-40.77-18.84-40.77-42.07S153,27.24,175.56,27.24s40.77,18.84,40.77,42.07S198.08,111.37,175.56,111.37ZM26.84,69.31c0-23.23,18.25-42.07,40.77-42.07s40.77,18.84,40.77,42.07-18.26,42.07-40.77,42.07S26.84,92.54,26.84,69.31ZM27.27,0C11.54,0,0,12.34,0,28.58V110.9c0,16.24,11.54,30.83,27.27,30.83H99.57c2.17,0,4.19-1.83,5.4-3.7L116.47,118a8,8,0,0,1,12.52-.18l11.51,20.34c1.2,1.86,3.22,3.61,5.39,3.61h72.29c15.74,0,27.63-14.6,27.63-30.83V28.58C245.82,12.34,233.93,0,218.19,0H27.27Z'}, + CreateSVG : function(group,btn,size,title) { + var svg = group.append("svg:svg") + .attr("class", "svg_toolbar_btn") + .attr("width",size+"px") + .attr("height",size+"px") + .attr("viewBox", "0 0 512 512") + .style("overflow","hidden"); + + if ('recs' in btn) { + var rec = {}; + for (var n=0;n<btn.recs.length;++n) { + JSROOT.extend(rec, btn.recs[n]); + svg.append('rect').attr("x", rec.x).attr("y", rec.y) + .attr("width", rec.w).attr("height", rec.h) + .attr("fill", rec.f); + } + } else { + svg.append('svg:path').attr('d',btn.path); + } + + // special rect to correctly get mouse events for whole button area + svg.append("svg:rect").attr("x",0).attr("y",0).attr("width",512).attr("height",512) + .style('opacity',0).style('fill',"none").style("pointer-events","visibleFill") + .append("svg:title").text(title); + + return svg; + } + }; + + // ========================================================================================== + + /** @summary Draw options interpreter. + * @constructor + * @memberof JSROOT + */ + var DrawOptions = function(opt) { + this.opt = opt && (typeof opt=="string") ? opt.toUpperCase().trim() : ""; + this.part = ""; + } + + /** @summary Returns true if remaining options are empty. */ + DrawOptions.prototype.empty = function() { + return this.opt.length === 0; + } + + /** @summary Returns remaining part of the draw options. */ + DrawOptions.prototype.remain = function() { + return this.opt; + } + + /** @summary Checks if given option exists */ + DrawOptions.prototype.check = function(name,postpart) { + var pos = this.opt.indexOf(name); + if (pos < 0) return false; + this.opt = this.opt.substr(0, pos) + this.opt.substr(pos + name.length); + this.part = ""; + if (!postpart) return true; + + var pos2 = pos; + while ((pos2<this.opt.length) && (this.opt[pos2] !== ' ') && (this.opt[pos2] !== ',') && (this.opt[pos2] !== ';')) pos2++; + if (pos2 > pos) { + this.part = this.opt.substr(pos, pos2-pos); + this.opt = this.opt.substr(0, pos) + this.opt.substr(pos2); + } + return true; + } + + /** @summary Returns remaining part of found option as integer. */ + DrawOptions.prototype.partAsInt = function(offset, dflt) { + var val = this.part.replace( /^\D+/g, ''); + val = val ? parseInt(val,10) : Number.NaN; + return isNaN(val) ? (dflt || 0) : val + (offset || 0); + } + + // ============================================================================================ + + var Painter = { + Coord: { + kCARTESIAN : 1, + kPOLAR : 2, + kCYLINDRICAL : 3, + kSPHERICAL : 4, + kRAPIDITY : 5 + }, + root_colors: [], + root_line_styles: ["", "", "3,3", "1,2", + "3,4,1,4", "5,3,1,3", "5,3,1,3,1,3,1,3", "5,5", + "5,3,1,3,1,3", "20,5", "20,10,1,10", "1,3"], + root_markers: [ 0, 100, 8, 7, 0, // 0..4 + 9, 100, 100, 100, 100, // 5..9 + 100, 100, 100, 100, 100, // 10..14 + 100, 100, 100, 100, 100, // 15..19 + 100, 103, 105, 104, 0, // 20..24 + 3, 4, 2, 1, 106, // 25..29 + 6, 7, 5, 102, 101], // 30..34 + root_fonts: ['Arial', 'iTimes New Roman', + 'bTimes New Roman', 'biTimes New Roman', 'Arial', + 'oArial', 'bArial', 'boArial', 'Courier New', + 'oCourier New', 'bCourier New', 'boCourier New', + 'Symbol', 'Times New Roman', 'Wingdings', 'iSymbol', 'Verdana'], + // taken from https://www.math.utah.edu/~beebe/fonts/afm-widths.html + root_fonts_aver_width: [ 0.537, 0.510, + 0.535, 0.520, 0.537, + 0.54, 0.556, 0.56, 0.6, + 0.6, 0.6, 0.6, + 0.587, 0.514, 0.896, 0.587, 0.55 ], + symbols_map: { + // greek letters + '#alpha': '\u03B1', + '#beta': '\u03B2', + '#chi': '\u03C7', + '#delta': '\u03B4', + '#varepsilon': '\u03B5', + '#phi': '\u03C6', + '#gamma': '\u03B3', + '#eta': '\u03B7', + '#iota': '\u03B9', + '#varphi': '\u03C6', + '#kappa': '\u03BA', + '#lambda': '\u03BB', + '#mu': '\u03BC', + '#nu': '\u03BD', + '#omicron': '\u03BF', + '#pi': '\u03C0', + '#theta': '\u03B8', + '#rho': '\u03C1', + '#sigma': '\u03C3', + '#tau': '\u03C4', + '#upsilon': '\u03C5', + '#varomega': '\u03D6', + '#omega': '\u03C9', + '#xi': '\u03BE', + '#psi': '\u03C8', + '#zeta': '\u03B6', + '#Alpha': '\u0391', + '#Beta': '\u0392', + '#Chi': '\u03A7', + '#Delta': '\u0394', + '#Epsilon': '\u0395', + '#Phi': '\u03A6', + '#Gamma': '\u0393', + '#Eta': '\u0397', + '#Iota': '\u0399', + '#vartheta': '\u03D1', + '#Kappa': '\u039A', + '#Lambda': '\u039B', + '#Mu': '\u039C', + '#Nu': '\u039D', + '#Omicron': '\u039F', + '#Pi': '\u03A0', + '#Theta': '\u0398', + '#Rho': '\u03A1', + '#Sigma': '\u03A3', + '#Tau': '\u03A4', + '#Upsilon': '\u03A5', + '#varsigma': '\u03C2', + '#Omega': '\u03A9', + '#Xi': '\u039E', + '#Psi': '\u03A8', + '#Zeta': '\u0396', + '#varUpsilon': '\u03D2', + '#epsilon': '\u03B5', + + // only required for MathJax to provide correct replacement + '#sqrt': '\u221A', + '#bar': '', + + // from TLatex tables #2 & #3 + '#leq': '\u2264', + '#/': '\u2044', + '#infty': '\u221E', + '#voidb': '\u0192', + '#club': '\u2663', + '#diamond': '\u2666', + '#heart': '\u2665', + '#spade': '\u2660', + '#leftrightarrow': '\u2194', + '#leftarrow': '\u2190', + '#uparrow': '\u2191', + '#rightarrow': '\u2192', + '#downarrow': '\u2193', + '#circ': '\u02C6', // ^ + '#pm': '\xB1', + '#doublequote': '\u2033', + '#geq': '\u2265', + '#times': '\xD7', + '#propto': '\u221D', + '#partial': '\u2202', + '#bullet': '\u2022', + '#divide': '\xF7', + '#neq': '\u2260', + '#equiv': '\u2261', + '#approx': '\u2248', // should be \u2245 ? + '#3dots': '\u2026', + '#cbar': '\x7C', + '#topbar': '\xAF', + '#downleftarrow': '\u21B5', + '#aleph': '\u2135', + '#Jgothic': '\u2111', + '#Rgothic': '\u211C', + '#voidn': '\u2118', + '#otimes': '\u2297', + '#oplus': '\u2295', + '#oslash': '\u2205', + '#cap': '\u2229', + '#cup': '\u222A', + '#supseteq': '\u2287', + '#supset': '\u2283', + '#notsubset': '\u2284', + '#subseteq': '\u2286', + '#subset': '\u2282', + '#int': '\u222B', + '#in': '\u2208', + '#notin': '\u2209', + '#angle': '\u2220', + '#nabla': '\u2207', + '#oright': '\xAE', + '#ocopyright': '\xA9', + '#trademark': '\u2122', + '#prod': '\u220F', + '#surd': '\u221A', + '#upoint': '\u02D9', + '#corner': '\xAC', + '#wedge': '\u2227', + '#vee': '\u2228', + '#Leftrightarrow': '\u21D4', + '#Leftarrow': '\u21D0', + '#Uparrow': '\u21D1', + '#Rightarrow': '\u21D2', + '#Downarrow': '\u21D3', + '#LT': '\x3C', + '#void1': '\xAE', + '#copyright': '\xA9', + '#void3': '\u2122', + '#sum': '\u2211', + '#arctop': '\u239B', + '#lbar': '\u23B8', + '#arcbottom': '\u239D', + '#void8': '', + '#bottombar': '\u230A', + '#arcbar': '\u23A7', + '#ltbar': '\u23A8', + '#AA': '\u212B', + '#aa': '\u00E5', + '#void06': '', + '#GT': '\x3E', + '#forall': '\u2200', + '#exists': '\u2203', + '#vec': '', + '#dot': '\u22C5', + '#hat': '\xB7', + '#ddot': '', + '#acute': '\acute', + '#grave': '', + '#check': '\u2713', + '#tilde': '\u02DC', + '#slash': '\u2044', + '#hbar': '\u0127', + '#box': '\u25FD', + '#Box': '\u2610', + '#parallel': '\u2225', + '#perp': '\u22A5', + '#odot': '\u2299', + '#left': '', + '#right': '', + '{}': '' + }, + math_symbols_map: { + '#LT':"\\langle", + '#GT':"\\rangle", + '#club':"\\clubsuit", + '#spade':"\\spadesuit", + '#heart':"\\heartsuit", + '#diamond':"\\diamondsuit", + '#voidn':"\\wp", + '#voidb':"f", + '#copyright':"(c)", + '#ocopyright':"(c)", + '#trademark':"TM", + '#void3':"TM", + '#oright':"R", + '#void1':"R", + '#3dots':"\\ldots", + '#lbar':"\\mid", + '#void8':"\\mid", + '#divide':"\\div", + '#Jgothic':"\\Im", + '#Rgothic':"\\Re", + '#doublequote':"\"", + '#plus':"+", + '#minus':"-", + '#\/':"/", + '#upoint':".", + '#aa':"\\mathring{a}", + '#AA':"\\mathring{A}", + '#omicron':"o", + '#Alpha':"A", + '#Beta':"B", + '#Epsilon':"E", + '#Zeta':"Z", + '#Eta':"H", + '#Iota':"I", + '#Kappa':"K", + '#Mu':"M", + '#Nu':"N", + '#Omicron':"O", + '#Rho':"P", + '#Tau':"T", + '#Chi':"X", + '#varomega':"\\varpi", + '#corner':"?", + '#ltbar':"?", + '#bottombar':"?", + '#notsubset':"?", + '#arcbottom':"?", + '#cbar':"?", + '#arctop':"?", + '#topbar':"?", + '#arcbar':"?", + '#downleftarrow':"?", + '#splitline':"\\genfrac{}{}{0pt}{}", + '#it':"\\textit", + '#bf':"\\textbf", + '#frac':"\\frac", + '#left{':"\\lbrace", + '#right}':"\\rbrace", + '#left\\[':"\\lbrack", + '#right\\]':"\\rbrack", + '#\\[\\]{':"\\lbrack", + ' } ':"\\rbrack", + '#\\[':"\\lbrack", + '#\\]':"\\rbrack", + '#{':"\\lbrace", + '#}':"\\rbrace", + ' ':"\\;" + } + }; + + JSROOT.Painter = Painter; // export here to avoid ambiguity + + Painter.convertSymbol = function(charactere) { + // example: '#pi' will give '\u03A0' + return Painter.symbols_map[charactere]; + } + + Painter.createMenu = function(painter, maincallback) { + // dummy functions, forward call to the jquery function + document.body.style.cursor = 'wait'; + JSROOT.AssertPrerequisites('hierarchy;jq2d;', function() { + document.body.style.cursor = 'auto'; + Painter.createMenu(painter, maincallback); + }); + } + + Painter.closeMenu = function(menuname) { + var x = document.getElementById(menuname || 'root_ctx_menu'); + if (x) { x.parentNode.removeChild(x); return true; } + return false; + } + + Painter.readStyleFromURL = function(url) { + var optimize = JSROOT.GetUrlOption("optimize", url); + if (optimize=="") JSROOT.gStyle.OptimizeDraw = 2; else + if (optimize!==null) { + JSROOT.gStyle.OptimizeDraw = parseInt(optimize); + if (isNaN(JSROOT.gStyle.OptimizeDraw)) JSROOT.gStyle.OptimizeDraw = 2; + } + + var inter = JSROOT.GetUrlOption("interactive", url); + if (inter === "nomenu") JSROOT.gStyle.ContextMenu = false; + else if (inter !== null) { + if (!inter || (inter=="1")) inter = "111111"; else + if (inter=="0") inter = "000000"; + if (inter.length === 6) { + if (inter[0] == "0") JSROOT.gStyle.ToolBar = false; else + if (inter[0] == "1") JSROOT.gStyle.ToolBar = 'popup'; else + if (inter[0] == "2") JSROOT.gStyle.ToolBar = true; + inter = inter.substr(1); + } + if (inter.length==5) { + JSROOT.gStyle.Tooltip = parseInt(inter[0]); + JSROOT.gStyle.ContextMenu = (inter[1] != '0'); + JSROOT.gStyle.Zooming = (inter[2] != '0'); + JSROOT.gStyle.MoveResize = (inter[3] != '0'); + JSROOT.gStyle.DragAndDrop = (inter[4] != '0'); + } + } + + var tt = JSROOT.GetUrlOption("tooltip", url); + if (tt !== null) JSROOT.gStyle.Tooltip = parseInt(tt); + + var mathjax = JSROOT.GetUrlOption("mathjax", url), + latex = JSROOT.GetUrlOption("latex", url); + + if ((mathjax!==null) && (mathjax!="0") && (latex===null)) latex = "math"; + if (latex!==null) JSROOT.gStyle.Latex = latex; // decoding will be performed with the first text drawing + + if (JSROOT.GetUrlOption("nomenu", url)!==null) JSROOT.gStyle.ContextMenu = false; + if (JSROOT.GetUrlOption("noprogress", url)!==null) JSROOT.gStyle.ProgressBox = false; + if (JSROOT.GetUrlOption("notouch", url)!==null) JSROOT.touches = false; + if (JSROOT.GetUrlOption("adjframe", url)!==null) JSROOT.gStyle.CanAdjustFrame = true; + + var optstat = JSROOT.GetUrlOption("optstat", url); + if (optstat!==null) JSROOT.gStyle.fOptStat = parseInt(optstat); + var optfit = JSROOT.GetUrlOption("optfit", url); + if (optfit!==null) JSROOT.gStyle.fOptFit = parseInt(optfit); + JSROOT.gStyle.fStatFormat = JSROOT.GetUrlOption("statfmt", url, JSROOT.gStyle.fStatFormat); + JSROOT.gStyle.fFitFormat = JSROOT.GetUrlOption("fitfmt", url, JSROOT.gStyle.fFitFormat); + + var toolbar = JSROOT.GetUrlOption("toolbar", url); + if (toolbar !== null) { + var val = null; + if (toolbar.indexOf('popup')>=0) val = 'popup'; + if (toolbar.indexOf('left')>=0) { JSROOT.gStyle.ToolBarSide = 'left'; val = 'popup'; } + if (toolbar.indexOf('right')>=0) { JSROOT.gStyle.ToolBarSide = 'right'; val = 'popup'; } + if (toolbar.indexOf('vert')>=0) { JSROOT.gStyle.ToolBarVert = true; val = 'popup'; } + if (toolbar.indexOf('show')>=0) val = true; + JSROOT.gStyle.ToolBar = val || ((toolbar.indexOf("0")<0) && (toolbar.indexOf("false")<0) && (toolbar.indexOf("off")<0)); + } + + var palette = JSROOT.GetUrlOption("palette", url); + if (palette!==null) { + palette = parseInt(palette); + if (!isNaN(palette) && (palette>0) && (palette<113)) JSROOT.gStyle.Palette = palette; + } + + var embed3d = JSROOT.GetUrlOption("embed3d", url); + if (embed3d !== null) JSROOT.gStyle.Embed3DinSVG = parseInt(embed3d); + + var webgl = JSROOT.GetUrlOption("webgl", url); + if ((webgl === "0") || (webgl === "false")) JSROOT.gStyle.NoWebGL = true; else + if (webgl === "ie") JSROOT.gStyle.NoWebGL = !JSROOT.browser.isIE; + + var geosegm = JSROOT.GetUrlOption("geosegm", url); + if (geosegm!==null) JSROOT.gStyle.GeoGradPerSegm = Math.max(2, parseInt(geosegm)); + var geocomp = JSROOT.GetUrlOption("geocomp", url); + if (geocomp!==null) JSROOT.gStyle.GeoCompressComp = (geocomp!=='0') && (geocomp!=='false'); + } + + /** Function that generates all root colors */ + Painter.createRootColors = function() { + var colorMap = ['white','black','red','green','blue','yellow','magenta','cyan','rgb(89,212,84)','rgb(89,84,217)', 'white']; + colorMap[110] = 'white'; + + var moreCol = [ + {col:11,str:'c1b7ad4d4d4d6666668080809a9a9ab3b3b3cdcdcde6e6e6f3f3f3cdc8accdc8acc3c0a9bbb6a4b3a697b8a49cae9a8d9c8f83886657b1cfc885c3a48aa9a1839f8daebdc87b8f9a768a926983976e7b857d9ad280809caca6c0d4cf88dfbb88bd9f83c89a7dc08378cf5f61ac8f94a6787b946971d45a549300ff7b00ff6300ff4b00ff3300ff1b00ff0300ff0014ff002cff0044ff005cff0074ff008cff00a4ff00bcff00d4ff00ecff00fffd00ffe500ffcd00ffb500ff9d00ff8500ff6d00ff5500ff3d00ff2600ff0e0aff0022ff003aff0052ff006aff0082ff009aff00b1ff00c9ff00e1ff00f9ff00ffef00ffd700ffbf00ffa700ff8f00ff7700ff6000ff4800ff3000ff1800ff0000'}, + {col:201,str:'5c5c5c7b7b7bb8b8b8d7d7d78a0f0fb81414ec4848f176760f8a0f14b81448ec4876f1760f0f8a1414b84848ec7676f18a8a0fb8b814ecec48f1f1768a0f8ab814b8ec48ecf176f10f8a8a14b8b848ecec76f1f1'}, + {col:390,str:'ffffcdffff9acdcd9affff66cdcd669a9a66ffff33cdcd339a9a33666633ffff00cdcd009a9a00666600333300'}, + {col:406,str:'cdffcd9aff9a9acd9a66ff6666cd66669a6633ff3333cd33339a3333663300ff0000cd00009a00006600003300'}, + {col:422,str:'cdffff9affff9acdcd66ffff66cdcd669a9a33ffff33cdcd339a9a33666600ffff00cdcd009a9a006666003333'}, + {col:590,str:'cdcdff9a9aff9a9acd6666ff6666cd66669a3333ff3333cd33339a3333660000ff0000cd00009a000066000033'}, + {col:606,str:'ffcdffff9affcd9acdff66ffcd66cd9a669aff33ffcd33cd9a339a663366ff00ffcd00cd9a009a660066330033'}, + {col:622,str:'ffcdcdff9a9acd9a9aff6666cd66669a6666ff3333cd33339a3333663333ff0000cd00009a0000660000330000'}, + {col:791,str:'ffcd9acd9a669a66339a6600cd9a33ffcd66ff9a00ffcd33cd9a00ffcd00ff9a33cd66006633009a3300cd6633ff9a66ff6600ff6633cd3300ff33009aff3366cd00336600339a0066cd339aff6666ff0066ff3333cd0033ff00cdff9a9acd66669a33669a009acd33cdff669aff00cdff339acd00cdff009affcd66cd9a339a66009a6633cd9a66ffcd00ff6633ffcd00cd9a00ffcd33ff9a00cd66006633009a3333cd6666ff9a00ff9a33ff6600cd3300ff339acdff669acd33669a00339a3366cd669aff0066ff3366ff0033cd0033ff339aff0066cd00336600669a339acd66cdff009aff33cdff009acd00cdffcd9aff9a66cd66339a66009a9a33cdcd66ff9a00ffcd33ff9a00cdcd00ff9a33ff6600cd33006633009a6633cd9a66ff6600ff6633ff3300cd3300ffff339acd00666600339a0033cd3366ff669aff0066ff3366cd0033ff0033ff9acdcd669a9a33669a0066cd339aff66cdff009acd009aff33cdff009a'}, + {col:920,str:'cdcdcd9a9a9a666666333333'}]; + + for (var indx = 0; indx < moreCol.length; ++indx) { + var entry = moreCol[indx]; + for (var n=0; n<entry.str.length; n+=6) { + var num = parseInt(entry.col) + parseInt(n/6); + colorMap[num] = 'rgb(' + parseInt("0x" +entry.str.slice(n,n+2)) + "," + parseInt("0x" + entry.str.slice(n+2,n+4)) + "," + parseInt("0x" + entry.str.slice(n+4,n+6)) + ")"; + } + } + + Painter.root_colors = colorMap; + } + + Painter.MakeColorRGB = function(col) { + if ((col==null) || (col._typename != 'TColor')) return null; + var rgb = Math.round(col.fRed*255) + "," + Math.round(col.fGreen*255) + "," + Math.round(col.fBlue*255); + if ((col.fAlpha === undefined) || (col.fAlpha == 1.)) + rgb = "rgb(" + rgb + ")"; + else + rgb = "rgba(" + rgb + "," + col.fAlpha.toFixed(3) + ")"; + + switch (rgb) { + case 'rgb(255,255,255)': rgb = 'white'; break; + case 'rgb(0,0,0)': rgb = 'black'; break; + case 'rgb(255,0,0)': rgb = 'red'; break; + case 'rgb(0,255,0)': rgb = 'green'; break; + case 'rgb(0,0,255)': rgb = 'blue'; break; + case 'rgb(255,255,0)': rgb = 'yellow'; break; + case 'rgb(255,0,255)': rgb = 'magenta'; break; + case 'rgb(0,255,255)': rgb = 'cyan'; break; + } + return rgb; + } + + /** Add new colors from object array. */ + Painter.extendRootColors = function(jsarr, objarr) { + if (!jsarr) { + jsarr = []; + for (var n=0;n<this.root_colors.length;++n) + jsarr[n] = this.root_colors[n]; + } + + if (!objarr) return jsarr; + + var rgb_array = objarr; + if (objarr._typename && objarr.arr) { + rgb_array = []; + for (var n = 0; n < objarr.arr.length; ++n) { + var col = objarr.arr[n]; + if (!col || (col._typename != 'TColor')) continue; + + if ((col.fNumber>=0) && (col.fNumber<=10000)) + rgb_array[col.fNumber] = Painter.MakeColorRGB(col); + } + } + + + for (var n = 0; n < rgb_array.length; ++n) + if (rgb_array[n] && (jsarr[n] != rgb_array[n])) + jsarr[n] = rgb_array[n]; + + return jsarr; + } + + /** Set global list of colors. + * Either TObjArray of TColor instances or just plain array with rgb() code. + * List of colors typically stored together with TCanvas primitives + * @private */ + Painter.adoptRootColors = function(objarr) { + this.extendRootColors(this.root_colors, objarr); + } + + // ===================================================================== + + /** + * Color palette handle. + * @constructor + * @memberof JSROOT + * @private + */ + + function ColorPalette(arr) { + this.palette = arr; + } + + /** @summary Returns color index which correspond to contour index of provided length */ + ColorPalette.prototype.calcColorIndex = function(i,len) { + var theColor = Math.floor((i+0.99)*this.palette.length/(len-1)); + if (theColor > this.palette.length-1) theColor = this.palette.length-1; + return theColor; + } + + /** @summary Returns color with provided index */ + ColorPalette.prototype.getColor = function(indx) { + return this.palette[indx]; + } + + /** @summary Returns number of colors in the palette */ + ColorPalette.prototype.getLength = function() { + return this.palette.length; + } + + /** @summary Calculate color for given i and len */ + ColorPalette.prototype.calcColor = function(i,len) { + var indx = this.calcColorIndex(i,len); + return this.getColor(indx); + } + + // ============================================================================= + + /** + * @summary Handle for marker attributes. + * @constructor + * @memberof JSROOT + */ + + function TAttMarkerHandler(args) { + this.x0 = this.y0 = 0; + this.color = 'black'; + this.style = 1; + this.size = 8; + this.scale = 1; + this.stroke = true; + this.fill = true; + this.marker = ""; + this.ndig = 0; + this.used = true; + this.changed = false; + + this.func = this.Apply.bind(this); + + this.SetArgs(args); + + this.changed = false; + } + + /** @summary Set marker attributes. + * + * @param {object} args - arguments can be + * @param {object} args.attr - instance of TAttrMarker (or derived class) or + * @param {string} args.color - color in HTML form like grb(1,4,5) or 'green' + * @param {number} args.style - marker style + * @param {number} args.size - marker size + */ + TAttMarkerHandler.prototype.SetArgs = function(args) { + if ((typeof args == 'object') && (typeof args.fMarkerStyle == 'number')) args = { attr: args }; + + if (args.attr) { + if (args.color === undefined) args.color = Painter.root_colors[args.attr.fMarkerColor]; + if (!args.style || (args.style<0)) args.style = args.attr.fMarkerStyle; + if (!args.size) args.size = args.attr.fMarkerSize; + } + + this.Change(args.color, args.style, args.size); + } + + /** @summary Reset position, used for optimization of drawing of multiple markers + * @private */ + TAttMarkerHandler.prototype.reset_pos = function() { + this.lastx = this.lasty = null; + } + + /** @summary Create marker path for given position. + * + * @desc When drawing many elementary points, created path may depend from previously produced markers. + * + * @param {number} x - first coordinate + * @param {number} y - second coordinate + * @returns {string} path string + */ + TAttMarkerHandler.prototype.create = function(x,y) { + if (!this.optimized) + return "M" + (x+this.x0).toFixed(this.ndig)+ "," + (y+this.y0).toFixed(this.ndig) + this.marker; + + // use optimized handling with relative position + var xx = Math.round(x), yy = Math.round(y), m1 = "M"+xx+","+yy+"h1", + m2 = (this.lastx===null) ? m1 : ("m"+(xx-this.lastx)+","+(yy-this.lasty)+"h1"); + this.lastx = xx+1; this.lasty = yy; + return (m2.length < m1.length) ? m2 : m1; + } + + /** @summary Returns full size of marker */ + TAttMarkerHandler.prototype.GetFullSize = function() { + return this.scale*this.size; + } + + /** @summary Returns approximate length of produced marker string */ + TAttMarkerHandler.prototype.MarkerLength = function() { + return this.marker ? this.marker.length : 10; + } + + /** @summary Change marker attributes. + * + * @param {string} color - marker color + * @param {number} style - marker style + * @param {number} size - marker size + */ + TAttMarkerHandler.prototype.Change = function(color, style, size) { + this.changed = true; + + if (color!==undefined) this.color = color; + if ((style!==undefined) && (style>=0)) this.style = style; + if (size!==undefined) this.size = size; else size = this.size; + + this.x0 = this.y0 = 0; + + if ((this.style === 1) || (this.style === 777)) { + this.fill = false; + this.marker = "h1"; + this.size = 1; + this.optimized = true; + this.reset_pos(); + return true; + } + + this.optimized = false; + + var marker_kind = Painter.root_markers[this.style]; + if (marker_kind === undefined) marker_kind = 100; + var shape = marker_kind % 100; + + this.fill = (marker_kind>=100); + + switch(this.style) { + case 1: this.size = 1; this.scale = 1; break; + case 6: this.size = 2; this.scale = 1; break; + case 7: this.size = 3; this.scale = 1; break; + default: this.size = size; this.scale = 8; + } + + size = this.GetFullSize(); + + this.ndig = (size>7) ? 0 : ((size>2) ? 1 : 2); + if (shape == 6) this.ndig++; + var half = (size/2).toFixed(this.ndig), full = size.toFixed(this.ndig); + + switch(shape) { + case 0: // circle + this.x0 = -parseFloat(half); + full = (parseFloat(half)*2).toFixed(this.ndig); + this.marker = "a"+half+","+half+",0,1,0,"+full+",0a"+half+","+half+",0,1,0,-"+full+",0z"; + break; + case 1: // cross + var d = (size/3).toFixed(this.ndig); + this.x0 = this.y0 = size/6; + this.marker = "h"+d+"v-"+d+"h-"+d+"v-"+d+"h-"+d+"v"+d+"h-"+d+"v"+d+"h"+d+"v"+d+"h"+d+"z"; + break; + case 2: // diamond + this.x0 = -size/2; + this.marker = "l"+half+",-"+half+"l"+half+","+half+"l-"+half+","+half + "z"; + break; + case 3: // square + this.x0 = this.y0 = -size/2; + this.marker = "v"+full+"h"+full+"v-"+full+"z"; + break; + case 4: // triangle-up + this.y0 = size/2; + this.marker = "l-"+half+",-"+full+"h"+full+"z"; + break; + case 5: // triangle-down + this.y0 = -size/2; + this.marker = "l-"+half+","+full+"h"+full+"z"; + break; + case 6: // star + this.y0 = -size/2; + this.marker = "l" + (size/3).toFixed(this.ndig) + "," + full + + "l-" + (5/6*size).toFixed(this.ndig) + ",-" + (5/8*size).toFixed(this.ndig) + + "h" + full + + "l-" + (5/6*size).toFixed(this.ndig) + "," + (5/8*size).toFixed(this.ndig) + "z"; + break; + case 7: // asterisk + this.x0 = this.y0 = -size/2; + this.marker = "l"+full+","+full + + "m0,-"+full+"l-"+full+","+full+ + "m0,-"+half+"h"+full+"m-"+half+",-"+half+"v"+full; + break; + case 8: // plus + this.y0 = -size/2; + this.marker = "v"+full+"m-"+half+",-"+half+"h"+full; + break; + case 9: // mult + this.x0 = this.y0 = -size/2; + this.marker = "l"+full+","+full + "m0,-"+full+"l-"+full+","+full; + break; + default: // diamand + this.x0 = -size/2; + this.marker = "l"+half+",-"+half+"l"+half+","+half+"l-"+half+","+half+"z"; + break; + } + + return true; + } + + /** @summary Apply marker styles to created element */ + TAttMarkerHandler.prototype.Apply = function(selection) { + selection.style('stroke', this.stroke ? this.color : "none"); + selection.style('fill', this.fill ? this.color : "none"); + } + + /** Method used when color or pattern were changed with OpenUi5 widgets. + * @private */ + TAttMarkerHandler.prototype.verifyDirectChange = function(painter) { + this.Change(this.color, parseInt(this.style), parseFloat(this.size)); + } + + /** @summary Create sample with marker in given SVG element + * + * @param {selection} svg - SVG element + * @param {number} width - width of sample SVG + * @param {number} height - height of sample SVG + * @private + */ + TAttMarkerHandler.prototype.CreateSample = function(svg, width, height) { + this.reset_pos(); + + svg.append("path") + .attr("d", this.create(width/2, height/2)) + .call(this.func); + } + + // ======================================================================= + + /** + * Handle for line attributes. + * @constructor + * @memberof JSROOT + */ + + function TAttLineHandler(args) { + this.func = this.Apply.bind(this); + this.used = true; + if (args._typename && (args.fLineStyle!==undefined)) args = { attr: args }; + + this.SetArgs(args); + } + + /** + * @summary Set line attributes. + * + * @param {object} args - specify attributes by different ways + * @param {object} args.attr - TAttLine object with appropriate data members or + * @param {string} args.color - color in html like rgb(10,0,0) or "red" + * @param {number} args.style - line style number + * @param {number} args.width - line width + */ + TAttLineHandler.prototype.SetArgs = function(args) { + if (args.attr) { + args.color = args.color0 || Painter.root_colors[args.attr.fLineColor]; + if (args.width===undefined) args.width = args.attr.fLineWidth; + args.style = args.attr.fLineStyle; + } else if (typeof args.color == 'string') { + if ((args.color !== 'none') && !args.width) args.width = 1; + } else if (typeof args.color == 'number') { + args.color = Painter.root_colors[args.color]; + } + + if (args.width===undefined) + args.width = (args.color && args.color!='none') ? 1 : 0; + + this.color = (args.width===0) ? 'none' : args.color; + this.width = args.width; + this.style = args.style; + + if (args.can_excl) { + this.excl_side = this.excl_width = 0; + if (Math.abs(this.width) > 99) { + // exclusion graph + this.excl_side = (this.width < 0) ? -1 : 1; + this.excl_width = Math.floor(this.width / 100) * 5; + this.width = Math.abs(this.width % 100); // line width + } + } + + // if custom color number used, use lightgrey color to show lines + if (!this.color && (this.width > 0)) + this.color = 'lightgrey'; + } + + /** + * @summary Change exclusion attributes. + * @private + */ + + TAttLineHandler.prototype.ChangeExcl = function(side,width) { + if (width !== undefined) this.excl_width = width; + if (side !== undefined) { + this.excl_side = side; + if ((this.excl_width===0) && (this.excl_side!==0)) this.excl_width = 20; + } + this.changed = true; + } + + /** + * @summary Returns true if line attribute is empty and will not be applied. + */ + + TAttLineHandler.prototype.empty = function() { + return this.color == 'none'; + } + + /** + * @summary Applies line attribute to selection. + * + * @param {object} selection - d3.js selection + */ + + TAttLineHandler.prototype.Apply = function(selection) { + this.used = true; + if (this.empty()) + selection.style('stroke', null) + .style('stroke-width', null) + .style('stroke-dasharray', null); + else + selection.style('stroke', this.color) + .style('stroke-width', this.width) + .style('stroke-dasharray', Painter.root_line_styles[this.style] || null); + } + + /** + * @summary Change line attributes + * @private + */ + + TAttLineHandler.prototype.Change = function(color, width, style) { + if (color !== undefined) this.color = color; + if (width !== undefined) this.width = width; + if (style !== undefined) this.style = style; + this.changed = true; + } + + /** + * Create sample element inside primitive SVG - used in context menu + * @private + */ + + TAttLineHandler.prototype.CreateSample = function(svg, width, height) { + svg.append("path") + .attr("d","M0," + height/2+"h"+width) + .call(this.func); + } + + // ======================================================================= + + + /** + * @summary Handle for fill attributes. + * @constructor + * @memberof JSROOT + * @param {object} args - different arguments to set fill attributes + * @param {number} [args.kind = 2] - 1 means object drawing where combination fillcolor==0 and fillstyle==1001 means no filling, 2 means all other objects where such combination is white-color filling + */ + + function TAttFillHandler(args) { + this.color = "none"; + this.colorindx = 0; + this.pattern = 0; + this.used = true; + this.kind = args.kind || 2; + this.changed = false; + this.func = this.Apply.bind(this); + this.SetArgs(args); + this.changed = false; // unset change property that + } + + /** @summary Set fill style as arguments */ + TAttFillHandler.prototype.SetArgs = function(args) { + if (args.attr && (typeof args.attr == 'object')) { + if ((args.pattern===undefined) && (args.attr.fFillStyle!==undefined)) args.pattern = args.attr.fFillStyle; + if ((args.color===undefined) && (args.attr.fFillColor!==undefined)) args.color = args.attr.fFillColor; + } + this.Change(args.color, args.pattern, args.svg, args.color_as_svg); + } + + /** @summary Apply fill style to selection */ + TAttFillHandler.prototype.Apply = function(selection) { + this.used = true; + + selection.style('fill', this.fillcolor()); + + if ('opacity' in this) + selection.style('opacity', this.opacity); + + if ('antialias' in this) + selection.style('antialias', this.antialias); + } + + /** @summary Returns fill color (or pattern url) */ + TAttFillHandler.prototype.fillcolor = function() { + return this.pattern_url || this.color; + } + + /** @summary Returns fill color without pattern url. + * + * @desc If empty, alternative color will be provided + * @param {string} [altern=undefined] - alternative color which returned when fill color not exists + * @private */ + TAttFillHandler.prototype.fillcoloralt = function(altern) { + return this.color && (this.color!="none") ? this.color : altern; + } + + /** @summary Returns true if color not specified or fill style not specified */ + TAttFillHandler.prototype.empty = function() { + var fill = this.fillcolor(); + return !fill || (fill == 'none'); + } + + /** @summary Set solid fill color as fill pattern + * @param {string} col - solid color */ + TAttFillHandler.prototype.SetSolidColor = function(col) { + delete this.pattern_url; + this.color = col; + this.pattern = 1001; + } + + /** @summary Check if solid fill is used, also color can be checked + * @param {string} [solid_color = undefined] - when specified, checks if fill color matches */ + TAttFillHandler.prototype.isSolid = function(solid_color) { + if (this.pattern !== 1001) return false; + return !solid_color || solid_color==this.color; + } + + /** @summary Method used when color or pattern were changed with OpenUi5 widgets + * @private */ + TAttFillHandler.prototype.verifyDirectChange = function(painter) { + if (typeof this.pattern == 'string') this.pattern = parseInt(this.pattern); + if (isNaN(this.pattern)) this.pattern = 0; + + this.Change(this.color, this.pattern, painter ? painter.svg_canvas() : null, true); + } + + /** @summary Method to change fill attributes. + * + * @param {number} color - color index + * @param {number} pattern - pattern index + * @param {selection} svg - top canvas element for pattern storages + * @param {string} [color_as_svg = undefined] - color as HTML string index + */ + TAttFillHandler.prototype.Change = function(color, pattern, svg, color_as_svg) { + delete this.pattern_url; + this.changed = true; + + if ((color !== undefined) && !isNaN(color) && !color_as_svg) + this.colorindx = parseInt(color); + + if ((pattern !== undefined) && !isNaN(pattern)) { + this.pattern = parseInt(pattern); + delete this.opacity; + delete this.antialias; + } + + if ((this.pattern == 1000) && (this.colorindx === 0)) { + this.pattern_url = 'white'; + return true; + } + + if (this.pattern == 1000) this.pattern = 1001; + + if (this.pattern < 1001) { + this.pattern_url = 'none'; + return true; + } + + if (this.isSolid() && (this.colorindx===0) && (this.kind===1) && !color_as_svg) { + this.pattern_url = 'none'; + return true; + } + + var indx = this.colorindx; + + if (color_as_svg) { + this.color = color; + indx = 10000 + JSROOT.id_counter++; // use fictional unique index far away from existing color indexes + } else { + this.color = JSROOT.Painter.root_colors[indx]; + } + + if (typeof this.color != 'string') this.color = "none"; + + if (this.isSolid()) return true; + + if ((this.pattern >= 4000) && (this.pattern <= 4100)) { + // special transparent colors (use for subpads) + this.opacity = (this.pattern - 4000)/100; + return true; + } + + if (!svg || svg.empty() || (this.pattern < 3000)) return false; + + var id = "pat_" + this.pattern + "_" + indx, + defs = svg.select('.canvas_defs'); + + if (defs.empty()) + defs = svg.insert("svg:defs",":first-child").attr("class","canvas_defs"); + + this.pattern_url = "url(#" + id + ")"; + this.antialias = false; + + if (!defs.select("."+id).empty()) { + if (color_as_svg) console.log('find id in def', id); + return true; + } + + var lines = "", lfill = null, fills = "", fills2 = "", w = 2, h = 2; + + switch (this.pattern) { + case 3001: w = h = 2; fills = "M0,0h1v1h-1zM1,1h1v1h-1z"; break; + case 3002: w = 4; h = 2; fills = "M1,0h1v1h-1zM3,1h1v1h-1z"; break; + case 3003: w = h = 4; fills = "M2,1h1v1h-1zM0,3h1v1h-1z"; break; + case 3004: w = h = 8; lines = "M8,0L0,8"; break; + case 3005: w = h = 8; lines = "M0,0L8,8"; break; + case 3006: w = h = 4; lines = "M1,0v4"; break; + case 3007: w = h = 4; lines = "M0,1h4"; break; + case 3008: + w = h = 10; + fills = "M0,3v-3h3ZM7,0h3v3ZM0,7v3h3ZM7,10h3v-3ZM5,2l3,3l-3,3l-3,-3Z"; + lines = "M0,3l5,5M3,10l5,-5M10,7l-5,-5M7,0l-5,5"; + break; + case 3009: w = 12; h = 12; lines = "M0,0A6,6,0,0,0,12,0M6,6A6,6,0,0,0,12,12M6,6A6,6,0,0,1,0,12"; lfill = "none"; break; + case 3010: w = h = 10; lines = "M0,2h10M0,7h10M2,0v2M7,2v5M2,7v3"; break; // bricks + case 3011: w = 9; h = 18; lines = "M5,0v8M2,1l6,6M8,1l-6,6M9,9v8M6,10l3,3l-3,3M0,9v8M3,10l-3,3l3,3"; lfill = "none"; break; + case 3012: w = 10; h = 20; lines = "M5,1A4,4,0,0,0,5,9A4,4,0,0,0,5,1M0,11A4,4,0,0,1,0,19M10,11A4,4,0,0,0,10,19"; lfill = "none"; break; + case 3013: w = h = 7; lines = "M0,0L7,7M7,0L0,7"; lfill = "none"; break; + case 3014: w = h = 16; lines = "M0,0h16v16h-16v-16M0,12h16M12,0v16M4,0v8M4,4h8M0,8h8M8,4v8"; lfill = "none"; break; + case 3015: w = 6; h = 12; lines = "M2,1A2,2,0,0,0,2,5A2,2,0,0,0,2,1M0,7A2,2,0,0,1,0,11M6,7A2,2,0,0,0,6,11"; lfill = "none"; break; + case 3016: w = 12; h = 7; lines = "M0,1A3,2,0,0,1,3,3A3,2,0,0,0,9,3A3,2,0,0,1,12,1"; lfill = "none"; break; + case 3017: w = h = 4; lines = "M3,1l-2,2"; break; + case 3018: w = h = 4; lines = "M1,1l2,2"; break; + case 3019: + w = h = 12; + lines = "M1,6A5,5,0,0,0,11,6A5,5,0,0,0,1,6h-1h1A5,5,0,0,1,6,11v1v-1" + + "A5,5,0,0,1,11,6h1h-1A5,5,0,0,1,6,1v-1v1A5,5,0,0,1,1,6"; + lfill = "none"; + break; + case 3020: w = 7; h = 12; lines = "M1,0A2,3,0,0,0,3,3A2,3,0,0,1,3,9A2,3,0,0,0,1,12"; lfill = "none"; break; + case 3021: w = h = 8; lines = "M8,2h-2v4h-4v2M2,0v2h-2"; lfill = "none"; break; // left stairs + case 3022: w = h = 8; lines = "M0,2h2v4h4v2M6,0v2h2"; lfill = "none"; break; // right stairs + case 3023: w = h = 8; fills = "M4,0h4v4zM8,4v4h-4z"; fills2 = "M4,0L0,4L4,8L8,4Z"; break; + case 3024: w = h = 16; fills = "M0,8v8h2v-8zM8,0v8h2v-8M4,14v2h12v-2z"; fills2 = "M0,2h8v6h4v-6h4v12h-12v-6h-4z"; break; + case 3025: w = h = 18; fills = "M5,13v-8h8ZM18,0v18h-18l5,-5h8v-8Z"; break; + default: + if ((this.pattern>3025) && (this.pattern<3100)) { + // same as 3002, see TGX11.cxx, line 2234 + w = 4; h = 2; fills = "M1,0h1v1h-1zM3,1h1v1h-1z"; break; + } + + var code = this.pattern % 1000, + k = code % 10, j = ((code - k) % 100) / 10, i = (code - j*10 - k)/100; + if (!i) break; + + var sz = i*12; // axis distance between lines + + w = h = 6*sz; // we use at least 6 steps + + function produce(dy,swap) { + var pos = [], step = sz, y1 = 0, y2, max = h; + + // reduce step for smaller angles to keep normal distance approx same + if (Math.abs(dy)<3) step = Math.round(sz/12*9); + if (dy==0) { step = Math.round(sz/12*8); y1 = step/2; } + else if (dy>0) max -= step; else y1 = step; + + while(y1<=max) { + y2 = y1 + dy*step; + if (y2 < 0) { + var x2 = Math.round(y1/(y1-y2)*w); + pos.push(0,y1,x2,0); + pos.push(w,h-y1,w-x2,h); + } else if (y2 > h) { + var x2 = Math.round((h-y1)/(y2-y1)*w); + pos.push(0,y1,x2,h); + pos.push(w,h-y1,w-x2,0); + } else { + pos.push(0,y1,w,y2); + } + y1+=step; + } + for (var k=0;k<pos.length;k+=4) + if (swap) lines += "M"+pos[k+1]+","+pos[k]+"L"+pos[k+3]+","+pos[k+2]; + else lines += "M"+pos[k]+","+pos[k+1]+"L"+pos[k+2]+","+pos[k+3]; + } + + switch (j) { + case 0: produce(0); break; + case 1: produce(1); break; + case 2: produce(2); break; + case 3: produce(3); break; + case 4: produce(6); break; + case 6: produce(3,true); break; + case 7: produce(2,true); break; + case 8: produce(1,true); break; + case 9: produce(0,true); break; + } + + switch (k) { + case 0: if (j) produce(0); break; + case 1: produce(-1); break; + case 2: produce(-2); break; + case 3: produce(-3); break; + case 4: produce(-6); break; + case 6: produce(-3,true); break; + case 7: produce(-2,true); break; + case 8: produce(-1,true); break; + case 9: if (j!=9) produce(0,true); break; + } + + break; + } + + if (!fills && !lines) return false; + + var patt = defs.append('svg:pattern').attr("id",id).attr("class",id).attr("patternUnits","userSpaceOnUse") + .attr("width", w).attr("height", h); + + if (fills2) { + var col = d3.rgb(this.color); + col.r = Math.round((col.r+255)/2); col.g = Math.round((col.g+255)/2); col.b = Math.round((col.b+255)/2); + patt.append("svg:path").attr("d", fills2).style("fill", col); + } + if (fills) patt.append("svg:path").attr("d", fills).style("fill", this.color); + if (lines) patt.append("svg:path").attr("d", lines).style('stroke', this.color).style("stroke-width", 1).style("fill", lfill); + + return true; + } + + /** @summary Create sample of fill pattern inside SVG + * @private */ + TAttFillHandler.prototype.CreateSample = function(sample_svg, width, height) { + + // we need to create extra handle to change + var sample = new TAttFillHandler({ svg: sample_svg, pattern: this.pattern, color: this.color, color_as_svg: true }); + + sample_svg.append("path") + .attr("d","M0,0h" + width+"v"+height+"h-" + width + "z") + .call(sample.func); + } + + // =========================================================================== + + Painter.getFontDetails = function(fontIndex, size) { + + var res = { name: "Arial", size: Math.round(size || 11), weight: null, style: null }, + indx = Math.floor(fontIndex / 10), + fontName = Painter.root_fonts[indx] || ""; + + while (fontName.length > 0) { + if (fontName[0]==='b') res.weight = "bold"; else + if (fontName[0]==='i') res.style = "italic"; else + if (fontName[0]==='o') res.style = "oblique"; else break; + fontName = fontName.substr(1); + } + + if (fontName == 'Symbol') + res.weight = res.style = null; + + res.name = fontName; + res.aver_width = Painter.root_fonts_aver_width[indx] || 0.55; + + res.setFont = function(selection, arg) { + selection.attr("font-family", this.name); + if (arg != 'without-size') + selection.attr("font-size", this.size) + .attr("xml:space", "preserve"); + if (this.weight) + selection.attr("font-weight", this.weight); + if (this.style) + selection.attr("font-style", this.style); + } + + res.func = res.setFont.bind(res); + + return res; + } + + Painter.chooseTimeFormat = function(awidth, ticks) { + if (awidth < .5) return ticks ? "%S.%L" : "%H:%M:%S.%L"; + if (awidth < 30) return ticks ? "%Mm%S" : "%H:%M:%S"; + awidth /= 60; if (awidth < 30) return ticks ? "%Hh%M" : "%d/%m %H:%M"; + awidth /= 60; if (awidth < 12) return ticks ? "%d-%Hh" : "%d/%m/%y %Hh"; + awidth /= 24; if (awidth < 15.218425) return ticks ? "%d/%m" : "%d/%m/%y"; + awidth /= 30.43685; if (awidth < 6) return "%d/%m/%y"; + awidth /= 12; if (awidth < 2) return ticks ? "%m/%y" : "%d/%m/%y"; + return "%Y"; + } + + Painter.getTimeFormat = function(axis) { + var idF = axis.fTimeFormat.indexOf('%F'); + if (idF >= 0) return axis.fTimeFormat.substr(0, idF); + return axis.fTimeFormat; + } + + Painter.getTimeOffset = function(axis) { + var idF = axis.fTimeFormat.indexOf('%F'); + if (idF < 0) return JSROOT.gStyle.fTimeOffset*1000; + var sof = axis.fTimeFormat.substr(idF + 2); + // default string in axis offset + if (sof.indexOf('1995-01-01 00:00:00s0')==0) return 788918400000; + // special case, used from DABC painters + if ((sof == "0") || (sof == "")) return 0; + + // decode time from ROOT string + function next(separ, min, max) { + var pos = sof.indexOf(separ); + if (pos < 0) { pos = ""; return min; } + var val = parseInt(sof.substr(0,pos)); + sof = sof.substr(pos+1); + if (isNaN(val) || (val<min) || (val>max)) { pos = ""; return min; } + return val; + } + + var year = next("-", 1970, 2300), + month = next("-", 1, 12) - 1, + day = next(" ", 1, 31), + hour = next(":", 0, 23), + min = next(":", 0, 59), + sec = next("s", 0, 59), + msec = next(" ", 0, 999); + + var dt = new Date(Date.UTC(year, month, day, hour, min, sec, msec)); + + var offset = dt.getTime(); + + // now also handle suffix like GMT or GMT -0600 + sof = sof.toUpperCase(); + + if (sof.indexOf('GMT')==0) { + offset += dt.getTimezoneOffset()*60000; + sof = sof.substr(4).trim(); + if (sof.length > 3) { + var p = 0, sign = 1000; + if (sof[0]=='-') { p = 1; sign = -1000; } + offset -= sign * (parseInt(sof.substr(p,2))*3600 + parseInt(sof.substr(p+2,2))*60); + } + } + + return offset; + } + + Painter.translateLaTeX = function(str) { + while ((str.length>2) && (str[0]=='{') && (str[str.length-1]=='}')) + str = str.substr(1,str.length-2); + + if (!Painter.symbolsRegexCache) { + // Create a single regex to detect any symbol to replace + Painter.symbolsRegexCache = new RegExp('(' + Object.keys(Painter.symbols_map).join('|').replace(/\{/g, '\{').replace(/\\}/g, '\\}') + ')', 'g'); + } + + str = str.replace(Painter.symbolsRegexCache, Painter.convertSymbol); + + str = str.replace(/\{\}/g, ""); + + return str; + } + + Painter.approxTextWidth = function(font, label) { + // returns approximate width of given label, required for reasonable scaling of text in node.js + + return label.length * font.size * font.aver_width; + } + + Painter.isAnyLatex = function(str) { + return (str.indexOf("#")>=0) || (str.indexOf("\\")>=0) || (str.indexOf("{")>=0); + } + + /** Function translates ROOT TLatex into MathJax format */ + Painter.translateMath = function(str, kind, color, painter) { + + if (kind != 2) { + for (var x in Painter.math_symbols_map) + str = str.replace(new RegExp(x,'g'), Painter.math_symbols_map[x]); + + for (var x in Painter.symbols_map) + if (x.length > 2) + str = str.replace(new RegExp(x,'g'), "\\" + x.substr(1)); + + // replace all #color[]{} occurances + var clean = "", first = true; + while (str) { + var p = str.indexOf("#color["); + if ((p<0) && first) { clean = str; break; } + first = false; + if (p!=0) { + var norm = (p<0) ? str : str.substr(0, p); + clean += norm; + if (p<0) break; + } + + str = str.substr(p+7); + p = str.indexOf("]{"); + if (p<=0) break; + var colindx = parseInt(str.substr(0,p)); + if (isNaN(colindx)) break; + var col = painter.get_color(colindx), cnt = 1; + str = str.substr(p+2); + p = -1; + while (cnt && (++p<str.length)) { + if (str[p]=='{') cnt++; else if (str[p]=='}') cnt--; + } + if (cnt!=0) break; + + var part = str.substr(0,p); + str = str.substr(p+1); + if (part) + clean += "\\color{" + col + '}{' + part + "}"; + } + + str = clean; + } else { + str = str.replace(/\\\^/g, "\\hat"); + } + + if (typeof color != 'string') return "\\(" + str + "\\)"; + + // MathJax SVG converter use colors in normal form + //if (color.indexOf("rgb(")>=0) + // color = color.replace(/rgb/g, "[RGB]") + // .replace(/\(/g, '{') + // .replace(/\)/g, '}'); + return "\\(\\color{" + color + '}{' + str + "}\\)"; + } + + /** Function used to provide svg:path for the smoothed curves. + * + * reuse code from d3.js. Used in TH1, TF1 and TGraph painters + * kind should contain "bezier" or "line". + * If first symbol "L", then it used to continue drawing + * @private + */ + Painter.BuildSvgPath = function(kind, bins, height, ndig) { + + var smooth = kind.indexOf("bezier") >= 0; + + if (ndig===undefined) ndig = smooth ? 2 : 0; + if (height===undefined) height = 0; + + function jsroot_d3_svg_lineSlope(p0, p1) { + return (p1.gry - p0.gry) / (p1.grx - p0.grx); + } + function jsroot_d3_svg_lineFiniteDifferences(points) { + var i = 0, j = points.length - 1, m = [], p0 = points[0], p1 = points[1], d = m[0] = jsroot_d3_svg_lineSlope(p0, p1); + while (++i < j) { + m[i] = (d + (d = jsroot_d3_svg_lineSlope(p0 = p1, p1 = points[i + 1]))) / 2; + } + m[i] = d; + return m; + } + function jsroot_d3_svg_lineMonotoneTangents(points) { + var d, a, b, s, m = jsroot_d3_svg_lineFiniteDifferences(points), i = -1, j = points.length - 1; + while (++i < j) { + d = jsroot_d3_svg_lineSlope(points[i], points[i + 1]); + if (Math.abs(d) < 1e-6) { + m[i] = m[i + 1] = 0; + } else { + a = m[i] / d; + b = m[i + 1] / d; + s = a * a + b * b; + if (s > 9) { + s = d * 3 / Math.sqrt(s); + m[i] = s * a; + m[i + 1] = s * b; + } + } + } + i = -1; + while (++i <= j) { + s = (points[Math.min(j, i + 1)].grx - points[Math.max(0, i - 1)].grx) / (6 * (1 + m[i] * m[i])); + points[i].dgrx = s || 0; + points[i].dgry = m[i]*s || 0; + } + } + + var res = { path: "", close: "" }, bin = bins[0], prev, maxy = Math.max(bin.gry, height+5), + currx = Math.round(bin.grx), curry = Math.round(bin.gry), dx, dy, npnts = bins.length; + + function conv(val) { + var vvv = Math.round(val); + if ((ndig==0) || (vvv===val)) return vvv.toString(); + var str = val.toFixed(ndig); + while ((str[str.length-1] == '0') && (str.lastIndexOf(".") < str.length-1)) + str = str.substr(0,str.length-1); + if (str[str.length-1] == '.') + str = str.substr(0,str.length-1); + if (str == "-0") str = "0"; + return str; + } + + res.path = ((kind[0] == "L") ? "L" : "M") + conv(bin.grx) + "," + conv(bin.gry); + + // just calculate all deltas, can be used to build exclusion + if (smooth || kind.indexOf('calc')>=0) + jsroot_d3_svg_lineMonotoneTangents(bins); + + if (smooth) { + // build smoothed curve + res.path += "c" + conv(bin.dgrx) + "," + conv(bin.dgry) + ","; + for(var n=1; n<npnts; ++n) { + var prev = bin; + bin = bins[n]; + if (n > 1) res.path += "s"; + res.path += conv(bin.grx-bin.dgrx-prev.grx) + "," + conv(bin.gry-bin.dgry-prev.gry) + "," + conv(bin.grx-prev.grx) + "," + conv(bin.gry-prev.gry); + maxy = Math.max(maxy, prev.gry); + } + } else if (npnts < 10000) { + // build simple curve + for(var n=1; n<npnts; ++n) { + bin = bins[n]; + dx = Math.round(bin.grx) - currx; + dy = Math.round(bin.gry) - curry; + if (dx && dy) res.path += "l"+dx+","+dy; + else if (!dx && dy) res.path += "v"+dy; + else if (dx && !dy) res.path += "h"+dx; + currx += dx; curry += dy; + maxy = Math.max(maxy, curry); + } + } else { + // build line with trying optimize many vertical moves + var lastx, lasty, cminy = curry, cmaxy = curry, prevy = curry; + for(var n=1; n<npnts; ++n) { + bin = bins[n]; + lastx = Math.round(bin.grx); + lasty = Math.round(bin.gry); + maxy = Math.max(maxy, lasty); + dx = lastx - currx; + if (dx===0) { + // if X not change, just remember amplitude and + cminy = Math.min(cminy, lasty); + cmaxy = Math.max(cmaxy, lasty); + prevy = lasty; + continue; + } + + if (cminy !== cmaxy) { + if (cminy != curry) res.path += "v" + (cminy-curry); + res.path += "v" + (cmaxy-cminy); + if (cmaxy != prevy) res.path += "v" + (prevy-cmaxy); + curry = prevy; + } + dy = lasty - curry; + if (dy) res.path += "l"+dx+","+dy; + else res.path += "h"+dx; + currx = lastx; curry = lasty; + prevy = cminy = cmaxy = lasty; + } + + if (cminy != cmaxy) { + if (cminy != curry) res.path += "v"+(cminy-curry); + res.path += "v"+(cmaxy-cminy); + if (cmaxy != prevy) res.path += "v"+(prevy-cmaxy); + curry = prevy; + } + + } + + if (height>0) + res.close = "L"+conv(bin.grx)+","+conv(maxy) + + "h"+conv(bins[0].grx-bin.grx) + "Z"; + + return res; + } + + // ============================================================================== + + function LongPollSocket(addr, _raw, _args) { + this.path = addr; + this.connid = null; + this.req = null; + this.raw = _raw; + this.args = _args; + + this.nextrequest("", "connect"); + } + + LongPollSocket.prototype.nextrequest = function(data, kind) { + var url = this.path, reqmode = "buf", post = null; + if (kind === "connect") { + url += this.raw ? "?raw_connect" : "?txt_connect"; + if (this.args) url += "&" + this.args; + console.log('longpoll connect ' + url + ' raw = ' + this.raw); + this.connid = "connect"; + } else if (kind === "close") { + if ((this.connid===null) || (this.connid==="close")) return; + url+="?connection="+this.connid + "&close"; + this.connid = "close"; + reqmode += ";sync"; // use sync mode to close connection before browser window closed + } else if ((this.connid===null) || (typeof this.connid!=='number')) { + return console.error("No connection"); + } else { + url+="?connection="+this.connid; + if (kind==="dummy") url+="&dummy"; + } + + if (data) { + if (this.raw) { + // special workaround to avoid POST request, use base64 coding + url += "&post=" + btoa(data); + } else { + // send data with post request - most efficient way + reqmode = "post"; + post = data; + } + } + + var req = JSROOT.NewHttpRequest(url, reqmode, function(res) { + // this set to the request itself, res is response + + if (this.handle.req === this) + this.handle.req = null; // get response for existing dummy request + + if (res === null) + return this.handle.processreq(null); + + if (this.handle.raw) { + // raw mode - all kind of reply data packed into binary buffer + // first 4 bytes header "txt:" or "bin:" + // after the "bin:" there is length of optional text argument like "bin:14 :optional_text" + // and immedaitely after text binary data. Server sends binary data so, that offset should be multiple of 8 + + var str = "", i = 0, u8Arr = new Uint8Array(res), offset = u8Arr.length; + if (offset < 4) { + console.error('longpoll got short message in raw mode ' + offset); + return this.handle.processreq(null); + } + + while(i<4) str += String.fromCharCode(u8Arr[i++]); + if (str != "txt:") { + str = ""; + while ((i<offset) && (String.fromCharCode(u8Arr[i]) != ':')) str += String.fromCharCode(u8Arr[i++]); + ++i; + offset = i + parseInt(str.trim()); + } + + str = ""; + while (i<offset) str += String.fromCharCode(u8Arr[i++]); + + if (str) { + if (str == "<<nope>>") str = ""; + this.handle.processreq(str); + } + if (offset < u8Arr.length) + this.handle.processreq(res, offset); + } else if (this.getResponseHeader("Content-Type") == "application/x-binary") { + // binary reply with optional header + var extra_hdr = this.getResponseHeader("LongpollHeader"); + if (extra_hdr) this.handle.processreq(extra_hdr); + this.handle.processreq(res, 0); + } else { + // text reply + if (res && typeof res !== "string") { + var str = "", u8Arr = new Uint8Array(res); + for (var i = 0; i < u8Arr.length; ++i) + str += String.fromCharCode(u8Arr[i]); + res = str; + } + if (res == "<<nope>>") res = ""; + this.handle.processreq(res); + } + }); + + req.handle = this; + if (kind==="dummy") this.req = req; // remember last dummy request, wait for reply + req.send(post); + } + + LongPollSocket.prototype.processreq = function(res, _offset) { + if (res===null) { + if (typeof this.onerror === 'function') this.onerror("receive data with connid " + (this.connid || "---")); + // if (typeof this.onclose === 'function') this.onclose(); + this.connid = null; + return; + } + + if (this.connid==="connect") { + if (!res) { + this.connid = null; + if (typeof this.onerror === 'function') this.onerror("connection rejected"); + return; + } + + this.connid = parseInt(res); + console.log('Get new longpoll connection with id ' + this.connid); + if (typeof this.onopen == 'function') this.onopen(); + } else if (this.connid==="close") { + if (typeof this.onclose == 'function') this.onclose(); + return; + } else { + if ((typeof this.onmessage==='function') && res) + this.onmessage({ data: res, offset: _offset }); + } + + if (!this.req) this.nextrequest("","dummy"); // send new poll request when necessary + } + + LongPollSocket.prototype.send = function(str) { + this.nextrequest(str); + } + + LongPollSocket.prototype.close = function() { + this.nextrequest("", "close"); + } + + // ======================================================================================== + + function FileDumpSocket(receiver) { + this.receiver = receiver; + this.protocol = []; + this.cnt = 0; + JSROOT.NewHttpRequest("protocol.json", "text", this.get_protocol.bind(this)).send(); + } + + FileDumpSocket.prototype.get_protocol = function(res) { + if (!res) return; + this.protocol = JSON.parse(res); + if (typeof this.onopen == 'function') this.onopen(); + this.next_operation(); + } + + FileDumpSocket.prototype.send = function(str) { + if (this.protocol[this.cnt] == "send") { + this.cnt++; + setTimeout(this.next_operation.bind(this),10); + } + } + + FileDumpSocket.prototype.close = function() { + } + + FileDumpSocket.prototype.next_operation = function() { + // when file request running - just ignore + if (this.wait_for_file) return; + var fname = this.protocol[this.cnt]; + if (!fname) return; + if (fname == "send") return; // waiting for send + // console.log("getting file", fname, "wait", this.wait_for_file); + this.wait_for_file = true; + JSROOT.NewHttpRequest(fname, (fname.indexOf(".bin") > 0 ? "buf" : "text"), this.get_file.bind(this, fname)).send(); + this.cnt++; + } + + FileDumpSocket.prototype.get_file = function(fname, res) { + // console.log('got file', fname, typeof res, !!res); + this.wait_for_file = false; + if (!res) return; + if (this.receiver.ProvideData) + this.receiver.ProvideData(res, 0); + setTimeout(this.next_operation.bind(this),10); + } + + // ======================================================================================== + + + /** Client communication handle for TWebWindow. + * + * Should be created with {@link JSROOT.ConnectWebWindow} function + * + * @constructor + * @memberof JSROOT + */ + function WebWindowHandle(socket_kind) { + this.kind = socket_kind; + this.state = 0; + this.cansend = 10; + this.ackn = 10; + } + + /** Set callbacks reciever. + * + * Following function can be defined in receiver object: + * - OnWebsocketMsg + * - OnWebsocketOpened, + * - OnWebsocketClosed + */ + WebWindowHandle.prototype.SetReceiver = function(obj) { + this.receiver = obj; + } + + /** Cleanup and close connection. */ + WebWindowHandle.prototype.Cleanup = function() { + delete this.receiver; + this.Close(true); + } + + /** Invoke method in the receiver. + * @private */ + WebWindowHandle.prototype.InvokeReceiver = function(method, arg, arg2) { + if (this.receiver && (typeof this.receiver[method] == 'function')) + this.receiver[method](this, arg, arg2); + } + + /** Provide data for receiver. When no queue - do it directly. + * @private */ + WebWindowHandle.prototype.ProvideData = function(_msg, _len) { + if (!this.msgqueue || !this.msgqueue.length) + return this.InvokeReceiver("OnWebsocketMsg", _msg, _len); + this.msgqueue.push({ ready: true, msg: _msg, len: _len}); + } + + /** Reserve entry in queue for data, which is not yet decoded. + * @private */ + WebWindowHandle.prototype.ReserveQueueItem = function() { + if (!this.msgqueue) this.msgqueue = []; + var item = { ready: false, msg: null, len: 0 }; + this.msgqueue.push(item); + return item; + } + + /** Reserver entry in queue for data, which is not yet decoded. + * @private */ + WebWindowHandle.prototype.DoneItem = function(item, _msg, _len) { + item.ready = true; + item.msg = _msg; + item.len = _len; + if (this._loop_msgqueue) return; + this._loop_msgqueue = true; + while ((this.msgqueue.length > 0) && this.msgqueue[0].ready) { + var front = this.msgqueue.shift(); + this.InvokeReceiver("OnWebsocketMsg", front.msg, front.len); + } + if (this.msgqueue.length == 0) + delete this.msgqueue; + delete this._loop_msgqueue; + } + + /** Close connection. */ + WebWindowHandle.prototype.Close = function(force) { + + if (this.timerid) { + clearTimeout(this.timerid); + delete this.timerid; + } + + if (this._websocket && (this.state > 0)) { + this.state = force ? -1 : 0; // -1 prevent socket from reopening + this._websocket.onclose = null; // hide normal handler + this._websocket.close(); + delete this._websocket; + } + } + + /** Returns if one can send text message to server. Checks number of send credits */ + WebWindowHandle.prototype.CanSend = function(numsend) { + return (this.cansend >= (numsend || 1)); + } + + /** Send text message via the connection. */ + WebWindowHandle.prototype.Send = function(msg, chid) { + if (!this._websocket || (this.state<=0)) return false; + + if (isNaN(chid) || (chid===undefined)) chid = 1; // when not configured, channel 1 is used - main widget + + if (this.cansend <= 0) console.error('should be queued before sending cansend: ' + this.cansend); + + var prefix = this.ackn + ":" + this.cansend + ":" + chid + ":"; + this.ackn = 0; + this.cansend--; // decrease number of allowed sebd packets + + this._websocket.send(prefix + msg); + if (this.kind === "websocket") { + if (this.timerid) clearTimeout(this.timerid); + this.timerid = setTimeout(this.KeepAlive.bind(this), 10000); + } + + return true; + } + + /** Send keepalive message. + * @private */ + WebWindowHandle.prototype.KeepAlive = function() { + delete this.timerid; + this.Send("KEEPALIVE", 0); + } + + /** Method opens relative path with the same kind of socket. + * @private + */ + WebWindowHandle.prototype.CreateRelative = function(relative) { + if (!relative || !this.kind || !this.href) return null; + + var handle = new WebWindowHandle(this.kind); + console.log('Try to connect ', this.href + relative); + handle.Connect(this.href + relative); + return handle; + } + + /** Create configured socket for current object. */ + WebWindowHandle.prototype.Connect = function(href) { + + this.Close(); + + var pthis = this, ntry = 0, args = (this.key ? ("key=" + this.key) : ""); + + function retry_open(first_time) { + + if (pthis.state != 0) return; + + if (!first_time) console.log("try connect window again" + (new Date()).getTime()); + + if (pthis._websocket) pthis._websocket.close(); + delete pthis._websocket; + + var conn = null; + if (!href) { + href = window.location.href; + if (href && href.lastIndexOf("/")>0) href = href.substr(0, href.lastIndexOf("/")+1); + } + pthis.href = href; + ntry++; + + if (first_time) console.log('Opening web socket at ' + href); + + if (ntry>2) JSROOT.progress("Trying to connect " + href); + + var path = href; + + if (pthis.kind == "file") { + path += "root.filedump"; + conn = new FileDumpSocket(pthis); + console.log('configure protocol log ' + path); + } else if ((pthis.kind === 'websocket') && first_time) { + path = path.replace("http://", "ws://").replace("https://", "wss://") + "root.websocket"; + if (args) path += "?" + args; + console.log('configure websocket ' + path); + conn = new WebSocket(path); + } else { + path += "root.longpoll"; + console.log('configure longpoll ' + path); + conn = new LongPollSocket(path, (pthis.kind === 'rawlongpoll'), args); + } + + if (!conn) return; + + pthis._websocket = conn; + + conn.onopen = function() { + if (ntry > 2) JSROOT.progress(); + pthis.state = 1; + + var key = pthis.key || ""; + + pthis.Send("READY=" + key, 0); // need to confirm connection + pthis.InvokeReceiver('OnWebsocketOpened'); + } + + conn.onmessage = function(e) { + var msg = e.data; + + if (pthis.next_binary) { + delete pthis.next_binary; + + if (msg instanceof Blob) { + // this is case of websocket + // console.log('Get Blob object - convert to buffer array'); + var reader = new FileReader, qitem = pthis.ReserveQueueItem(); + reader.onload = function(event) { + // The file's text will be printed here + pthis.DoneItem(qitem, event.target.result, 0); + } + reader.readAsArrayBuffer(msg, e.offset || 0); + } else { + // console.log('got array ' + (typeof msg) + ' len = ' + msg.byteLength); + // this is from CEF or LongPoll handler + pthis.ProvideData(msg, e.offset || 0); + } + + return; + } + + if (typeof msg != 'string') return console.log("unsupported message kind: " + (typeof msg)); + + var i1 = msg.indexOf(":"), + credit = parseInt(msg.substr(0,i1)), + i2 = msg.indexOf(":", i1+1), + cansend = parseInt(msg.substr(i1+1,i2-i1)), + i3 = msg.indexOf(":", i2+1), + chid = parseInt(msg.substr(i2+1,i3-i2)); + + // console.log('msg(20)', msg.substr(0,20), credit, cansend, chid, i3); + + pthis.ackn++; // count number of received packets, + pthis.cansend += credit; // how many packets client can send + + msg = msg.substr(i3+1); + + if (chid == 0) { + console.log('GET chid=0 message', msg); + if (msg == "CLOSE") { + pthis.Close(true); // force closing of socket + pthis.InvokeReceiver('OnWebsocketClosed'); + } + } else if (msg == "$$binary$$") { + pthis.next_binary = true; + } else if (msg == "$$nullbinary$$") { + pthis.ProvideData(new ArrayBuffer(0), 0); + } else { + pthis.ProvideData(msg); + } + + if (pthis.ackn > 7) + pthis.Send('READY', 0); // send dummy message to server + } + + conn.onclose = function() { + delete pthis._websocket; + if (pthis.state > 0) { + console.log('websocket closed'); + pthis.state = 0; + pthis.InvokeReceiver('OnWebsocketClosed'); + } + } + + conn.onerror = function (err) { + console.log("websocket error " + err); + if (pthis.state > 0) { + pthis.InvokeReceiver('OnWebsocketError', err); + pthis.state = 0; + } + } + + // only in interactive mode try to reconnect + if (!JSROOT.BatchMode) + setTimeout(retry_open, 3000); // after 3 seconds try again + + } // retry_open + + retry_open(true); // call for the first time + } + + /** @summary Method used to initialize connection to web window. + * + * @param {object} arg - arguemnts + * @param {string} [arg.prereq] - prerequicities, which should be loaded + * @param {string} [arg.openui5src] - source of openui5, either URL like "https://openui5.hana.ondemand.com" or "jsroot" which provides its own reduced openui5 package + * @param {string} [arg.openui5libs] - list of openui5 libraries loaded, default is "sap.m, sap.ui.layout, sap.ui.unified" + * @param {string} [arg.socket_kind] - kind of connection longpoll|websocket, detected automatically from URL + * @param {object} arg.receiver - instance of receiver for websocket events, allows to initiate connection immediately + * @param {string} arg.first_recv - required prefix in the first message from TWebWindow, remain part of message will be returned as arg.first_msg + * @param {string} [arg.prereq2] - second part of prerequcities, which is loaded parallel to connecting with WebWindow + * @param {function} arg.callback - function which is called with WebWindowHandle or when establish connection and get first portion of data + */ + + JSROOT.ConnectWebWindow = function(arg) { + if (typeof arg == 'function') arg = { callback: arg }; else + if (!arg || (typeof arg != 'object')) arg = {}; + + if (arg.prereq) { + if (arg.openui5src) JSROOT.openui5src = arg.openui5src; + if (arg.openui5libs) JSROOT.openui5libs = arg.openui5libs; + return JSROOT.AssertPrerequisites(arg.prereq, function() { + delete arg.prereq; JSROOT.ConnectWebWindow(arg); + }, arg.prereq_logdiv); + } + + // special hold script, prevents headless browser from too early exit + if ((JSROOT.GetUrlOption("batch_mode")!==null) && JSROOT.GetUrlOption("key") && (JSROOT.browser.isChromeHeadless || JSROOT.browser.isChrome)) + JSROOT.loadScript("root_batch_holder.js?key=" + JSROOT.GetUrlOption("key")); + + if (!arg.platform) + arg.platform = JSROOT.GetUrlOption("platform"); + + if (arg.platform == "qt5") JSROOT.browser.qt5 = true; else + if (arg.platform == "cef3") JSROOT.browser.cef3 = true; + + if (arg.batch === undefined) + arg.batch = (JSROOT.GetUrlOption("batch_mode")!==null); // && (JSROOT.browser.qt5 || JSROOT.browser.cef3 || JSROOT.browser.isChrome); + + if (arg.batch) JSROOT.BatchMode = true; + + if (!arg.socket_kind) + arg.socket_kind = JSROOT.GetUrlOption("ws"); + + if (!arg.socket_kind) { + if (JSROOT.browser.qt5) arg.socket_kind = "rawlongpoll"; else + if (JSROOT.browser.cef3) arg.socket_kind = "longpoll"; else arg.socket_kind = "websocket"; + } + + // only for debug purposes + // arg.socket_kind = "longpoll"; + + var handle = new WebWindowHandle(arg.socket_kind); + + if (window) { + window.onbeforeunload = handle.Close.bind(handle, true); + if (JSROOT.browser.qt5) window.onqt5unload = window.onbeforeunload; + } + + if (arg.first_recv) { + arg.receiver = { + OnWebsocketOpened: function(handle) { + }, + + OnWebsocketMsg: function(handle, msg) { + // console.log('Get message ' + msg + ' handle ' + !!handle); + if (msg.indexOf(arg.first_recv)!=0) + return handle.Close(); + arg.first_msg = msg.substr(arg.first_recv.length); + + if (!arg.prereq2) JSROOT.CallBack(arg.callback, handle, arg); + }, + + OnWebsocketClosed: function(handle) { + // when connection closed, close panel as well + JSROOT.CloseCurrentWindow(); + } + }; + } + + handle.key = JSROOT.GetUrlOption("key"); + + if (!arg.receiver) + return JSROOT.CallBack(arg.callback, handle, arg); + + // when receiver is exists, it handles itself callbacks + handle.SetReceiver(arg.receiver); + handle.Connect(); + + if (arg.prereq2) { + JSROOT.AssertPrerequisites(arg.prereq2, function() { + delete arg.prereq2; // indicate that func is loaded + if (!arg.first_recv || arg.first_msg) JSROOT.CallBack(arg.callback, handle, arg); + }); + } else if (!arg.first_recv) { + JSROOT.CallBack(arg.callback, handle, arg); + } + } + + // ======================================================================================== + + /** + * @summary Basic painter class. + * @constructor + * @memberof JSROOT + */ + + function TBasePainter() { + this.divid = null; // either id of element (preferable) or element itself + } + + /** @summary Access painter reference, stored in first child element. + * + * - on === true - set *this* as painter + * - on === false - delete painter reference + * - on === undefined - return painter + * + * @param {boolean} on - that to perfrom + * @private + */ + TBasePainter.prototype.AccessTopPainter = function(on) { + var main = this.select_main().node(), + chld = main ? main.firstChild : null; + if (!chld) return null; + if (on===true) chld.painter = this; else + if (on===false) delete chld.painter; + return chld.painter; + } + + /** @summary Generic method to cleanup painter */ + TBasePainter.prototype.Cleanup = function(keep_origin) { + + var origin = this.select_main('origin'); + if (!origin.empty() && !keep_origin) origin.html(""); + if (this._changed_layout) + this.set_layout_kind('simple'); + this.AccessTopPainter(false); + this.divid = null; + delete this._selected_main; + + if (this._hpainter && typeof this._hpainter.ClearPainter === 'function') this._hpainter.ClearPainter(this); + + delete this._changed_layout; + delete this._hitemname; + delete this._hdrawopt; + delete this._hpainter; + } + + /** @summary Function should be called by the painter when first drawing is completed + * @private */ + + TBasePainter.prototype.DrawingReady = function(res_painter) { + this._ready_called_ = true; + if (this._ready_callback_ !== undefined) { + var callbacks = this._ready_callback_; + if (!this._return_res_painter) res_painter = this; + + delete this._return_res_painter; + delete this._ready_callback_; + + while (callbacks.length) + JSROOT.CallBack(callbacks.shift(), res_painter); + } + return this; + } + + /** @summary Call back will be called when painter ready with the drawing + * @private + */ + TBasePainter.prototype.WhenReady = function(callback) { + if (typeof callback !== 'function') return; + if ('_ready_called_' in this) return JSROOT.CallBack(callback, this); + if (this._ready_callback_ === undefined) this._ready_callback_ = []; + this._ready_callback_.push(callback); + } + + /** @summary Reset ready state - painter should again call DrawingReady to signal readyness + * @private + */ + TBasePainter.prototype.ResetReady = function() { + delete this._ready_called_; + delete this._ready_callback_; + } + + /** @summary Returns drawn object + * + * @abstract + */ + TBasePainter.prototype.GetObject = function() { + return null; + } + + /** @summary Returns true if type match with drawn object type + * @abstract + * @private + */ + TBasePainter.prototype.MatchObjectType = function(typ) { + return false; + } + + /** @summary Called to update drawn object content + * @abstract + * @private */ + TBasePainter.prototype.UpdateObject = function(obj) { + return false; + } + + /** @summary Redraw all objects in current pad + * @abstract + * @private */ + TBasePainter.prototype.RedrawPad = function(resize) { + } + + /** @summary Updates object and readraw it + * @param {object} obj - new version of object, values will be updated in original object + * @returns {boolean} true if object updated and redrawn */ + TBasePainter.prototype.RedrawObject = function(obj) { + if (!this.UpdateObject(obj)) return false; + var current = document.body.style.cursor; + document.body.style.cursor = 'wait'; + this.RedrawPad(); + document.body.style.cursor = current; + return true; + } + + /** @summary Checks if draw elements were resized and drawing should be updated + * @abstract + * @private */ + TBasePainter.prototype.CheckResize = function(arg) { + return false; + } + + /** @summary Method called when interactively changes attribute in given class + * @abstract + * @private */ + TBasePainter.prototype.AttributeChange = function(class_name, member_name, new_value) { + // function called when user interactively changes attribute in given class + + // console.log("Changed attribute", class_name, member_name, new_value); + } + + /** @summary Returns d3.select for main element for drawing, defined with this.divid. + * + * @desc if main element was layouted, returns main element inside layout */ + TBasePainter.prototype.select_main = function(is_direct) { + + if (!this.divid) return d3.select(null); + + var res = this._selected_main; + if (!res) { + if (typeof this.divid == "string") { + var id = this.divid; + if (id[0]!='#') id = "#" + id; + res = d3.select(id); + if (!res.empty()) this.divid = res.node(); + } else { + res = d3.select(this.divid); + } + this._selected_main = res; + } + + if (!res || res.empty() || (is_direct==='origin')) return res; + + var use_enlarge = res.property('use_enlarge'), + layout = res.property('layout') || 'simple', + layout_selector = (layout=='simple') ? "" : res.property('layout_selector'); + + if (layout_selector) res = res.select(layout_selector); + + // one could redirect here + if (!is_direct && !res.empty() && use_enlarge) res = d3.select("#jsroot_enlarge_div"); + + return res; + } + + /** @summary Returns string with value of main element id attribute + * + * @desc if main element does not have id, it will be generated */ + TBasePainter.prototype.get_main_id = function() { + var elem = this.select_main(); + if (elem.empty()) return ""; + var id = elem.attr("id"); + if (!id) { + id = "jsroot_element_" + JSROOT.id_counter++; + elem.attr("id", id); + } + return id; + } + + /** @summary Returns layout kind + * @private + */ + TBasePainter.prototype.get_layout_kind = function() { + var origin = this.select_main('origin'), + layout = origin.empty() ? "" : origin.property('layout'); + + return layout || 'simple'; + } + + /** @summary Set layout kind + * @private + */ + TBasePainter.prototype.set_layout_kind = function(kind, main_selector) { + // change layout settings + var origin = this.select_main('origin'); + if (!origin.empty()) { + if (!kind) kind = 'simple'; + origin.property('layout', kind); + origin.property('layout_selector', (kind!='simple') && main_selector ? main_selector : null); + this._changed_layout = (kind !== 'simple'); // use in cleanup + } + } + + /** @summary Function checks if geometry of main div was changed. + * + * @desc returns size of area when main div is drawn + * take into account enlarge state + * + * @private + */ + TBasePainter.prototype.check_main_resize = function(check_level, new_size, height_factor) { + + var enlarge = this.enlarge_main('state'), + main_origin = this.select_main('origin'), + main = this.select_main(), + lmt = 5; // minimal size + + if (enlarge !== 'on') { + if (new_size && new_size.width && new_size.height) + main_origin.style('width',new_size.width+"px") + .style('height',new_size.height+"px"); + } + + var rect_origin = this.get_visible_rect(main_origin, true), + can_resize = main_origin.attr('can_resize'), + do_resize = false; + + if (can_resize == "height") + if (height_factor && Math.abs(rect_origin.width*height_factor - rect_origin.height) > 0.1*rect_origin.width) do_resize = true; + + if (((rect_origin.height <= lmt) || (rect_origin.width <= lmt)) && + can_resize && can_resize !== 'false') do_resize = true; + + if (do_resize && (enlarge !== 'on')) { + // if zero size and can_resize attribute set, change container size + + if (rect_origin.width > lmt) { + height_factor = height_factor || 0.66; + main_origin.style('height', Math.round(rect_origin.width * height_factor)+'px'); + } else + if (can_resize !== 'height') { + main_origin.style('width', '200px').style('height', '100px'); + } + } + + var rect = this.get_visible_rect(main), + old_h = main.property('draw_height'), old_w = main.property('draw_width'); + + rect.changed = false; + + if (old_h && old_w && (old_h>0) && (old_w>0)) { + if ((old_h !== rect.height) || (old_w !== rect.width)) + if ((check_level>1) || (rect.width/old_w<0.66) || (rect.width/old_w>1.5) || + (rect.height/old_h<0.66) && (rect.height/old_h>1.5)) rect.changed = true; + } else { + rect.changed = true; + } + + return rect; + } + + /** @summary Try enlarge main drawing element to full HTML page. + * + * @desc Possible values for parameter: + * + * - true - try to enlarge + * - false - cancel enlarge state + * - 'toggle' - toggle enlarge state + * - 'state' - return current state + * - 'verify' - check if element can be enlarged + * + * if action not specified, just return possibility to enlarge main div + * + * @private + */ + TBasePainter.prototype.enlarge_main = function(action, skip_warning) { + + var main = this.select_main(true), + origin = this.select_main('origin'); + + if (main.empty() || !JSROOT.gStyle.CanEnlarge || (origin.property('can_enlarge')===false)) return false; + + if (action===undefined) return true; + + if (action==='verify') return true; + + var state = origin.property('use_enlarge') ? "on" : "off"; + + if (action === 'state') return state; + + if (action === 'toggle') action = (state==="off"); + + var enlarge = d3.select("#jsroot_enlarge_div"); + + if ((action === true) && (state!=="on")) { + if (!enlarge.empty()) return false; + + enlarge = d3.select(document.body) + .append("div") + .attr("id","jsroot_enlarge_div"); + + var rect1 = this.get_visible_rect(main), + rect2 = this.get_visible_rect(enlarge); + + // if new enlarge area not big enough, do not do it + if ((rect2.width <= rect1.width) || (rect2.height <= rect1.height)) + if (rect2.width*rect2.height < rect1.width*rect1.height) { + if (!skip_warning) + console.log('Enlarged area ' + rect2.width+"x"+rect2.height + ' smaller then original drawing ' + rect1.width+"x"+rect1.height); + enlarge.remove(); + return false; + } + + while (main.node().childNodes.length > 0) + enlarge.node().appendChild(main.node().firstChild); + + origin.property('use_enlarge', true); + + return true; + } + if ((action === false) && (state!=="off")) { + + while (enlarge.node() && enlarge.node().childNodes.length > 0) + main.node().appendChild(enlarge.node().firstChild); + + enlarge.remove(); + origin.property('use_enlarge', false); + return true; + } + + return false; + } + + /** @summary Return CSS value in given HTML element + * @private */ + TBasePainter.prototype.GetStyleValue = function(elem, name) { + if (!elem || elem.empty()) return 0; + var value = elem.style(name); + if (!value || (typeof value !== 'string')) return 0; + value = parseFloat(value.replace("px","")); + return isNaN(value) ? 0 : Math.round(value); + } + + /** @summary Returns rect with width/height which correspond to the visible area of drawing region of element. + * @private */ + TBasePainter.prototype.get_visible_rect = function(elem, fullsize) { + + if (JSROOT.nodejs) + return { width : parseInt(elem.attr("width")), height: parseInt(elem.attr("height")) }; + + var rect = elem.node().getBoundingClientRect(), + res = { width: Math.round(rect.width), height: Math.round(rect.height) }; + + if (!fullsize) { + // this is size exclude padding area + res.width -= this.GetStyleValue(elem,'padding-left') + this.GetStyleValue(elem,'padding-right'); + res.height -= this.GetStyleValue(elem,'padding-top') - this.GetStyleValue(elem,'padding-bottom'); + } + + return res; + } + + /** @summary Assign painter to specified element + * + * @desc base painter does not creates canvas or frames + * it registered in the first child element + * + * @param {string|object} divid - element ID or DOM Element + */ + TBasePainter.prototype.SetDivId = function(divid) { + if (divid !== undefined) { + this.divid = divid; + delete this._selected_main; + } + + this.AccessTopPainter(true); + } + + /** @summary Set item name, associated with the painter + * + * @desc Used by {@link JSROOT.HiearchyPainter} + * @private + */ + TBasePainter.prototype.SetItemName = function(name, opt, hpainter) { + if (typeof name === 'string') this._hitemname = name; + else delete this._hitemname; + // only upate draw option, never delete. null specified when update drawing + if (typeof opt === 'string') this._hdrawopt = opt; + + this._hpainter = hpainter; + } + + /** @summary Returns assigned item name + * @private */ + TBasePainter.prototype.GetItemName = function() { + return ('_hitemname' in this) ? this._hitemname : null; + } + + /** @summary Returns assigned item draw option + * @private */ + TBasePainter.prototype.GetItemDrawOpt = function() { + return ('_hdrawopt' in this) ? this._hdrawopt : ""; + } + + /** @summary Check if it makes sense to zoom inside specified axis range + * + * @param {string} axis - name of axis like 'x', 'y', 'z' + * @param {number} left - left axis range + * @param {number} right - right axis range + * @returns true is zooming makes sense + * @abstract + * @private + */ + TBasePainter.prototype.CanZoomIn = function(axis,left,right) { + return false; + } + + // ============================================================================== + + /** + * Basic painter for objects inside TCanvas/TPad. + * + * @constructor + * @memberof JSROOT + * @augments JSROOT.TBasePainter + * @param {object} obj - object to draw + */ + function TObjectPainter(obj, opt) { + TBasePainter.call(this); + this.draw_g = null; // container for all drawn objects + this.pad_name = ""; // name of pad where object is drawn + this.main = null; // main painter, received from pad + if (typeof opt == "string") this.options = { original: opt }; + this.AssignObject(obj); + } + + TObjectPainter.prototype = Object.create(TBasePainter.prototype); + + TObjectPainter.prototype.AssignObject = function(obj) { + this.draw_object = ((obj!==undefined) && (typeof obj == 'object')) ? obj : null; + } + + /** @summary Generic method to cleanup painter. + * + * @desc Remove object drawing and in case of main painter - also main HTML components + */ + TObjectPainter.prototype.Cleanup = function() { + + this.RemoveDrawG(); + + var keep_origin = true; + + if (this.is_main_painter()) { + var pp = this.pad_painter(); + if (!pp || pp.normal_canvas === false) keep_origin = false; + } + + // cleanup all existing references + this.pad_name = ""; + this.main = null; + this.draw_object = null; + + // remove attributes objects (if any) + delete this.fillatt; + delete this.lineatt; + delete this.markeratt; + delete this.bins; + delete this.root_colors; + delete this.options; + delete this.options_store; + + TBasePainter.prototype.Cleanup.call(this, keep_origin); + } + + /** @summary Returns drawn object */ + TObjectPainter.prototype.GetObject = function() { + return this.draw_object; + } + + /** @summary Returns drawn object class name */ + TObjectPainter.prototype.GetClassName = function() { + var res = this.draw_object ? this.draw_object._typename : ""; + return res || ""; + } + + /** @summary Checks if drawn object matches with provided typename + * + * @param {string} arg - typename + * @param {string} arg._typename - if arg is object, use its typename + */ + TObjectPainter.prototype.MatchObjectType = function(arg) { + if (!arg || !this.draw_object) return false; + if (typeof arg === 'string') return (this.draw_object._typename === arg); + if (arg._typename) return (this.draw_object._typename === arg._typename); + return this.draw_object._typename.match(arg); + } + + /** @summary Changes item name. + * + * @desc When available, used for svg:title proprty + * @private */ + TObjectPainter.prototype.SetItemName = function(name, opt, hpainter) { + TBasePainter.prototype.SetItemName.call(this, name, opt, hpainter); + if (this.no_default_title || (name=="")) return; + var can = this.svg_canvas(); + if (!can.empty()) can.select("title").text(name); + else this.select_main().attr("title", name); + } + + /** @summary Store actual options together with original string + * @private */ + TObjectPainter.prototype.OptionsStore = function(original) { + if (!this.options) return; + this.options.original = original || ""; + this.options_store = JSROOT.extend({}, this.options); + } + + /** @summary Checks if any draw options were changed + * + * @private + */ + TObjectPainter.prototype.OptionesChanged = function() { + if (!this.options) return false; + if (!this.options_store) return true; + + for (var k in this.options) + if (this.options[k] !== this.options_store[k]) return true; + + return false; + } + + /** @summary Return actual draw options as string + * @private + */ + TObjectPainter.prototype.OptionsAsString = function() { + if (!this.options) return ""; + + if (!this.OptionesChanged()) + return this.options.original || ""; + + if (typeof this.options.asString == "function") + return this.options.asString(); + + return this.options.original || ""; // nothing better, return original draw option + } + + /** @summary Generic method to update object content. + * + * @desc Just copy all members from source object + * @param {object} obj - object with new data + */ + TObjectPainter.prototype.UpdateObject = function(obj) { + if (!this.MatchObjectType(obj)) return false; + JSROOT.extend(this.GetObject(), obj); + return true; + } + + /** @summary Returns string which either item or object name. + * + * @desc Such string can be used as tooltip. If result string larger than 20 symbols, it will be cutted. + * @private + */ + TObjectPainter.prototype.GetTipName = function(append) { + var res = this.GetItemName(), obj = this.GetObject(); + if (!res) res = obj && obj.fName ? obj.fName : ""; + if (res.lenght > 20) res = res.substr(0,17) + "..."; + if (res && append) res += append; + return res; + } + + /** @summary returns pad painter for specified pad + * @private */ + TObjectPainter.prototype.pad_painter = function(pad_name) { + var elem = this.svg_pad(typeof pad_name == "string" ? pad_name : undefined); + return elem.empty() ? null : elem.property('pad_painter'); + } + + /** @summary returns canvas painter + * @private */ + TObjectPainter.prototype.canv_painter = function() { + var elem = this.svg_canvas(); + return elem.empty() ? null : elem.property('pad_painter'); + } + + /** @summary returns color from current list of colors + * @private */ + TObjectPainter.prototype.get_color = function(indx) { + var jsarr = this.root_colors; + + if (!jsarr) { + var pp = this.canv_painter(); + jsarr = this.root_colors = (pp && pp.root_colors) ? pp.root_colors : JSROOT.Painter.root_colors; + } + + return jsarr[indx]; + } + + /** @summary add color to list of colors + * @private */ + TObjectPainter.prototype.add_color = function(color) { + var jsarr = this.root_colors; + if (!jsarr) { + var pp = this.canv_painter(); + jsarr = this.root_colors = (pp && pp.root_colors) ? pp.root_colors : JSROOT.Painter.root_colors; + } + var indx = jsarr.indexOf(color); + if (indx >= 0) return indx; + jsarr.push(color); + return jsarr.length-1; + } + + /** @summary returns tooltip allowed flag. Check canvas painter + * @private */ + TObjectPainter.prototype.IsTooltipAllowed = function() { + var src = this.canv_painter() || this; + return src.tooltip_allowed ? true : false; + } + + /** @summary returns tooltip allowed flag + * @private */ + TObjectPainter.prototype.SetTooltipAllowed = function(on) { + var src = this.canv_painter() || this; + src.tooltip_allowed = (on == "toggle") ? !src.tooltip_allowed : on; + } + + /** @summary returns custom palette for the object. If forced, will be created + * @private */ + TObjectPainter.prototype.get_palette = function(force, palettedid) { + if (!palettedid) { + var pp = this.pad_painter(); + if (!pp) return null; + if (pp.custom_palette) return pp.custom_palette; + } + + var cp = this.canv_painter(); + if (!cp) return null; + if (cp.custom_palette && !palettedid) return cp.custom_palette; + + if (force && JSROOT.Painter.GetColorPalette) + cp.custom_palette = JSROOT.Painter.GetColorPalette(palettedid); + + return cp.custom_palette; + } + + + + /** @summary Checks if draw elements were resized and drawing should be updated. + * + * @desc Redirects to {@link TPadPainter.CheckCanvasResize} + * @private */ + TObjectPainter.prototype.CheckResize = function(arg) { + var pad_painter = this.canv_painter(); + if (!pad_painter) return false; + + // only canvas should be checked + pad_painter.CheckCanvasResize(arg); + return true; + } + + /** @summary removes <g> element with object drawing + * @desc generic method to delete all graphical elements, associated with painter */ + TObjectPainter.prototype.RemoveDrawG = function() { + if (this.draw_g) { + this.draw_g.remove(); + this.draw_g = null; + } + } + + /** @summary recreates <g> element for object drawing + * @desc obsolete function, will be removed soon + * @private */ + TObjectPainter.prototype.RecreateDrawG = function(usepad, layer) { + // keep old function for a while - later + console.warn("Obsolete RecreateDrawG is used, will be removed soon. Change to CreateG"); + return this.CreateG(usepad ? undefined : layer); + } + + /** @summary (re)creates svg:g element for object drawings + * + * @desc either one attach svg:g to pad list of primitives (default) + * or svg:g element created in specified frame layer (default main_layer) + * @param {string} [frame_layer=undefined] - when specified, <g> element will be created inside frame layer, otherwise in pad primitives list + */ + TObjectPainter.prototype.CreateG = function(frame_layer) { + if (this.draw_g) { + // one should keep svg:g element on its place + // d3.selectAll(this.draw_g.node().childNodes).remove(); + this.draw_g.selectAll('*').remove(); + } else if (frame_layer) { + var frame = this.svg_frame(); + if (frame.empty()) return frame; + if (typeof frame_layer != 'string') frame_layer = "main_layer"; + var layer = frame.select("." + frame_layer); + if (layer.empty()) layer = frame.select(".main_layer"); + this.draw_g = layer.append("svg:g"); + } else { + var layer = this.svg_layer("primitives_layer"); + this.draw_g = layer.append("svg:g"); + + // layer.selectAll(".most_upper_primitives").raise(); + var up = [], chlds = layer.node().childNodes; + for (var n=0;n<chlds.length;++n) + if (d3.select(chlds[n]).classed("most_upper_primitives")) up.push(chlds[n]); + + up.forEach(function(top) { d3.select(top).raise(); }); + } + + // set attributes for debugging + if (this.draw_object) { + this.draw_g.attr('objname', encodeURI(this.draw_object.fName || "name")); + this.draw_g.attr('objtype', encodeURI(this.draw_object._typename || "type")); + } + + return this.draw_g; + } + + /** @summary This is main graphical SVG element, where all drawings are performed + * @private */ + TObjectPainter.prototype.svg_canvas = function() { + return this.select_main().select(".root_canvas"); + } + + /** @summary This is SVG element, correspondent to current pad + * @private */ + TObjectPainter.prototype.svg_pad = function(pad_name) { + if (pad_name === undefined) pad_name = this.pad_name; + + var c = this.svg_canvas(); + if (!pad_name || c.empty()) return c; + + var cp = c.property('pad_painter'); + if (cp.pads_cache && cp.pads_cache[pad_name]) + return d3.select(cp.pads_cache[pad_name]); + + c = c.select(".primitives_layer .__root_pad_" + pad_name); + if (!cp.pads_cache) cp.pads_cache = {}; + cp.pads_cache[pad_name] = c.node(); + return c; + } + + /** @summary Method selects immediate layer under canvas/pad main element + * @private */ + TObjectPainter.prototype.svg_layer = function(name, pad_name) { + var svg = this.svg_pad(pad_name); + if (svg.empty()) return svg; + + if (name.indexOf("prim#")==0) { + svg = svg.select(".primitives_layer"); + name = name.substr(5); + } + + var node = svg.node().firstChild; + while (node!==null) { + var elem = d3.select(node); + if (elem.classed(name)) return elem; + node = node.nextSibling; + } + + return d3.select(null); + } + + /** @summary Method returns current pad name + * @param {string} [new_name = undefined] - when specified, new current pad name will be configured + * @private */ + TObjectPainter.prototype.CurrentPadName = function(new_name) { + var svg = this.svg_canvas(); + if (svg.empty()) return ""; + var curr = svg.property('current_pad'); + if (new_name !== undefined) svg.property('current_pad', new_name); + return curr; + } + + /** @summary Returns ROOT TPad object + * @private */ + TObjectPainter.prototype.root_pad = function() { + var pad_painter = this.pad_painter(); + return pad_painter ? pad_painter.pad : null; + } + + /** @summary Converts pad x or y coordinate into NDC value + * @private */ + TObjectPainter.prototype.ConvertToNDC = function(axis, value, isndc) { + if (isndc) return value; + var pad = this.root_pad(); + if (!pad) return value; + + if (axis=="y") { + if (pad.fLogy) + value = (value>0) ? JSROOT.log10(value) : pad.fUymin; + return (value - pad.fY1) / (pad.fY2 - pad.fY1); + } + if (pad.fLogx) + value = (value>0) ? JSROOT.log10(value) : pad.fUxmin; + return (value - pad.fX1) / (pad.fX2 - pad.fX1); + } + + /** @summary Converts x or y coordinate into SVG pad or frame coordinates. + * + * @param {string} axis - name like "x" or "y" + * @param {number} value - axis value to convert. + * @param {boolean|string} kind - false or undefined is coordinate inside frame, true - when NDC pad coordinates are used, "pad" - when pad coordinates relative to pad ranges are specified + * @returns {number} rounded value of requested coordiantes + * @private + */ + TObjectPainter.prototype.AxisToSvg = function(axis, value, kind) { + var main = this.frame_painter(); + if (main && !kind && main["gr"+axis]) { + // this is frame coordinates + value = (axis=="y") ? main.gry(value) + main.frame_y() + : main.grx(value) + main.frame_x(); + } else { + if (kind !== true) value = this.ConvertToNDC(axis, value); + value = (axis=="y") ? (1-value)*this.pad_height() : value*this.pad_width(); + } + return Math.round(value); + } + + /** @summary Return functor, which can convert x and y coordinates into pixels, used for drawing + * + * Produce functor can convert x and y value by calling func.x(x) and func.y(y) + * @param {boolean|string} kind - false or undefined is coordinate inside frame, true - when NDC pad coordinates are used, "pad" - when pad coordinates relative to pad ranges are specified + * @private + */ + TObjectPainter.prototype.AxisToSvgFunc = function(kind) { + var func = { kind: kind }, main = this.frame_painter(); + if (main && !kind && main.grx && main.gry) { + func.main = main; + func.offx = main.frame_x(); + func.offy = main.frame_y(); + func.x = function(x) { return Math.round(this.main.grx(x) + this.offx); } + func.y = function(y) { return Math.round(this.main.gry(y) + this.offy); } + } else { + if (kind !== true) func.p = this; // need for NDC conversion + func.padh = this.pad_height(); + func.padw = this.pad_width(); + func.x = function(x) { if (this.p) x = this.p.ConvertToNDC("x", x); return Math.round(x*this.padw); } + func.y = function(y) { if (this.p) y = this.p.ConvertToNDC("y", y); return Math.round((1-y)*this.padh); } + } + return func; + } + + + /** @summary Returns svg element for the frame. + * + * @param {string} [pad_name = undefined] - optional pad name, otherwise where object painter is drawn + * @private */ + TObjectPainter.prototype.svg_frame = function(pad_name) { + return this.svg_layer("primitives_layer", pad_name).select(".root_frame"); + } + + /** @summary Returns pad width. + * + * @param {string} [pad_name = undefined] - optional pad name, otherwise where object painter is drawn + * @private + */ + TObjectPainter.prototype.pad_width = function(pad_name) { + var res = this.svg_pad(pad_name); + res = res.empty() ? 0 : res.property("draw_width"); + return isNaN(res) ? 0 : res; + } + + /** @summary Returns pad height + * + * @param {string} [pad_name = undefined] - optional pad name, otherwise where object painter is drawn + * @private + */ + TObjectPainter.prototype.pad_height = function(pad_name) { + var res = this.svg_pad(pad_name); + res = res.empty() ? 0 : res.property("draw_height"); + return isNaN(res) ? 0 : res; + } + + /** @summary Returns frame painter in current pad + * @private */ + TObjectPainter.prototype.frame_painter = function() { + var pp = this.pad_painter(); + return pp ? pp.frame_painter_ref : null; + } + + /** @summary Returns property of the frame painter + * @private */ + TObjectPainter.prototype.frame_property = function(name) { + var pp = this.frame_painter(); + return pp && pp[name] ? pp[name] : 0; + } + + /** @summary Returns frame X coordinate relative to current pad */ + TObjectPainter.prototype.frame_x = function() { + return this.frame_property("_frame_x"); + } + + /** @summary Returns frame Y coordinate relative to current pad */ + TObjectPainter.prototype.frame_y = function() { + return this.frame_property("_frame_y"); + } + + /** @summary Returns frame width */ + TObjectPainter.prototype.frame_width = function() { + return this.frame_property("_frame_width"); + } + + /** @summary Returns frame height */ + TObjectPainter.prototype.frame_height = function() { + return this.frame_property("_frame_height"); + } + + /** @summary Returns embed mode for 3D drawings (three.js) inside SVG. + * + * - 0 no embedding, 3D drawing take full size of canvas + * - 1 no embedding, canvas placed over svg with proper size (resize problem may appear) + * - 2 normall embedding via ForeginObject, works only with Firefox + * - 3 embedding 3D drawing as SVG canvas, requires SVG renderer + * - 4 embed 3D drawing as <image> element + * + * @private + */ + TObjectPainter.prototype.embed_3d = function() { + if (JSROOT.BatchMode) return 4; // in batch - directly create svg::image after rendering + if (JSROOT.gStyle.Embed3DinSVG < 2) return JSROOT.gStyle.Embed3DinSVG; + if (JSROOT.browser.isFirefox /*|| JSROOT.browser.isWebKit*/) + return JSROOT.gStyle.Embed3DinSVG; // use specified mode + return 1; // default is overlay + } + + /** @summary Access current 3d mode + * + * @param {string} [new_value = undefined] - when specified, set new 3d mode + * @private + */ + TObjectPainter.prototype.access_3d_kind = function(new_value) { + var svg = this.svg_pad(this.this_pad_name); + if (svg.empty()) return -1; + + // returns kind of currently created 3d canvas + var kind = svg.property('can3d'); + if (new_value !== undefined) svg.property('can3d', new_value); + return ((kind===null) || (kind===undefined)) ? -1 : kind; + } + + /** @summary Returns size which availble for 3D drawing. + * + * @desc One uses frame sizes for the 3D drawing - like TH2/TH3 objects + * @private + */ + TObjectPainter.prototype.size_for_3d = function(can3d) { + + if (can3d === undefined) can3d = this.embed_3d(); + + var pad = this.svg_pad(this.this_pad_name), + clname = "draw3d_" + (this.this_pad_name || this.pad_name || 'canvas'); + + if (pad.empty()) { + // this is a case when object drawn without canvas + + var rect = this.get_visible_rect(this.select_main()); + + if ((rect.height<10) && (rect.width>10)) { + rect.height = Math.round(0.66*rect.width); + this.select_main().style('height', rect.height + "px"); + } + rect.x = 0; rect.y = 0; rect.clname = clname; rect.can3d = -1; + return rect; + } + + var elem = pad, fp = this.frame_painter(); + if (can3d === 0) elem = this.svg_canvas(); + + var size = { x: 0, y: 0, width: 100, height: 100, clname: clname, can3d: can3d }; + + if (fp && !fp.mode3d) { + elem = this.svg_frame(); + size.x = elem.property("draw_x"); + size.y = elem.property("draw_y"); + } + + size.width = elem.property("draw_width"); + size.height = elem.property("draw_height"); + + if ((!fp || fp.mode3d) && (can3d > 0)) { + size.x = Math.round(size.x + size.width*JSROOT.gStyle.fPadLeftMargin); + size.y = Math.round(size.y + size.height*JSROOT.gStyle.fPadTopMargin); + size.width = Math.round(size.width*(1 - JSROOT.gStyle.fPadLeftMargin - JSROOT.gStyle.fPadRightMargin)); + size.height = Math.round(size.height*(1- JSROOT.gStyle.fPadTopMargin - JSROOT.gStyle.fPadBottomMargin)); + } + + var pw = this.pad_width(this.this_pad_name), x2 = pw - size.x - size.width, + ph = this.pad_height(this.this_pad_name), y2 = ph - size.y - size.height; + + if ((x2 >= 0) && (y2 >= 0)) { + // while 3D canvas uses area also for the axis labels, extend area relative to normal frame + size.x = Math.round(size.x * 0.3); + size.y = Math.round(size.y * 0.9); + size.width = pw - size.x - Math.round(x2*0.3); + size.height = ph - size.y - Math.round(y2*0.5); + } + + if (can3d === 1) + this.CalcAbsolutePosition(this.svg_pad(this.this_pad_name), size); + + return size; + } + + /** @summary Clear all 3D drawings + * @private */ + TObjectPainter.prototype.clear_3d_canvas = function() { + var can3d = this.access_3d_kind(null); + if (can3d < 0) return; + + var size = this.size_for_3d(can3d); + + if (size.can3d === 0) { + d3.select(this.svg_canvas().node().nextSibling).remove(); // remove html5 canvas + this.svg_canvas().style('display', null); // show SVG canvas + } else { + if (this.svg_pad(this.this_pad_name).empty()) return; + + this.apply_3d_size(size).remove(); + + this.svg_frame().style('display', null); // clear display property + } + } + + /** @summary Add 3D canvas + * @private */ + TObjectPainter.prototype.add_3d_canvas = function(size, canv) { + + if (!canv || (size.can3d < -1)) return; + + if (size.can3d === -1) { + // case when 3D object drawn without canvas + + var main = this.select_main().node(); + if (main !== null) { + main.appendChild(canv); + canv.painter = this; + } + + return; + } + + this.access_3d_kind(size.can3d); + + if (size.can3d === 0) { + this.svg_canvas().style('display', 'none'); // hide SVG canvas + + this.svg_canvas().node().parentNode.appendChild(canv); // add directly + } else { + if (this.svg_pad(this.this_pad_name).empty()) return; + + // first hide normal frame + this.svg_frame().style('display', 'none'); + + var elem = this.apply_3d_size(size); + + elem.attr('title','').node().appendChild(canv); + } + } + + /** @summary Apply size to 3D elements + * @private */ + TObjectPainter.prototype.apply_3d_size = function(size, onlyget) { + + if (size.can3d < 0) return d3.select(null); + + var elem; + + if (size.can3d > 1) { + + elem = this.svg_layer(size.clname); + + // elem = layer.select("." + size.clname); + if (onlyget) return elem; + + var svg = this.svg_pad(); + + if ((size.can3d === 3) || (size.can3d === 4)) { + // this is SVG mode or image mode - just create group to hold element + + if (elem.empty()) + elem = svg.insert("g",".primitives_layer").attr("class", size.clname); + + elem.attr("transform", "translate(" + size.x + "," + size.y + ")"); + + } else { + + if (elem.empty()) + elem = svg.insert("foreignObject",".primitives_layer").attr("class", size.clname); + + elem.attr('x', size.x) + .attr('y', size.y) + .attr('width', size.width) + .attr('height', size.height) + .attr('viewBox', "0 0 " + size.width + " " + size.height) + .attr('preserveAspectRatio','xMidYMid'); + } + + } else { + var prnt = this.svg_canvas().node().parentNode; + + elem = d3.select(prnt).select("." + size.clname); + if (onlyget) return elem; + + // force redraw by resize + this.svg_canvas().property('redraw_by_resize', true); + + if (elem.empty()) + elem = d3.select(prnt).append('div').attr("class", size.clname + " jsroot_noselect"); + + // our position inside canvas, but to set 'absolute' position we should use + // canvas element offset relative to first parent with non-static position + // now try to use getBoundingClientRect - it should be more precise + + var pos0 = prnt.getBoundingClientRect(); + + while (prnt) { + if (prnt === document) { prnt = null; break; } + try { + if (getComputedStyle(prnt).position !== 'static') break; + } catch(err) { + break; + } + prnt = prnt.parentNode; + } + + var pos1 = prnt ? prnt.getBoundingClientRect() : { top: 0, left: 0 }; + + var offx = Math.round(pos0.left - pos1.left), + offy = Math.round(pos0.top - pos1.top); + + elem.style('position','absolute').style('left',(size.x+offx)+'px').style('top',(size.y+offy)+'px').style('width',size.width+'px').style('height',size.height+'px'); + } + + return elem; + } + + /** @summary Returns main object painter on the pad. + * + * @desc Normally this is first histogram drawn on the pad, which also draws all axes + * @param {boolean} [not_store = undefined] - if true, prevent temporary store of main painter reference + * @param {string} [pad_name = undefined] - when specified, returns main painter from specified pad */ + TObjectPainter.prototype.main_painter = function(not_store, pad_name) { + var res = this.main; + if (!res) { + var svg_p = this.svg_pad(pad_name); + if (svg_p.empty()) { + res = this.AccessTopPainter(); + } else { + res = svg_p.property('mainpainter'); + } + if (!res) res = null; + if (!not_store) this.main = res; + } + return res; + } + + /** @summary Returns true if this is main painter */ + TObjectPainter.prototype.is_main_painter = function() { + return this === this.main_painter(); + } + + /** @summary Assigns id of top element (normally div where drawing is done). + * + * @desc In some situations canvas may not exists - for instance object drawn as html, not as svg. + * In such case the only painter will be assigned to the first element + * + * Following value of is_main parameter is allowed: + * -1 - only assign id, this painter not add to painters list, + * 0 - normal painter (default), + * 1 - major objects like TH1/TH2 (required canvas with frame) + * 2 - if canvas missing, create it, but not set as main object + * 3 - if canvas and (or) frame missing, create them, but not set as main object + * 4 - major objects like TH3 (required canvas and frame in 3d mode) + * 5 - major objects like TGeoVolume (do not require canvas) + * + * @param {string|object} divid - id of div element or directly DOMElement + * @param {number} [kind = 0] - kind of object drawn with painter + * @param {string} [pad_name = undefined] - when specified, subpad name used for object drawin + */ + TObjectPainter.prototype.SetDivId = function(divid, is_main, pad_name) { + + if (divid !== undefined) { + this.divid = divid; + delete this._selected_main; + } + + if (!is_main) is_main = 0; + + // check if element really exists + if ((is_main >= 0) && this.select_main(true).empty()) { + if (typeof divid == 'string') console.error('element with id ' + divid + ' not exists'); + else console.error('specified HTML element can not be selected with d3.select()'); + return; + } + + this.create_canvas = false; + + // SVG element where canvas is drawn + var svg_c = this.svg_canvas(); + + if (svg_c.empty() && (is_main > 0) && (is_main!==5)) { + JSROOT.Painter.drawCanvas(divid, null, ((is_main == 2) || (is_main == 4)) ? "noframe" : ""); + svg_c = this.svg_canvas(); + this.create_canvas = true; + } + + if (svg_c.empty()) { + if ((is_main < 0) || (is_main===5) || this.iscan) return; + this.AccessTopPainter(true); + return; + } + + // SVG element where current pad is drawn (can be canvas itself) + this.pad_name = pad_name; + if (this.pad_name === undefined) + this.pad_name = this.CurrentPadName(); + + if (is_main < 0) return; + + // create TFrame element if not exists + if (this.svg_frame().select(".main_layer").empty() && ((is_main == 1) || (is_main == 3) || (is_main == 4))) { + if (typeof JSROOT.Painter.drawFrame == 'function') + JSROOT.Painter.drawFrame(divid, null, (is_main == 4) ? "3d" : ""); + if ((is_main != 4) && this.svg_frame().empty()) return alert("Fail to draw dummy TFrame"); + } + + var svg_p = this.svg_pad(); + if (svg_p.empty()) return; + + var pp = svg_p.property('pad_painter'); + if (pp && (pp !== this)) + pp.painters.push(this); + + if (((is_main === 1) || (is_main === 4) || (is_main === 5)) && !svg_p.property('mainpainter')) + // when this is first main painter in the pad + svg_p.property('mainpainter', this); + } + + /** @summary Calculate absolute position of provided selection. + * @private */ + TObjectPainter.prototype.CalcAbsolutePosition = function(sel, pos) { + while (!sel.empty() && !sel.classed('root_canvas')) { + var cl = sel.attr("class"); + if (cl && ((cl.indexOf("root_frame")>=0) || (cl.indexOf("__root_pad_")>=0))) { + pos.x += sel.property("draw_x") || 0; + pos.y += sel.property("draw_y") || 0; + } + sel = d3.select(sel.node().parentNode); + } + return pos; + } + + /** @summary Creates marker attributes object. + * + * @desc Can be used to produce markers in painter. + * See {@link JSROOT.TAttMarkerHandler} for more info. + * Instance assigned as this.markeratt data member, recognized by GED editor + * @param {object} args - either TAttMarker or see arguments of {@link JSROOT.TAttMarkerHandler} + * @returns created handler + */ + TObjectPainter.prototype.createAttMarker = function(args) { + if (!args || (typeof args !== 'object')) args = { std: true }; else + if (args.fMarkerColor!==undefined && args.fMarkerStyle!==undefined && args.fMarkerSize!==undefined) args = { attr: args, std: false }; + + if (args.std === undefined) args.std = true; + + var handler = args.std ? this.markeratt : null; + + if (!handler) handler = new TAttMarkerHandler(args); + else if (!handler.changed || args.force) handler.SetArgs(args); + + if (args.std) this.markeratt = handler; + + // handler.used = false; // mark that line handler is not yet used + return handler; + } + + + /** @summary Creates line attributes object. + * + * @desc Can be used to produce lines in painter. + * See {@link JSROOT.TAttLineHandler} for more info. + * Instance assigned as this.lineatt data member, recognized by GED editor + * @param {object} args - either TAttLine or see constructor arguments of {@link JSROOT.TAttLineHandler} + */ + TObjectPainter.prototype.createAttLine = function(args) { + if (!args || (typeof args !== 'object')) args = { std: true }; else + if (args.fLineColor!==undefined && args.fLineStyle!==undefined && args.fLineWidth!==undefined) args = { attr: args, std: false }; + + if (args.std === undefined) args.std = true; + + var handler = args.std ? this.lineatt : null; + + if (!handler) handler = new TAttLineHandler(args); + else if (!handler.changed || args.force) handler.SetArgs(args); + + if (args.std) this.lineatt = handler; + + // handler.used = false; // mark that line handler is not yet used + return handler; + } + + /** @summary Creates fill attributes object. + * + * @desc Method dedicated to create fill attributes, bound to canvas SVG + * otherwise newly created patters will not be usable in the canvas + * See {@link JSROOT.TAttFillHandler} for more info. + * Instance assigned as this.fillatt data member, recognized by GED editor + + * @param {object} args - for special cases one can specify TAttFill as args or number of parameters + * @param {boolean} [args.std = true] - this is standard fill attribute for object and should be used as this.fillatt + * @param {object} [args.attr = null] - object, derived from TAttFill + * @param {number} [args.pattern = undefined] - integer index of fill pattern + * @param {number} [args.color = undefined] - integer index of fill color + * @param {string} [args.color_as_svg = undefined] - color will be specified as SVG string, not as index from color palette + * @param {number} [args.kind = undefined] - some special kind which is handled differently from normal patterns + * @returns created handle + */ + TObjectPainter.prototype.createAttFill = function(args) { + if (!args || (typeof args !== 'object')) args = { std: true }; else + if (args._typename && args.fFillColor!==undefined && args.fFillStyle!==undefined) args = { attr: args, std: false }; + + if (args.std === undefined) args.std = true; + + var handler = args.std ? this.fillatt : null; + + if (!args.svg) args.svg = this.svg_canvas(); + + if (!handler) handler = new TAttFillHandler(args); + else if (!handler.changed || args.force) handler.SetArgs(args); + + if (args.std) this.fillatt = handler; + + // handler.used = false; // mark that fill handler is not yet used + + return handler; + } + + /** @summary call function for each painter in the pad + * @private */ + TObjectPainter.prototype.ForEachPainter = function(userfunc, kind) { + // Iterate over all known painters + + // special case of the painter set as pointer of first child of main element + var painter = this.AccessTopPainter(); + if (painter) { + if (kind !== "pads") userfunc(painter); + return; + } + + // iterate over all painters from pad list + var pp = this.pad_painter(); + if (pp) pp.ForEachPainterInPad(userfunc, kind); + } + + /** @summary indicate that redraw was invoked via interactive action (like context menu) + * desc use to catch such action by GED + * @private */ + TObjectPainter.prototype.InteractiveRedraw = function(arg, info) { + + if (arg == "pad") this.RedrawPad(); else + if (arg !== true) this.Redraw(); + + // inform GED that something changes + var pad_painter = this.pad_painter(); + if (pad_painter && pad_painter.InteractiveObjectRedraw) + pad_painter.InteractiveObjectRedraw(this); + + // inform server that drawopt changes + var canp = this.canv_painter(); + if (canp && canp.ProcessChanges) + canp.ProcessChanges(info, this.pad_painter()); + } + + /** @summary Redraw all objects in correspondent pad */ + TObjectPainter.prototype.RedrawPad = function() { + var pad_painter = this.pad_painter(); + if (pad_painter) pad_painter.Redraw(); + } + + /** @summary Switch tooltip mode in frame painter + * @private */ + TObjectPainter.prototype.SwitchTooltip = function(on) { + var fp = this.frame_painter(); + if (fp) fp.ProcessTooltipEvent(null, on); + // this is 3D control object + if (this.control && (typeof this.control.SwitchTooltip == 'function')) + this.control.SwitchTooltip(on); + } + + /** @summary Add drag interactive elements + * @private */ + TObjectPainter.prototype.AddDrag = function(callback) { + if (!JSROOT.gStyle.MoveResize) return; + + var pthis = this, drag_rect = null, pp = this.pad_painter(); + if (pp && pp._fast_drawing) return; + + function detectRightButton(event) { + if ('buttons' in event) return event.buttons === 2; + else if ('which' in event) return event.which === 3; + else if ('button' in event) return event.button === 2; + return false; + } + + function rect_width() { return Number(pthis.draw_g.attr("width")); } + function rect_height() { return Number(pthis.draw_g.attr("height")); } + + function MakeResizeElements(group, width, height, handler) { + function make(cursor,d) { + var clname = "js_" + cursor.replace('-','_'), + elem = group.select('.'+clname); + if (elem.empty()) elem = group.append('path').classed(clname,true); + elem.style('opacity', 0).style('cursor', cursor).attr('d',d); + if (handler) elem.call(handler); + } + + make("nw-resize", "M2,2h15v-5h-20v20h5Z"); + make("ne-resize", "M" + (width-2) + ",2h-15v-5h20v20h-5 Z"); + make("sw-resize", "M2," + (height-2) + "h15v5h-20v-20h5Z"); + make("se-resize", "M" + (width-2) + "," + (height-2) + "h-15v5h20v-20h-5Z"); + + make("w-resize", "M-3,18h5v" + Math.max(0, height - 2*18) + "h-5Z"); + make("e-resize", "M" + (width+3) + ",18h-5v" + Math.max(0, height - 2*18) + "h5Z"); + make("n-resize", "M18,-3v5h" + Math.max(0, width - 2*18) + "v-5Z"); + make("s-resize", "M18," + (height+3) + "v-5h" + Math.max(0, width - 2*18) + "v5Z"); + } + + function complete_drag() { + drag_rect.style("cursor", "auto"); + + if (!pthis.draw_g) { + drag_rect.remove(); + drag_rect = null; + return false; + } + + var oldx = Number(pthis.draw_g.attr("x")), + oldy = Number(pthis.draw_g.attr("y")), + newx = Number(drag_rect.attr("x")), + newy = Number(drag_rect.attr("y")), + newwidth = Number(drag_rect.attr("width")), + newheight = Number(drag_rect.attr("height")); + + if (callback.minwidth && newwidth < callback.minwidth) newwidth = callback.minwidth; + if (callback.minheight && newheight < callback.minheight) newheight = callback.minheight; + + var change_size = (newwidth !== rect_width()) || (newheight !== rect_height()), + change_pos = (newx !== oldx) || (newy !== oldy); + + pthis.draw_g.attr('x', newx).attr('y', newy) + .attr("transform", "translate(" + newx + "," + newy + ")") + .attr('width', newwidth).attr('height', newheight); + + drag_rect.remove(); + drag_rect = null; + + pthis.SwitchTooltip(true); + + MakeResizeElements(pthis.draw_g, newwidth, newheight); + + if (change_size || change_pos) { + if (change_size && ('resize' in callback)) callback.resize(newwidth, newheight); + if (change_pos && ('move' in callback)) callback.move(newx, newy, newx - oldxx, newy-oldy); + + if (change_size || change_pos) { + if ('obj' in callback) { + callback.obj.fX1NDC = newx / pthis.pad_width(); + callback.obj.fX2NDC = (newx + newwidth) / pthis.pad_width(); + callback.obj.fY1NDC = 1 - (newy + newheight) / pthis.pad_height(); + callback.obj.fY2NDC = 1 - newy / pthis.pad_height(); + callback.obj.modified_NDC = true; // indicate that NDC was interactively changed, block in updated + } + if ('redraw' in callback) callback.redraw(); + } + } + + return change_size || change_pos; + } + + var prefix = "", drag_move, drag_resize; + if (JSROOT._test_d3_ === 3) { + prefix = "drag"; + drag_move = d3.behavior.drag().origin(Object); + drag_resize = d3.behavior.drag().origin(Object); + } else { + drag_move = d3.drag().subject(Object); + drag_resize = d3.drag().subject(Object); + } + + drag_move + .on(prefix+"start", function() { + if (detectRightButton(d3.event.sourceEvent)) return; + + JSROOT.Painter.closeMenu(); // close menu + + pthis.SwitchTooltip(false); // disable tooltip + + d3.event.sourceEvent.preventDefault(); + d3.event.sourceEvent.stopPropagation(); + + var handle = { + acc_x1: Number(pthis.draw_g.attr("x")), + acc_y1: Number(pthis.draw_g.attr("y")), + pad_w: pthis.pad_width() - rect_width(), + pad_h: pthis.pad_height() - rect_height(), + drag_tm: new Date() + }; + + drag_rect = d3.select(pthis.draw_g.node().parentNode).append("rect") + .classed("zoom", true) + .attr("x", handle.acc_x1) + .attr("y", handle.acc_y1) + .attr("width", rect_width()) + .attr("height", rect_height()) + .style("cursor", "move") + .style("pointer-events","none") // let forward double click to underlying elements + .property('drag_handle', handle); + + + }).on("drag", function() { + if (!drag_rect) return; + + d3.event.sourceEvent.preventDefault(); + d3.event.sourceEvent.stopPropagation(); + + var handle = drag_rect.property('drag_handle'); + + handle.acc_x1 += d3.event.dx; + handle.acc_y1 += d3.event.dy; + + drag_rect.attr("x", Math.min( Math.max(handle.acc_x1, 0), handle.pad_w)) + .attr("y", Math.min( Math.max(handle.acc_y1, 0), handle.pad_h)); + + }).on(prefix+"end", function() { + if (!drag_rect) return; + + d3.event.sourceEvent.preventDefault(); + + var handle = drag_rect.property('drag_handle'); + + if (complete_drag() === false) { + var spent = (new Date()).getTime() - handle.drag_tm.getTime(); + if (callback.ctxmenu && (spent > 600)) { + var rrr = resize_se.node().getBoundingClientRect(); + pthis.ShowContextMenu('main', { clientX: rrr.left, clientY: rrr.top } ); + } else if (callback.canselect && (spent <= 600)) { + pthis.canv_painter().SelectObjectPainter(pthis); + } + } + }); + + drag_resize + .on(prefix+"start", function() { + if (detectRightButton(d3.event.sourceEvent)) return; + + d3.event.sourceEvent.stopPropagation(); + d3.event.sourceEvent.preventDefault(); + + pthis.SwitchTooltip(false); // disable tooltip + + var handle = { + acc_x1: Number(pthis.draw_g.attr("x")), + acc_y1: Number(pthis.draw_g.attr("y")), + pad_w: pthis.pad_width(), + pad_h: pthis.pad_height() + }; + + handle.acc_x2 = handle.acc_x1 + rect_width(); + handle.acc_y2 = handle.acc_y1 + rect_height(); + + drag_rect = d3.select(pthis.draw_g.node().parentNode) + .append("rect") + .classed("zoom", true) + .style("cursor", d3.select(this).style("cursor")) + .attr("x", handle.acc_x1) + .attr("y", handle.acc_y1) + .attr("width", handle.acc_x2 - handle.acc_x1) + .attr("height", handle.acc_y2 - handle.acc_y1) + .property('drag_handle', handle); + + }).on("drag", function() { + if (!drag_rect) return; + + d3.event.sourceEvent.preventDefault(); + d3.event.sourceEvent.stopPropagation(); + + var handle = drag_rect.property('drag_handle'), + dx = d3.event.dx, dy = d3.event.dy, elem = d3.select(this); + + if (elem.classed('js_nw_resize')) { handle.acc_x1 += dx; handle.acc_y1 += dy; } + else if (elem.classed('js_ne_resize')) { handle.acc_x2 += dx; handle.acc_y1 += dy; } + else if (elem.classed('js_sw_resize')) { handle.acc_x1 += dx; handle.acc_y2 += dy; } + else if (elem.classed('js_se_resize')) { handle.acc_x2 += dx; handle.acc_y2 += dy; } + else if (elem.classed('js_w_resize')) { handle.acc_x1 += dx; } + else if (elem.classed('js_n_resize')) { handle.acc_y1 += dy; } + else if (elem.classed('js_e_resize')) { handle.acc_x2 += dx; } + else if (elem.classed('js_s_resize')) { handle.acc_y2 += dy; } + + var x1 = Math.max(0, handle.acc_x1), x2 = Math.min(handle.acc_x2, handle.pad_w), + y1 = Math.max(0, handle.acc_y1), y2 = Math.min(handle.acc_y2, handle.pad_h); + + drag_rect.attr("x", x1).attr("y", y1).attr("width", Math.max(0, x2-x1)).attr("height", Math.max(0, y2-y1)); + + }).on(prefix+"end", function() { + if (!drag_rect) return; + + d3.event.sourceEvent.preventDefault(); + + complete_drag(); + }); + + if (!callback.only_resize) + this.draw_g.style("cursor", "move").call(drag_move); + + MakeResizeElements(this.draw_g, rect_width(), rect_height(), drag_resize); + } + + /** @summary Activate context menu via touch events + * @private */ + TObjectPainter.prototype.startTouchMenu = function(kind) { + // method to let activate context menu via touch handler + + var arr = d3.touches(this.svg_frame().node()); + if (arr.length != 1) return; + + if (!kind || (kind=="")) kind = "main"; + var fld = "touch_" + kind; + + d3.event.preventDefault(); + d3.event.stopPropagation(); + + this[fld] = { dt: new Date(), pos: arr[0] }; + + this.svg_frame().on("touchcancel", this.endTouchMenu.bind(this, kind)) + .on("touchend", this.endTouchMenu.bind(this, kind)); + } + + /** @summary Close context menu, started via touch events + * @private */ + TObjectPainter.prototype.endTouchMenu = function(kind) { + var fld = "touch_" + kind; + + if (! (fld in this)) return; + + d3.event.preventDefault(); + d3.event.stopPropagation(); + + var diff = new Date().getTime() - this[fld].dt.getTime(); + + this.svg_frame().on("touchcancel", null) + .on("touchend", null); + + if (diff>500) { + var rect = this.svg_frame().node().getBoundingClientRect(); + this.ShowContextMenu(kind, { clientX: rect.left + this[fld].pos[0], + clientY: rect.top + this[fld].pos[1] } ); + } + + delete this[fld]; + } + + /** @summary Add color selection menu entries + * @private */ + TObjectPainter.prototype.AddColorMenuEntry = function(menu, name, value, set_func, fill_kind) { + if (value === undefined) return; + menu.add("sub:"+name, function() { + // todo - use jqury dialog here + var useid = (typeof value !== 'string'); + var col = prompt("Enter color " + (useid ? "(only id number)" : "(name or id)"), value); + if (col == null) return; + var id = parseInt(col); + if (!isNaN(id) && (JSROOT.Painter.root_colors[id] !== undefined)) { + col = JSROOT.Painter.root_colors[id]; + } else { + if (useid) return; + } + set_func.bind(this)(useid ? id : col); + }); + var useid = (typeof value !== 'string'); + for (var n=-1;n<11;++n) { + if ((n<0) && useid) continue; + if ((n==10) && (fill_kind!==1)) continue; + var col = (n<0) ? 'none' : JSROOT.Painter.root_colors[n]; + if ((n==0) && (fill_kind==1)) col = 'none'; + var svg = "<svg width='100' height='18' style='margin:0px;background-color:" + col + "'><text x='4' y='12' style='font-size:12px' fill='" + (n==1 ? "white" : "black") + "'>"+col+"</text></svg>"; + menu.addchk((value == (useid ? n : col)), svg, (useid ? n : col), set_func); + } + menu.add("endsub:"); + } + + /** @summary Add size selection menu entries + * @private */ + TObjectPainter.prototype.AddSizeMenuEntry = function(menu, name, min, max, step, value, set_func) { + if (value === undefined) return; + + menu.add("sub:"+name, function() { + // todo - use jqury dialog here + var entry = value.toFixed(4); + if (step>=0.1) entry = value.toFixed(2); + if (step>=1) entry = value.toFixed(0); + var val = prompt("Enter value of " + name, entry); + if (val==null) return; + var val = parseFloat(val); + if (!isNaN(val)) set_func.bind(this)((step>=1) ? Math.round(val) : val); + }); + for (var val=min;val<=max;val+=step) { + var entry = val.toFixed(2); + if (step>=0.1) entry = val.toFixed(1); + if (step>=1) entry = val.toFixed(0); + menu.addchk((Math.abs(value - val) < step/2), entry, val, set_func); + } + menu.add("endsub:"); + } + + /** @summary execute selected menu command, either locally or remotely + * @private */ + TObjectPainter.prototype.ExecuteMenuCommand = function(method) { + + if (method.fName == "Inspect") { + this.ShowInpsector(); + return true; + } + + var canvp = this.canv_painter(); + if (!canvp) return false; + + if ((method.fName == "FitPanel") && canvp.ActivateFitPanel) { + canvp.ActivateFitPanel(this); + return true; + } + + if (canvp.ActivateGed && ((method.fName == "DrawPanel") || (method.fName == "SetLineAttributes") + || (method.fName == "SetFillAttributes") || (method.fName == "SetMarkerAttributes"))) { + canvp.ActivateGed(this); // activate GED + return true; + } + + return false; + } + + /** @summary Fill object menu in web canvas + * @private */ + TObjectPainter.prototype.FillObjectExecMenu = function(menu, kind, call_back) { + + var canvp = this.canv_painter(); + + if (!this.snapid || !canvp || !canvp._websocket || canvp._getmenu_callback) + return JSROOT.CallBack(call_back); + + function DoExecMenu(arg) { + var execp = this.exec_painter || this, + canvp = execp.canv_painter(), + item = execp.args_menu_items[parseInt(arg)]; + + if (!item || !item.fName) return; + + if (canvp.MethodsDialog && (item.fArgs!==undefined)) + return canvp.MethodsDialog(execp, item, execp.args_menu_id); + + if (execp.ExecuteMenuCommand(item)) return; + + if (canvp._websocket && execp.args_menu_id) { + console.log('execute method ' + item.fExec + ' for object ' + execp.args_menu_id); + canvp.SendWebsocket('OBJEXEC:' + execp.args_menu_id + ":" + item.fExec); + } + } + + function DoFillMenu(_menu, _reqid, _call_back, items, replyid) { + + // avoid multiple call of the callback after timeout + if (!canvp._getmenu_callback) return; + delete canvp._getmenu_callback; + + if (_reqid !== replyid) + console.error('missmatch between request ' + _reqid + ' and reply ' + replyid + ' identifiers'); + + if (items && items.length) { + _menu.add("separator"); + _menu.add("sub:Online"); + + this.args_menu_items = items; + this.args_menu_id = replyid; + + var lastclname; + + for (var n=0;n<items.length;++n) { + var item = items[n]; + + if (item.fClassName && lastclname && (lastclname!=item.fClassName)) _menu.add("separator"); + lastclname = item.fClassName; + + if ((item.fChecked === undefined) || (item.fChecked < 0)) + _menu.add(item.fName, n, DoExecMenu); + else + _menu.addchk(item.fChecked, item.fName, n, DoExecMenu); + } + + _menu.add("endsub:"); + } + + JSROOT.CallBack(_call_back); + } + + var reqid = this.snapid; + if (kind) reqid += "#" + kind; // use # to separate object id from member specifier like 'x' or 'z' + + // if menu painter differs from this, remember it for further usage + if (menu.painter) + menu.painter.exec_painter = (menu.painter !== this) ? this : undefined; + + canvp._getmenu_callback = DoFillMenu.bind(this, menu, reqid, call_back); + + canvp.SendWebsocket('GETMENU:' + reqid); // request menu items for given painter + + setTimeout(canvp._getmenu_callback, 2000); // set timeout to avoid menu hanging + } + + /** @summary remove all created draw attributes + * @private */ + TObjectPainter.prototype.DeleteAtt = function() { + delete this.lineatt; + delete this.fillatt; + delete this.markeratt; + } + + /** @summary Fill context menu for graphical attributes + * @private */ + TObjectPainter.prototype.FillAttContextMenu = function(menu, preffix) { + // this method used to fill entries for different attributes of the object + // like TAttFill, TAttLine, .... + // all menu call-backs need to be rebind, while menu can be used from other painter + + if (!preffix) preffix = ""; + + if (this.lineatt && this.lineatt.used) { + menu.add("sub:"+preffix+"Line att"); + this.AddSizeMenuEntry(menu, "width", 1, 10, 1, this.lineatt.width, + function(arg) { this.lineatt.Change(undefined, parseInt(arg)); this.InteractiveRedraw(); }.bind(this)); + this.AddColorMenuEntry(menu, "color", this.lineatt.color, + function(arg) { this.lineatt.Change(arg); this.InteractiveRedraw(); }.bind(this)); + menu.add("sub:style", function() { + var id = prompt("Enter line style id (1-solid)", 1); + if (id == null) return; + id = parseInt(id); + if (isNaN(id) || !JSROOT.Painter.root_line_styles[id]) return; + this.lineatt.Change(undefined, undefined, id); + this.InteractiveRedraw(); + }.bind(this)); + for (var n=1;n<11;++n) { + + var dash = JSROOT.Painter.root_line_styles[n]; + + var svg = "<svg width='100' height='18'><text x='1' y='12' style='font-size:12px'>" + n + "</text><line x1='30' y1='8' x2='100' y2='8' stroke='black' stroke-width='3' stroke-dasharray='" + dash + "'></line></svg>"; + + menu.addchk((this.lineatt.style==n), svg, n, function(arg) { this.lineatt.Change(undefined, undefined, parseInt(arg)); this.InteractiveRedraw(); }.bind(this)); + } + menu.add("endsub:"); + menu.add("endsub:"); + + if (('excl_side' in this.lineatt) && (this.lineatt.excl_side!==0)) { + menu.add("sub:Exclusion"); + menu.add("sub:side"); + for (var side=-1;side<=1;++side) + menu.addchk((this.lineatt.excl_side==side), side, side, function(arg) { + this.lineatt.ChangeExcl(parseInt(arg)); + this.InteractiveRedraw(); + }.bind(this)); + menu.add("endsub:"); + + this.AddSizeMenuEntry(menu, "width", 10, 100, 10, this.lineatt.excl_width, + function(arg) { this.lineatt.ChangeExcl(undefined, parseInt(arg)); this.InteractiveRedraw(); }.bind(this)); + + menu.add("endsub:"); + } + } + + if (this.fillatt && this.fillatt.used) { + menu.add("sub:"+preffix+"Fill att"); + this.AddColorMenuEntry(menu, "color", this.fillatt.colorindx, + function(arg) { this.fillatt.Change(parseInt(arg), undefined, this.svg_canvas()); this.InteractiveRedraw(); }.bind(this), this.fillatt.kind); + menu.add("sub:style", function() { + var id = prompt("Enter fill style id (1001-solid, 3000..3010)", this.fillatt.pattern); + if (id == null) return; + id = parseInt(id); + if (isNaN(id)) return; + this.fillatt.Change(undefined, id, this.svg_canvas()); + this.InteractiveRedraw(); + }.bind(this)); + + var supported = [1, 1001, 3001, 3002, 3003, 3004, 3005, 3006, 3007, 3010, 3021, 3022]; + + for (var n=0; n<supported.length; ++n) { + + var sample = this.createAttFill({ std: false, pattern: supported[n], color: this.fillatt.colorindx || 1 }), + svg = "<svg width='100' height='18'><text x='1' y='12' style='font-size:12px'>" + supported[n].toString() + "</text><rect x='40' y='0' width='60' height='18' stroke='none' fill='" + sample.fillcolor() + "'></rect></svg>"; + + menu.addchk(this.fillatt.pattern == supported[n], svg, supported[n], function(arg) { + this.fillatt.Change(undefined, parseInt(arg), this.svg_canvas()); + this.InteractiveRedraw(); + }.bind(this)); + } + menu.add("endsub:"); + menu.add("endsub:"); + } + + if (this.markeratt && this.markeratt.used) { + menu.add("sub:"+preffix+"Marker att"); + this.AddColorMenuEntry(menu, "color", this.markeratt.color, + function(arg) { this.markeratt.Change(arg); this.InteractiveRedraw(); }.bind(this)); + this.AddSizeMenuEntry(menu, "size", 0.5, 6, 0.5, this.markeratt.size, + function(arg) { this.markeratt.Change(undefined, undefined, parseFloat(arg)); this.InteractiveRedraw(); }.bind(this)); + + menu.add("sub:style"); + var supported = [1,2,3,4,5,6,7,8,21,22,23,24,25,26,27,28,29,30,31,32,33,34]; + + for (var n=0; n<supported.length; ++n) { + + var clone = new TAttMarkerHandler({ style: supported[n], color: this.markeratt.color, size: 1.7 }), + svg = "<svg width='60' height='18'><text x='1' y='12' style='font-size:12px'>" + supported[n].toString() + "</text><path stroke='black' fill='" + (clone.fill ? "black" : "none") + "' d='" + clone.create(40,8) + "'></path></svg>"; + + menu.addchk(this.markeratt.style == supported[n], svg, supported[n], + function(arg) { this.markeratt.Change(undefined, parseInt(arg)); this.InteractiveRedraw(); }.bind(this)); + } + menu.add("endsub:"); + menu.add("endsub:"); + } + } + + /** @summary Fill context menu for text attributes + * @private */ + TObjectPainter.prototype.TextAttContextMenu = function(menu, prefix) { + // for the moment, text attributes accessed directly from objects + + var obj = this.GetObject(); + if (!obj || !('fTextColor' in obj)) return; + + menu.add("sub:" + (prefix ? prefix : "Text")); + this.AddColorMenuEntry(menu, "color", obj.fTextColor, + function(arg) { this.GetObject().fTextColor = parseInt(arg); this.InteractiveRedraw(); }.bind(this)); + + var align = [11, 12, 13, 21, 22, 23, 31, 32, 33], + hnames = ['left', 'centered' , 'right'], + vnames = ['bottom', 'centered', 'top']; + + menu.add("sub:align"); + for (var n=0; n<align.length; ++n) { + menu.addchk(align[n] == obj.fTextAlign, + align[n], align[n], + // align[n].toString() + "_h:" + hnames[Math.floor(align[n]/10) - 1] + "_v:" + vnames[align[n]%10-1], align[n], + function(arg) { this.GetObject().fTextAlign = parseInt(arg); this.InteractiveRedraw(); }.bind(this)); + } + menu.add("endsub:"); + + menu.add("sub:font"); + for (var n=1; n<16; ++n) { + menu.addchk(n == Math.floor(obj.fTextFont/10), n, n, + function(arg) { this.GetObject().fTextFont = parseInt(arg)*10+2; this.InteractiveRedraw(); }.bind(this)); + } + menu.add("endsub:"); + + menu.add("endsub:"); + } + + /** @symmary Show object in inspector */ + TObjectPainter.prototype.ShowInpsector = function() { + JSROOT.draw(this.divid, this.GetObject(), 'inspect'); + } + + /** @symmary Fill context menu for the object + * @private */ + TObjectPainter.prototype.FillContextMenu = function(menu) { + + var title = this.GetTipName(); + if (this.GetObject() && ('_typename' in this.GetObject())) + title = this.GetObject()._typename + "::" + title; + + menu.add("header:"+ title); + + this.FillAttContextMenu(menu); + + if (menu.size()>0) menu.add('Inspect', this.ShowInpsector); + + return menu.size() > 0; + } + + /** @symmary returns function used to display object status + * @private */ + TObjectPainter.prototype.GetShowStatusFunc = function() { + // return function used to display object status + // automatically disabled when drawing is enlarged - status line will be invisible + + var pp = this.canv_painter(), res = JSROOT.Painter.ShowStatus; + + if (pp && pp.use_openui && (typeof pp.fullShowStatus === 'function')) res = pp.fullShowStatus.bind(pp); + + if (res && (this.enlarge_main('state')==='on')) res = null; + + return res; + } + + /** @symmary shows objects status + * @private */ + TObjectPainter.prototype.ShowObjectStatus = function() { + // method called normally when mouse enter main object element + + var obj = this.GetObject(), + status_func = this.GetShowStatusFunc(); + + if (obj && status_func) status_func(this.GetItemName() || obj.fName, obj.fTitle || obj._typename, obj._typename); + } + + + /** @summary try to find object by name in list of pad primitives + * @desc used to find title drawing + * @private */ + TObjectPainter.prototype.FindInPrimitives = function(objname) { + + var painter = this.pad_painter(); + if (!painter || !painter.pad) return null; + + if (painter.pad.fPrimitives) + for (var n=0;n<painter.pad.fPrimitives.arr.length;++n) { + var prim = painter.pad.fPrimitives.arr[n]; + if (('fName' in prim) && (prim.fName === objname)) return prim; + } + + return null; + } + + /** @summary Try to find painter for specified object + * @desc can be used to find painter for some special objects, registered as + * histogram functions + * @private */ + TObjectPainter.prototype.FindPainterFor = function(selobj,selname,seltype) { + + var painter = this.pad_painter(); + var painters = painter ? painter.painters : null; + if (!painters) return null; + + for (var n = 0; n < painters.length; ++n) { + var pobj = painters[n].GetObject(); + if (!pobj) continue; + + if (selobj && (pobj === selobj)) return painters[n]; + if (!selname && !seltype) continue; + if (selname && (pobj.fName !== selname)) continue; + if (seltype && (pobj._typename !== seltype)) continue; + return painters[n]; + } + + return null; + } + + /** @summary Remove painter from list of painters and cleanup all drawings */ + TObjectPainter.prototype.DeleteThis = function() { + var pp = this.pad_painter(); + if (pp) { + var k = pp.painters.indexOf(this); + if (k>=0) pp.painters.splice(k,1); + } + + this.Cleanup(); + } + + /** @summary Configure user-defined tooltip callback + * + * @desc Hook for the users to get tooltip information when mouse cursor moves over frame area + * call_back function will be called every time when new data is selected + * when mouse leave frame area, call_back(null) will be called + */ + + TObjectPainter.prototype.ConfigureUserTooltipCallback = function(call_back, user_timeout) { + + if (!call_back || (typeof call_back !== 'function')) { + delete this.UserTooltipCallback; + delete this.UserTooltipTimeout; + return; + } + + if (user_timeout===undefined) user_timeout = 500; + + this.UserTooltipCallback = call_back; + this.UserTooltipTimeout = user_timeout; + } + + /** @summary Configure user-defined click handler + * + * @desc Function will be called every time when frame click was perfromed + * As argument, tooltip object with selected bins will be provided + * If handler function returns true, default handling of click will be disabled + */ + + TObjectPainter.prototype.ConfigureUserClickHandler = function(handler) { + var fp = this.frame_painter(); + if (fp && typeof fp.ConfigureUserClickHandler == 'function') + fp.ConfigureUserClickHandler(handler); + } + + /** @summary Configure user-defined dblclick handler + * + * @desc Function will be called every time when double click was called + * As argument, tooltip object with selected bins will be provided + * If handler function returns true, default handling of dblclick (unzoom) will be disabled + */ + + TObjectPainter.prototype.ConfigureUserDblclickHandler = function(handler) { + var fp = this.frame_painter(); + if (fp && typeof fp.ConfigureUserDblclickHandler == 'function') + fp.ConfigureUserDblclickHandler(handler); + } + + /** @summary Check if user-defined tooltip callback is configured + * @returns {Boolean} + * @private */ + TObjectPainter.prototype.IsUserTooltipCallback = function() { + return typeof this.UserTooltipCallback == 'function'; + } + + /** @summary Provide tooltips data to user-defained function + * @param {object} data - tooltip data + * @private */ + TObjectPainter.prototype.ProvideUserTooltip = function(data) { + + if (!this.IsUserTooltipCallback()) return; + + if (this.UserTooltipTimeout <= 0) + return this.UserTooltipCallback(data); + + if (typeof this.UserTooltipTHandle != 'undefined') { + clearTimeout(this.UserTooltipTHandle); + delete this.UserTooltipTHandle; + } + + if (data==null) + return this.UserTooltipCallback(data); + + this.UserTooltipTHandle = setTimeout(function(d) { + // only after timeout user function will be called + delete this.UserTooltipTHandle; + this.UserTooltipCallback(d); + }.bind(this, data), this.UserTooltipTimeout); + } + + /** @summary Redraw object + * + * @desc Basic method, should be reimplemented in all derived objects + * for the case when drawing should be repeated + * @abstract + */ + + TObjectPainter.prototype.Redraw = function() { + } + + /** @summary Start text drawing + * + * @desc required before any text can be drawn + */ + TObjectPainter.prototype.StartTextDrawing = function(font_face, font_size, draw_g, max_font_size) { + // we need to preserve font to be able rescale at the end + + if (!draw_g) draw_g = this.draw_g; + + var font = (font_size==='font') ? font_face : JSROOT.Painter.getFontDetails(font_face, font_size); + + var pp = this.pad_painter(); + + draw_g.call(font.func); + + draw_g.property('draw_text_completed', false) + .property('text_font', font) + .property('mathjax_use', false) + .property('text_factor', 0.) + .property('max_text_width', 0) // keep maximal text width, use it later + .property('max_font_size', max_font_size) + .property("_fast_drawing", pp && pp._fast_drawing); + + if (draw_g.property("_fast_drawing")) + draw_g.property("_font_too_small", (max_font_size && (max_font_size<5)) || (font.size < 4)); + } + + /** @summary function used to remember maximal text scaling factor + * @private */ + TObjectPainter.prototype.TextScaleFactor = function(value, draw_g) { + if (!draw_g) draw_g = this.draw_g; + if (value && (value > draw_g.property('text_factor'))) draw_g.property('text_factor', value); + } + + /** @summary getBBox does not work in mozilla when object is not displayed or not visible :( + * getBoundingClientRect() returns wrong sizes for MathJax + * are there good solution? + * @private */ + TObjectPainter.prototype.GetBoundarySizes = function(elem) { + if (elem===null) { console.warn('empty node in GetBoundarySizes'); return { width:0, height:0 }; } + var box = elem.getBoundingClientRect(); // works always, but returns sometimes results in ex values, which is difficult to use + if (parseFloat(box.width) > 0) box = elem.getBBox(); // check that elements visible, request precise value + var res = { width : parseInt(box.width), height : parseInt(box.height) }; + if ('left' in box) { res.x = parseInt(box.left); res.y = parseInt(box.right); } else + if ('x' in box) { res.x = parseInt(box.x); res.y = parseInt(box.y); } + return res; + } + + /** @summary Finish text drawing + * + * @desc Should be called to complete all text drawing operations + */ + TObjectPainter.prototype.FinishTextDrawing = function(draw_g, call_ready) { + if (!draw_g) draw_g = this.draw_g; + + if (draw_g.property('draw_text_completed')) { + JSROOT.CallBack(call_ready); + return draw_g.property('max_text_width'); + } + + if (call_ready) draw_g.node().text_callback = call_ready; + + var svgs = null; + + if (draw_g.property('mathjax_use')) { + + var missing = 0; + svgs = draw_g.selectAll(".math_svg"); + + svgs.each(function() { + var fo_g = d3.select(this); + if (fo_g.node().parentNode !== draw_g.node()) return; + if (fo_g.select("svg").empty()) missing++; + }); + + // is any svg missing we should wait until drawing is really finished + if (missing) return; + } + + //if (!svgs) svgs = draw_g.selectAll(".math_svg"); + + //var missing = 0; + //svgs.each(function() { + // var fo_g = d3.select(this); + // if (fo_g.node().parentNode !== draw_g.node()) return; + // var entry = fo_g.property('_element'); + // if (d3.select(entry).select("svg").empty()) missing++; + //}); + //if (missing) console.warn('STILL SVG MISSING', missing); + + // adjust font size (if there are normal text) + var painter = this, + svg_factor = 0, + f = draw_g.property('text_factor'), + font = draw_g.property('text_font'), + max_sz = draw_g.property('max_font_size'), + font_size = font.size; + + if ((f > 0) && ((f < 0.9) || (f > 1))) + font.size = Math.floor(font.size/f); + + if (max_sz && (font.size > max_sz)) + font.size = max_sz; + + if (font.size != font_size) { + draw_g.call(font.func); + font_size = font.size; + } + + // first analyze all MathJax SVG and repair width/height attributes + if (svgs) + svgs.each(function() { + var fo_g = d3.select(this); + if (fo_g.node().parentNode !== draw_g.node()) return; + + var vvv = fo_g.select("svg"); + if (vvv.empty()) { + console.log('MathJax SVG ouptut error'); + return; + } + + function transform(value) { + if (!value || (typeof value !== "string")) return null; + if (value.indexOf("ex")!==value.length-2) return null; + value = parseFloat(value.substr(0, value.length-2)); + return isNaN(value) ? null : value*font_size*0.5; + } + + var width = transform(vvv.attr("width")), + height = transform(vvv.attr("height")), + valign = vvv.attr("style"); + + if (valign && valign.indexOf("vertical-align:")==0 && valign.indexOf("ex;")==valign.length-3) { + valign = transform(valign.substr(16, valign.length-17)); + } else { + valign = null; + } + + width = (!width || (width<=0.5)) ? 1 : Math.round(width); + height = (!height || (height<=0.5)) ? 1 : Math.round(height); + + vvv.attr("width", width).attr('height', height).attr("style",null); + + if (!JSROOT.nodejs) { + var box = painter.GetBoundarySizes(fo_g.node()); + width = 1.05*box.width; height = 1.05*box.height; + } + + var arg = fo_g.property("_arg"); + + arg.valign = valign; + + if (arg.scale) + svg_factor = Math.max(svg_factor, width / arg.width, height / arg.height); + }); + + if (svgs) + svgs.each(function() { + var fo_g = d3.select(this); + // only direct parent + if (fo_g.node().parentNode !== draw_g.node()) return; + + var arg = fo_g.property("_arg"), + m = fo_g.select("svg"), // MathJax svg + mw = parseInt(m.attr("width")), + mh = parseInt(m.attr("height")); + + if (!isNaN(mh) && !isNaN(mw)) { + if (svg_factor > 0.) { + mw = mw/svg_factor; + mh = mh/svg_factor; + m.attr("width", Math.round(mw)).attr("height", Math.round(mh)); + } + } else { + var box = painter.GetBoundarySizes(fo_g.node()); // sizes before rotation + mw = box.width || mw || 100; + mh = box.height || mh || 10; + } + + if ((svg_factor > 0.) && arg.valign) arg.valign = arg.valign/svg_factor; + + if (arg.valign===null) arg.valign = (font_size - mh)/2; + + var sign = { x:1, y:1 }, nx = "x", ny = "y"; + if (arg.rotate == 180) { sign.x = sign.y = -1; } else + if ((arg.rotate == 270) || (arg.rotate == 90)) { + sign.x = (arg.rotate == 270) ? -1 : 1; + sign.y = -sign.x; + nx = "y"; ny = "x"; // replace names to which align applied + } + + if (arg.align[0] == 'middle') arg[nx] += sign.x*(arg.width - mw)/2; else + if (arg.align[0] == 'end') arg[nx] += sign.x*(arg.width - mw); + + if (arg.align[1] == 'middle') arg[ny] += sign.y*(arg.height - mh)/2; else + if (arg.align[1] == 'bottom') arg[ny] += sign.y*(arg.height - mh); else + if (arg.align[1] == 'bottom-base') arg[ny] += sign.y*(arg.height - mh - arg.valign); + + var trans = "translate("+arg.x+","+arg.y+")"; + if (arg.rotate) trans += " rotate("+arg.rotate+")"; + + fo_g.attr('transform', trans).attr('visibility', null).property('_arg',null); + }); + + // now hidden text after rescaling can be shown + draw_g.selectAll('.hidden_text').attr('visibility', null).attr('class', null).each(function() { + // case when scaling is changed and we can shift text position only after final text size is defined + var txt = d3.select(this), + arg = txt.property("_arg"); + + txt.property("_arg", null); + + if (!arg) return; + + if (JSROOT.nodejs) { + if (arg.scale && (f>0)) { arg.box.width = arg.box.width/f; arg.box.height = arg.box.height/f; } + } else if (!arg.plain && !arg.fast) { + // exact box dimension only required when complex text was build + arg.box = painter.GetBoundarySizes(txt.node()); + } + + // if (arg.text.length>20) console.log(arg.box, arg.align, arg.x, arg.y, 'plain', arg.plain, 'inside', arg.width, arg.height); + + if (arg.width) { + // adjust x position when scale into specified rectangle + if (arg.align[0]=="middle") arg.x += arg.width/2; else + if (arg.align[0]=="end") arg.x += arg.width; + } + + arg.dx = arg.dy = 0; + + if (arg.plain) { + txt.attr("text-anchor", arg.align[0]); + } else { + txt.attr("text-anchor", "start"); + arg.dx = ((arg.align[0]=="middle") ? -0.5 : ((arg.align[0]=="end") ? -1 : 0)) * arg.box.width; + } + + if (arg.height) { + if (arg.align[1].indexOf('bottom')===0) arg.y += arg.height; else + if (arg.align[1] == 'middle') arg.y += arg.height/2; + } + + if (arg.plain) { + if (arg.align[1] == 'top') txt.attr("dy", ".8em"); else + if (arg.align[1] == 'middle') { + if (JSROOT.browser.isIE || JSROOT.nodejs) txt.attr("dy", ".4em"); else txt.attr("dominant-baseline", "middle"); + } + } else { + arg.dy = ((arg.align[1] == 'top') ? (arg.top_shift || 1) : (arg.align[1] == 'middle') ? (arg.mid_shift || 0.5) : 0) * arg.box.height; + } + + // if (arg.text.length>20) console.log(arg.x, arg.y, arg.dx, arg.dy); + + if (!arg.rotate) { arg.x += arg.dx; arg.y += arg.dy; arg.dx = arg.dy = 0; } + + // use translate and then rotate to avoid complex sign calculations + var trans = (arg.x || arg.y) ? "translate("+Math.round(arg.x)+","+Math.round(arg.y)+")" : ""; + if (arg.rotate) trans += " rotate("+Math.round(arg.rotate)+")"; + if (arg.dx || arg.dy) trans += " translate("+Math.round(arg.dx)+","+Math.round(arg.dy)+")"; + if (trans) txt.attr("transform", trans); + + if (JSROOT.browser.isWebKit && draw_g.node().insertAdjacentHTML && arg.large_latex) { + // this is workaround for sporadic placement problem in Chrome/Opera + // Due to unclear reasons tspan elements placed wrongly + // Full refresh of created elements (including text itself) solves problem + var html = txt.node().outerHTML; + txt.remove(); + draw_g.node().insertAdjacentHTML( 'beforeend', html ); + } + }); + + if (!call_ready) call_ready = draw_g.node().text_callback; + draw_g.node().text_callback = null; + + draw_g.property('draw_text_completed', true); + + // if specified, call ready function + JSROOT.CallBack(call_ready); + + return draw_g.property('max_text_width'); + } + + /** @ummary draw TLatex inside element + * + * @desc attempt to implement subset of TLatex with plain SVG text and tspan elements + * @private + */ + TObjectPainter.prototype.produceLatex = function(node, label, arg, curr) { + + if (!curr) { + // initial dy = -0.1 is to move complete from very bottom line like with normal text drawing + curr = { lvl: 0, x: 0, y: 0, dx: 0, dy: -0.1, fsize: arg.font_size, parent: null }; + arg.mainnode = node.node(); + } + + function extend_pos(pos, value) { + + var dx1, dx2, dy1, dy2; + + if (typeof value == 'string') { + if (!pos.rect) pos.rect = { x: pos.x, y: pos.y, height: 0, width: 0 }; + dx1 = -pos.x; + pos.x += value.length * arg.font.aver_width * pos.fsize; + dx2 = pos.x; + dy1 = -(pos.y-pos.fsize*1.1); + dy2 = pos.y + pos.fsize*0.1; + } else { + if (!pos.rect) pos.rect = JSROOT.extend({}, value); + dx1 = -value.x; + dx2 = value.x+value.width; + dy1 = -value.y; + dy2 = value.y+value.height; + } + + var rect = pos.rect; + + dx1 += rect.x; + dx2 -= (rect.x+rect.width); + dy1 += rect.y; + dy2 -= (rect.y+rect.height); + + if (dx1>0) { rect.x -= dx1; rect.width += dx1; } + if (dx2>0) rect.width += dx2; + if (dy1>0) { rect.y -= dy1; rect.height += dy1; } + if (dy2>0) rect.height+=dy2; + + if (pos.parent) return extend_pos(pos.parent, rect) + + // calculate dimensions for the + arg.text_rect = rect; + + var h = rect.height, mid = rect.y + rect.height/2; + + if (h>0) { + arg.mid_shift = -mid/h || 0.001; // relative shift to get latex middle at given point + arg.top_shift = -rect.y/h || 0.001; // relative shift to get latex top at given point + } + } + + function makeem(value) { + if (Math.abs(value)<1e-2) return null; // very small values not needed, attribute will be removed + if (value==Math.round(value)) return Math.round(value) + "em"; + var res = value.toFixed(2); + if (res.indexOf("0.")==0) res = res.substr(1); else + if (res.indexOf("-0.")==0) res = "-." + res.substr(3); + if (res[res.length-1]=='0') res = res.substr(0, res.length-1); + return res+"em"; + } + + function get_boundary(painter, element, approx_rect) { + // actually, it is workaround for getBBox() or getElementBounday, + // which is not implemented for tspan element in Firefox + + if (JSROOT.nodejs || !element || element.empty()) + return approx_rect || { height: 0, width: 0 }; + + var important = [], prnt = element.node(); + + // if (element.node().getBBox && !JSROOT.browser.isFirefox) return element.node().getBBox(); + + while (prnt && (prnt!=arg.mainnode)) { + important.push(prnt); + prnt = prnt.parentNode; + } + + element.selectAll('tspan').each(function() { important.push(this) }); + + var tspans = d3.select(arg.mainnode).selectAll('tspan'); + + // this is just workaround to know that many elements are created and in Chrome we need to redo them once again + if (tspans.size()>3) arg.large_latex = true; + + tspans.each(function() { if (important.indexOf(this)<0) d3.select(this).attr('display', 'none'); }); + var box = painter.GetBoundarySizes(arg.mainnode); + + tspans.each(function() { if (important.indexOf(this)<0) d3.select(this).attr('display', null); }); + + return box; + } + + var features = [ + { name: "#it{" }, // italic + { name: "#bf{" }, // bold + { name: "kern[", arg: 'float' }, // horizontal shift + { name: "lower[", arg: 'float' }, // vertical shift + { name: "scale[", arg: 'float' }, // font scale + { name: "#color[", arg: 'int' }, + { name: "#font[", arg: 'int' }, + { name: "_{" }, // subscript + { name: "^{" }, // superscript + { name: "#bar{", accent: "\u02C9" }, // "\u0305" + { name: "#hat{", accent: "\u02C6" }, // "\u0302" + { name: "#check{", accent: "\u02C7" }, // "\u030C" + { name: "#acute{", accent: "\u02CA" }, // "\u0301" + { name: "#grave{", accent: "\u02CB" }, // "\u0300" + { name: "#dot{", accent: "\u02D9" }, // "\u0307" + { name: "#ddot{", accent: "\u02BA" }, // "\u0308" + { name: "#tilde{", accent: "\u02DC" }, // "\u0303" + { name: "#slash{", accent: "\u2215" }, // "\u0337" + { name: "#vec{", accent: "\u02ED" }, // "\u0350" arrowhead + { name: "#frac{" }, + { name: "#splitline{" }, + { name: "#sqrt[", arg: 'int' }, // root with arbitrary power (now only 3 or 4) + { name: "#sqrt{" }, + { name: "#sum", special: '\u2211', w: 0.8, h: 0.9 }, + { name: "#int", special: '\u222B', w: 0.3, h: 1.0 }, + { name: "#left[", right: "#right]", braces: "[]" }, + { name: "#left(", right: "#right)", braces: "()" }, + { name: "#left{", right: "#right}", braces: "{}" }, + { name: "#left|", right: "#right|", braces: "||" }, + { name: "#[]{", braces: "[]" }, + { name: "#(){", braces: "()" }, + { name: "#{}{", braces: "{}" }, + { name: "#||{", braces: "||" } + ]; + + var isany = false, best, found, foundarg, pos, n, subnode, subnode1, subpos = null, prevsubpos = null; + + while (label) { + + best = label.length; found = null; foundarg = null; + + for(n=0;n<features.length;++n) { + pos = label.indexOf(features[n].name); + if ((pos>=0) && (pos<best)) { best = pos; found = features[n]; } + } + + if (!found && !isany) { + var s = JSROOT.Painter.translateLaTeX(label); + if (!curr.lvl && (s==label)) return 0; // indicate that nothing found - plain string + extend_pos(curr, s); + + if (curr.accent && (s.length==1)) { + var elem = node.append('svg:tspan').text(s), + rect = get_boundary(this, elem, { width : 10000 }), + w = Math.min(rect.width/curr.fsize, 0.5); // at maximum, 0.5 should be used + + node.append('svg:tspan').attr('dx', makeem(curr.dx-w)).attr('dy', makeem(curr.dy-0.2)).text(curr.accent); + curr.dy = 0.2;; // compensate hat + curr.dx = Math.max(0.2, w-0.2); // extra horizontal gap + curr.accent = false; + } else { + node.text(s); + } + return true; + } + + if (best>0) { + var s = JSROOT.Painter.translateLaTeX(label.substr(0,best)); + if (s.length>0) { + extend_pos(curr, s); + node.append('svg:tspan') + .attr('dx', makeem(curr.dx)) + .attr('dy', makeem(curr.dy)) + .text(s); + curr.dx = curr.dy = 0; + } + subpos = null; // indicate that last element is plain + delete curr.special; // and any special handling is also over + delete curr.next_super_dy; // remove potential shift + } + + if (!found) return true; + + // remove preceeding block and tag itself + label = label.substr(best + found.name.length); + + subnode1 = subnode = node.append('svg:tspan'); + + prevsubpos = subpos; + + subpos = { lvl: curr.lvl+1, x: curr.x, y: curr.y, fsize: curr.fsize, dx:0, dy: 0, parent: curr }; + + isany = true; + + if (found.arg) { + pos = label.indexOf("]{"); + if (pos < 0) { console.log('missing argument for ', found.name); return false; } + foundarg = label.substr(0,pos); + if (found.arg == 'int') { + foundarg = parseInt(foundarg); + if (isNaN(foundarg)) { console.log('wrong int argument', label.substr(0,pos)); return false; } + } else if (found.arg == 'float') { + foundarg = parseFloat(foundarg); + if (isNaN(foundarg)) { console.log('wrong float argument', label.substr(0,pos)); return false; } + } + label = label.substr(pos + 2); + } + + var nextdy = curr.dy, nextdx = curr.dx, trav = null, + scale = 1, left_brace = "{", right_brace = "}"; // this will be applied to the next element + + curr.dy = curr.dx = 0; // relative shift for elements + + if (found.special) { + subnode.attr('dx', makeem(nextdx)).attr('dy', makeem(nextdy)).text(found.special); + nextdx = nextdy = 0; + curr.special = found; + + var rect = get_boundary(this, subnode); + if (rect.width && rect.height) { + found.w = rect.width/curr.fsize; + found.h = rect.height/curr.fsize-0.1; + } + continue; // just create special node + } + + if (found.braces) { + // special handling of large braces + subpos.left_cont = subnode.append('svg:tspan'); // container for left brace + subpos.left = subpos.left_cont.append('svg:tspan').text(found.braces[0]); + subnode1 = subnode.append('svg:tspan'); + subpos.left_rect = { y: curr.y - curr.fsize*1.1, height: curr.fsize*1.2, x: curr.x, width: curr.fsize*0.6 }; + extend_pos(curr, subpos.left_rect); + subpos.braces = found; // indicate braces handling + if (found.right) { + left_brace = found.name; + right_brace = found.right; + } + } else if (found.accent) { + subpos.accent = found.accent; + } else + switch(found.name) { + case "#color[": + if (this.get_color(foundarg)) + subnode.attr('fill', this.get_color(foundarg)); + break; + case "#kern[": // horizontal shift + nextdx += foundarg; + break; + case "#lower[": // after vertical shift one need to compensate it back + curr.dy -= foundarg; + nextdy += foundarg; + break; + case "scale[": + scale = foundarg; + break; + case "#font[": + JSROOT.Painter.getFontDetails(foundarg).setFont(subnode,'without-size'); + break; + case "#it{": + curr.italic = true; + trav = curr; + while (trav = trav.parent) + if (trav.italic!==undefined) { + curr.italic = !trav.italic; + break; + } + subnode.attr('font-style', curr.italic ? 'italic' : 'normal'); + break; + case "#bf{": + curr.bold = true; + trav = curr; + while (trav = trav.parent) + if (trav.bold!==undefined) { + curr.bold = !trav.bold; + break; + } + subnode.attr('font-weight', curr.bold ? 'bold' : 'normal'); + break; + case "_{": + scale = 0.6; + subpos.script = 'sub'; + + if (curr.special) { + curr.dx = curr.special.w; + curr.dy = -0.7; + nextdx -= curr.dx; + nextdy -= curr.dy; + } else { + nextdx += 0.1*scale; + nextdy += 0.4*scale; + subpos.y += 0.4*subpos.fsize; + curr.dy = -0.4*scale; // compensate vertical shift back + + if (prevsubpos && (prevsubpos.script === 'super')) { + var rect = get_boundary(this, prevsubpos.node, prevsubpos.rect); + subpos.width_limit = rect.width; + nextdx -= (rect.width/subpos.fsize+0.1)*scale; + } + } + break; + case "^{": + scale = 0.6; + subpos.script = 'super'; + + if (curr.special) { + curr.dx = curr.special.w; + curr.dy = curr.special.h; + nextdx -= curr.dx; + nextdy -= curr.dy; + } else { + + curr.dy = 0.6*scale; // compensate vertical shift afterwards + if (curr.next_super_dy) curr.dy -= curr.next_super_dy; + + nextdx += 0.1*scale; + nextdy -= curr.dy; + + subpos.y -= 0.4*subpos.fsize; + + if (prevsubpos && (prevsubpos.script === 'sub')) { + var rect = get_boundary(this, prevsubpos.node, prevsubpos.rect); + subpos.width_limit = rect.width; + nextdx -= (rect.width/subpos.fsize+0.1)*scale; + } + } + break; + case "#frac{": + case "#splitline{": + subpos.first = subnode; + subpos.two_lines = true; + subpos.need_middle = (found.name == "#frac{"); + subpos.x0 = subpos.x; + nextdy -= 0.6; + curr.dy = -0.6; + break; + case "#sqrt{": + foundarg = 2; + case "#sqrt[": + subpos.square_root = subnode.append('svg:tspan'); + subpos.square_root.append('svg:tspan').text((foundarg==3) ? '\u221B' : ((foundarg==4) ? '\u221C' : '\u221A')); // unicode square, cubic and fourth root + subnode1 = subnode.append('svg:tspan'); + subpos.sqrt_rect = { y: curr.y - curr.fsize*1.1, height: curr.fsize*1.2, x: 0, width: curr.fsize*0.7 }; + extend_pos(curr, subpos.sqrt_rect); // just dummy symbol instead of square root + break; + } + + if (scale!==1) { + // handle centrally change of scale factor + subnode.attr('font-size', Math.round(scale*100)+'%'); + subpos.fsize *= scale; + nextdx = nextdx/scale; + nextdy = nextdy/scale; + } + + if (curr.special && !subpos.script) delete curr.special; + delete curr.next_super_dy; + + subpos.node = subnode; // remember node where sublement is build + + while (true) { + // loop need to create two lines for #frac or #splitline + // normally only one sub-element is created + + // moving cursor with the tspan + subpos.x += nextdx*subpos.fsize; + subpos.y += nextdy*subpos.fsize; + + subnode.attr('dx', makeem(nextdx)).attr('dy', makeem(nextdy)); + nextdx = nextdy = 0; + + pos = -1; n = 1; + + while ((n!=0) && (++pos < label.length)) { + if (label.indexOf(left_brace, pos) === pos) n++; else + if (label.indexOf(right_brace, pos) === pos) n--; + } + + if (n!=0) { + console.log('mismatch with open ' + left_brace + ' and close ' + right_brace + ' braces in Latex', label); + return false; + } + + var sublabel = label.substr(0,pos); + + // if (subpos.square_root) sublabel = "#frac{a}{bc}"; + + if (!this.produceLatex(subnode1, sublabel, arg, subpos)) return false; + + // takeover current possition and deltas + curr.x = subpos.x; + curr.y = subpos.y; + + curr.dx += subpos.dx*subpos.fsize/curr.fsize; + curr.dy += subpos.dy*subpos.fsize/curr.fsize; + + label = label.substr(pos+right_brace.length); + + if (subpos.width_limit) { + // special handling for the case when created element does not reach its minimal width + // use when super-script and subscript should be combined together + + var rect = get_boundary(this, subnode1, subpos.rect); + if (rect.width < subpos.width_limit) + curr.dx += (subpos.width_limit-rect.width)/curr.fsize; + delete subpos.width_limit; + } + + if (curr.special) { + // case over #sum or #integral one need to compensate width + var rect = get_boundary(this, subnode1, subpos.rect); + curr.dx -= rect.width/curr.fsize; // compensate width as much as we can + } + + if (subpos.square_root) { + // creating cap for square root + // while overline symbol does not match with square root, use empty text with overline + var len = 2, scale = 1, sqrt_dy = 0, yscale = 1, + bs = get_boundary(this, subpos.square_root, subpos.sqrt_rect), + be = get_boundary(this, subnode1, subpos.rect); + + // we can compare y coordinates while both nodes (root and element) on the same level + if ((be.height > bs.height) && (bs.height > 0)) { + yscale = be.height/bs.height*1.2; + sqrt_dy = ((be.y+be.height) - (bs.y+bs.height))/curr.fsize/yscale; + subpos.square_root.style('font-size', Math.round(100*yscale)+'%').attr('dy', makeem(sqrt_dy)); + } + + // we taking into account only element width + len = be.width / subpos.fsize / yscale; + + var a = "", nn = Math.round(Math.max(len*3,2)); + while (nn--) a += '\u203E'; // unicode overline + + subpos.square_root.append('svg:tspan').attr("dy", makeem(-0.25)).text(a); + + subpos.square_root.append('svg:tspan').attr("dy", makeem(0.25-sqrt_dy)).attr("dx", makeem(-a.length/3-0.2)).text('\u2009'); // unicode tiny space + + break; + } + + if (subpos.braces) { + // handling braces + + var bs = get_boundary(this, subpos.left_cont, subpos.left_rect), + be = get_boundary(this, subnode1, subpos.rect), + yscale = 1, brace_dy = 0; + + // console.log('braces height', bs.height, ' entry height', be.height); + + if (1.2*bs.height < be.height) { + // make scaling + yscale = be.height/bs.height; + // brace_dy = ((be.y+be.height) - (bs.y+bs.height))/curr.fsize/yscale - 0.15; + brace_dy = 0; + subpos.left.style('font-size', Math.round(100*yscale)+'%').attr('dy', makeem(brace_dy)); + // unicode tiny space, used to return cursor on vertical position + subpos.left_cont.append('svg:tspan').attr("dx",makeem(-0.2)) + .attr("dy", makeem(-brace_dy*yscale)).text('\u2009'); + curr.next_super_dy = -0.3*yscale; // special shift for next comming superscript + } + + subpos.left_rect.y = curr.y; + subpos.left_rect.height *= yscale; + + extend_pos(curr, subpos.left_rect); // just dummy symbol instead of right brace for accounting + + var right_cont = subnode.append('svg:tspan') + .attr("dx", makeem(curr.dx)) + .attr("dy", makeem(curr.dy)); + + curr.dx = curr.dy = 0; + + if (yscale!=1) right_cont.append('svg:tspan').attr("dx",makeem(-0.2)).text('\u2009'); // unicode tiny space if larger brace is used + + var right = right_cont.append('svg:tspan').text(subpos.braces.braces[1]); + + if (yscale!=1) { + right.style('font-size', Math.round(100*yscale)+'%').attr('dy', makeem(brace_dy)); + curr.dy = -brace_dy*yscale; // compensation of right brace + } + + break; + } + + if (subpos.first && subpos.second) { + // when two lines created, adjust horizontal position and place divider if required + + var rect1 = get_boundary(this, subpos.first, subpos.rect1), + rect2 = get_boundary(this, subpos.second, subpos.rect), + l1 = rect1.width / subpos.fsize, + l2 = rect2.width / subpos.fsize, + l3 = Math.max(l2, l1); + + if (subpos.need_middle) { + // starting from content len 1.2 two -- will be inserted + l3 = Math.round(Math.max(l3,1)+0.3); + var a = ""; + while (a.length < l3) a += '\u2014'; + node.append('svg:tspan') + .attr("dx", makeem(-0.5*(l3+l2))) + .attr("dy", makeem(curr.dy-0.2)) + .text(a); + curr.dy = 0.2; // return to the normal level + curr.dx = 0.2; // extra spacing + } else { + curr.dx = 0.2; + if (l2<l1) curr.dx += 0.5*(l1-l2); + } + + if (subpos.need_middle || arg.align[0]=='middle') { + subpos.first.attr("dx", makeem(0.5*(l3-l1))); + subpos.second.attr("dx", makeem(-0.5*(l2+l1))); + } else if (arg.align[0]=='end') { + if (l1<l2) subpos.first.attr("dx", makeem(l2-l1)); + subpos.second.attr("dx", makeem(-l2)); + } else { + subpos.second.attr("dx", makeem(-l1)); + } + + delete subpos.first; + delete subpos.second; + } + + if (!subpos.two_lines) break; + + if (label[0] != '{') { + console.log('missing { for second line', label); + return false; + } + + label = label.substr(1); + + subnode = subnode1 = node.append('svg:tspan'); + + subpos.two_lines = false; + subpos.rect1 = subpos.rect; // remember first rect + delete subpos.rect; // reset rectangle calculations + subpos.x = subpos.x0; // it is used only for SVG, make it more realistic + subpos.second = subnode; + + nextdy = curr.dy + 1.6; + curr.dy = -0.4; + subpos.dx = subpos.dy = 0; // reset variable + } + + } + + return true; + } + + /** @summary draw text + * + * @param {object} arg - different text draw options + * @param {string} arg.text - text to draw + * @param {number} [arg.align = 12] - int value like 12 or 31 + * @param {string} [arg.align = undefined] - end;bottom + * @param {number} [arg.x = 0] - x position + * @param {number} [arg.y = 0] - y position + * @param {number} [arg.width = undefined] - when specified, adjust font size in the specified box + * @param {number} [arg.height = undefined] - when specified, adjust font size in the specified box + * @param {number} arg.latex - 0 - plain text, 1 - normal TLatex, 2 - math + * @param {string} [arg.color=black] - text color + * @param {number} [arg.rotate = undefined] - rotaion angle + * @param {number} [arg.font_size = undefined] - fixed font size + * @param {object} [arg.draw_g = this.draw_g] - element where to place text, if not specified central painter container is used + */ + TObjectPainter.prototype.DrawText = function(arg) { + + var label = arg.text || "", + align = ['start', 'middle']; + + if (typeof arg.align == 'string') { + align = arg.align.split(";"); + if (align.length==1) align.push('middle'); + } else if (typeof arg.align == 'number') { + if ((arg.align / 10) >= 3) align[0] = 'end'; else + if ((arg.align / 10) >= 2) align[0] = 'middle'; + if ((arg.align % 10) == 0) align[1] = 'bottom'; else + if ((arg.align % 10) == 1) align[1] = 'bottom-base'; else + if ((arg.align % 10) == 3) align[1] = 'top'; + } + + arg.draw_g = arg.draw_g || this.draw_g; + if (arg.latex===undefined) arg.latex = 1; // latex 0-text, 1-latex, 2-math + arg.align = align; + arg.x = arg.x || 0; + arg.y = arg.y || 0; + arg.scale = arg.width && arg.height && !arg.font_size; + arg.width = arg.width || 0; + arg.height = arg.height || 0; + + if (arg.draw_g.property("_fast_drawing")) { + if (arg.scale) { + // area too small - ignore such drawing + if (arg.height < 4) return 0; + } else if (arg.font_size) { + // font size too small + if (arg.font_size < 4) return 0; + } else if (arg.draw_g.property("_font_too_small")) { + // configure font is too small - ignore drawing + return 0; + } + } + + if (JSROOT.gStyle.MathJax !== undefined) { + switch (JSROOT.gStyle.MathJax) { + case 0: JSROOT.gStyle.Latex = 2; break; + case 2: JSROOT.gStyle.Latex = 4; break; + default: JSROOT.gStyle.Latex = 3; + } + delete JSROOT.gStyle.MathJax; + } + + if (typeof JSROOT.gStyle.Latex == 'string') { + switch (JSROOT.gStyle.Latex) { + case "off": JSROOT.gStyle.Latex = 0; break; + case "symbols": JSROOT.gStyle.Latex = 1; break; + case "MathJax": + case "mathjax": + case "math": JSROOT.gStyle.Latex = 3; break; + case "AlwaysMathJax": + case "alwaysmath": + case "alwaysmathjax": JSROOT.gStyle.Latex = 4; break; + default: + var code = parseInt(JSROOT.gStyle.Latex); + JSROOT.gStyle.Latex = (!isNaN(code) && (code>=0) && (code<=4)) ? code : 2; + } + } + + var font = arg.draw_g.property('text_font'), + use_mathjax = (arg.latex == 2); + + if (arg.latex === 1) + use_mathjax = (JSROOT.gStyle.Latex > 3) || ((JSROOT.gStyle.Latex == 3) && JSROOT.Painter.isAnyLatex(label)); + + // only Firefox can correctly rotate incapsulated SVG, produced by MathJax + // if (!use_normal_text && (h<0) && !JSROOT.browser.isFirefox) use_normal_text = true; + + if (!use_mathjax || arg.nomathjax) { + + var txt = arg.draw_g.append("svg:text"); + + if (arg.color) txt.attr("fill", arg.color); + + if (arg.font_size) txt.attr("font-size", arg.font_size); + else arg.font_size = font.size; + + arg.font = font; // use in latex conversion + + arg.plain = !arg.latex || (JSROOT.gStyle.Latex < 2) || (this.produceLatex(txt, label, arg) === 0); + + if (arg.plain) { + if (arg.latex && (JSROOT.gStyle.Latex == 1)) label = Painter.translateLaTeX(label); // replace latex symbols + txt.text(label); + } + + // complete rectangle with very rougth size estimations + arg.box = !JSROOT.nodejs && !JSROOT.gStyle.ApproxTextSize && !arg.fast ? this.GetBoundarySizes(txt.node()) : + (arg.text_rect || { height: arg.font_size*1.2, width: JSROOT.Painter.approxTextWidth(font, label) }); + + txt.attr('class','hidden_text') + .attr('visibility','hidden') // hide elements until text drawing is finished + .property("_arg", arg); + + if (arg.box.width > arg.draw_g.property('max_text_width')) arg.draw_g.property('max_text_width', arg.box.width); + if (arg.scale) this.TextScaleFactor(1.05*arg.box.width/arg.width, arg.draw_g); + if (arg.scale) this.TextScaleFactor(1.*arg.box.height/arg.height, arg.draw_g); + + return arg.box.width; + } + + var mtext = JSROOT.Painter.translateMath(label, arg.latex, arg.color, this), + fo_g = arg.draw_g.append("svg:g") + .attr('class', 'math_svg') + .attr('visibility','hidden') + .property('_arg', arg); + + arg.draw_g.property('mathjax_use', true); // one need to know that mathjax is used + + if (JSROOT.nodejs) { + // special handling for Node.js + + if (!JSROOT.nodejs_mathjax) { + JSROOT.nodejs_mathjax = require("mathjax-node"); + JSROOT.nodejs_mathjax.config({ + TeX: { extensions: ["color.js"] }, + SVG: { mtextFontInherit: true, minScaleAdjust: 100, matchFontHeight: true, useFontCache: false } + }); + JSROOT.nodejs_mathjax.start(); + } + + if ((mtext.indexOf("\\(")==0) && (mtext.lastIndexOf("\\)")==mtext.length-2)) + mtext = mtext.substr(2,mtext.length-4); + + JSROOT.nodejs_mathjax.typeset({ + jsroot_painter: this, + jsroot_drawg: arg.draw_g, + jsroot_fog: fo_g, + ex: font.size, + math: mtext, + useFontCache: false, + useGlobalCache: false, + format: "TeX", // "TeX", "inline-TeX", "MathML" + svg: true // svg:true, + }, function (data, opt) { + if (!data.errors) { + opt.jsroot_fog.html(data.svg); + } else { + console.log('MathJax error', opt.math); + opt.jsroot_fog.html("<svg></svg>"); + } + opt.jsroot_painter.FinishTextDrawing(opt.jsroot_drawg); + }); + + return 0; + } + + var element = document.createElement("p"); + + d3.select(element).style('visibility',"hidden").style('overflow',"hidden").style('position',"absolute") + .style("font-size",font.size+'px').style("font-family",font.name) + .html('<mtext>' + mtext + '</mtext>'); + document.body.appendChild(element); + + fo_g.property('_element', element); + + var painter = this; + + JSROOT.AssertPrerequisites('mathjax', function() { + + MathJax.Hub.Typeset(element, ["FinishMathjax", painter, arg.draw_g, fo_g]); + + MathJax.Hub.Queue(["FinishMathjax", painter, arg.draw_g, fo_g]); // repeat once again, while Typeset not always invoke callback + }); + + return 0; + } + + /** @summary Finish MathJax drawing + * @desc function should be called when processing of element is completed + * @private + */ + + TObjectPainter.prototype.FinishMathjax = function(draw_g, fo_g, id) { + + if (fo_g.node().parentNode !== draw_g.node()) return; + + var entry = fo_g.property('_element'); + if (!entry) return; + + var vvv = d3.select(entry).select("svg"); + + if (vvv.empty()) { + + var merr = d3.select(entry).select("merror"); // indication of error + + if (merr.empty()) return; // not yet finished + + console.warn('MathJax error', merr.text()); + + var arg = fo_g.property('_arg'); + + if (arg && arg.latex!=2) { + arg.nomathjax = true; + fo_g.remove(); // delete special entry + this.DrawText(arg); + } else + fo_g.append("svg").attr('width', Math.min(20, merr.text().length + 5) + 'ex') + .attr('height', '3ex') + .style('vertical-align','0ex') + .append("text") + .style('font-size','12px') + .style('fill','red') + .attr('x','0') + .attr('y','2ex') + .text("Err: " + merr.text()); + } else { + vvv.remove(); + fo_g.append(function() { return vvv.node(); }); + } + + fo_g.property('_element', null); + document.body.removeChild(entry); + + this.FinishTextDrawing(draw_g); // check if all other elements are completed + } + + // =========================================================== + + /** @summary Set active pad painter + * + * @desc Should be used to handle key press events, which are global in the web browser + * @param {object} args - functions arguments + * @param {object} args.pp - pad painter + * @param {boolean} [args.active = false] - is pad activated or not + * @private */ + Painter.SelectActivePad = function(args) { + if (args.active) { + if (this.$active_pp && (typeof this.$active_pp.SetActive == 'function')) + this.$active_pp.SetActive(false); + + this.$active_pp = args.pp; + + if (this.$active_pp && (typeof this.$active_pp.SetActive == 'function')) + this.$active_pp.SetActive(true); + } else if (this.$active_pp === args.pp) { + delete this.$active_pp; + } + } + + /** @summary Returns current active pad + * @desc Should be used only for keyboard handling + * @private */ + + Painter.GetActivePad = function() { + return this.$active_pp; + } + + // ===================================================================== + + function TooltipHandler(obj) { + JSROOT.TObjectPainter.call(this, obj); + this.tooltip_enabled = true; // this is internally used flag to temporary disbale/enable tooltip + } + + TooltipHandler.prototype = Object.create(TObjectPainter.prototype); + + TooltipHandler.prototype.hints_layer = function() { + // return layer where frame tooltips are shown + // only canvas info_layer can be used while other pads can overlay + + var pp = this.canv_painter(); + return pp ? pp.svg_layer("info_layer") : d3.select(null); + } + + TooltipHandler.prototype.IsTooltipShown = function() { + // return true if tooltip is shown, use to prevent some other action + if (!this.tooltip_enabled || !this.IsTooltipAllowed()) return false; + var hintsg = this.hints_layer().select(".objects_hints"); + return hintsg.empty() ? false : hintsg.property("hints_pad") == this.pad_name; + } + + TooltipHandler.prototype.ProcessTooltipEvent = function(pnt, enabled) { + // make central function which let show selected hints for the object + + if (enabled !== undefined) this.tooltip_enabled = enabled; + + if (pnt && pnt.handler) { + // special use of interactive handler in the frame painter + var rect = this.draw_g ? this.draw_g.select(".interactive_rect") : null; + if (!rect || rect.empty()) { + pnt = null; // disable + } else if (pnt.touch) { + var pos = d3.touches(rect.node()); + pnt = (pos && pos.length == 1) ? { touch: true, x: pos[0][0], y: pos[0][1] } : null; + } else { + var pos = d3.mouse(rect.node()); + pnt = { touch: false, x: pos[0], y: pos[1] }; + } + } + + var hints = [], nhints = 0, maxlen = 0, lastcolor1 = 0, usecolor1 = false, + textheight = 11, hmargin = 3, wmargin = 3, hstep = 1.2, + frame_rect = this.GetFrameRect(), + pad_width = this.pad_width(), + pp = this.pad_painter(), + font = JSROOT.Painter.getFontDetails(160, textheight), + status_func = this.GetShowStatusFunc(), + disable_tootlips = !this.IsTooltipAllowed() || !this.tooltip_enabled; + + if ((pnt === undefined) || (disable_tootlips && !status_func)) pnt = null; + if (pnt && disable_tootlips) pnt.disabled = true; // indicate that highlighting is not required + if (pnt) pnt.painters = true; // get also painter + + // collect tooltips from pad painter - it has list of all drawn objects + if (pp) hints = pp.GetTooltips(pnt); + + if (pnt && pnt.touch) textheight = 15; + + for (var n = 0; n < hints.length; ++n) { + var hint = hints[n]; + if (!hint) continue; + + if (hint.painter && (hint.user_info!==undefined)) + if (hint.painter.ProvideUserTooltip(hint.user_info)); + + if (!hint.lines || (hint.lines.length===0)) { + hints[n] = null; continue; + } + + // check if fully duplicated hint already exists + for (var k=0;k<n;++k) { + var hprev = hints[k], diff = false; + if (!hprev || (hprev.lines.length !== hint.lines.length)) continue; + for (var l=0;l<hint.lines.length && !diff;++l) + if (hprev.lines[l] !== hint.lines[l]) diff = true; + if (!diff) { hints[n] = null; break; } + } + if (!hints[n]) continue; + + nhints++; + + for (var l=0;l<hint.lines.length;++l) + maxlen = Math.max(maxlen, hint.lines[l].length); + + hint.height = Math.round(hint.lines.length*textheight*hstep + 2*hmargin - textheight*(hstep-1)); + + if ((hint.color1!==undefined) && (hint.color1!=='none')) { + if ((lastcolor1!==0) && (lastcolor1 !== hint.color1)) usecolor1 = true; + lastcolor1 = hint.color1; + } + } + + var layer = this.hints_layer(), + hintsg = layer.select(".objects_hints"); // group with all tooltips + + if (status_func) { + var title = "", name = "", info = "", + hint = null, best_dist2 = 1e10, best_hint = null, + coordinates = pnt ? Math.round(pnt.x)+","+Math.round(pnt.y) : ""; + // try to select hint with exact match of the position when several hints available + for (var k=0; k < (hints ? hints.length : 0); ++k) { + if (!hints[k]) continue; + if (!hint) hint = hints[k]; + if (hints[k].exact && (!hint || !hint.exact)) { hint = hints[k]; break; } + + if (!pnt || (hints[k].x===undefined) || (hints[k].y===undefined)) continue; + + var dist2 = (pnt.x-hints[k].x)*(pnt.x-hints[k].x) + (pnt.y-hints[k].y)*(pnt.y-hints[k].y); + if (dist2<best_dist2) { best_dist2 = dist2; best_hint = hints[k]; } + } + + if ((!hint || !hint.exact) && (best_dist2 < 400)) hint = best_hint; + + if (hint) { + name = (hint.lines && hint.lines.length>1) ? hint.lines[0] : hint.name; + title = hint.title || ""; + info = hint.line; + if (!info && hint.lines) info = hint.lines.slice(1).join(' '); + } + + status_func(name, title, info, coordinates); + } + + // end of closing tooltips + if (!pnt || disable_tootlips || (hints.length===0) || (maxlen===0) || (nhints > 15)) { + hintsg.remove(); + return; + } + + // we need to set pointer-events=none for all elements while hints + // placed in front of so-called interactive rect in frame, used to catch mouse events + + if (hintsg.empty()) + hintsg = layer.append("svg:g") + .attr("class", "objects_hints") + .style("pointer-events","none"); + + var frame_shift = { x: 0, y: 0 }, trans = frame_rect.transform || ""; + if (!pp.iscan) { + pp.CalcAbsolutePosition(this.svg_pad(), frame_shift); + trans = "translate(" + frame_shift.x + "," + frame_shift.y + ") " + trans; + } + + // copy transform attributes from frame itself + hintsg.attr("transform", trans) + .property("last_point", pnt) + .property("hints_pad", this.pad_name); + + var viewmode = hintsg.property('viewmode') || "", + actualw = 0, posx = pnt.x + frame_rect.hint_delta_x; + + if (nhints > 1) { + // if there are many hints, place them left or right + + var bleft = 0.5, bright = 0.5; + + if (viewmode=="left") bright = 0.7; else + if (viewmode=="right") bleft = 0.3; + + if (posx <= bleft*frame_rect.width) { + viewmode = "left"; + posx = 20; + } else if (posx >= bright*frame_rect.width) { + viewmode = "right"; + posx = frame_rect.width - 60; + } else { + posx = hintsg.property('startx'); + } + } else { + viewmode = "single"; + posx += 15; + } + + if (viewmode !== hintsg.property('viewmode')) { + hintsg.property('viewmode', viewmode); + hintsg.selectAll("*").remove(); + } + + var curry = 10, // normal y coordinate + gapy = 10, // y coordinate, taking into account all gaps + gapminx = -1111, gapmaxx = -1111, + minhinty = -frame_shift.y, + maxhinty = this.pad_height("") - frame_rect.y - frame_shift.y; + + function FindPosInGap(y) { + for (var n=0;(n<hints.length) && (y < maxhinty); ++n) { + var hint = hints[n]; + if (!hint) continue; + if ((hint.y>=y-5) && (hint.y <= y+hint.height+5)) { + y = hint.y+10; + n = -1; + } + } + return y; + } + + for (var n=0; n < hints.length; ++n) { + var hint = hints[n], + group = hintsg.select(".painter_hint_"+n); + if (hint===null) { + group.remove(); + continue; + } + + var was_empty = group.empty(), dx = 0, dy = 0; + + if (was_empty) + group = hintsg.append("svg:svg") + .attr("class", "painter_hint_"+n) + .attr('opacity', 0) // use attribute, not style to make animation with d3.transition() + .style('overflow','hidden') + .style("pointer-events","none"); + + if (viewmode == "single") { + curry = pnt.touch ? (pnt.y - hint.height - 5) : Math.min(pnt.y + 15, maxhinty - hint.height - 3) + frame_rect.hint_delta_y; + } else { + gapy = FindPosInGap(gapy); + if ((gapminx === -1111) && (gapmaxx === -1111)) gapminx = gapmaxx = hint.x; + gapminx = Math.min(gapminx, hint.x); + gapmaxx = Math.min(gapmaxx, hint.x); + } + + group.attr("x", posx) + .attr("y", curry) + .property("curry", curry) + .property("gapy", gapy); + + curry += hint.height + 5; + gapy += hint.height + 5; + + if (!was_empty) + group.selectAll("*").remove(); + + group.attr("width", 60) + .attr("height", hint.height); + + var r = group.append("rect") + .attr("x",0) + .attr("y",0) + .attr("width", 60) + .attr("height", hint.height) + .attr("fill","lightgrey") + .style("pointer-events","none"); + + if (nhints > 1) { + var col = usecolor1 ? hint.color1 : hint.color2; + if ((col !== undefined) && (col!=='none')) + r.attr("stroke", col).attr("stroke-width", hint.exact ? 3 : 1); + } + + for (var l=0; l < (hint.lines ? hint.lines.length : 0); l++) + if (hint.lines[l]!==null) { + var txt = group.append("svg:text") + .attr("text-anchor", "start") + .attr("x", wmargin) + .attr("y", hmargin + l*textheight*hstep) + .attr("dy", ".8em") + .attr("fill","black") + .style("pointer-events","none") + .call(font.func) + .text(hint.lines[l]); + + var box = this.GetBoundarySizes(txt.node()); + + actualw = Math.max(actualw, box.width); + } + + function translateFn() { + // We only use 'd', but list d,i,a as params just to show can have them as params. + // Code only really uses d and t. + return function(d, i, a) { + return function(t) { + return t < 0.8 ? "0" : (t-0.8)*5; + }; + }; + } + + if (was_empty) + if (JSROOT.gStyle.TooltipAnimation > 0) + group.transition().duration(JSROOT.gStyle.TooltipAnimation).attrTween("opacity", translateFn()); + else + group.attr('opacity',1); + } + + actualw += 2*wmargin; + + var svgs = hintsg.selectAll("svg"); + + if ((viewmode == "right") && (posx + actualw > frame_rect.width - 20)) { + posx = frame_rect.width - actualw - 20; + svgs.attr("x", posx); + } + + if ((viewmode == "single") && (posx + actualw > pad_width - frame_rect.x) && (posx > actualw+20)) { + posx -= (actualw + 20); + svgs.attr("x", posx); + } + + // if gap not very big, apply gapy coordinate to open view on the histogram + if ((viewmode !== "single") && (gapy < maxhinty) && (gapy !== curry)) { + if ((gapminx <= posx+actualw+5) && (gapmaxx >= posx-5)) + svgs.attr("y", function() { return d3.select(this).property('gapy'); }); + } else if ((viewmode !== 'single') && (curry > maxhinty)) { + var shift = Math.max((maxhinty - curry - 10), minhinty); + if (shift<0) + svgs.attr("y", function() { return d3.select(this).property('curry') + shift; }); + } + + if (actualw > 10) + svgs.attr("width",actualw) + .select('rect').attr("width", actualw); + + hintsg.property('startx', posx); + } + + JSROOT.TCanvasStatusBits = { + kShowEventStatus : JSROOT.BIT(15), + kAutoExec : JSROOT.BIT(16), + kMenuBar : JSROOT.BIT(17), + kShowToolBar : JSROOT.BIT(18), + kShowEditor : JSROOT.BIT(19), + kMoveOpaque : JSROOT.BIT(20), + kResizeOpaque : JSROOT.BIT(21), + kIsGrayscale : JSROOT.BIT(22), + kShowToolTips : JSROOT.BIT(23) + }; + + JSROOT.EAxisBits = { + kTickPlus : JSROOT.BIT(9), + kTickMinus : JSROOT.BIT(10), + kAxisRange : JSROOT.BIT(11), + kCenterTitle : JSROOT.BIT(12), + kCenterLabels : JSROOT.BIT(14), + kRotateTitle : JSROOT.BIT(15), + kPalette : JSROOT.BIT(16), + kNoExponent : JSROOT.BIT(17), + kLabelsHori : JSROOT.BIT(18), + kLabelsVert : JSROOT.BIT(19), + kLabelsDown : JSROOT.BIT(20), + kLabelsUp : JSROOT.BIT(21), + kIsInteger : JSROOT.BIT(22), + kMoreLogLabels : JSROOT.BIT(23), + kDecimals : JSROOT.BIT(11) + }; + + // ================= painter of raw text ======================================== + + + Painter.drawRawText = function(divid, txt, opt) { + + var painter = new TBasePainter(); + painter.txt = txt; + painter.SetDivId(divid); + + painter.RedrawObject = function(obj) { + this.txt = obj; + this.Draw(); + return true; + } + + painter.Draw = function() { + var txt = (this.txt._typename && (this.txt._typename == "TObjString")) ? this.txt.fString : this.txt.value; + if (typeof txt != 'string') txt = "<undefined>"; + + var mathjax = this.txt.mathjax || (JSROOT.gStyle.Latex == 4); + + if (!mathjax && !('as_is' in this.txt)) { + var arr = txt.split("\n"); txt = ""; + for (var i = 0; i < arr.length; ++i) + txt += "<pre style='margin:0'>" + arr[i] + "</pre>"; + } + + var frame = this.select_main(), + main = frame.select("div"); + if (main.empty()) + main = frame.append("div").style('max-width','100%').style('max-height','100%').style('overflow','auto'); + main.html(txt); + + // (re) set painter to first child element + this.SetDivId(this.divid); + + if (mathjax) + JSROOT.AssertPrerequisites('mathjax', function() { + MathJax.Hub.Typeset(frame.node()); + }); + } + + painter.Draw(); + return painter.DrawingReady(); + } + + /** @summary Register handle to react on window resize + * + * @desc function used to react on browser window resize event + * While many resize events could come in short time, + * resize will be handled with delay after last resize event + * handle can be function or object with CheckResize function + * one could specify delay after which resize event will be handled + * @private + */ + JSROOT.RegisterForResize = function(handle, delay) { + + if (!handle) return; + + var myInterval = null, myDelay = delay ? delay : 300; + + if (myDelay < 20) myDelay = 20; + + function ResizeTimer() { + myInterval = null; + + document.body.style.cursor = 'wait'; + if (typeof handle == 'function') handle(); else + if ((typeof handle == 'object') && (typeof handle.CheckResize == 'function')) handle.CheckResize(); else + if (typeof handle == 'string') { + var node = d3.select('#'+handle); + if (!node.empty()) { + var mdi = node.property('mdi'); + if (mdi) { + mdi.CheckMDIResize(); + } else { + JSROOT.resize(node.node()); + } + } + } + document.body.style.cursor = 'auto'; + } + + function ProcessResize() { + if (myInterval !== null) clearTimeout(myInterval); + myInterval = setTimeout(ResizeTimer, myDelay); + } + + window.addEventListener('resize', ProcessResize); + } + + JSROOT.addDrawFunc({ name: "TCanvas", icon: "img_canvas", prereq: "v6", func: "JSROOT.Painter.drawCanvas", opt: ";grid;gridx;gridy;tick;tickx;ticky;log;logx;logy;logz", expand_item: "fPrimitives" }); + JSROOT.addDrawFunc({ name: "TPad", icon: "img_canvas", prereq: "v6", func: "JSROOT.Painter.drawPad", opt: ";grid;gridx;gridy;tick;tickx;ticky;log;logx;logy;logz", expand_item: "fPrimitives" }); + JSROOT.addDrawFunc({ name: "TSlider", icon: "img_canvas", prereq: "v6", func: "JSROOT.Painter.drawPad" }); + JSROOT.addDrawFunc({ name: "TFrame", icon: "img_frame", prereq: "v6", func: "JSROOT.Painter.drawFrame" }); + JSROOT.addDrawFunc({ name: "TPave", icon: "img_pavetext", prereq: "v6;hist", func: "JSROOT.Painter.drawPave" }); + JSROOT.addDrawFunc({ name: "TPaveText", icon: "img_pavetext", prereq: "v6;hist", func: "JSROOT.Painter.drawPave" }); + JSROOT.addDrawFunc({ name: "TPavesText", icon: "img_pavetext", prereq: "v6;hist", func: "JSROOT.Painter.drawPave" }); + JSROOT.addDrawFunc({ name: "TPaveStats", icon: "img_pavetext", prereq: "v6;hist", func: "JSROOT.Painter.drawPave" }); + JSROOT.addDrawFunc({ name: "TPaveLabel", icon: "img_pavelabel", prereq: "v6;hist", func: "JSROOT.Painter.drawPave" }); + JSROOT.addDrawFunc({ name: "TDiamond", icon: "img_pavelabel", prereq: "v6;hist", func: "JSROOT.Painter.drawPave" }); + JSROOT.addDrawFunc({ name: "TLatex", icon: "img_text", prereq: "more2d", func: "JSROOT.Painter.drawText", direct: true }); + JSROOT.addDrawFunc({ name: "TMathText", icon: "img_text", prereq: "more2d", func: "JSROOT.Painter.drawText", direct: true }); + JSROOT.addDrawFunc({ name: "TText", icon: "img_text", prereq: "more2d", func: "JSROOT.Painter.drawText", direct: true }); + JSROOT.addDrawFunc({ name: /^TH1/, icon: "img_histo1d", prereq: "v6;hist", func: "JSROOT.Painter.drawHistogram1D", opt:";hist;P;P0;E;E1;E2;E3;E4;E1X0;L;LF2;B;B1;A;TEXT;LEGO;same", ctrl: "l" }); + JSROOT.addDrawFunc({ name: "TProfile", icon: "img_profile", prereq: "v6;hist", func: "JSROOT.Painter.drawHistogram1D", opt:";E0;E1;E2;p;AH;hist"}); + JSROOT.addDrawFunc({ name: "TH2Poly", icon: "img_histo2d", prereq: "v6;hist", func: "JSROOT.Painter.drawHistogram2D", opt:";COL;COL0;COLZ;LCOL;LCOL0;LCOLZ;LEGO;same", expand_item: "fBins", theonly: true }); + JSROOT.addDrawFunc({ name: "TProfile2Poly", sameas: "TH2Poly" }); + JSROOT.addDrawFunc({ name: "TH2PolyBin", icon: "img_histo2d", draw_field: "fPoly" }); + JSROOT.addDrawFunc({ name: /^TH2/, icon: "img_histo2d", prereq: "v6;hist", func: "JSROOT.Painter.drawHistogram2D", opt:";COL;COLZ;COL0;COL1;COL0Z;COL1Z;COLA;BOX;BOX1;SCAT;TEXT;CONT;CONT1;CONT2;CONT3;CONT4;ARR;SURF;SURF1;SURF2;SURF4;SURF6;E;A;LEGO;LEGO0;LEGO1;LEGO2;LEGO3;LEGO4;same", ctrl: "colz" }); + JSROOT.addDrawFunc({ name: "TProfile2D", sameas: "TH2" }); + JSROOT.addDrawFunc({ name: /^TH3/, icon: 'img_histo3d', prereq: "v6;hist3d", func: "JSROOT.Painter.drawHistogram3D", opt:";SCAT;BOX;BOX2;BOX3;GLBOX1;GLBOX2;GLCOL" }); + JSROOT.addDrawFunc({ name: "THStack", icon: "img_histo1d", prereq: "v6;hist", func: "JSROOT.Painter.drawHStack", expand_item: "fHists", opt: "NOSTACK;HIST;E;PFC;PLC" }); + JSROOT.addDrawFunc({ name: "TPolyMarker3D", icon: 'img_histo3d', prereq: "v6;hist3d", func: "JSROOT.Painter.drawPolyMarker3D" }); + JSROOT.addDrawFunc({ name: "TPolyLine3D", icon: 'img_graph', prereq: "3d", func: "JSROOT.Painter.drawPolyLine3D", direct: true }); + JSROOT.addDrawFunc({ name: "TGraphStruct" }); + JSROOT.addDrawFunc({ name: "TGraphNode" }); + JSROOT.addDrawFunc({ name: "TGraphEdge" }); + JSROOT.addDrawFunc({ name: "TGraphTime", icon:"img_graph", prereq: "more2d", func: "JSROOT.Painter.drawGraphTime", opt: "once;repeat;first", theonly: true }); + JSROOT.addDrawFunc({ name: "TGraph2D", icon:"img_graph", prereq: "v6;hist3d", func: "JSROOT.Painter.drawGraph2D", opt: ";P;PCOL", theonly: true }); + JSROOT.addDrawFunc({ name: "TGraph2DErrors", icon:"img_graph", prereq: "v6;hist3d", func: "JSROOT.Painter.drawGraph2D", opt: ";P;PCOL;ERR", theonly: true }); + JSROOT.addDrawFunc({ name: "TGraphPolargram", icon:"img_graph", prereq: "more2d", func: "JSROOT.Painter.drawGraphPolargram", theonly: true }); + JSROOT.addDrawFunc({ name: "TGraphPolar", icon:"img_graph", prereq: "more2d", func: "JSROOT.Painter.drawGraphPolar", opt: ";F;L;P;PE", theonly: true }); + JSROOT.addDrawFunc({ name: /^TGraph/, icon:"img_graph", prereq: "more2d", func: "JSROOT.Painter.drawGraph", opt: ";L;P" }); + JSROOT.addDrawFunc({ name: "TEfficiency", icon:"img_graph", prereq: "more2d", func: "JSROOT.Painter.drawEfficiency", opt: ";AP" }); + JSROOT.addDrawFunc({ name: "TCutG", sameas: "TGraph" }); + JSROOT.addDrawFunc({ name: /^RooHist/, sameas: "TGraph" }); + JSROOT.addDrawFunc({ name: /^RooCurve/, sameas: "TGraph" }); + JSROOT.addDrawFunc({ name: "RooPlot", icon: "img_canvas", prereq: "more2d", func: "JSROOT.Painter.drawRooPlot" }); + JSROOT.addDrawFunc({ name: "TMultiGraph", icon: "img_mgraph", prereq: "more2d", func: "JSROOT.Painter.drawMultiGraph", expand_item: "fGraphs" }); + JSROOT.addDrawFunc({ name: "TStreamerInfoList", icon: 'img_question', prereq: "hierarchy", func: "JSROOT.Painter.drawStreamerInfo" }); + JSROOT.addDrawFunc({ name: "TPaletteAxis", icon: "img_colz", prereq: "v6;hist", func: "JSROOT.Painter.drawPaletteAxis" }); + JSROOT.addDrawFunc({ name: "TWebPainting", icon: "img_graph", prereq: "more2d", func: "JSROOT.Painter.drawWebPainting" }); + JSROOT.addDrawFunc({ name: "TPadWebSnapshot", icon: "img_canvas", prereq: "v6", func: "JSROOT.Painter.drawPadSnapshot" }); + JSROOT.addDrawFunc({ name: "kind:Text", icon: "img_text", func: JSROOT.Painter.drawRawText }); + JSROOT.addDrawFunc({ name: "TObjString", icon: "img_text", func: JSROOT.Painter.drawRawText }); + JSROOT.addDrawFunc({ name: "TF1", icon: "img_tf1", prereq: "math;more2d", func: "JSROOT.Painter.drawFunction" }); + JSROOT.addDrawFunc({ name: "TF2", icon: "img_tf2", prereq: "math;hist", func: "JSROOT.Painter.drawTF2" }); + JSROOT.addDrawFunc({ name: "TSpline3", icon: "img_tf1", prereq: "more2d", func: "JSROOT.Painter.drawSpline" }); + JSROOT.addDrawFunc({ name: "TSpline5", icon: "img_tf1", prereq: "more2d", func: "JSROOT.Painter.drawSpline" }); + JSROOT.addDrawFunc({ name: "TEllipse", icon: 'img_graph', prereq: "more2d", func: "JSROOT.Painter.drawEllipse", direct: true }); + JSROOT.addDrawFunc({ name: "TArc", sameas: 'TEllipse' }); + JSROOT.addDrawFunc({ name: "TCrown", sameas: 'TEllipse' }); + JSROOT.addDrawFunc({ name: "TPie", icon: 'img_graph', prereq: "more2d", func: "JSROOT.Painter.drawPie", direct: true }); + JSROOT.addDrawFunc({ name: "TLine", icon: 'img_graph', prereq: "more2d", func: "JSROOT.Painter.drawLine", direct: true }); + JSROOT.addDrawFunc({ name: "TArrow", icon: 'img_graph', prereq: "more2d", func: "JSROOT.Painter.drawArrow", direct: true }); + JSROOT.addDrawFunc({ name: "TPolyLine", icon: 'img_graph', prereq: "more2d", func: "JSROOT.Painter.drawPolyLine", direct: true }); + JSROOT.addDrawFunc({ name: "TCurlyLine", sameas: 'TPolyLine' }); + JSROOT.addDrawFunc({ name: "TCurlyArc", sameas: 'TPolyLine' }); + JSROOT.addDrawFunc({ name: "TGaxis", icon: "img_graph", prereq: "v6", func: "JSROOT.Painter.drawGaxis" }); + JSROOT.addDrawFunc({ name: "TLegend", icon: "img_pavelabel", prereq: "v6;hist", func: "JSROOT.Painter.drawPave" }); + JSROOT.addDrawFunc({ name: "TBox", icon: 'img_graph', prereq: "more2d", func: "JSROOT.Painter.drawBox", direct: true }); + JSROOT.addDrawFunc({ name: "TWbox", icon: 'img_graph', prereq: "more2d", func: "JSROOT.Painter.drawBox", direct: true }); + JSROOT.addDrawFunc({ name: "TSliderBox", icon: 'img_graph', prereq: "more2d", func: "JSROOT.Painter.drawBox", direct: true }); + JSROOT.addDrawFunc({ name: "TAxis3D", prereq: "v6;hist3d", func: "JSROOT.Painter.drawAxis3D" }); + JSROOT.addDrawFunc({ name: "TMarker", icon: 'img_graph', prereq: "more2d", func: "JSROOT.Painter.drawMarker", direct: true }); + JSROOT.addDrawFunc({ name: "TPolyMarker", icon: 'img_graph', prereq: "more2d", func: "JSROOT.Painter.drawPolyMarker", direct: true }); + JSROOT.addDrawFunc({ name: "TASImage", icon: 'img_mgraph', prereq: "more2d", func: "JSROOT.Painter.drawASImage" }); + JSROOT.addDrawFunc({ name: "TJSImage", icon: 'img_mgraph', prereq: "more2d", func: "JSROOT.Painter.drawJSImage", opt: ";scale;center" }); + JSROOT.addDrawFunc({ name: "TGeoVolume", icon: 'img_histo3d', prereq: "geom", func: "JSROOT.Painter.drawGeoObject", expand: "JSROOT.GEO.expandObject", opt:";more;all;count;projx;projz;dflt", ctrl: "dflt" }); + JSROOT.addDrawFunc({ name: "TEveGeoShapeExtract", icon: 'img_histo3d', prereq: "geom", func: "JSROOT.Painter.drawGeoObject", expand: "JSROOT.GEO.expandObject", opt: ";more;all;count;projx;projz;dflt", ctrl: "dflt" }); + JSROOT.addDrawFunc({ name: "ROOT::Experimental::TEveGeoShapeExtract", icon: 'img_histo3d', prereq: "geom", func: "JSROOT.Painter.drawGeoObject", expand: "JSROOT.GEO.expandObject", opt: ";more;all;count;projx;projz;dflt", ctrl: "dflt" }); + JSROOT.addDrawFunc({ name: "TGeoManager", icon: 'img_histo3d', prereq: "geom", expand: "JSROOT.GEO.expandObject", func: "JSROOT.Painter.drawGeoObject", opt: ";more;all;count;projx;projz;dflt", dflt: "expand", ctrl: "dflt" }); + JSROOT.addDrawFunc({ name: /^TGeo/, icon: 'img_histo3d', prereq: "geom", func: "JSROOT.Painter.drawGeoObject", opt: ";more;all;axis;compa;count;projx;projz;dflt", ctrl: "dflt" }); + // these are not draw functions, but provide extra info about correspondent classes + JSROOT.addDrawFunc({ name: "kind:Command", icon: "img_execute", execute: true }); + JSROOT.addDrawFunc({ name: "TFolder", icon: "img_folder", icon2: "img_folderopen", noinspect: true, prereq: "hierarchy", expand: "JSROOT.Painter.FolderHierarchy" }); + JSROOT.addDrawFunc({ name: "TTask", icon: "img_task", prereq: "hierarchy", expand: "JSROOT.Painter.TaskHierarchy", for_derived: true }); + JSROOT.addDrawFunc({ name: "TTree", icon: "img_tree", prereq: "tree;more2d", expand: 'JSROOT.Painter.TreeHierarchy', func: 'JSROOT.Painter.drawTree', dflt: "expand", opt: "player;testio", shift: "inspect" }); + JSROOT.addDrawFunc({ name: "TNtuple", icon: "img_tree", prereq: "tree;more2d", expand: 'JSROOT.Painter.TreeHierarchy', func: 'JSROOT.Painter.drawTree', dflt: "expand", opt: "player;testio", shift: "inspect" }); + JSROOT.addDrawFunc({ name: "TNtupleD", icon: "img_tree", prereq: "tree;more2d", expand: 'JSROOT.Painter.TreeHierarchy', func: 'JSROOT.Painter.drawTree', dflt: "expand", opt: "player;testio", shift: "inspect" }); + JSROOT.addDrawFunc({ name: "TBranchFunc", icon: "img_leaf_method", prereq: "tree;more2d", func: 'JSROOT.Painter.drawTree', opt: ";dump", noinspect: true }); + JSROOT.addDrawFunc({ name: /^TBranch/, icon: "img_branch", prereq: "tree;more2d", func: 'JSROOT.Painter.drawTree', dflt: "expand", opt: ";dump", ctrl: "dump", shift: "inspect", ignore_online: true }); + JSROOT.addDrawFunc({ name: /^TLeaf/, icon: "img_leaf", prereq: "tree;more2d", noexpand: true, func: 'JSROOT.Painter.drawTree', opt: ";dump", ctrl: "dump", ignore_online: true }); + JSROOT.addDrawFunc({ name: "TList", icon: "img_list", prereq: "hierarchy", func: "JSROOT.Painter.drawList", expand: "JSROOT.Painter.ListHierarchy", dflt: "expand" }); + JSROOT.addDrawFunc({ name: "THashList", sameas: "TList" }); + JSROOT.addDrawFunc({ name: "TObjArray", sameas: "TList" }); + JSROOT.addDrawFunc({ name: "TClonesArray", sameas: "TList" }); + JSROOT.addDrawFunc({ name: "TMap", sameas: "TList" }); + JSROOT.addDrawFunc({ name: "TColor", icon: "img_color" }); + JSROOT.addDrawFunc({ name: "TFile", icon: "img_file", noinspect:true }); + JSROOT.addDrawFunc({ name: "TMemFile", icon: "img_file", noinspect:true }); + JSROOT.addDrawFunc({ name: "TStyle", icon: "img_question", noexpand:true }); + JSROOT.addDrawFunc({ name: "Session", icon: "img_globe" }); + JSROOT.addDrawFunc({ name: "kind:TopFolder", icon: "img_base" }); + JSROOT.addDrawFunc({ name: "kind:Folder", icon: "img_folder", icon2: "img_folderopen", noinspect:true }); + + JSROOT.addDrawFunc({ name: "ROOT::Experimental::TCanvas", icon: "img_canvas", prereq: "v7", func: "JSROOT.v7.drawCanvas", opt: "", expand_item: "fPrimitives" }); + + + JSROOT.getDrawHandle = function(kind, selector) { + // return draw handle for specified item kind + // kind could be ROOT.TH1I for ROOT classes or just + // kind string like "Command" or "Text" + // selector can be used to search for draw handle with specified option (string) + // or just sequence id + + if (typeof kind != 'string') return null; + if (selector === "") selector = null; + + var first = null; + + if ((selector === null) && (kind in JSROOT.DrawFuncs.cache)) + return JSROOT.DrawFuncs.cache[kind]; + + var search = (kind.indexOf("ROOT.")==0) ? kind.substr(5) : "kind:"+kind, counter = 0; + for (var i=0; i < JSROOT.DrawFuncs.lst.length; ++i) { + var h = JSROOT.DrawFuncs.lst[i]; + if (typeof h.name == "string") { + if (h.name != search) continue; + } else { + if (!search.match(h.name)) continue; + } + + if (h.sameas !== undefined) + return JSROOT.getDrawHandle("ROOT."+h.sameas, selector); + + if ((selector === null) || (selector === undefined)) { + // store found handle in cache, can reuse later + if (!(kind in JSROOT.DrawFuncs.cache)) JSROOT.DrawFuncs.cache[kind] = h; + return h; + } else if (typeof selector == 'string') { + if (!first) first = h; + // if drawoption specified, check it present in the list + + if (selector == "::expand") { + if (('expand' in h) || ('expand_item' in h)) return h; + } else + if ('opt' in h) { + var opts = h.opt.split(';'); + for (var j=0; j < opts.length; ++j) opts[j] = opts[j].toLowerCase(); + if (opts.indexOf(selector.toLowerCase())>=0) return h; + } + } else if (selector === counter) { + return h; + } + ++counter; + } + + return first; + } + + /** @summary Scan streamer infos for derived classes + * @desc Assign draw functions for such derived classes + * @private */ + JSROOT.addStreamerInfos = function(lst) { + if (!lst) return; + + function CheckBaseClasses(si, lvl) { + if (si.fElements == null) return null; + if (lvl>10) return null; // protect against recursion + + for (var j=0; j<si.fElements.arr.length; ++j) { + // extract streamer info for each class member + var element = si.fElements.arr[j]; + if (element.fTypeName !== 'BASE') continue; + + var handle = JSROOT.getDrawHandle("ROOT." + element.fName); + if (handle && !handle.for_derived) handle = null; + + // now try find that base class of base in the list + if (handle === null) + for (var k=0;k<lst.arr.length; ++k) + if (lst.arr[k].fName === element.fName) { + handle = CheckBaseClasses(lst.arr[k], lvl+1); + break; + } + + if (handle && handle.for_derived) return handle; + } + return null; + } + + for (var n=0;n<lst.arr.length;++n) { + var si = lst.arr[n]; + if (JSROOT.getDrawHandle("ROOT." + si.fName) !== null) continue; + + var handle = CheckBaseClasses(si, 0); + + if (!handle) continue; + + var newhandle = JSROOT.extend({}, handle); + // delete newhandle.for_derived; // should we disable? + newhandle.name = si.fName; + JSROOT.DrawFuncs.lst.push(newhandle); + } + } + + /** @summary Provide draw settings for specified class or kind + * @private + */ + JSROOT.getDrawSettings = function(kind, selector) { + var res = { opts: null, inspect: false, expand: false, draw: false, handle: null }; + if (typeof kind != 'string') return res; + var allopts = null, isany = false, noinspect = false, canexpand = false; + if (typeof selector !== 'string') selector = ""; + + for (var cnt=0;cnt<1000;++cnt) { + var h = JSROOT.getDrawHandle(kind, cnt); + if (!h) break; + if (!res.handle) res.handle = h; + if (h.noinspect) noinspect = true; + if (h.expand || h.expand_item || h.can_expand) canexpand = true; + if (!('func' in h)) break; + isany = true; + if (! ('opt' in h)) continue; + var opts = h.opt.split(';'); + for (var i = 0; i < opts.length; ++i) { + opts[i] = opts[i].toLowerCase(); + if ((selector.indexOf('nosame')>=0) && (opts[i].indexOf('same')==0)) continue; + + if (res.opts===null) res.opts = []; + if (res.opts.indexOf(opts[i])<0) res.opts.push(opts[i]); + } + if (h.theonly) break; + } + + if (selector.indexOf('noinspect')>=0) noinspect = true; + + if (isany && (res.opts===null)) res.opts = [""]; + + // if no any handle found, let inspect ROOT-based objects + if (!isany && (kind.indexOf("ROOT.")==0) && !noinspect) res.opts = []; + + if (!noinspect && res.opts) + res.opts.push("inspect"); + + res.inspect = !noinspect; + res.expand = canexpand; + res.draw = res.opts && (res.opts.length>0); + + return res; + } + + /** Returns array with supported draw options for the specified kind + * @private */ + JSROOT.getDrawOptions = function(kind, selector) { + return JSROOT.getDrawSettings(kind).opts; + } + + /** @summary Returns true if provided object class can be drawn + * @private */ + JSROOT.canDraw = function(classname) { + return JSROOT.getDrawSettings("ROOT." + classname).opts !== null; + } + + /** + * @summary Draw object in specified HTML element with given draw options. + * + * @param {string|object} divid - id of div element to draw or directly DOMElement + * @param {object} obj - object to draw, object type should be registered before in JSROOT + * @param {string} opt - draw options separated by space, comma or semicolon + * @param {function} drawcallback - function called when drawing is completed, first argument is object painter instance + * + * @desc + * A complete list of options can be found depending of the object's ROOT class to draw: {@link https://root.cern/js/latest/examples.htm} + * + * @example + * var filename = "https://root.cern/js/files/hsimple.root"; + * JSROOT.OpenFile(filename, function(file) { + * file.ReadObject("hpxpy;1", function(obj) { + * JSROOT.draw("drawing", obj, "colz;logx;gridx;gridy"); + * }); + * }); + * + */ + JSROOT.draw = function(divid, obj, opt, drawcallback) { + + var isdirectdraw = true; // indicates if extra callbacks (via AssertPrerequisites) was invoked to process + + function completeDraw(painter) { + var callbackfunc = null, ishandle = false; + if (typeof drawcallback == 'function') callbackfunc = drawcallback; else + if (drawcallback && (typeof drawcallback == 'object') && (typeof drawcallback.func=='function')) { + callbackfunc = drawcallback.func; + ishandle = true; + } + + if (ishandle && isdirectdraw) { + // if there is no painter or drawing is already completed, return directly + if (!painter || painter._ready_called_) { drawcallback.completed = true; return painter; } + } + + if (painter && drawcallback && (typeof painter.WhenReady == 'function')) + painter.WhenReady(callbackfunc); + else + JSROOT.CallBack(callbackfunc, painter); + return painter; + } + + if ((obj === null) || (typeof obj !== 'object')) return completeDraw(null); + + if (opt == 'inspect') { + var func = JSROOT.findFunction("JSROOT.Painter.drawInspector"); + if (func) return completeDraw(func(divid, obj)); + JSROOT.AssertPrerequisites("hierarchy", function() { + completeDraw(JSROOT.Painter.drawInspector(divid, obj)); + }); + return null; + } + + var handle = null, painter = null; + if ('_typename' in obj) handle = JSROOT.getDrawHandle("ROOT." + obj._typename, opt); + else if ('_kind' in obj) handle = JSROOT.getDrawHandle(obj._kind, opt); + + if (!handle) return completeDraw(null); + + if (handle.draw_field && obj[handle.draw_field]) + return JSROOT.draw(divid, obj[handle.draw_field], opt, drawcallback); + + if (!handle.func) { + if (opt && (opt.indexOf("same")>=0)) { + var main_painter = JSROOT.GetMainPainter(divid); + if (main_painter && (typeof main_painter.PerformDrop === 'function')) + return main_painter.PerformDrop(obj, "", null, opt, completeDraw); + } + + return completeDraw(null); + } + + function performDraw() { + if (handle.direct) { + painter = new TObjectPainter(obj, opt); + painter.SetDivId(divid, 2); + painter.Redraw = handle.func; + painter.Redraw(); + painter.DrawingReady(); + } else { + painter = handle.func(divid, obj, opt); + + if (painter && !painter.options) painter.options = { original: opt || "" }; + } + + return completeDraw(painter); + } + + if (typeof handle.func == 'function') return performDraw(); + + var funcname = "", prereq = ""; + if (typeof handle.func == 'object') { + if ('func' in handle.func) funcname = handle.func.func; + if ('script' in handle.func) prereq = "user:" + handle.func.script; + } else + if (typeof handle.func == 'string') { + funcname = handle.func; + if (('prereq' in handle) && (typeof handle.prereq == 'string')) prereq = handle.prereq; + if (('script' in handle) && (typeof handle.script == 'string')) prereq += ";user:" + handle.script; + } + + if (funcname.length === 0) return completeDraw(null); + + // try to find function without prerequisites + var func = JSROOT.findFunction(funcname); + if (func) { + handle.func = func; // remember function once it is found + return performDraw(); + } + + if (prereq.length === 0) return completeDraw(null); + + isdirectdraw = false; + + JSROOT.AssertPrerequisites(prereq, function() { + var func = JSROOT.findFunction(funcname); + if (!func) { + alert('Fail to find function ' + funcname + ' after loading ' + prereq); + return completeDraw(null); + } + + handle.func = func; // remember function once it found + + performDraw(); + }); + + return painter; + } + + /** + * @summary Redraw object in specified HTML element with given draw options. + * + * @desc If drawing was not drawn before, it will be performed with {@link JSROOT.draw}. + * If drawing was already done, that content will be updated + * @param {string|object} divid - id of div element to draw or directly DOMElement + * @param {object} obj - object to draw, object type should be registered before in JSROOT + * @param {string} opt - draw options + * @param {function} callback - function called when drawing is completed, first argument will be object painter instance + */ + JSROOT.redraw = function(divid, obj, opt, callback) { + if (!obj) return JSROOT.CallBack(callback, null); + + var dummy = new TObjectPainter(); + dummy.SetDivId(divid, -1); + var can_painter = dummy.canv_painter(); + + var handle = null; + if (obj._typename) handle = JSROOT.getDrawHandle("ROOT." + obj._typename); + if (handle && handle.draw_field && obj[handle.draw_field]) + obj = obj[handle.draw_field]; + + if (can_painter) { + if (obj._typename === "TCanvas") { + can_painter.RedrawObject(obj); + JSROOT.CallBack(callback, can_painter); + return can_painter; + } + + for (var i = 0; i < can_painter.painters.length; ++i) { + var painter = can_painter.painters[i]; + if (painter.MatchObjectType(obj._typename)) + if (painter.UpdateObject(obj)) { + can_painter.RedrawPad(); + JSROOT.CallBack(callback, painter); + return painter; + } + } + } + + if (can_painter) + JSROOT.console("Cannot find painter to update object of type " + obj._typename); + + JSROOT.cleanup(divid); + + return JSROOT.draw(divid, obj, opt, callback); + } + + /** @summary Save object, drawn in specified element, as JSON. + * + * @desc Normally it is TCanvas object with list of primitives + * @param {string|object} divid - id of top div element or directly DOMElement + * @returns {string} produced JSON string + */ + + JSROOT.StoreJSON = function(divid) { + var p = new TObjectPainter; + p.SetDivId(divid,-1); + + var canp = p.canv_painter(); + return canp ? canp.ProduceJSON() : ""; + } + + + /** @summary Create SVG image for provided object. + * + * @desc Function especially useful in Node.js environment to generate images for + * supported ROOT classes + * + * @param {object} args - contains different settings + * @param {object} args.object - object for the drawing + * @param {string} [args.option] - draw options + * @param {number} [args.width = 1200] - image width + * @param {number} [args.height = 800] - image height + * @param {function} callback called with svg code as string argument + */ + JSROOT.MakeSVG = function(args, callback) { + + if (!args) args = {}; + + if (!args.object) return JSROOT.CallBack(callback, null); + + if (!args.width) args.width = 1200; + if (!args.height) args.height = 800; + + function build(main) { + + main.attr("width", args.width).attr("height", args.height); + + main.style("width", args.width+"px").style("height", args.height+"px"); + + JSROOT.svg_workaround = undefined; + + JSROOT.draw(main.node(), args.object, args.option || "", function(painter) { + + var has_workarounds = JSROOT.Painter.ProcessSVGWorkarounds && JSROOT.svg_workaround; + + main.select('svg').attr("xmlns", "http://www.w3.org/2000/svg") + .attr("xmlns:xlink", "http://www.w3.org/1999/xlink") + .attr("width", args.width) + .attr("height", args.height) + .attr("style", null).attr("class", null).attr("x", null).attr("y", null); + + var svg = main.html(); + + if (JSROOT.nodejs) + svg = svg.replace(/xlink_href_nodejs=/g,"xlink:href="); + + if (has_workarounds) + svg = JSROOT.Painter.ProcessSVGWorkarounds(svg); + + svg = svg.replace(/url\(\"\;\#(\w+)\"\;\)/g,"url(#$1)") // decode all URL + .replace(/ class=\"\w*\"/g,"") // remove all classes + .replace(/<g transform=\"translate\(\d+\,\d+\)\"><\/g>/g,"") // remove all empty groups with transform + .replace(/<g><\/g>/g,""); // remove all empty groups + + if (svg.indexOf("xlink:href")<0) + svg = svg.replace(/ xmlns:xlink=\"http:\/\/www.w3.org\/1999\/xlink\"/g,""); + + main.remove(); + + JSROOT.CallBack(callback, svg); + }); + } + + if (!JSROOT.nodejs) { + build(d3.select(window.document).append("div").style("visible", "hidden")); + } else if (JSROOT.nodejs_document) { + build(JSROOT.nodejs_window.d3.select('body').append('div')); + } else { + // use eval while old minifier is not able to parse newest Node.js syntax + eval('const { JSDOM } = require("jsdom"); JSROOT.nodejs_window = (new JSDOM("<!DOCTYPE html>hello")).window;'); + JSROOT.nodejs_document = JSROOT.nodejs_window.document; // used with three.js + JSROOT.nodejs_window.d3 = d3.select(JSROOT.nodejs_document); //get d3 into the dom + build(JSROOT.nodejs_window.d3.select('body').append('div')); + } + } + + /** + * @summary Check resize of drawn element + * + * @desc As first argument divid one should use same argument as for the drawing + * As second argument, one could specify "true" value to force redrawing of + * the element even after minimal resize of the element + * Or one just supply object with exact sizes like { width:300, height:200, force:true }; + * @param {string|object} divid - id or DOM element + * @param {boolean|object} arg - options on how to resize + * + * @example + * JSROOT.resize("drawing", { width: 500, height: 200 } ); + * JSROOT.resize(document.querySelector("#drawing"), true); + */ + JSROOT.resize = function(divid, arg) { + if (arg === true) arg = { force: true }; else + if (typeof arg !== 'object') arg = null; + var dummy = new TObjectPainter(), done = false; + dummy.SetDivId(divid, -1); + dummy.ForEachPainter(function(painter) { + if (!done && typeof painter.CheckResize == 'function') + done = painter.CheckResize(arg); + }); + return done; + } + + /** + * For compatibility, see {@link JSROOT.resize} + * @private + */ + JSROOT.CheckElementResize = JSROOT.resize; + + /** @summary Returns main painter object for specified HTML element + * @param {string|object} divid - id or DOM element + */ + + JSROOT.GetMainPainter = function(divid) { + var dummy = new JSROOT.TObjectPainter(); + dummy.SetDivId(divid, -1); + return dummy.main_painter(true); + } + + /** + * @summary Safely remove all JSROOT objects from specified element + * + * @param {string|object} divid - id or DOM element + * + * @example + * JSROOT.cleanup("drawing"); + * JSROOT.cleanup(document.querySelector("#drawing")); + */ + JSROOT.cleanup = function(divid) { + var dummy = new TObjectPainter(), lst = []; + dummy.SetDivId(divid, -1); + dummy.ForEachPainter(function(painter) { + if (lst.indexOf(painter) < 0) lst.push(painter); + }); + for (var n=0;n<lst.length;++n) lst[n].Cleanup(); + dummy.select_main().html(""); + return lst; + } + + /** Display progress message in the left bottom corner. + * + * Previous message will be overwritten + * if no argument specified, any shown messages will be removed + * @param {string} msg - message to display + * @param {number} tmout - optional timeout in milliseconds, after message will disappear + * @private + */ + JSROOT.progress = function(msg, tmout) { + if (JSROOT.BatchMode || (typeof document === 'undefined')) return; + var id = "jsroot_progressbox", + box = d3.select("#"+id); + + if (!JSROOT.gStyle.ProgressBox) return box.remove(); + + if ((arguments.length == 0) || !msg) { + if ((tmout !== -1) || (!box.empty() && box.property("with_timeout"))) box.remove(); + return; + } + + if (box.empty()) { + box = d3.select(document.body) + .append("div") + .attr("id", id); + box.append("p"); + } + + box.property("with_timeout", false); + + if (typeof msg === "string") { + box.select("p").html(msg); + } else { + box.html(""); + box.node().appendChild(msg); + } + + if (!isNaN(tmout) && (tmout>0)) { + box.property("with_timeout", true); + setTimeout(JSROOT.progress.bind(JSROOT,'',-1), tmout); + } + } + + /** Tries to close current browser tab + * + * Many browsers do not allow simple window.close() call, + * therefore try several workarounds + */ + + JSROOT.CloseCurrentWindow = function() { + if (!window) return; + window.close(); + window.open('','_self').close(); + } + + Painter.createRootColors(); + + JSROOT.LongPollSocket = LongPollSocket; + JSROOT.WebWindowHandle = WebWindowHandle; + JSROOT.DrawOptions = DrawOptions; + JSROOT.ColorPalette = ColorPalette; + JSROOT.TAttLineHandler = TAttLineHandler; + JSROOT.TAttFillHandler = TAttFillHandler; + JSROOT.TAttMarkerHandler = TAttMarkerHandler; + JSROOT.TBasePainter = TBasePainter; + JSROOT.TObjectPainter = TObjectPainter; + JSROOT.TooltipHandler = TooltipHandler; + + return JSROOT; + +})); diff --git a/js/scripts/JSRootPainter.more.js b/js/scripts/JSRootPainter.more.js new file mode 100644 index 00000000000..3e17f3348d7 --- /dev/null +++ b/js/scripts/JSRootPainter.more.js @@ -0,0 +1,3702 @@ +/// @file JSRootPainter.more.js +/// Part of JavaScript ROOT graphics with more classes like TEllipse, TLine, ... +/// Such classes are rarely used and therefore loaded only on demand + +(function( factory ) { + if ( typeof define === "function" && define.amd ) { + define( ['JSRootPainter', 'd3', 'JSRootMath'], factory ); + } else + if (typeof exports === 'object' && typeof module !== 'undefined') { + factory(require("./JSRootCore.js"), require("./d3.min.js"), require("./JSRootMath.js")); + } else { + + if (typeof d3 != 'object') + throw new Error('This extension requires d3.v3.js', 'JSRootPainter.more.js'); + + if (typeof JSROOT == 'undefined') + throw new Error('JSROOT is not defined', 'JSRootPainter.more.js'); + + if (typeof JSROOT.Painter != 'object') + throw new Error('JSROOT.Painter not defined', 'JSRootPainter.more.js'); + + factory(JSROOT, d3); + } +} (function(JSROOT, d3) { + + "use strict"; + + JSROOT.sources.push("more2d"); + + function drawText() { + var text = this.GetObject(), + w = this.pad_width(), h = this.pad_height(), + pos_x = text.fX, pos_y = text.fY, + tcolor = this.get_color(text.fTextColor), + use_frame = false, + fact = 1., textsize = text.fTextSize || 0.05, + main = this.frame_painter(); + + if (text.TestBit(JSROOT.BIT(14))) { + // NDC coordinates + pos_x = pos_x * w; + pos_y = (1 - pos_y) * h; + } else if (main && !main.mode3d) { + w = this.frame_width(); h = this.frame_height(); use_frame = "upper_layer"; + pos_x = main.grx(pos_x); + pos_y = main.gry(pos_y); + } else if (this.root_pad() !== null) { + pos_x = this.ConvertToNDC("x", pos_x) * w; + pos_y = (1 - this.ConvertToNDC("y", pos_y)) * h; + } else { + text.fTextAlign = 22; + pos_x = w/2; + pos_y = h/2; + if (!tcolor) tcolor = 'black'; + } + + this.CreateG(use_frame); + + var arg = { align: text.fTextAlign, x: Math.round(pos_x), y: Math.round(pos_y), text: text.fTitle, color: tcolor, latex: 0 }; + + if (text.fTextAngle) arg.rotate = -text.fTextAngle; + + if (text._typename == 'TLatex') { arg.latex = 1; fact = 0.9; } else + if (text._typename == 'TMathText') { arg.latex = 2; fact = 0.8; } + + this.StartTextDrawing(text.fTextFont, Math.round((textsize>1) ? textsize : textsize*Math.min(w,h)*fact)); + + this.DrawText(arg); + + this.FinishTextDrawing(); + } + + // ===================================================================================== + + function drawLine() { + + var line = this.GetObject(), + lineatt = new JSROOT.TAttLineHandler(line), + kLineNDC = JSROOT.BIT(14), + isndc = line.TestBit(kLineNDC); + + // create svg:g container for line drawing + this.CreateG(); + + this.draw_g + .append("svg:line") + .attr("x1", this.AxisToSvg("x", line.fX1, isndc)) + .attr("y1", this.AxisToSvg("y", line.fY1, isndc)) + .attr("x2", this.AxisToSvg("x", line.fX2, isndc)) + .attr("y2", this.AxisToSvg("y", line.fY2, isndc)) + .call(lineatt.func); + } + + // ============================================================================= + + function drawPolyLine() { + + var polyline = this.GetObject(), + lineatt = new JSROOT.TAttLineHandler(polyline), + fillatt = this.createAttFill(polyline), + kPolyLineNDC = JSROOT.BIT(14), + isndc = polyline.TestBit(kPolyLineNDC), + cmd = "", func = this.AxisToSvgFunc(isndc); + + // create svg:g container for polyline drawing + this.CreateG(); + + for (var n=0;n<=polyline.fLastPoint;++n) + cmd += ((n>0) ? "L" : "M") + func.x(polyline.fX[n]) + "," + func.y(polyline.fY[n]); + + if (polyline._typename != "TPolyLine") fillatt.SetSolidColor("none"); + + if (!fillatt.empty()) cmd+="Z"; + + this.draw_g + .append("svg:path") + .attr("d", cmd) + .call(lineatt.func) + .call(fillatt.func); + } + + // ============================================================================== + + function drawEllipse() { + + var ellipse = this.GetObject(); + + this.createAttLine({ attr: ellipse }); + this.createAttFill({ attr: ellipse }); + + // create svg:g container for ellipse drawing + this.CreateG(); + + var x = this.AxisToSvg("x", ellipse.fX1, false), + y = this.AxisToSvg("y", ellipse.fY1, false), + rx = this.AxisToSvg("x", ellipse.fX1 + ellipse.fR1, false) - x, + ry = y - this.AxisToSvg("y", ellipse.fY1 + ellipse.fR2, false); + + if (ellipse._typename == "TCrown") { + if (ellipse.fR1 <= 0) { + // handle same as ellipse with equal radius + rx = this.AxisToSvg("x", ellipse.fX1 + ellipse.fR2, false) - x; + } else { + var rx1 = rx, ry2 = ry, + ry1 = y - this.AxisToSvg("y", ellipse.fY1 + ellipse.fR1, false), + rx2 = this.AxisToSvg("x", ellipse.fX1 + ellipse.fR2, false) - x; + + var elem = this.draw_g + .attr("transform","translate("+x+","+y+")") + .append("svg:path") + .call(this.lineatt.func).call(this.fillatt.func); + + if ((ellipse.fPhimin == 0) && (ellipse.fPhimax == 360)) { + elem.attr("d", "M-"+rx1+",0" + + "A"+rx1+","+ry1+",0,1,0,"+rx1+",0" + + "A"+rx1+","+ry1+",0,1,0,-"+rx1+",0" + + "M-"+rx2+",0" + + "A"+rx2+","+ry2+",0,1,0,"+rx2+",0" + + "A"+rx2+","+ry2+",0,1,0,-"+rx2+",0"); + + } else { + var large_arc = (ellipse.fPhimax-ellipse.fPhimin>=180) ? 1 : 0; + + var a1 = ellipse.fPhimin*Math.PI/180, a2 = ellipse.fPhimax*Math.PI/180, + dx1 = rx1 * Math.cos(a1), dy1 = ry1 * Math.sin(a1), + dx2 = rx1 * Math.cos(a2), dy2 = ry1 * Math.sin(a2), + dx3 = rx2 * Math.cos(a1), dy3 = ry2 * Math.sin(a1), + dx4 = rx2 * Math.cos(a2), dy4 = ry2 * Math.sin(a2); + + elem.attr("d", "M"+Math.round(dx2)+","+Math.round(dy2)+ + "A"+rx1+","+ry1+",0,"+large_arc+",0,"+Math.round(dx1)+","+Math.round(dy1)+ + "L"+Math.round(dx3)+","+Math.round(dy3) + + "A"+rx2+","+ry2+",0,"+large_arc+",1,"+Math.round(dx4)+","+Math.round(dy4)+"Z"); + } + + return; + } + } + + if ((ellipse.fPhimin == 0) && (ellipse.fPhimax == 360) && (ellipse.fTheta == 0)) { + // this is simple case, which could be drawn with svg:ellipse + this.draw_g.append("svg:ellipse") + .attr("cx", x).attr("cy", y) + .attr("rx", rx).attr("ry", ry) + .call(this.lineatt.func).call(this.fillatt.func); + return; + } + + // here svg:path is used to draw more complex figure + + var ct = Math.cos(Math.PI*ellipse.fTheta/180), + st = Math.sin(Math.PI*ellipse.fTheta/180), + dx1 = rx * Math.cos(ellipse.fPhimin*Math.PI/180), + dy1 = ry * Math.sin(ellipse.fPhimin*Math.PI/180), + x1 = dx1*ct - dy1*st, + y1 = -dx1*st - dy1*ct, + dx2 = rx * Math.cos(ellipse.fPhimax*Math.PI/180), + dy2 = ry * Math.sin(ellipse.fPhimax*Math.PI/180), + x2 = dx2*ct - dy2*st, + y2 = -dx2*st - dy2*ct; + + this.draw_g + .attr("transform","translate("+x+","+y+")") + .append("svg:path") + .attr("d", "M0,0" + + "L" + Math.round(x1) + "," + Math.round(y1) + + "A"+rx+ ","+ry + "," + Math.round(-ellipse.fTheta) + ",1,0," + Math.round(x2) + "," + Math.round(y2) + + "Z") + .call(this.lineatt.func).call(this.fillatt.func); + } + + // ============================================================================== + + function drawPie() { + var pie = this.GetObject(); + + // create svg:g container for ellipse drawing + this.CreateG(); + + var xc = this.AxisToSvg("x", pie.fX, false), + yc = this.AxisToSvg("y", pie.fY, false), + rx = this.AxisToSvg("x", pie.fX + pie.fRadius, false) - xc, + ry = this.AxisToSvg("y", pie.fY + pie.fRadius, false) - yc; + + this.draw_g.attr("transform","translate("+xc+","+yc+")"); + + // Draw the slices + var nb = pie.fPieSlices.length, + slice, title, value, total = 0, lineatt, fillatt; + + for (var n=0;n<nb; n++) { + slice = pie.fPieSlices[n]; + total = total + slice.fValue; + } + + var af = (pie.fAngularOffset*Math.PI)/180.; + var x1 = rx*Math.cos(af); + var y1 = ry*Math.sin(af); + var x2, y2, a = af; + + for (var n=0;n<nb; n++) { + slice = pie.fPieSlices[n]; + lineatt = new JSROOT.TAttLineHandler(slice); + fillatt = this.createAttFill(slice); + value = slice.fValue; + a = a + ((2*Math.PI)/total)*value; + x2 = rx*Math.cos(a); + y2 = ry*Math.sin(a); + title = slice.fTitle; + this.draw_g + .append("svg:path") + .attr("d", "M0,0L"+x1.toFixed(1)+","+y1.toFixed(1)+"A"+ + rx.toFixed(1)+","+ry.toFixed(1)+",0,0,0,"+x2.toFixed(1)+","+y2.toFixed(1)+ + "Z") + .call(lineatt.func) + .call(fillatt.func); + x1 = x2; + y1 = y2; + } + } + + // ============================================================================= + + function drawBox() { + + var box = this.GetObject(), + opt = this.OptionsAsString(), + draw_line = (opt.toUpperCase().indexOf("L")>=0), + lineatt = this.createAttLine(box), + fillatt = this.createAttFill(box); + + // create svg:g container for box drawing + this.CreateG(); + + var x1 = this.AxisToSvg("x", box.fX1, false), + x2 = this.AxisToSvg("x", box.fX2, false), + y1 = this.AxisToSvg("y", box.fY1, false), + y2 = this.AxisToSvg("y", box.fY2, false), + xx = Math.min(x1,x2), yy = Math.min(y1,y2), + ww = Math.abs(x2-x1), hh = Math.abs(y1-y2); + + // if box filled, contour line drawn only with "L" draw option: + if (!fillatt.empty() && !draw_line) lineatt.color = "none"; + + this.draw_g + .append("svg:rect") + .attr("x", xx).attr("y", yy) + .attr("width", ww) + .attr("height", hh) + .call(lineatt.func) + .call(fillatt.func); + + if (box.fBorderMode && box.fBorderSize && (fillatt.color!=='none')) { + var pww = box.fBorderSize, phh = box.fBorderSize, + side1 = "M"+xx+","+yy + "h"+ww + "l"+(-pww)+","+phh + "h"+(2*pww-ww) + + "v"+(hh-2*phh)+ "l"+(-pww)+","+phh + "z", + side2 = "M"+(xx+ww)+","+(yy+hh) + "v"+(-hh) + "l"+(-pww)+","+phh + "v"+(hh-2*phh)+ + "h"+(2*pww-ww) + "l"+(-pww)+","+phh + "z"; + + if (box.fBorderMode<0) { var s = side1; side1 = side2; side2 = s; } + + this.draw_g.append("svg:path") + .attr("d", side1) + .style("stroke","none") + .call(fillatt.func) + .style("fill", d3.rgb(fillatt.color).brighter(0.5).toString()); + + this.draw_g.append("svg:path") + .attr("d", side2) + .style("stroke","none") + .call(fillatt.func) + .style("fill", d3.rgb(fillatt.color).darker(0.5).toString()); + } + } + + // ============================================================================= + + function drawMarker() { + var marker = this.GetObject(), + att = new JSROOT.TAttMarkerHandler(marker), + kMarkerNDC = JSROOT.BIT(14), + isndc = marker.TestBit(kMarkerNDC); + + // create svg:g container for box drawing + this.CreateG(); + + var x = this.AxisToSvg("x", marker.fX, isndc), + y = this.AxisToSvg("y", marker.fY, isndc), + path = att.create(x,y); + + if (path) + this.draw_g.append("svg:path") + .attr("d", path) + .call(att.func); + } + + // ============================================================================= + + function drawPolyMarker() { + var poly = this.GetObject(), + att = new JSROOT.TAttMarkerHandler(poly), + func = this.AxisToSvgFunc(false), + path = ""; + + // create svg:g container for box drawing + this.CreateG(); + + for (var n=0;n<poly.fN;++n) + path += att.create(func.x(poly.fX[n]), func.y(poly.fY[n])); + + if (path) + this.draw_g.append("svg:path") + .attr("d", path) + .call(att.func); + } + + // ====================================================================================== + + function drawArrow() { + var arrow = this.GetObject(), + wsize = Math.max(3, Math.round(Math.max(this.pad_width(), this.pad_height()) * arrow.fArrowSize)), + hsize = Math.round(wsize * Math.tan(arrow.fAngle/2*Math.PI/180)); + + this.createAttLine({ attr: arrow }); + this.createAttFill({ attr: arrow }); + + // create svg:g container for line drawing + this.CreateG(); + + var x1 = this.AxisToSvg("x", arrow.fX1, false), + y1 = this.AxisToSvg("y", arrow.fY1, false), + x2 = this.AxisToSvg("x", arrow.fX2, false), + y2 = this.AxisToSvg("y", arrow.fY2, false), + right_arrow = "M0,0" + "L"+wsize+","+hsize + "L0,"+(2*hsize), + left_arrow = "M"+wsize+",0" + "L0,"+hsize + "L"+wsize+","+(2*hsize), + m_start = null, m_mid = null, m_end = null, defs = null, + oo = arrow.fOption, oolen = oo.length; + + if (oo.indexOf("<")==0) { + var closed = (oo.indexOf("<|") == 0); + if (!defs) defs = this.draw_g.append("defs"); + m_start = "jsroot_arrowmarker_" + JSROOT.id_counter++; + var mbeg = defs.append("svg:marker") + .attr("id", m_start) + .attr("markerWidth", wsize) + .attr("markerHeight", 2*hsize) + .attr("refX", 0) + .attr("refY", hsize) + .attr("orient", "auto") + .attr("markerUnits", "userSpaceOnUse"); + var pbeg = mbeg.append("svg:path") + .style("fill","none") + .attr("d", left_arrow + (closed ? "Z" : "")) + .call(this.lineatt.func); + if (closed) { + pbeg.call(this.fillatt.func); + if ((this.fillatt.color == this.lineatt.color) && this.fillatt.isSolid()) pbeg.style('stroke-width',1); + var dx = x2-x1, dy = y2-y1, len = Math.sqrt(dx*dx + dy*dy); + if (len>wsize) { + var ratio = wsize/len; + x1 += ratio*dx; + y1 += ratio*dy; + mbeg.attr("refX", wsize); + } + } + } + + var midkind = 0; + if (oo.indexOf("->-")>=0) midkind = 1; else + if (oo.indexOf("-|>-")>=0) midkind = 11; else + if (oo.indexOf("-<-")>=0) midkind = 2; else + if (oo.indexOf("-<|-")>=0) midkind = 12; + + if (midkind > 0) { + var closed = midkind > 10; + if (!defs) defs = this.draw_g.append("defs"); + m_mid = "jsroot_arrowmarker_" + JSROOT.id_counter++; + + var pmid = defs.append("svg:marker") + .attr("id", m_mid) + .attr("markerWidth", wsize) + .attr("markerHeight", 2*hsize) + .attr("refX", Math.round(wsize*0.5)) + .attr("refY", hsize) + .attr("orient", "auto") + .attr("markerUnits", "userSpaceOnUse") + .append("svg:path") + .style("fill","none") + .attr("d", ((midkind % 10 == 1) ? right_arrow : left_arrow) + + ((midkind > 10) ? "Z" : "")) + .call(this.lineatt.func); + if (midkind > 10) { + pmid.call(this.fillatt.func); + if (this.fillatt.isSolid(this.lineatt.color)) pmid.style('stroke-width',1); + } + } + + if (oo.lastIndexOf(">") == oolen-1) { + var closed = (oo.lastIndexOf("|>") == oolen-2) && (oolen>1); + if (!defs) defs = this.draw_g.append("defs"); + m_end = "jsroot_arrowmarker_" + JSROOT.id_counter++; + var mend = defs.append("svg:marker") + .attr("id", m_end) + .attr("markerWidth", wsize) + .attr("markerHeight", 2*hsize) + .attr("refX", wsize) + .attr("refY", hsize) + .attr("orient", "auto") + .attr("markerUnits", "userSpaceOnUse"); + var pend = mend.append("svg:path") + .style("fill","none") + .attr("d", right_arrow + (closed ? "Z" : "")) + .call(this.lineatt.func); + if (closed) { + pend.call(this.fillatt.func); + if (this.fillatt.isSolid(this.lineatt.color)) pend.style('stroke-width',1); + var dx = x2-x1, dy = y2-y1, len = Math.sqrt(dx*dx + dy*dy); + if (len>wsize) { + var ratio = wsize/len; + x2 -= ratio*dx; + y2 -= ratio*dy; + mend.attr("refX", 0); + } + } + } + + var path = this.draw_g + .append("svg:path") + .attr("d", "M"+Math.round(x1)+","+Math.round(y1) + + ((m_mid == null) ? "" : "L" + Math.round(x1/2+x2/2) + "," + Math.round(y1/2+y2/2)) + + "L"+Math.round(x2)+","+Math.round(y2)) + .call(this.lineatt.func); + + if (m_start) path.style("marker-start","url(#" + m_start + ")"); + if (m_mid) path.style("marker-mid","url(#" + m_mid + ")"); + if (m_end) path.style("marker-end","url(#" + m_end + ")"); + } + + // ================================================================================= + + function drawRooPlot(divid, plot, opt) { + + var painter = new JSROOT.TObjectPainter(plot), cnt = -1; + + function DrawNextItem() { + if (++cnt >= plot._items.arr.length) return painter.DrawingReady(); + + JSROOT.draw(divid, plot._items.arr[cnt], plot._items.opt[cnt], DrawNextItem); + } + + JSROOT.draw(divid, plot._hist, "hist", DrawNextItem); + + return painter; + } + + // =================================================================================== + + /** + * @summary Painter for TF1 object. + * + * @constructor + * @memberof JSROOT + * @augments JSROOT.TObjectPainter + * @param {object} tf1 - TF1 object to draw + */ + + function TF1Painter(tf1) { + JSROOT.TObjectPainter.call(this, tf1); + this.bins = null; + } + + TF1Painter.prototype = Object.create(JSROOT.TObjectPainter.prototype); + + TF1Painter.prototype.Eval = function(x) { + return this.GetObject().evalPar(x); + } + + //TF1Painter.prototype.UpdateObject = function(obj, opt) { + // if (!this.MatchObjectType(obj)) return false; + // var tf1 = this.GetObject(); + // tf1.fSave = obj.fSave; + // return true; + //} + + TF1Painter.prototype.CreateBins = function(ignore_zoom) { + var main = this.frame_painter(), + gxmin = 0, gxmax = 0, tf1 = this.GetObject(); + + if (main && !ignore_zoom) { + if (main.zoom_xmin !== main.zoom_xmax) { + gxmin = main.zoom_xmin; + gxmax = main.zoom_xmax; + } else { + gxmin = main.xmin; + gxmax = main.xmax; + } + } + + if ((tf1.fSave.length > 0) && !this.nosave) { + // in the case where the points have been saved, useful for example + // if we don't have the user's function + var np = tf1.fSave.length - 2, + xmin = tf1.fSave[np], + xmax = tf1.fSave[np+1], + dx = (xmax - xmin) / (np-1), + res = []; + + for (var n=0; n < np; ++n) { + var xx = xmin + dx*n; + // check if points need to be displayed at all, keep at least 4-5 points for Bezier curves + if ((gxmin !== gxmax) && ((xx + 2*dx < gxmin) || (xx - 2*dx > gxmax))) continue; + var yy = tf1.fSave[n]; + + if (!isNaN(yy)) res.push({ x : xx, y : yy }); + } + return res; + } + + var xmin = tf1.fXmin, xmax = tf1.fXmax, logx = false; + + if (gxmin !== gxmax) { + if (gxmin > xmin) xmin = gxmin; + if (gxmax < xmax) xmax = gxmax; + } + + if (main && main.logx && (xmin>0) && (xmax>0)) { + logx = true; + xmin = Math.log(xmin); + xmax = Math.log(xmax); + } + + var np = Math.max(tf1.fNpx, 101), + dx = (xmax - xmin) / (np - 1), + res = []; + + for (var n=0; n < np; n++) { + var xx = xmin + n*dx; + if (logx) xx = Math.exp(xx); + var yy = this.Eval(xx); + if (!isNaN(yy)) res.push({ x: xx, y: yy }); + } + return res; + } + + TF1Painter.prototype.CreateDummyHisto = function() { + + var xmin = 0, xmax = 1, ymin = 0, ymax = 1, + bins = this.CreateBins(true); + + if (bins && (bins.length > 0)) { + + xmin = xmax = bins[0].x; + ymin = ymax = bins[0].y; + + bins.forEach(function(bin) { + xmin = Math.min(bin.x, xmin); + xmax = Math.max(bin.x, xmax); + ymin = Math.min(bin.y, ymin); + ymax = Math.max(bin.y, ymax); + }); + + if (ymax > 0.0) ymax *= 1.05; + if (ymin < 0.0) ymin *= 1.05; + } + + var histo = JSROOT.Create("TH1I"), + tf1 = this.GetObject(); + + histo.fName = tf1.fName + "_hist"; + histo.fTitle = tf1.fTitle; + + histo.fXaxis.fXmin = xmin; + histo.fXaxis.fXmax = xmax; + histo.fYaxis.fXmin = ymin; + histo.fYaxis.fXmax = ymax; + + return histo; + } + + TF1Painter.prototype.ProcessTooltip = function(pnt) { + var cleanup = false; + + if ((pnt === null) || (this.bins === null)) { + cleanup = true; + } else + if ((this.bins.length==0) || (pnt.x < this.bins[0].grx) || (pnt.x > this.bins[this.bins.length-1].grx)) { + cleanup = true; + } + + if (cleanup) { + if (this.draw_g !== null) + this.draw_g.select(".tooltip_bin").remove(); + return null; + } + + var min = 100000, best = -1, bin; + + for(var n=0; n<this.bins.length; ++n) { + bin = this.bins[n]; + var dist = Math.abs(bin.grx - pnt.x); + if (dist < min) { min = dist; best = n; } + } + + bin = this.bins[best]; + + var gbin = this.draw_g.select(".tooltip_bin"), + radius = this.lineatt.width + 3; + + if (gbin.empty()) + gbin = this.draw_g.append("svg:circle") + .attr("class","tooltip_bin") + .style("pointer-events","none") + .attr("r", radius) + .call(this.lineatt.func) + .call(this.fillatt.func); + + var res = { name: this.GetObject().fName, + title: this.GetObject().fTitle, + x: bin.grx, + y: bin.gry, + color1: this.lineatt.color, + color2: this.fillatt.fillcolor(), + lines: [], + exact: (Math.abs(bin.grx - pnt.x) < radius) && (Math.abs(bin.gry - pnt.y) < radius) }; + + res.changed = gbin.property("current_bin") !== best; + res.menu = res.exact; + res.menu_dist = Math.sqrt((bin.grx-pnt.x)*(bin.grx-pnt.x) + (bin.gry-pnt.y)*(bin.gry-pnt.y)); + + if (res.changed) + gbin.attr("cx", bin.grx) + .attr("cy", bin.gry) + .property("current_bin", best); + + var name = this.GetTipName(); + if (name.length > 0) res.lines.push(name); + + var pmain = this.frame_painter(); + if (pmain) + res.lines.push("x = " + pmain.AxisAsText("x",bin.x) + " y = " + pmain.AxisAsText("y",bin.y)); + + return res; + } + + TF1Painter.prototype.Redraw = function() { + + var w = this.frame_width(), + h = this.frame_height(), + tf1 = this.GetObject(), + fp = this.frame_painter(), + pmain = this.main_painter(), + name = this.GetTipName("\n"); + + this.CreateG(true); + + // recalculate drawing bins when necessary + this.bins = this.CreateBins(false); + + this.createAttLine({ attr: tf1 }); + this.lineatt.used = false; + + this.createAttFill({ attr: tf1, kind: 1 }); + this.fillatt.used = false; + + // first calculate graphical coordinates + for(var n=0; n<this.bins.length; ++n) { + var bin = this.bins[n]; + bin.grx = fp.grx(bin.x); + bin.gry = fp.gry(bin.y); + } + + if (this.bins.length > 2) { + + var h0 = h; // use maximal frame height for filling + if ((pmain.hmin!==undefined) && (pmain.hmin>=0)) { + h0 = Math.round(fp.gry(0)); + if ((h0 > h) || (h0 < 0)) h0 = h; + } + + var path = JSROOT.Painter.BuildSvgPath("bezier", this.bins, h0, 2); + + if (this.lineatt.color != "none") + this.draw_g.append("svg:path") + .attr("class", "line") + .attr("d", path.path) + .style("fill", "none") + .call(this.lineatt.func); + + if (!this.fillatt.empty()) + this.draw_g.append("svg:path") + .attr("class", "area") + .attr("d", path.path + path.close) + .style("stroke", "none") + .call(this.fillatt.func); + } + } + + TF1Painter.prototype.CanZoomIn = function(axis,min,max) { + if (axis!=="x") return false; + + var tf1 = this.GetObject(); + + if (tf1.fSave.length > 0) { + // in the case where the points have been saved, useful for example + // if we don't have the user's function + var nb_points = tf1.fNpx; + + var xmin = tf1.fSave[nb_points + 1]; + var xmax = tf1.fSave[nb_points + 2]; + + return Math.abs(xmin - xmax) / nb_points < Math.abs(min - max); + } + + // if function calculated, one always could zoom inside + return true; + } + + TF1Painter.prototype.PerformDraw = function() { + if (this.main_painter() === null) { + var histo = this.CreateDummyHisto(), pthis = this; + JSROOT.draw(this.divid, histo, "AXIS", function(hpainter) { + pthis.SetDivId(pthis.divid); + pthis.Redraw(); + return pthis.DrawingReady(); + }); + return pthis; + } + + this.SetDivId(this.divid); + this.Redraw(); + return this.DrawingReady(); + } + + function drawFunction(divid, tf1, opt) { + + var painter = new TF1Painter(tf1); + + painter.SetDivId(divid, -1); + var d = new JSROOT.DrawOptions(opt); + painter.nosave = d.check('NOSAVE'); + + if (JSROOT.Math !== undefined) + return painter.PerformDraw(); + + JSROOT.AssertPrerequisites("math", painter.PerformDraw.bind(painter)); + return painter; + } + + // ======================================================================= + + /** + * @summary Painter for TGraph object. + * + * @constructor + * @memberof JSROOT + * @augments JSROOT.TObjectPainter + * @param {object} graph - TGraph object to draw + */ + + function TGraphPainter(graph) { + JSROOT.TObjectPainter.call(this, graph); + this.axes_draw = false; // indicate if graph histogram was drawn for axes + this.bins = null; + this.xmin = this.ymin = this.xmax = this.ymax = 0; + this.wheel_zoomy = true; + this.is_bent = (graph._typename == 'TGraphBentErrors'); + this.has_errors = (graph._typename == 'TGraphErrors') || + (graph._typename == 'TGraphAsymmErrors') || + this.is_bent || graph._typename.match(/^RooHist/); + } + + TGraphPainter.prototype = Object.create(JSROOT.TObjectPainter.prototype); + + TGraphPainter.prototype.Redraw = function() { + this.DrawBins(); + } + + TGraphPainter.prototype.DecodeOptions = function(opt) { + + if (!opt) opt = this.main_painter() ? "lp" : "alp"; + + if ((typeof opt == "string") && (opt.indexOf("same ")==0)) + opt = opt.substr(5); + + var graph = this.GetObject(), + d = new JSROOT.DrawOptions(opt); + + if (!this.options) this.options = {}; + + JSROOT.extend(this.options, { Line: 0, Curve: 0, Rect: 0, Mark: 0, Bar: 0, OutRange: 0, EF:0, Fill: 0, NoOpt: 0, + MainError: 1, Ends: 1, Axis: "", original: opt }); + + var res = this.options; + + res._pfc = d.check("PFC"); + res._plc = d.check("PLC"); + res._pmc = d.check("PMC"); + + if (d.check('NOOPT')) res.NoOpt = 1; + if (d.check('L')) res.Line = 1; + if (d.check('F')) res.Fill = 1; + if (d.check('A')) res.Axis = d.check("I") ? "A" : "AXIS"; // I means invisible axis + if (d.check('X+')) res.Axis += "X+"; + if (d.check('Y+')) res.Axis += "Y+"; + if (d.check('RX')) res.Axis += "RX"; + if (d.check('RY')) res.Axis += "RY"; + if (d.check('C')) res.Curve = res.Line = 1; + if (d.check('*')) res.Mark = 103; + if (d.check('P0')) res.Mark = 104; + if (d.check('P')) res.Mark = 1; + if (d.check('B')) { res.Bar = 1; res.Errors = 0; } + if (d.check('Z')) { res.Errors = 1; res.Ends = 0; } + if (d.check('||')) { res.Errors = 1; res.MainError = 0; res.Ends = 1; } + if (d.check('[]')) { res.Errors = 1; res.MainError = 0; res.Ends = 2; } + if (d.check('|>')) { res.Errors = 1; res.Ends = 3; } + if (d.check('>')) { res.Errors = 1; res.Ends = 4; } + if (d.check('0')) { res.Mark = 1; res.Errors = 1; res.OutRange = 1; } + if (d.check('1')) { if (res.Bar == 1) res.Bar = 2; } + if (d.check('2')) { res.Rect = 1; res.Errors = 0; } + if (d.check('3')) { res.EF = 1; res.Errors = 0; } + if (d.check('4')) { res.EF = 2; res.Errors = 0; } + if (d.check('5')) { res.Rect = 2; res.Errors = 0; } + if (d.check('X')) res.Errors = 0; + // if (d.check('E')) res.Errors = 1; // E option only defined for TGraphPolar + + if (res.Errors === undefined) + res.Errors = this.has_errors ? 1 : 0; + + // special case - one could use svg:path to draw many pixels ( + if ((res.Mark == 1) && (graph.fMarkerStyle==1)) res.Mark = 101; + + // if no drawing option is selected and if opt=='' nothing is done. + if (res.Line + res.Fill + res.Mark + res.Bar + res.EF + res.Rect + res.Errors == 0) { + if (d.empty()) res.Line = 1; + } + + if (graph._typename == 'TGraphErrors') { + if (d3.max(graph.fEX) < 1.0e-300 && d3.max(graph.fEY) < 1.0e-300) + res.Errors = 0; + } + + if (!res.Axis) { + // check if axis should be drawn + // either graph drawn directly or + // graph is first object in list of primitives + var pad = this.root_pad(); + if (!pad || (pad.fPrimitives && (pad.fPrimitives.arr[0] === graph))) res.Axis = "AXIS"; + } else if (res.Axis.indexOf("A")<0) { + res.Axis = "AXIS," + res.Axis; + } + } + + TGraphPainter.prototype.CreateBins = function() { + var gr = this.GetObject(); + if (!gr) return; + + var p, kind = 0, npoints = gr.fNpoints; + if ((gr._typename==="TCutG") && (npoints>3)) npoints--; + + if (gr._typename == 'TGraphErrors') kind = 1; else + if (gr._typename == 'TGraphAsymmErrors' || gr._typename == 'TGraphBentErrors' + || gr._typename.match(/^RooHist/)) kind = 2; + + this.bins = []; + + for (p=0;p<npoints;++p) { + var bin = { x: gr.fX[p], y: gr.fY[p], indx: p }; + switch(kind) { + case 1: + bin.exlow = bin.exhigh = gr.fEX[p]; + bin.eylow = bin.eyhigh = gr.fEY[p]; + break; + case 2: + bin.exlow = gr.fEXlow[p]; + bin.exhigh = gr.fEXhigh[p]; + bin.eylow = gr.fEYlow[p]; + bin.eyhigh = gr.fEYhigh[p]; + break; + } + this.bins.push(bin); + + if (p===0) { + this.xmin = this.xmax = bin.x; + this.ymin = this.ymax = bin.y; + } + + if (kind > 0) { + this.xmin = Math.min(this.xmin, bin.x - bin.exlow, bin.x + bin.exhigh); + this.xmax = Math.max(this.xmax, bin.x - bin.exlow, bin.x + bin.exhigh); + this.ymin = Math.min(this.ymin, bin.y - bin.eylow, bin.y + bin.eyhigh); + this.ymax = Math.max(this.ymax, bin.y - bin.eylow, bin.y + bin.eyhigh); + } else { + this.xmin = Math.min(this.xmin, bin.x); + this.xmax = Math.max(this.xmax, bin.x); + this.ymin = Math.min(this.ymin, bin.y); + this.ymax = Math.max(this.ymax, bin.y); + } + } + } + + TGraphPainter.prototype.CreateHistogram = function() { + // bins should be created when calling this function + + var xmin = this.xmin, xmax = this.xmax, ymin = this.ymin, ymax = this.ymax; + + if (xmin >= xmax) xmax = xmin+1; + if (ymin >= ymax) ymax = ymin+1; + var dx = (xmax-xmin)*0.1, dy = (ymax-ymin)*0.1, + uxmin = xmin - dx, uxmax = xmax + dx, + minimum = ymin - dy, maximum = ymax + dy; + + if ((uxmin<0) && (xmin>=0)) uxmin = xmin*0.9; + if ((uxmax>0) && (xmax<=0)) uxmax = 0; + + var graph = this.GetObject(); + + if (graph.fMinimum != -1111) minimum = ymin = graph.fMinimum; + if (graph.fMaximum != -1111) maximum = ymax = graph.fMaximum; + if ((minimum < 0) && (ymin >=0)) minimum = 0.9*ymin; + + var kResetHisto = JSROOT.BIT(17); ///< fHistogram must be reset in GetHistogram + + var histo = graph.fHistogram; + + if (histo) { + // make logic like in the TGraph::GetHistogram + if (!graph.TestBit(kResetHisto)) return histo; + graph.InvertBit(kResetHisto); + } else { + graph.fHistogram = histo = JSROOT.CreateHistogram("TH1F", 100); + histo.fName = graph.fName + "_h"; + histo.fTitle = graph.fTitle; + histo.fBits = histo.fBits | JSROOT.TH1StatusBits.kNoStats; + } + + histo.fXaxis.fXmin = uxmin; + histo.fXaxis.fXmax = uxmax; + histo.fYaxis.fXmin = minimum; + histo.fYaxis.fXmax = maximum; + histo.fMinimum = minimum; + histo.fMaximum = maximum; + + return histo; + } + + /** Returns true if graph drawing can be optimize */ + TGraphPainter.prototype.CanOptimize = function() { + return JSROOT.gStyle.OptimizeDraw > 0 && !this.options.NoOpt; + } + + /** Returns optimized bins - if optimization enabled */ + TGraphPainter.prototype.OptimizeBins = function(maxpnt, filter_func) { + if ((this.bins.length < 30) && !filter_func) return this.bins; + + var selbins = null; + if (typeof filter_func == 'function') { + for (var n = 0; n < this.bins.length; ++n) { + if (filter_func(this.bins[n],n)) { + if (!selbins) selbins = (n==0) ? [] : this.bins.slice(0, n); + } else { + if (selbins) selbins.push(this.bins[n]); + } + } + } + if (!selbins) selbins = this.bins; + + if (!maxpnt) maxpnt = 500000; + + if ((selbins.length < maxpnt) || !this.CanOptimize()) return selbins; + var step = Math.floor(selbins.length / maxpnt); + if (step < 2) step = 2; + var optbins = []; + for (var n = 0; n < selbins.length; n+=step) + optbins.push(selbins[n]); + + return optbins; + } + + TGraphPainter.prototype.TooltipText = function(d) { + var pmain = this.frame_painter(), lines = []; + + lines.push(this.GetTipName()); + + if (d && pmain) { + lines.push("x = " + pmain.AxisAsText("x", d.x)); + lines.push("y = " + pmain.AxisAsText("y", d.y)); + + if (this.options.Errors && (pmain.x_kind=='normal') && ('exlow' in d) && ((d.exlow!=0) || (d.exhigh!=0))) + lines.push("error x = -" + pmain.AxisAsText("x", d.exlow) + "/+" + pmain.AxisAsText("x", d.exhigh)); + + if ((this.options.Errors || (this.options.EF > 0)) && (pmain.y_kind=='normal') && ('eylow' in d) && ((d.eylow!=0) || (d.eyhigh!=0))) + lines.push("error y = -" + pmain.AxisAsText("y", d.eylow) + "/+" + pmain.AxisAsText("y", d.eyhigh)); + } + return lines; + } + + TGraphPainter.prototype.get_main = function() { + var pmain = this.frame_painter(); + + if (pmain && pmain.grx && pmain.gry) return pmain; + + pmain = { + pad_layer: true, + pad: this.root_pad(), + pw: this.pad_width(), + ph: this.pad_height(), + grx: function(value) { + if (this.pad.fLogx) + value = (value>0) ? JSROOT.log10(value) : this.pad.fUxmin; + else + value = (value - this.pad.fX1) / (this.pad.fX2 - this.pad.fX1); + return value*this.pw; + }, + gry: function(value) { + if (this.pad.fLogy) + value = (value>0) ? JSROOT.log10(value) : this.pad.fUymin; + else + value = (value - this.pad.fY1) / (this.pad.fY2 - this.pad.fY1); + return (1-value)*this.ph; + } + } + + return pmain.pad ? pmain : null; + } + + TGraphPainter.prototype.DrawBins = function() { + + var pthis = this, + pmain = this.get_main(), + w = this.frame_width(), + h = this.frame_height(), + graph = this.GetObject(), + excl_width = 0, + pp = this.pad_painter(); + + if (!pmain) return; + + this.CreateG(!pmain.pad_layer); + + if (pp && (this.options._pfc || this.options._plc || this.options._pmc)) { + var icolor = pp.CreateAutoColor(this); + + if (this.options._pfc) { graph.fFillColor = icolor; delete this.fillatt; } + if (this.options._plc) { graph.fLineColor = icolor; delete this.lineatt; } + if (this.options._pmc) { graph.fMarkerColor = icolor; delete this.markeratt; } + + this.options._pfc = this.options._plc = this.options._pmc = false; + } + + this.createAttLine({ attr: graph, can_excl: true }); + + this.createAttFill({ attr: graph, kind: 1 }); + this.fillatt.used = false; // mark used only when really used + + this.draw_kind = "none"; // indicate if special svg:g were created for each bin + this.marker_size = 0; // indicate if markers are drawn + + if (this.lineatt.excl_side != 0) { + excl_width = this.lineatt.excl_width; + if (this.lineatt.width > 0) this.options.Line = 1; + } + + var drawbins = null; + + if (this.options.EF) { + + drawbins = this.OptimizeBins((this.options.EF > 1) ? 5000 : 0); + + // build lower part + for (var n=0;n<drawbins.length;++n) { + var bin = drawbins[n]; + bin.grx = pmain.grx(bin.x); + bin.gry = pmain.gry(bin.y - bin.eylow); + } + + var path1 = JSROOT.Painter.BuildSvgPath((this.options.EF > 1) ? "bezier" : "line", drawbins), + bins2 = []; + + for (var n=drawbins.length-1;n>=0;--n) { + var bin = drawbins[n]; + bin.gry = pmain.gry(bin.y + bin.eyhigh); + bins2.push(bin); + } + + // build upper part (in reverse direction) + var path2 = JSROOT.Painter.BuildSvgPath((this.options.EF > 1) ? "Lbezier" : "Lline", bins2); + + this.draw_g.append("svg:path") + .attr("d", path1.path + path2.path + "Z") + .style("stroke", "none") + .call(this.fillatt.func); + this.draw_kind = "lines"; + } + + if (this.options.Line == 1 || this.options.Fill == 1 || (excl_width!==0)) { + + var close_symbol = ""; + if (graph._typename=="TCutG") this.options.Fill = 1; + + if (this.options.Fill == 1) { + close_symbol = "Z"; // always close area if we want to fill it + excl_width = 0; + } + + if (!drawbins) drawbins = this.OptimizeBins(this.options.Curve ? 5000 : 0); + + for (var n=0;n<drawbins.length;++n) { + var bin = drawbins[n]; + bin.grx = pmain.grx(bin.x); + bin.gry = pmain.gry(bin.y); + } + + var kind = "line"; // simple line + if (this.options.Curve === 1) kind = "bezier"; else + if (excl_width!==0) kind+="calc"; // we need to calculated deltas to build exclusion points + + var path = JSROOT.Painter.BuildSvgPath(kind, drawbins); + + if (excl_width!==0) { + var extrabins = []; + for (var n=drawbins.length-1;n>=0;--n) { + var bin = drawbins[n]; + var dlen = Math.sqrt(bin.dgrx*bin.dgrx + bin.dgry*bin.dgry); + // shift point, using + bin.grx += excl_width*bin.dgry/dlen; + bin.gry -= excl_width*bin.dgrx/dlen; + extrabins.push(bin); + } + + var path2 = JSROOT.Painter.BuildSvgPath("L" + ((this.options.Curve === 1) ? "bezier" : "line"), extrabins); + + this.draw_g.append("svg:path") + .attr("d", path.path + path2.path + "Z") + .style("stroke", "none") + .call(this.fillatt.func) + .style('opacity', 0.75); + } + + if (this.options.Line || this.options.Fill) { + var elem = this.draw_g.append("svg:path") + .attr("d", path.path + close_symbol); + if (this.options.Line) + elem.call(this.lineatt.func); + else + elem.style('stroke','none'); + + if (this.options.Fill) + elem.call(this.fillatt.func); + else + elem.style('fill','none'); + } + + this.draw_kind = "lines"; + } + + var nodes = null; + + if (this.options.Errors || this.options.Rect || this.options.Bar) { + + drawbins = this.OptimizeBins(5000, function(pnt,i) { + + var grx = pmain.grx(pnt.x); + + // when drawing bars, take all points + if (!pthis.options.Bar && ((grx<0) || (grx>w))) return true; + + var gry = pmain.gry(pnt.y); + + if (!pthis.options.Bar && !pthis.options.OutRange && ((gry<0) || (gry>h))) return true; + + pnt.grx1 = Math.round(grx); + pnt.gry1 = Math.round(gry); + + if (pthis.has_errors) { + pnt.grx0 = Math.round(pmain.grx(pnt.x - pnt.exlow) - grx); + pnt.grx2 = Math.round(pmain.grx(pnt.x + pnt.exhigh) - grx); + pnt.gry0 = Math.round(pmain.gry(pnt.y - pnt.eylow) - gry); + pnt.gry2 = Math.round(pmain.gry(pnt.y + pnt.eyhigh) - gry); + + if (pthis.is_bent) { + pnt.grdx0 = Math.round(pmain.gry(pnt.y + graph.fEXlowd[i]) - gry); + pnt.grdx2 = Math.round(pmain.gry(pnt.y + graph.fEXhighd[i]) - gry); + pnt.grdy0 = Math.round(pmain.grx(pnt.x + graph.fEYlowd[i]) - grx); + pnt.grdy2 = Math.round(pmain.grx(pnt.x + graph.fEYhighd[i]) - grx); + } else { + pnt.grdx0 = pnt.grdx2 = pnt.grdy0 = pnt.grdy2 = 0; + } + } + + return false; + }); + + this.draw_kind = "nodes"; + + // here are up to five elements are collected, try to group them + nodes = this.draw_g.selectAll(".grpoint") + .data(drawbins) + .enter() + .append("svg:g") + .attr("class", "grpoint") + .attr("transform", function(d) { return "translate(" + d.grx1 + "," + d.gry1 + ")"; }); + } + + if (this.options.Bar) { + // calculate bar width + for (var i=1;i<drawbins.length-1;++i) + drawbins[i].width = Math.max(2, (drawbins[i+1].grx1 - drawbins[i-1].grx1) / 2 - 2); + + // first and last bins + switch (drawbins.length) { + case 0: break; + case 1: drawbins[0].width = w/4; break; // pathologic case of single bin + case 2: drawbins[0].width = drawbins[1].width = (drawbins[1].grx1-drawbins[0].grx1)/2; break; + default: + drawbins[0].width = drawbins[1].width; + drawbins[drawbins.length-1].width = drawbins[drawbins.length-2].width; + } + + var yy0 = Math.round(pmain.gry(0)); + + nodes.append("svg:rect") + .attr("x", function(d) { return Math.round(-d.width/2); }) + .attr("y", function(d) { + d.bar = true; // element drawn as bar + if (pthis.options.Bar!==1) return 0; + return (d.gry1 > yy0) ? yy0-d.gry1 : 0; + }) + .attr("width", function(d) { return Math.round(d.width); }) + .attr("height", function(d) { + if (pthis.options.Bar!==1) return h > d.gry1 ? h - d.gry1 : 0; + return Math.abs(yy0 - d.gry1); + }) + .call(this.fillatt.func); + } + + if (this.options.Rect) + nodes.filter(function(d) { return (d.exlow > 0) && (d.exhigh > 0) && (d.eylow > 0) && (d.eyhigh > 0); }) + .append("svg:rect") + .attr("x", function(d) { d.rect = true; return d.grx0; }) + .attr("y", function(d) { return d.gry2; }) + .attr("width", function(d) { return d.grx2 - d.grx0; }) + .attr("height", function(d) { return d.gry0 - d.gry2; }) + .call(this.fillatt.func) + .call(this.options.Rect === 2 ? this.lineatt.func : function() {}); + + this.error_size = 0; + + if (this.options.Errors) { + // to show end of error markers, use line width attribute + var lw = this.lineatt.width + JSROOT.gStyle.fEndErrorSize, bb = 0, + vv = this.options.Ends ? "m0," + lw + "v-" + 2*lw : "", + hh = this.options.Ends ? "m" + lw + ",0h-" + 2*lw : "", + vleft = vv, vright = vv, htop = hh, hbottom = hh, + mm = this.options.MainError ? "M0,0L" : "M"; // command to draw main errors + + switch (this.options.Ends) { + case 2: // option [] + bb = Math.max(this.lineatt.width+1, Math.round(lw*0.66)); + vleft = "m"+bb+","+lw + "h-"+bb + "v-"+2*lw + "h"+bb; + vright = "m-"+bb+","+lw + "h"+bb + "v-"+2*lw + "h-"+bb; + htop = "m-"+lw+","+bb + "v-"+bb + "h"+2*lw + "v"+bb; + hbottom = "m-"+lw+",-"+bb + "v"+bb + "h"+2*lw + "v-"+bb; + break; + case 3: // option |> + lw = Math.max(lw, Math.round(graph.fMarkerSize*8*0.66)); + bb = Math.max(this.lineatt.width+1, Math.round(lw*0.66)); + vleft = "l"+bb+","+lw + "v-"+2*lw + "l-"+bb+","+lw; + vright = "l-"+bb+","+lw + "v-"+2*lw + "l"+bb+","+lw; + htop = "l-"+lw+","+bb + "h"+2*lw + "l-"+lw+",-"+bb; + hbottom = "l-"+lw+",-"+bb + "h"+2*lw + "l-"+lw+","+bb; + break; + case 4: // option > + lw = Math.max(lw, Math.round(graph.fMarkerSize*8*0.66)); + bb = Math.max(this.lineatt.width+1, Math.round(lw*0.66)); + vleft = "l"+bb+","+lw + "m0,-"+2*lw + "l-"+bb+","+lw; + vright = "l-"+bb+","+lw + "m0,-"+2*lw + "l"+bb+","+lw; + htop = "l-"+lw+","+bb + "m"+2*lw + ",0l-"+lw+",-"+bb; + hbottom = "l-"+lw+",-"+bb + "m"+2*lw + ",0l-"+lw+","+bb; + break; + } + + this.error_size = lw; + + lw = Math.floor((this.lineatt.width-1)/2); // one should take into account half of end-cup line width + nodes.filter(function(d) { return (d.exlow > 0) || (d.exhigh > 0) || (d.eylow > 0) || (d.eyhigh > 0); }) + .append("svg:path") + .call(this.lineatt.func) + .style('fill', "none") + .attr("d", function(d) { + d.error = true; + return ((d.exlow > 0) ? mm + (d.grx0+lw) + "," + d.grdx0 + vleft : "") + + ((d.exhigh > 0) ? mm + (d.grx2-lw) + "," + d.grdx2 + vright : "") + + ((d.eylow > 0) ? mm + d.grdy0 + "," + (d.gry0-lw) + hbottom : "") + + ((d.eyhigh > 0) ? mm + d.grdy2 + "," + (d.gry2+lw) + htop : ""); + }); + } + + if (this.options.Mark) { + // for tooltips use markers only if nodes where not created + var path = "", pnt, grx, gry; + + this.createAttMarker({ attr: graph, style: this.options.Mark - 100 }); + + this.marker_size = this.markeratt.GetFullSize(); + + this.markeratt.reset_pos(); + + // let produce SVG at maximum 1MB + var maxnummarker = 1000000 / (this.markeratt.MarkerLength() + 7), step = 1; + + if (!drawbins) drawbins = this.OptimizeBins(maxnummarker); else + if (this.CanOptimize() && (drawbins.length > 1.5*maxnummarker)) + step = Math.min(2, Math.round(drawbins.length/maxnummarker)); + + for (var n=0;n<drawbins.length;n+=step) { + pnt = drawbins[n]; + grx = pmain.grx(pnt.x); + if ((grx > -this.marker_size) && (grx < w + this.marker_size)) { + gry = pmain.gry(pnt.y); + if ((gry > -this.marker_size) && (gry < h + this.marker_size)) + path += this.markeratt.create(grx, gry); + } + } + + if (path.length>0) { + this.draw_g.append("svg:path") + .attr("d", path) + .call(this.markeratt.func); + if ((nodes===null) && (this.draw_kind=="none")) + this.draw_kind = (this.options.Mark==101) ? "path" : "mark"; + + } + } + } + + TGraphPainter.prototype.ExtractTooltip = function(pnt) { + if (!pnt) return null; + + if ((this.draw_kind=="lines") || (this.draw_kind=="path") || (this.draw_kind=="mark")) + return this.ExtractTooltipForPath(pnt); + + if (this.draw_kind!="nodes") return null; + + var width = this.frame_width(), + height = this.frame_height(), + pmain = this.frame_painter(), + painter = this, + findbin = null, best_dist2 = 1e10, best = null, + msize = this.marker_size ? Math.round(this.marker_size/2 + 1.5) : 0; + + this.draw_g.selectAll('.grpoint').each(function() { + var d = d3.select(this).datum(); + if (d===undefined) return; + var dist2 = Math.pow(pnt.x - d.grx1, 2); + if (pnt.nproc===1) dist2 += Math.pow(pnt.y - d.gry1, 2); + if (dist2 >= best_dist2) return; + + var rect = null; + + if (d.error || d.rect || d.marker) { + rect = { x1: Math.min(-painter.error_size, d.grx0, -msize), + x2: Math.max(painter.error_size, d.grx2, msize), + y1: Math.min(-painter.error_size, d.gry2, -msize), + y2: Math.max(painter.error_size, d.gry0, msize) }; + } else if (d.bar) { + rect = { x1: -d.width/2, x2: d.width/2, y1: 0, y2: height - d.gry1 }; + + if (painter.options.Bar===1) { + var yy0 = pmain.gry(0); + rect.y1 = (d.gry1 > yy0) ? yy0-d.gry1 : 0; + rect.y2 = (d.gry1 > yy0) ? 0 : yy0-d.gry1; + } + } else { + rect = { x1: -5, x2: 5, y1: -5, y2: 5 }; + } + var matchx = (pnt.x >= d.grx1 + rect.x1) && (pnt.x <= d.grx1 + rect.x2), + matchy = (pnt.y >= d.gry1 + rect.y1) && (pnt.y <= d.gry1 + rect.y2); + + if (matchx && (matchy || (pnt.nproc > 1))) { + best_dist2 = dist2; + findbin = this; + best = rect; + best.exact = matchx && matchy; + } + }); + + if (findbin === null) return null; + + var d = d3.select(findbin).datum(); + + var res = { name: this.GetObject().fName, title: this.GetObject().fTitle, + x: d.grx1, y: d.gry1, + color1: this.lineatt.color, + lines: this.TooltipText(d), + rect: best, d3bin: findbin }; + + if (this.fillatt && this.fillatt.used && !this.fillatt.empty()) res.color2 = this.fillatt.fillcolor(); + + if (best.exact) res.exact = true; + res.menu = res.exact; // activate menu only when exactly locate bin + res.menu_dist = 3; // distance always fixed + res.bin = d; + res.binindx = d.indx; + + if (pnt.click_handler && res.exact && this.TestEditable()) + res.click_handler = this.InvokeClickHandler.bind(this); + + return res; + } + + TGraphPainter.prototype.ShowTooltip = function(hint) { + + if (!hint) { + if (this.draw_g) this.draw_g.select(".tooltip_bin").remove(); + return; + } + + if (hint.usepath) return this.ShowTooltipForPath(hint); + + var d = d3.select(hint.d3bin).datum(); + + var ttrect = this.draw_g.select(".tooltip_bin"); + + if (ttrect.empty()) + ttrect = this.draw_g.append("svg:rect") + .attr("class","tooltip_bin h1bin") + .style("pointer-events","none"); + + hint.changed = ttrect.property("current_bin") !== hint.d3bin; + + if (hint.changed) + ttrect.attr("x", d.grx1 + hint.rect.x1) + .attr("width", hint.rect.x2 - hint.rect.x1) + .attr("y", d.gry1 + hint.rect.y1) + .attr("height", hint.rect.y2 - hint.rect.y1) + .style("opacity", "0.3") + .property("current_bin", hint.d3bin); + } + + TGraphPainter.prototype.ProcessTooltip = function(pnt) { + var hint = this.ExtractTooltip(pnt); + if (!pnt || !pnt.disabled) this.ShowTooltip(hint); + return hint; + } + + TGraphPainter.prototype.FindBestBin = function(pnt) { + if (!this.bins) return null; + + var islines = (this.draw_kind=="lines"), + ismark = (this.draw_kind=="mark"), + bestindx = -1, + bestbin = null, + bestdist = 1e10, + pmain = this.frame_painter(), + dist, grx, gry, n, bin; + + for (n=0;n<this.bins.length;++n) { + bin = this.bins[n]; + + grx = pmain.grx(bin.x); + gry = pmain.gry(bin.y); + + dist = (pnt.x-grx)*(pnt.x-grx) + (pnt.y-gry)*(pnt.y-gry); + + if (dist < bestdist) { + bestdist = dist; + bestbin = bin; + bestindx = n; + } + } + + // check last point + if ((bestdist > 100) && islines) bestbin = null; + + var radius = Math.max(this.lineatt.width + 3, 4); + + if (this.marker_size > 0) radius = Math.max(this.marker_size, radius); + + if (bestbin) + bestdist = Math.sqrt(Math.pow(pnt.x-pmain.grx(bestbin.x),2) + Math.pow(pnt.y-pmain.gry(bestbin.y),2)); + + if (!islines && (bestdist > radius)) bestbin = null; + + if (!bestbin) bestindx = -1; + + var res = { bin: bestbin, indx: bestindx, dist: bestdist, radius: Math.round(radius) }; + + if (!bestbin && islines) { + + bestdist = 10000; + + function IsInside(x, x1, x2) { + return ((x1>=x) && (x>=x2)) || ((x1<=x) && (x<=x2)); + } + + var bin0 = this.bins[0], grx0 = pmain.grx(bin0.x), gry0, posy = 0; + for (n=1;n<this.bins.length;++n) { + bin = this.bins[n]; + grx = pmain.grx(bin.x); + + if (IsInside(pnt.x, grx0, grx)) { + // if inside interval, check Y distance + gry0 = pmain.gry(bin0.y) + gry = pmain.gry(bin.y); + + if (Math.abs(grx - grx0) < 1) { + // very close x - check only y + posy = pnt.y; + dist = IsInside(pnt.y, gry0, gry) ? 0 : Math.min(Math.abs(pnt.y-gry0), Math.abs(pnt.y-gry)); + } else { + posy = gry0 + (pnt.x - grx0) / (grx - grx0) * (gry - gry0); + dist = Math.abs(posy - pnt.y); + } + + if (dist < bestdist) { + bestdist = dist; + res.linex = pnt.x; + res.liney = posy; + } + } + + bin0 = bin; + grx0 = grx; + } + + if (bestdist < radius*0.5) { + res.linedist = bestdist; + res.closeline = true; + } + } + + return res; + } + + TGraphPainter.prototype.TestEditable = function(toggle) { + var obj = this.GetObject(), + kNotEditable = JSROOT.BIT(18); // bit set if graph is non editable + + if (!obj) return false; + if (toggle) obj.InvertBit(kNotEditable); + return !obj.TestBit(kNotEditable); + } + + TGraphPainter.prototype.ExtractTooltipForPath = function(pnt) { + + if (this.bins === null) return null; + + var best = this.FindBestBin(pnt); + + if (!best || (!best.bin && !best.closeline)) return null; + + var islines = (this.draw_kind=="lines"), + ismark = (this.draw_kind=="mark"), + pmain = this.frame_painter(), + gr = this.GetObject(), + res = { name: gr.fName, title: gr.fTitle, + x: best.bin ? pmain.grx(best.bin.x) : best.linex, + y: best.bin ? pmain.gry(best.bin.y) : best.liney, + color1: this.lineatt.color, + lines: this.TooltipText(best.bin), + usepath: true }; + + res.ismark = ismark; + res.islines = islines; + + if (best.closeline) { + res.menu = res.exact = true; + res.menu_dist = best.linedist; + } else if (best.bin) { + if (this.options.EF && islines) { + res.gry1 = pmain.gry(best.bin.y - best.bin.eylow); + res.gry2 = pmain.gry(best.bin.y + best.bin.eyhigh); + } else { + res.gry1 = res.gry2 = pmain.gry(best.bin.y); + } + + res.binindx = best.indx; + res.bin = best.bin; + res.radius = best.radius; + + res.exact = (Math.abs(pnt.x - res.x) <= best.radius) && + ((Math.abs(pnt.y - res.gry1) <= best.radius) || (Math.abs(pnt.y - res.gry2) <= best.radius)); + + res.menu = res.exact; + res.menu_dist = Math.sqrt((pnt.x-res.x)*(pnt.x-res.x) + Math.pow(Math.min(Math.abs(pnt.y-res.gry1),Math.abs(pnt.y-res.gry2)),2)); + + if (pnt.click_handler && res.exact && this.TestEditable()) + res.click_handler = this.InvokeClickHandler.bind(this); + } + + if (this.fillatt && this.fillatt.used && !this.fillatt.empty()) res.color2 = this.fillatt.fillcolor(); + + if (!islines) { + res.color1 = this.get_color(gr.fMarkerColor); + if (!res.color2) res.color2 = res.color1; + } + + return res; + } + + TGraphPainter.prototype.ShowTooltipForPath = function(hint) { + + var ttbin = this.draw_g.select(".tooltip_bin"); + + if (!hint || !hint.bin) { + ttbin.remove(); + return; + } + + if (ttbin.empty()) + ttbin = this.draw_g.append("svg:g") + .attr("class","tooltip_bin"); + + hint.changed = ttbin.property("current_bin") !== hint.bin; + + if (hint.changed) { + ttbin.selectAll("*").remove(); // first delete all children + ttbin.property("current_bin", hint.bin); + + if (hint.ismark) { + ttbin.append("svg:rect") + .attr("class","h1bin") + .style("pointer-events","none") + .style("opacity", "0.3") + .attr("x", Math.round(hint.x - hint.radius)) + .attr("y", Math.round(hint.y - hint.radius)) + .attr("width", 2*hint.radius) + .attr("height", 2*hint.radius); + } else { + ttbin.append("svg:circle").attr("cy", Math.round(hint.gry1)) + if (Math.abs(hint.gry1-hint.gry2) > 1) + ttbin.append("svg:circle").attr("cy", Math.round(hint.gry2)); + + var elem = ttbin.selectAll("circle") + .attr("r", hint.radius) + .attr("cx", Math.round(hint.x)); + + if (!hint.islines) { + elem.style('stroke', hint.color1 == 'black' ? 'green' : 'black').style('fill','none'); + } else { + if (this.options.Line) + elem.call(this.lineatt.func); + else + elem.style('stroke','black'); + if (this.options.Fill) + elem.call(this.fillatt.func); + else + elem.style('fill','none'); + } + } + } + } + + TGraphPainter.prototype.movePntHandler = function(first_time) { + var pos = d3.mouse(this.svg_frame().node()), + main = this.frame_painter(); + + if (!main || !this.interactive_bin) return; + + this.interactive_bin.x = main.RevertX(pos[0] + this.interactive_delta_x); + this.interactive_bin.y = main.RevertY(pos[1] + this.interactive_delta_y); + this.DrawBins(); + } + + TGraphPainter.prototype.endPntHandler = function() { + if (this.snapid && this.interactive_bin) { + var exec = "SetPoint(" + this.interactive_bin.indx + "," + this.interactive_bin.x + "," + this.interactive_bin.y + ")"; + var canp = this.canv_painter(); + if (canp) canp.SendWebsocket("OBJEXEC:" + this.snapid + ":" + exec); + } + + delete this.interactive_bin; + d3.select(window).on("mousemove.graphPnt", null) + .on("mouseup.graphPnt", null); + } + + TGraphPainter.prototype.InvokeClickHandler = function(hint) { + if (!hint.bin) return; // + + this.interactive_bin = hint.bin; + + d3.select(window).on("mousemove.graphPnt", this.movePntHandler.bind(this)) + .on("mouseup.graphPnt", this.endPntHandler.bind(this), true); + + var pos = d3.mouse(this.svg_frame().node()), + main = this.frame_painter(); + + this.interactive_delta_x = main ? main.x(this.interactive_bin.x) - pos[0] : 0; + this.interactive_delta_y = main ? main.y(this.interactive_bin.y) - pos[1] : 0; + } + + TGraphPainter.prototype.FillContextMenu = function(menu) { + JSROOT.TObjectPainter.prototype.FillContextMenu.call(this, menu); + + if (!this.snapid) + menu.addchk(this.TestEditable(), "Editable", this.TestEditable.bind(this, true)); + + return menu.size() > 0; + } + + TGraphPainter.prototype.ExecuteMenuCommand = function(method, args) { + if (JSROOT.TObjectPainter.prototype.ExecuteMenuCommand.call(this,method,args)) return true; + + var canp = this.canv_painter(), fp = this.frame_painter(); + + if ((method.fName == 'RemovePoint') || (method.fName == 'InsertPoint')) { + var pnt = fp ? fp.GetLastEventPos() : null; + + if (!canp || !fp || !pnt) return true; // ignore function + + var hint = this.ExtractTooltip(pnt); + + if (method.fName == 'InsertPoint') { + var main = this.frame_painter(), + userx = main && main.RevertX ? main.RevertX(pnt.x) : 0, + usery = main && main.RevertY ? main.RevertY(pnt.y) : 0; + canp.ShowMessage('InsertPoint(' + userx.toFixed(3) + ',' + usery.toFixed(3) + ') not yet implemented'); + } else + if (this.args_menu_id && hint && (hint.binindx !== undefined)) { + var exec = "RemovePoint(" + hint.binindx + ")"; + console.log('execute ' + exec + ' for object ' + this.args_menu_id); + canp.SendWebsocket('OBJEXEC:' + this.args_menu_id + ":" + exec); + } + + return true; // call is processed + } + + return false; + } + + TGraphPainter.prototype.UpdateObject = function(obj, opt) { + if (!this.MatchObjectType(obj)) return false; + + if ((opt !== undefined) && (opt != this.options.original)) + this.DecodeOptions(opt); + + var graph = this.GetObject(); + // TODO: make real update of TGraph object content + graph.fBits = obj.fBits; + graph.fTitle = obj.fTitle; + graph.fX = obj.fX; + graph.fY = obj.fY; + graph.fNpoints = obj.fNpoints; + this.CreateBins(); + + // if our own histogram was used as axis drawing, we need update histogram as well + if (this.axes_draw) { + var main = this.main_painter(); + main.UpdateObject(obj.fHistogram || this.CreateHistogram()); + main.GetObject().fTitle = graph.fTitle; // copy title + } + + return true; + } + + TGraphPainter.prototype.CanZoomIn = function(axis,min,max) { + // allow to zoom TGraph only when at least one point in the range + + var gr = this.GetObject(); + if ((gr===null) || (axis!=="x")) return false; + + for (var n=0; n < gr.fNpoints; ++n) + if ((min < gr.fX[n]) && (gr.fX[n] < max)) return true; + + return false; + } + + TGraphPainter.prototype.ButtonClick = function(funcname) { + + if (funcname !== "ToggleZoom") return false; + + var main = this.frame_painter(); + if (!main) return false; + + if ((this.xmin===this.xmax) && (this.ymin = this.ymax)) return false; + + main.Zoom(this.xmin, this.xmax, this.ymin, this.ymax); + + return true; + } + + TGraphPainter.prototype.FindFunc = function() { + var gr = this.GetObject(); + if (gr && gr.fFunctions) + for (var i = 0; i < gr.fFunctions.arr.length; ++i) { + var func = gr.fFunctions.arr[i]; + if ((func._typename == 'TF1') || (func._typename == 'TF2')) return func; + } + return null; + } + + TGraphPainter.prototype.FindStat = function() { + var gr = this.GetObject(); + if (gr && gr.fFunctions) + for (var i = 0; i < gr.fFunctions.arr.length; ++i) { + var func = gr.fFunctions.arr[i]; + if ((func._typename == 'TPaveStats') && (func.fName == 'stats')) return func; + } + + return null; + } + + TGraphPainter.prototype.CreateStat = function() { + var func = this.FindFunc(); + if (!func) return null; + + var stats = this.FindStat(); + if (stats) return stats; + + // do not create stats box when drawing canvas + var pp = this.canv_painter(); + if (pp && pp.normal_canvas) return null; + + this.create_stats = true; + + var st = JSROOT.gStyle; + + stats = JSROOT.Create('TPaveStats'); + JSROOT.extend(stats, { fName : 'stats', + fOptStat: 0, + fOptFit: st.fOptFit || 111, + fBorderSize : 1} ); + + stats.fX1NDC = st.fStatX - st.fStatW; + stats.fY1NDC = st.fStatY - st.fStatH; + stats.fX2NDC = st.fStatX; + stats.fY2NDC = st.fStatY; + + stats.fFillColor = st.fStatColor; + stats.fFillStyle = st.fStatStyle; + + stats.fTextAngle = 0; + stats.fTextSize = st.fStatFontSize; // 9 ?? + stats.fTextAlign = 12; + stats.fTextColor = st.fStatTextColor; + stats.fTextFont = st.fStatFont; + + stats.AddText(func.fName); + + // while TF1 was found, one can be sure that stats is existing + this.GetObject().fFunctions.Add(stats); + + return stats; + } + + TGraphPainter.prototype.FillStatistic = function(stat, dostat, dofit) { + + // cannot fill stats without func + var func = this.FindFunc(); + + if (!func || !dofit || !this.create_stats) return false; + + stat.ClearPave(); + + stat.FillFunctionStat(func, dofit); + + return true; + } + + TGraphPainter.prototype.DrawNextFunction = function(indx, callback) { + // method draws next function from the functions list + + var graph = this.GetObject(); + + if (!graph.fFunctions || (indx >= graph.fFunctions.arr.length)) + return JSROOT.CallBack(callback); + + var func = graph.fFunctions.arr[indx], opt = graph.fFunctions.opt[indx]; + + // required for stats filling + // TODO: use weak reference (via pad list of painters and any kind of string) + func.$main_painter = this; + + JSROOT.draw(this.divid, func, opt, this.DrawNextFunction.bind(this, indx+1, callback)); + } + + TGraphPainter.prototype.PerformDrawing = function(divid, hpainter) { + if (hpainter) { this.axes_draw = true; hpainter.$secondary = true; } + this.SetDivId(divid); + this.DrawBins(); + this.DrawNextFunction(0, this.DrawingReady.bind(this)); + return this; + } + + function drawGraph(divid, graph, opt) { + + var painter = new TGraphPainter(graph); + + painter.SetDivId(divid, -1); // just to get access to existing elements + + painter.DecodeOptions(opt); + + painter.CreateBins(); + + painter.CreateStat(); + + if (!painter.main_painter() && painter.options.Axis) { + JSROOT.draw(divid, painter.CreateHistogram(), painter.options.Axis, painter.PerformDrawing.bind(painter, divid)); + } else { + painter.PerformDrawing(divid); + } + + return painter; + } + + // ============================================================== + + function TGraphPolargramPainter(polargram) { + JSROOT.TooltipHandler.call(this, polargram); + this.$polargram = true; // indicate that this is polargram + this.zoom_rmin = this.zoom_rmax = 0; + } + + TGraphPolargramPainter.prototype = Object.create(JSROOT.TooltipHandler.prototype); + + TGraphPolargramPainter.prototype.translate = function(angle, radius, keep_float) { + var _rx = this.r(radius), _ry = _rx/this.szx*this.szy, + pos = { + x: _rx * Math.cos(-angle - this.angle), + y: _ry * Math.sin(-angle - this.angle), + rx: _rx, + ry: _ry + }; + + if (!keep_float) { + pos.x = Math.round(pos.x); + pos.y = Math.round(pos.y); + pos.rx = Math.round(pos.rx); + pos.ry = Math.round(pos.ry); + } + return pos; + } + + TGraphPolargramPainter.prototype.format = function(radius) { + // used to format label for radius ticks + + if (radius === Math.round(radius)) return radius.toString(); + if (this.ndig>10) return radius.toExponential(4); + + return radius.toFixed((this.ndig > 0) ? this.ndig : 0); + } + + TGraphPolargramPainter.prototype.AxisAsText = function(axis, value) { + + if (axis == "r") { + if (value === Math.round(value)) return value.toString(); + if (this.ndig>10) return value.toExponential(4); + return value.toFixed(this.ndig+2); + } + + value *= 180/Math.PI; + return (value === Math.round(value)) ? value.toString() : value.toFixed(1); + } + + TGraphPolargramPainter.prototype.MouseEvent = function(kind) { + var layer = this.svg_layer("primitives_layer"), + interactive = layer.select(".interactive_ellipse"); + if (interactive.empty()) return; + + var pnt = null; + + if (kind !== 'leave') { + var pos = d3.mouse(interactive.node()); + pnt = { x: pos[0], y: pos[1], touch: false }; + } + + this.ProcessTooltipEvent(pnt); + } + + TGraphPolargramPainter.prototype.GetFrameRect = function() { + var pad = this.root_pad(), + w = this.pad_width(), + h = this.pad_height(), + rect = {}; + + rect.szx = Math.round(Math.max(0.1, 0.5 - Math.max(pad.fLeftMargin, pad.fRightMargin))*w); + rect.szy = Math.round(Math.max(0.1, 0.5 - Math.max(pad.fBottomMargin, pad.fTopMargin))*h); + + rect.width = 2*rect.szx; + rect.height = 2*rect.szy; + rect.midx = Math.round(w/2); + rect.midy = Math.round(h/2); + rect.x = rect.midx - rect.szx; + rect.y = rect.midy - rect.szy; + + rect.hint_delta_x = rect.szx; + rect.hint_delta_y = rect.szy; + + rect.transform = "translate(" + rect.x + "," + rect.y + ")"; + + return rect; + } + + TGraphPolargramPainter.prototype.MouseWheel = function() { + d3.event.stopPropagation(); + d3.event.preventDefault(); + + this.ProcessTooltipEvent(null); // remove all tooltips + + var polar = this.GetObject(); + + if (!d3.event || !polar) return; + + var delta = d3.event.wheelDelta ? -d3.event.wheelDelta : (d3.event.deltaY || d3.event.detail); + if (!delta) return; + + delta = (delta<0) ? -0.2 : 0.2; + + var rmin = this.scale_rmin, rmax = this.scale_rmax, range = rmax - rmin; + + // rmin -= delta*range; + rmax += delta*range; + + if ((rmin<polar.fRwrmin) || (rmax>polar.fRwrmax)) rmin = rmax = 0; + + if ((this.zoom_rmin != rmin) || (this.zoom_rmax != rmax)) { + this.zoom_rmin = rmin; + this.zoom_rmax = rmax; + this.RedrawPad(); + } + } + + TGraphPolargramPainter.prototype.Redraw = function() { + if (!this.is_main_painter()) return; + + var pad = this.root_pad(), + polar = this.GetObject(), + rect = this.GetFrameRect(); + + this.CreateG(); + + this.draw_g.attr("transform", "translate(" + rect.midx + "," + rect.midy + ")"); + this.szx = rect.szx; + this.szy = rect.szy; + + this.scale_rmin = polar.fRwrmin; + this.scale_rmax = polar.fRwrmax; + if (this.zoom_rmin != this.zoom_rmax) { + this.scale_rmin = this.zoom_rmin; + this.scale_rmax = this.zoom_rmax; + } + + this.r = d3.scaleLinear().domain([this.scale_rmin, this.scale_rmax]).range([ 0, this.szx ]); + this.angle = polar.fAxisAngle || 0; + + var ticks = this.r.ticks(5), + nminor = Math.floor((polar.fNdivRad % 10000) / 100); + + this.createAttLine({ attr: polar }); + if (!this.gridatt) this.gridatt = new JSROOT.TAttLineHandler({ color: polar.fLineColor, style: 2, width: 1 }); + + var range = Math.abs(polar.fRwrmax - polar.fRwrmin); + this.ndig = (range <= 0) ? -3 : Math.round(JSROOT.log10(ticks.length / range)); + + // verify that all radius labels are unique + var lbls = [], indx = 0; + while (indx<ticks.length) { + var lbl = this.format(ticks[indx]); + if (lbls.indexOf(lbl)>=0) { + if (++this.ndig>10) break; + lbls = []; indx = 0; continue; + } + lbls.push(lbl); + indx++; + } + + var exclude_last = false; + + if ((ticks[ticks.length-1] < polar.fRwrmax) && (this.zoom_rmin == this.zoom_rmax)) { + ticks.push(polar.fRwrmax); + exclude_last = true; + } + + this.StartTextDrawing(polar.fRadialLabelFont, Math.round(polar.fRadialTextSize * this.szy * 2)); + + for (var n=0;n<ticks.length;++n) { + var rx = this.r(ticks[n]), ry = rx/this.szx*this.szy; + this.draw_g.append("ellipse") + .attr("cx",0) + .attr("cy",0) + .attr("rx",Math.round(rx)) + .attr("ry",Math.round(ry)) + .style("fill", "none") + .call(this.lineatt.func); + + if ((n < ticks.length-1) || !exclude_last) + this.DrawText({ align: 23, x: Math.round(rx), y: Math.round(polar.fRadialTextSize * this.szy * 0.5), + text: this.format(ticks[n]), color: this.get_color[polar.fRadialLabelColor], latex: 0 }); + + if ((nminor>1) && ((n < ticks.length-1) || !exclude_last)) { + var dr = (ticks[1] - ticks[0]) / nminor; + for (var nn=1;nn<nminor;++nn) { + var gridr = ticks[n] + dr*nn; + if (gridr > this.scale_rmax) break; + rx = this.r(gridr); ry = rx/this.szx*this.szy; + this.draw_g.append("ellipse") + .attr("cx",0) + .attr("cy",0) + .attr("rx",Math.round(rx)) + .attr("ry",Math.round(ry)) + .style("fill", "none") + .call(this.gridatt.func); + } + } + } + + this.FinishTextDrawing(); + + var fontsize = Math.round(polar.fPolarTextSize * this.szy * 2); + this.StartTextDrawing(polar.fPolarLabelFont, fontsize); + + var nmajor = polar.fNdivPol % 100; + if ((nmajor !== 8) && (nmajor !== 3)) nmajor = 8; + + var lbls = (nmajor==8) ? ["0", "#frac{#pi}{4}", "#frac{#pi}{2}", "#frac{3#pi}{4}", "#pi", "#frac{5#pi}{4}", "#frac{3#pi}{2}", "#frac{7#pi}{4}"] : ["0", "#frac{2#pi}{3}", "#frac{4#pi}{3}"], + aligns = [12, 11, 21, 31, 32, 33, 23, 13 ]; + + for (var n=0;n<nmajor;++n) { + var angle = -n*2*Math.PI/nmajor - this.angle; + this.draw_g.append("line") + .attr("x1",0) + .attr("y1",0) + .attr("x2", Math.round(this.szx*Math.cos(angle))) + .attr("y2", Math.round(this.szy*Math.sin(angle))) + .call(this.lineatt.func); + + var aindx = Math.round(16 -angle/Math.PI*4) % 8; // index in align table, here absolute angle is important + + this.DrawText({ align: aligns[aindx], + x: Math.round((this.szx+fontsize)*Math.cos(angle)), + y: Math.round((this.szy + fontsize/this.szx*this.szy)*(Math.sin(angle))), + text: lbls[n], + color: this.get_color[polar.fPolarLabelColor], latex: 1 }); + } + + this.FinishTextDrawing(); + + var nminor = Math.floor((polar.fNdivPol % 10000) / 100); + + if (nminor > 1) + for (var n=0;n<nmajor*nminor;++n) { + if (n % nminor === 0) continue; + var angle = -n*2*Math.PI/nmajor/nminor - this.angle; + this.draw_g.append("line") + .attr("x1",0) + .attr("y1",0) + .attr("x2", Math.round(this.szx*Math.cos(angle))) + .attr("y2", Math.round(this.szy*Math.sin(angle))) + .call(this.gridatt.func); + } + + + if (JSROOT.BatchMode) return; + + var layer = this.svg_layer("primitives_layer"), + interactive = layer.select(".interactive_ellipse"); + + if (interactive.empty()) + interactive = layer.append("g") + .classed("most_upper_primitives", true) + .append("ellipse") + .classed("interactive_ellipse", true) + .attr("cx",0) + .attr("cy",0) + .style("fill", "none") + .style("pointer-events","visibleFill") + .on('mouseenter', this.MouseEvent.bind(this,'enter')) + .on('mousemove', this.MouseEvent.bind(this,'move')) + .on('mouseleave', this.MouseEvent.bind(this,'leave')); + + interactive.attr("rx", this.szx).attr("ry", this.szy); + + d3.select(interactive.node().parentNode).attr("transform", this.draw_g.attr("transform")); + + if (JSROOT.gStyle.Zooming && JSROOT.gStyle.ZoomWheel) + interactive.on("wheel", this.MouseWheel.bind(this)); + } + + function drawGraphPolargram(divid, polargram, opt) { + + var painter = new TGraphPolargramPainter(polargram); + + painter.SetDivId(divid, -1); // just to get access to existing elements + + var main = painter.main_painter(); + + if (main) { + if (main.GetObject() !== polargram) + console.error('Cannot superimpose TGraphPolargram with any other drawings'); + return null; + } + + painter.SetDivId(divid, 4); // main object without need of frame + painter.Redraw(); + return painter.DrawingReady(); + } + + // ============================================================== + + function TGraphPolarPainter(graph) { + JSROOT.TObjectPainter.call(this, graph); + } + + TGraphPolarPainter.prototype = Object.create(JSROOT.TObjectPainter.prototype); + + TGraphPolarPainter.prototype.Redraw = function() { + this.DrawBins(); + } + + TGraphPolarPainter.prototype.DecodeOptions = function(opt) { + + var d = new JSROOT.DrawOptions(opt || "L"); + + if (!this.options) this.options = {}; + + JSROOT.extend(this.options, { + mark: d.check("P"), + err: d.check("E"), + fill: d.check("F"), + line: d.check("L"), + curve: d.check("C") + }); + + this.OptionsStore(opt); + } + + TGraphPolarPainter.prototype.DrawBins = function() { + var graph = this.GetObject(), + main = this.main_painter(); + + if (!graph || !main || !main.$polargram) return; + + if (this.options.mark) this.createAttMarker({ attr: graph }); + if (this.options.err || this.options.line || this.options.curve) this.createAttLine({ attr: graph }); + if (this.options.fill) this.createAttFill({ attr: graph }); + + this.CreateG(); + + this.draw_g.attr("transform", main.draw_g.attr("transform")); + + var mpath = "", epath = "", lpath = "", bins = []; + + for (var n=0;n<graph.fNpoints;++n) { + + if (graph.fY[n] > main.scale_rmax) continue; + + if (this.options.err) { + var pos1 = main.translate(graph.fX[n], graph.fY[n] - graph.fEY[n]), + pos2 = main.translate(graph.fX[n], graph.fY[n] + graph.fEY[n]); + epath += "M" + pos1.x + "," + pos1.y + "L" + pos2.x + "," + pos2.y; + + pos1 = main.translate(graph.fX[n] + graph.fEX[n], graph.fY[n]); + pos2 = main.translate(graph.fX[n] - graph.fEX[n], graph.fY[n]); + + epath += "M" + pos1.x + "," + pos1.y + "A" + pos2.rx + "," + pos2.ry+ ",0,0,1," + pos2.x + "," + pos2.y; + } + + var pos = main.translate(graph.fX[n], graph.fY[n]); + + if (this.options.mark) { + mpath += this.markeratt.create(pos.x, pos.y); + } + + if (this.options.line || this.options.fill) { + lpath += (lpath ? "L" : "M") + pos.x + "," + pos.y; + } + + if (this.options.curve) { + pos.grx = pos.x; + pos.gry = pos.y; + bins.push(pos); + } + } + + if (this.options.fill && lpath) + this.draw_g.append("svg:path") + .attr("d",lpath + "Z") + .style("stroke","none") + .call(this.fillatt.func); + + if (this.options.line && lpath) + this.draw_g.append("svg:path") + .attr("d", lpath) + .style("fill", "none") + .call(this.lineatt.func); + + if (this.options.curve && bins.length) + this.draw_g.append("svg:path") + .attr("d", JSROOT.Painter.BuildSvgPath("bezier", bins).path) + .style("fill", "none") + .call(this.lineatt.func); + + if (epath) + this.draw_g.append("svg:path") + .attr("d",epath) + .style("fill","none") + .call(this.lineatt.func); + + if (mpath) + this.draw_g.append("svg:path") + .attr("d",mpath) + .call(this.markeratt.func); + + } + + TGraphPolarPainter.prototype.CreatePolargram = function() { + var polargram = JSROOT.Create("TGraphPolargram"), + gr = this.GetObject(); + + var rmin = gr.fY[0] || 0, rmax = rmin; + for (var n=0;n<gr.fNpoints;++n) { + rmin = Math.min(rmin, gr.fY[n] - gr.fEY[n]); + rmax = Math.max(rmax, gr.fY[n] + gr.fEY[n]); + } + + polargram.fRwrmin = rmin - (rmax-rmin)*0.1; + polargram.fRwrmax = rmax + (rmax-rmin)*0.1; + + return polargram; + } + + TGraphPolarPainter.prototype.ExtractTooltip = function(pnt) { + if (!pnt) return null; + + var graph = this.GetObject(), + main = this.main_painter(), + best_dist2 = 1e10, bestindx = -1, bestpos = null; + + for (var n=0;n<graph.fNpoints;++n) { + var pos = main.translate(graph.fX[n], graph.fY[n]); + + var dist2 = (pos.x-pnt.x)*(pos.x-pnt.x) + (pos.y-pnt.y)*(pos.y-pnt.y); + if (dist2<best_dist2) { best_dist2 = dist2; bestindx = n; bestpos = pos; } + } + + var match_distance = 5; + if (this.markeratt && this.markeratt.used) match_distance = this.markeratt.GetFullSize(); + + if (Math.sqrt(best_dist2) > match_distance) return null; + + var res = { name: this.GetObject().fName, title: this.GetObject().fTitle, + x: bestpos.x, y: bestpos.y, + color1: this.markeratt && this.markeratt.used ? this.markeratt.color : this.lineatt.color, + exact: Math.sqrt(best_dist2) < 4, + lines: [ this.GetTipName() ], + binindx: bestindx, + menu_dist: match_distance, + radius: match_distance + }; + + res.lines.push("r = " + main.AxisAsText("r", graph.fY[bestindx])); + res.lines.push("phi = " + main.AxisAsText("phi",graph.fX[bestindx])); + + if (graph.fEY && graph.fEY[bestindx]) + res.lines.push("error r = " + main.AxisAsText("r", graph.fEY[bestindx])); + + if (graph.fEX && graph.fEX[bestindx]) + res.lines.push("error phi = " + main.AxisAsText("phi", graph.fEX[bestindx])); + + return res; + } + + TGraphPolarPainter.prototype.ShowTooltip = function(hint) { + + if (!this.draw_g) return; + + var ttcircle = this.draw_g.select(".tooltip_bin"); + + if (!hint) { + ttcircle.remove(); + return; + } + + if (ttcircle.empty()) + ttcircle = this.draw_g.append("svg:ellipse") + .attr("class","tooltip_bin") + .style("pointer-events","none"); + + hint.changed = ttcircle.property("current_bin") !== hint.binindx; + + if (hint.changed) + ttcircle.attr("cx", hint.x) + .attr("cy", hint.y) + .attr("rx", Math.round(hint.radius)) + .attr("ry", Math.round(hint.radius)) + .style("fill", "none") + .style("stroke", hint.color1) + .property("current_bin", hint.binindx); + } + + TGraphPolarPainter.prototype.ProcessTooltip = function(pnt) { + var hint = this.ExtractTooltip(pnt); + if (!pnt || !pnt.disabled) this.ShowTooltip(hint); + return hint; + } + + TGraphPolarPainter.prototype.PerformDrawing = function(divid) { + this.SetDivId(divid); + this.DrawBins(); + this.DrawingReady(); + } + + function drawGraphPolar(divid, graph, opt) { + + var painter = new TGraphPolarPainter(graph); + + painter.DecodeOptions(opt); + + painter.SetDivId(divid, -1); // just to get access to existing elements + + var main = painter.main_painter(); + if (main) { + if (!main.$polargram) { + console.error('Cannot superimpose TGraphPolar with plain histograms'); + return null; + } + painter.PerformDrawing(divid); + + return painter; + } + + if (!graph.fPolargram) graph.fPolargram = painter.CreatePolargram(); + + return JSROOT.draw(divid, graph.fPolargram, "", painter.PerformDrawing.bind(painter, divid)); + } + + // ============================================================== + + function TSplinePainter(spline) { + JSROOT.TObjectPainter.call(this, spline); + this.bins = null; + } + + TSplinePainter.prototype = Object.create(JSROOT.TObjectPainter.prototype); + + TSplinePainter.prototype.UpdateObject = function(obj, opt) { + var spline = this.GetObject(); + + if (spline._typename != obj._typename) return false; + + if (spline !== obj) JSROOT.extend(spline, obj); + + if (opt !== undefined) this.DecodeOptions(opt); + + return true; + } + + TSplinePainter.prototype.Eval = function(knot, x) { + var dx = x - knot.fX; + + if (knot._typename == "TSplinePoly3") + return knot.fY + dx*(knot.fB + dx*(knot.fC + dx*knot.fD)); + + if (knot._typename == "TSplinePoly5") + return knot.fY + dx*(knot.fB + dx*(knot.fC + dx*(knot.fD + dx*(knot.fE + dx*knot.fF)))); + + return knot.fY + dx; + } + + TSplinePainter.prototype.FindX = function(x) { + var spline = this.GetObject(), + klow = 0, khig = spline.fNp - 1; + + if (x <= spline.fXmin) return 0; + if (x >= spline.fXmax) return khig; + + if(spline.fKstep) { + // Equidistant knots, use histogramming + klow = Math.round((x - spline.fXmin)/spline.fDelta); + // Correction for rounding errors + if (x < spline.fPoly[klow].fX) { + klow = Math.max(klow-1,0); + } else if (klow < khig) { + if (x > spline.fPoly[klow+1].fX) ++klow; + } + } else { + // Non equidistant knots, binary search + while(khig-klow>1) { + var khalf = Math.round((klow+khig)/2); + if(x > spline.fPoly[khalf].fX) klow = khalf; + else khig = khalf; + } + } + return klow; + } + + TSplinePainter.prototype.CreateDummyHisto = function() { + + var xmin = 0, xmax = 1, ymin = 0, ymax = 1, + spline = this.GetObject(); + + if (spline && spline.fPoly) { + + xmin = xmax = spline.fPoly[0].fX; + ymin = ymax = spline.fPoly[0].fY; + + spline.fPoly.forEach(function(knot) { + xmin = Math.min(knot.fX, xmin); + xmax = Math.max(knot.fX, xmax); + ymin = Math.min(knot.fY, ymin); + ymax = Math.max(knot.fY, ymax); + }); + + if (ymax > 0.0) ymax *= 1.05; + if (ymin < 0.0) ymin *= 1.05; + } + + var histo = JSROOT.Create("TH1I"); + + histo.fName = spline.fName + "_hist"; + histo.fTitle = spline.fTitle; + + histo.fXaxis.fXmin = xmin; + histo.fXaxis.fXmax = xmax; + histo.fYaxis.fXmin = ymin; + histo.fYaxis.fXmax = ymax; + + return histo; + } + + TSplinePainter.prototype.ProcessTooltip = function(pnt) { + + var cleanup = false, + spline = this.GetObject(), + main = this.frame_painter(), + xx, yy, knot = null, indx = 0; + + if ((pnt === null) || !spline || !main) { + cleanup = true; + } else { + xx = main.RevertX(pnt.x); + indx = this.FindX(xx); + knot = spline.fPoly[indx]; + yy = this.Eval(knot, xx); + + if ((indx < spline.fN-1) && (Math.abs(spline.fPoly[indx+1].fX-xx) < Math.abs(xx-knot.fX))) knot = spline.fPoly[++indx]; + + if (Math.abs(main.grx(knot.fX) - pnt.x) < 0.5*this.knot_size) { + xx = knot.fX; yy = knot.fY; + } else { + knot = null; + if ((xx < spline.fXmin) || (xx > spline.fXmax)) cleanup = true; + } + } + + if (cleanup) { + if (this.draw_g !== null) + this.draw_g.select(".tooltip_bin").remove(); + return null; + } + + var gbin = this.draw_g.select(".tooltip_bin"), + radius = this.lineatt.width + 3; + + if (gbin.empty()) + gbin = this.draw_g.append("svg:circle") + .attr("class", "tooltip_bin") + .style("pointer-events","none") + .attr("r", radius) + .style("fill", "none") + .call(this.lineatt.func); + + var res = { name: this.GetObject().fName, + title: this.GetObject().fTitle, + x: main.grx(xx), + y: main.gry(yy), + color1: this.lineatt.color, + lines: [], + exact: (knot !== null) || (Math.abs(main.gry(yy) - pnt.y) < radius) }; + + res.changed = gbin.property("current_xx") !== xx; + res.menu = res.exact; + res.menu_dist = Math.sqrt((res.x-pnt.x)*(res.x-pnt.x) + (res.y-pnt.y)*(res.y-pnt.y)); + + if (res.changed) + gbin.attr("cx", Math.round(res.x)) + .attr("cy", Math.round(res.y)) + .property("current_xx", xx); + + var name = this.GetTipName(); + if (name.length > 0) res.lines.push(name); + res.lines.push("x = " + main.AxisAsText("x", xx)) + res.lines.push("y = " + main.AxisAsText("y", yy)); + if (knot !== null) { + res.lines.push("knot = " + indx); + res.lines.push("B = " + JSROOT.FFormat(knot.fB, JSROOT.gStyle.fStatFormat)); + res.lines.push("C = " + JSROOT.FFormat(knot.fC, JSROOT.gStyle.fStatFormat)); + res.lines.push("D = " + JSROOT.FFormat(knot.fD, JSROOT.gStyle.fStatFormat)); + if ((knot.fE!==undefined) && (knot.fF!==undefined)) { + res.lines.push("E = " + JSROOT.FFormat(knot.fE, JSROOT.gStyle.fStatFormat)); + res.lines.push("F = " + JSROOT.FFormat(knot.fF, JSROOT.gStyle.fStatFormat)); + } + } + + return res; + } + + TSplinePainter.prototype.Redraw = function() { + + var w = this.frame_width(), + h = this.frame_height(), + spline = this.GetObject(), + pmain = this.frame_painter(), + name = this.GetTipName("\n"); + + this.CreateG(true); + + this.knot_size = 5; // used in tooltip handling + + this.createAttLine({ attr: spline }); + + if (this.options.Line || this.options.Curve) { + + var npx = Math.max(10, spline.fNpx); + + var xmin = Math.max(pmain.scale_xmin, spline.fXmin), + xmax = Math.min(pmain.scale_xmax, spline.fXmax), + indx = this.FindX(xmin), + bins = []; // index of current knot + + if (pmain.logx) { + xmin = Math.log(xmin); + xmax = Math.log(xmax); + } + + for (var n=0;n<npx;++n) { + var xx = xmin + (xmax-xmin)/npx*(n-1); + if (pmain.logx) xx = Math.exp(xx); + + while ((indx < spline.fNp-1) && (xx > spline.fPoly[indx+1].fX)) ++indx; + + var yy = this.Eval(spline.fPoly[indx], xx); + + bins.push({ x: xx, y: yy, grx: pmain.grx(xx), gry: pmain.gry(yy) }); + } + + var h0 = h; // use maximal frame height for filling + if ((pmain.hmin!==undefined) && (pmain.hmin>=0)) { + h0 = Math.round(pmain.gry(0)); + if ((h0 > h) || (h0 < 0)) h0 = h; + } + + var path = JSROOT.Painter.BuildSvgPath("bezier", bins, h0, 2); + + this.draw_g.append("svg:path") + .attr("class", "line") + .attr("d", path.path) + .style("fill", "none") + .call(this.lineatt.func); + } + + if (this.options.Mark) { + + // for tooltips use markers only if nodes where not created + var path = ""; + + this.createAttMarker({ attr: spline }) + + this.markeratt.reset_pos(); + + this.knot_size = this.markeratt.GetFullSize(); + + for (var n=0; n<spline.fPoly.length; n++) { + var knot = spline.fPoly[n], + grx = pmain.grx(knot.fX); + if ((grx > -this.knot_size) && (grx < w + this.knot_size)) { + var gry = pmain.gry(knot.fY); + if ((gry > -this.knot_size) && (gry < h + this.knot_size)) { + path += this.markeratt.create(grx, gry); + } + } + } + + if (path) + this.draw_g.append("svg:path") + .attr("d", path) + .call(this.markeratt.func); + } + + } + + TSplinePainter.prototype.CanZoomIn = function(axis,min,max) { + if (axis!=="x") return false; + + var spline = this.GetObject(); + if (!spline) return false; + + // if function calculated, one always could zoom inside + return true; + } + + TSplinePainter.prototype.DecodeOptions = function(opt) { + var d = new JSROOT.DrawOptions(opt); + + if (!this.options) this.options = {}; + + JSROOT.extend(this.options, { + Same: d.check('SAME'), + Line: d.check('L'), + Curve: d.check('C'), + Mark: d.check('P') + }); + + this.OptionsStore(opt); + } + + TSplinePainter.prototype.FirstDraw = function() { + this.SetDivId(this.divid); + this.Redraw(); + return this.DrawingReady(); + } + + JSROOT.Painter.drawSpline = function(divid, spline, opt) { + + var painter = new TSplinePainter(spline); + + painter.SetDivId(divid, -1); + painter.DecodeOptions(opt); + + if (!painter.main_painter()) { + if (painter.options.Same) { + console.warn('TSpline painter requires histogram to be drawn'); + return null; + } + var histo = painter.CreateDummyHisto(); + JSROOT.draw(divid, histo, "AXIS", painter.FirstDraw.bind(painter)); + return painter; + } + + return painter.FirstDraw(); + } + + // ============================================================= + + function TGraphTimePainter(gr) { + JSROOT.TObjectPainter.call(this, gr); + } + + TGraphTimePainter.prototype = Object.create(JSROOT.TObjectPainter.prototype); + + TGraphTimePainter.prototype.Redraw = function() { + if (this.step === undefined) this.StartDrawing(false); + } + + TGraphTimePainter.prototype.DecodeOptions = function(opt) { + + var d = new JSROOT.DrawOptions(opt || "REPEAT"); + + if (!this.options) this.options = {}; + + JSROOT.extend(this.options, { + once: d.check("ONCE"), + repeat: d.check("REPEAT"), + first: d.check("FIRST") + }); + + this.OptionsStore(opt); + } + + TGraphTimePainter.prototype.DrawPrimitives = function(indx, callback, ppainter) { + + if (indx===0) { + this._doing_primitives = true; + } + + var lst = this.GetObject().fSteps.arr[this.step]; + + while (true) { + if (ppainter) ppainter.$grtimeid = this.selfid; // indicator that painter created by ourself + + if (!lst || (indx >= lst.arr.length)) { + delete this._doing_primitives; + return JSROOT.CallBack(callback); + } + + // handle use to invoke callback only when necessary + var handle = { func: this.DrawPrimitives.bind(this, indx+1, callback) }; + + ppainter = JSROOT.draw(this.divid, lst.arr[indx], lst.opt[indx], handle); + + if (!handle.completed) return; + indx++; + } + } + + TGraphTimePainter.prototype.Selector = function(p) { + return p && (p.$grtimeid === this.selfid); + } + + TGraphTimePainter.prototype.ContineDrawing = function() { + if (!this.options) return; + + var gr = this.GetObject(); + + if (!this.ready_called) { + this.ready_called = true; + this.DrawingReady(); // do it already here, animation will continue in background + } + + if (this.options.first) { + // draw only single frame, cancel all others + delete this.step; + return; + } + + if (this.wait_animation_frame) { + delete this.wait_animation_frame; + + // clear pad + var pp = this.pad_painter(); + if (!pp) { + // most probably, pad is cleared + delete this.step; + return; + } + + // clear primitives produced by the TGraphTime + pp.CleanPrimitives(this.Selector.bind(this)); + + // draw ptrimitives again + this.DrawPrimitives(0, this.ContineDrawing.bind(this)); + } else if (this.running_timeout) { + clearTimeout(this.running_timeout); + delete this.running_timeout; + + this.wait_animation_frame = true; + // use animation frame to disable update in inactive form + requestAnimationFrame(this.ContineDrawing.bind(this)); + } else { + + var sleeptime = gr.fSleepTime; + if (!sleeptime || (sleeptime<100)) sleeptime = 10; + + if (++this.step > gr.fSteps.arr.length) { + if (this.options.repeat) { + this.step = 0; // start again + sleeptime = Math.max(5000, 5*sleeptime); // increase sleep time + } else { + delete this.step; // clear indicator that animation running + return; + } + } + + this.running_timeout = setTimeout(this.ContineDrawing.bind(this), sleeptime); + } + } + + TGraphTimePainter.prototype.StartDrawing = function(once_again) { + if (once_again!==false) this.SetDivId(this.divid); + + this.step = 0; + + this.DrawPrimitives(0, this.ContineDrawing.bind(this)); + } + + JSROOT.Painter.drawGraphTime = function(divid,gr,opt) { + + var painter = new TGraphTimePainter(gr); + painter.SetDivId(divid,-1); + + if (painter.main_painter()) { + console.error('Cannot draw graph time on top of other histograms'); + return null; + } + + if (!gr.fFrame) { + console.error('Frame histogram not exists'); + return null; + } + + painter.DecodeOptions(opt); + + if (!gr.fFrame.fTitle && gr.fTitle) gr.fFrame.fTitle = gr.fTitle; + + painter.selfid = "grtime" + JSROOT.id_counter++; // use to identify primitives which should be clean + + JSROOT.draw(divid, gr.fFrame, "AXIS", painter.StartDrawing.bind(painter)); + + return painter; + + } + + // ============================================================= + + function TEfficiencyPainter(eff) { + JSROOT.TObjectPainter.call(this, eff); + this.fBoundary = 'Normal'; + } + + TEfficiencyPainter.prototype = Object.create(JSROOT.TObjectPainter.prototype); + + TEfficiencyPainter.prototype.GetEfficiency = function(bin) { + var obj = this.GetObject(), + total = obj.fTotalHistogram.getBinContent(bin), + passed = obj.fPassedHistogram.getBinContent(bin); + + return total ? passed/total : 0; + } + +/** implementing of beta_quantile requires huge number of functions in JSRootMath.js + + TEfficiencyPainter.prototype.ClopperPearson = function(total,passed,level,bUpper) { + var alpha = (1.0 - level) / 2; + if(bUpper) + return ((passed == total) ? 1.0 : JSROOT.Math.beta_quantile(1 - alpha,passed + 1,total-passed)); + else + return ((passed == 0) ? 0.0 : JSROOT.Math.beta_quantile(alpha,passed,total-passed+1.0)); + } +*/ + + TEfficiencyPainter.prototype.Normal = function(total,passed,level,bUpper) { + if (total == 0) return bUpper ? 1 : 0; + + var alpha = (1.0 - level)/2, + average = passed / total, + sigma = Math.sqrt(average * (1 - average) / total), + delta = JSROOT.Math.normal_quantile(1 - alpha,sigma); + + if(bUpper) + return ((average + delta) > 1) ? 1.0 : (average + delta); + + return ((average - delta) < 0) ? 0.0 : (average - delta); + } + + TEfficiencyPainter.prototype.GetEfficiencyErrorLow = function(bin) { + var obj = this.GetObject(), + total = obj.fTotalHistogram.getBinContent(bin), + passed = obj.fPassedHistogram.getBinContent(bin), + eff = this.GetEfficiency(bin); + + return eff - this[this.fBoundary](total,passed, obj.fConfLevel, false); + } + + TEfficiencyPainter.prototype.GetEfficiencyErrorUp = function(bin) { + var obj = this.GetObject(), + total = obj.fTotalHistogram.getBinContent(bin), + passed = obj.fPassedHistogram.getBinContent(bin), + eff = this.GetEfficiency(bin); + + return this[this.fBoundary]( total, passed, obj.fConfLevel, true) - eff; + } + + TEfficiencyPainter.prototype.CreateGraph = function() { + var gr = JSROOT.Create('TGraphAsymmErrors'); + gr.fName = "eff_graph"; + return gr; + } + + TEfficiencyPainter.prototype.FillGraph = function(gr, opt) { + var eff = this.GetObject(), + npoints = eff.fTotalHistogram.fXaxis.fNbins, + option = opt.toLowerCase(), + plot0Bins = false, j = 0; + if (option.indexOf("e0")>=0) plot0Bins = true; + for (var n=0;n<npoints;++n) { + if (!plot0Bins && eff.fTotalHistogram.getBinContent(n+1) === 0) continue; + gr.fX[j] = eff.fTotalHistogram.fXaxis.GetBinCenter(n+1); + gr.fY[j] = this.GetEfficiency(n+1); + gr.fEXlow[j] = eff.fTotalHistogram.fXaxis.GetBinCenter(n+1) - eff.fTotalHistogram.fXaxis.GetBinLowEdge(n+1); + gr.fEXhigh[j] = eff.fTotalHistogram.fXaxis.GetBinLowEdge(n+2) - eff.fTotalHistogram.fXaxis.GetBinCenter(n+1); + gr.fEYlow[j] = this.GetEfficiencyErrorLow(n+1); + gr.fEYhigh[j] = this.GetEfficiencyErrorUp(n+1); + ++j; + } + gr.fNpoints = j; + } + + JSROOT.Painter.drawEfficiency = function(divid, eff, opt) { + + if (!eff || !eff.fTotalHistogram || (eff.fTotalHistogram._typename.indexOf("TH1")!=0)) return null; + + var painter = new TEfficiencyPainter(eff); + painter.options = opt; + + var gr = painter.CreateGraph(); + painter.FillGraph(gr, opt); + + JSROOT.draw(divid, gr, opt, function() { + painter.SetDivId(divid); + painter.DrawingReady(); + }); + + return painter; + } + + + // ============================================================= + + function TMultiGraphPainter(mgraph) { + JSROOT.TObjectPainter.call(this, mgraph); + this.firstpainter = null; + this.autorange = false; + this.painters = []; // keep painters to be able update objects + } + + TMultiGraphPainter.prototype = Object.create(JSROOT.TObjectPainter.prototype); + + TMultiGraphPainter.prototype.Cleanup = function() { + this.painters = []; + JSROOT.TObjectPainter.prototype.Cleanup.call(this); + } + + TMultiGraphPainter.prototype.UpdateObject = function(obj) { + if (!this.MatchObjectType(obj)) return false; + + var mgraph = this.GetObject(), + graphs = obj.fGraphs; + + mgraph.fTitle = obj.fTitle; + + var isany = false; + if (this.firstpainter) { + var histo = obj.fHistogram; + if (this.autorange && !histo) + histo = this.ScanGraphsRange(graphs); + + if (this.firstpainter.UpdateObject(histo)) isany = true; + } + + for (var i = 0; i < graphs.arr.length; ++i) { + if (i<this.painters.length) + if (this.painters[i].UpdateObject(graphs.arr[i])) isany = true; + } + + if (obj.fFunctions) + for (var i = 0; i < obj.fFunctions.arr.length; ++i) { + var func = obj.fFunctions.arr[i]; + if (!func || !func._typename || !func.fName) continue; + var funcpainter = this.FindPainterFor(null, func.fName, func._typename); + if (funcpainter) funcpainter.UpdateObject(func); + } + + return isany; + } + + TMultiGraphPainter.prototype.ComputeGraphRange = function(res, gr) { + // Compute the x/y range of the points in this graph + if (gr.fNpoints == 0) return; + if (res.first) { + res.xmin = res.xmax = gr.fX[0]; + res.ymin = res.ymax = gr.fY[0]; + res.first = false; + } + for (var i=0; i < gr.fNpoints; ++i) { + res.xmin = Math.min(res.xmin, gr.fX[i]); + res.xmax = Math.max(res.xmax, gr.fX[i]); + res.ymin = Math.min(res.ymin, gr.fY[i]); + res.ymax = Math.max(res.ymax, gr.fY[i]); + } + return res; + } + + TMultiGraphPainter.prototype.padtoX = function(pad, x) { + // Convert x from pad to X. + if (pad.fLogx && (x < 50)) + return Math.exp(2.302585092994 * x); + return x; + } + + TMultiGraphPainter.prototype.ScanGraphsRange = function(graphs, histo, pad) { + var mgraph = this.GetObject(), + maximum, minimum, dx, dy, uxmin = 0, uxmax = 0, logx = false, logy = false, + time_display = false, time_format = "", + rw = { xmin: 0, xmax: 0, ymin: 0, ymax: 0, first: true }; + + if (pad) { + logx = pad.fLogx; + logy = pad.fLogy; + rw.xmin = pad.fUxmin; + rw.xmax = pad.fUxmax; + rw.ymin = pad.fUymin; + rw.ymax = pad.fUymax; + rw.first = false; + } + if (histo) { + minimum = histo.fYaxis.fXmin; + maximum = histo.fYaxis.fXmax; + if (pad) { + uxmin = this.padtoX(pad, rw.xmin); + uxmax = this.padtoX(pad, rw.xmax); + } + } else { + this.autorange = true; + + for (var i = 0; i < graphs.arr.length; ++i) + this.ComputeGraphRange(rw, graphs.arr[i]); + + if (graphs.arr[0] && graphs.arr[0].fHistogram && graphs.arr[0].fHistogram.fXaxis.fTimeDisplay) { + time_display = true; + time_format = graphs.arr[0].fHistogram.fXaxis.fTimeFormat; + } + + if (rw.xmin == rw.xmax) rw.xmax += 1.; + if (rw.ymin == rw.ymax) rw.ymax += 1.; + dx = 0.05 * (rw.xmax - rw.xmin); + dy = 0.05 * (rw.ymax - rw.ymin); + uxmin = rw.xmin - dx; + uxmax = rw.xmax + dx; + if (logy) { + if (rw.ymin <= 0) rw.ymin = 0.001 * rw.ymax; + minimum = rw.ymin / (1 + 0.5 * JSROOT.log10(rw.ymax / rw.ymin)); + maximum = rw.ymax * (1 + 0.2 * JSROOT.log10(rw.ymax / rw.ymin)); + } else { + minimum = rw.ymin - dy; + maximum = rw.ymax + dy; + } + if (minimum < 0 && rw.ymin >= 0) + minimum = 0; + if (maximum > 0 && rw.ymax <= 0) + maximum = 0; + } + + if (uxmin < 0 && rw.xmin >= 0) + uxmin = logx ? 0.9 * rw.xmin : 0; + if (uxmax > 0 && rw.xmax <= 0) + uxmax = logx? 1.1 * rw.xmax : 0; + + if (mgraph.fMinimum != -1111) + rw.ymin = minimum = mgraph.fMinimum; + if (mgraph.fMaximum != -1111) + rw.ymax = maximum = mgraph.fMaximum; + + if (minimum < 0 && rw.ymin >= 0 && logy) minimum = 0.9 * rw.ymin; + if (maximum > 0 && rw.ymax <= 0 && logy) maximum = 1.1 * rw.ymax; + if (minimum <= 0 && logy) minimum = 0.001 * maximum; + if (!logy && minimum > 0 && minimum < 0.05*maximum) minimum = 0; + if (uxmin <= 0 && logx) + uxmin = (uxmax > 1000) ? 1 : 0.001 * uxmax; + + // Create a temporary histogram to draw the axis (if necessary) + if (!histo) { + histo = JSROOT.Create("TH1I"); + histo.fTitle = mgraph.fTitle; + histo.fXaxis.fXmin = uxmin; + histo.fXaxis.fXmax = uxmax; + histo.fXaxis.fTimeDisplay = time_display; + if (time_display) histo.fXaxis.fTimeFormat = time_format; + } + + histo.fYaxis.fXmin = minimum; + histo.fYaxis.fXmax = maximum; + + return histo; + } + + TMultiGraphPainter.prototype.DrawAxis = function(callback) { + // draw special histogram + + var mgraph = this.GetObject(), + histo = this.ScanGraphsRange(mgraph.fGraphs, mgraph.fHistogram, this.root_pad()); + + // histogram painter will be first in the pad, will define axis and + // interactive actions + JSROOT.draw(this.divid, histo, "AXIS", callback); + } + + TMultiGraphPainter.prototype.DrawNextFunction = function(indx, callback) { + // method draws next function from the functions list + + var mgraph = this.GetObject(); + + if (!mgraph.fFunctions || (indx >= mgraph.fFunctions.arr.length)) + return JSROOT.CallBack(callback); + + JSROOT.draw(this.divid, mgraph.fFunctions.arr[indx], mgraph.fFunctions.opt[indx], + this.DrawNextFunction.bind(this, indx+1, callback)); + } + + TMultiGraphPainter.prototype.DrawNextGraph = function(indx, opt, subp, used_timeout) { + if (subp) this.painters.push(subp); + + var graphs = this.GetObject().fGraphs; + + // at the end of graphs drawing draw functions (if any) + if (indx >= graphs.arr.length) { + this._pfc = this._plc = this._pmc = false; // disable auto coloring at the end + return this.DrawNextFunction(0, this.DrawingReady.bind(this)); + } + + // when too many graphs are drawn, avoid deep stack with timeout + if ((indx % 500 === 499) && !used_timeout) + return setTimeout(this.DrawNextGraph.bind(this,indx,opt,null,true),0); + + // if there is auto colors assignment, try to provide it + if (this._pfc || this._plc || this._pmc) { + if (!this.pallette && JSROOT.Painter.GetColorPalette) + this.palette = JSROOT.Painter.GetColorPalette(); + if (this.palette) { + var color = this.palette.calcColor(indx, graphs.arr.length+1); + var icolor = this.add_color(color); + + if (this._pfc) graphs.arr[indx].fFillColor = icolor; + if (this._plc) graphs.arr[indx].fLineColor = icolor; + if (this._pmc) graphs.arr[indx].fMarkerColor = icolor; + } + } + + JSROOT.draw(this.divid, graphs.arr[indx], graphs.opt[indx] || opt, + this.DrawNextGraph.bind(this, indx+1, opt)); + } + + JSROOT.Painter.drawMultiGraph = function(divid, mgraph, opt) { + + var painter = new TMultiGraphPainter(mgraph); + + painter.SetDivId(divid, -1); // it may be no element to set divid + + var d = new JSROOT.DrawOptions(opt); + d.check("3D"); d.check("FB"); // no 3D supported, FB not clear + + painter._pfc = d.check("PFC"); + painter._plc = d.check("PLC"); + painter._pmc = d.check("PMC"); + + if (d.check("A") || !painter.main_painter()) { + painter.DrawAxis(function(hpainter) { + painter.firstpainter = hpainter; + painter.SetDivId(divid); + painter.DrawNextGraph(0, d.remain()); + }); + } else { + painter.SetDivId(divid); + painter.DrawNextGraph(0, d.remain()); + } + + return painter; + } + + // ========================================================================================= + + function drawWebPainting(divid, obj, opt) { + + var painter = new JSROOT.TObjectPainter(obj, opt); + + painter.UpdateObject = function(obj) { + if (!this.MatchObjectType(obj)) return false; + this.draw_object = obj; + return true; + } + + painter.ReadAttr = function(str, names) { + var lastp = 0, obj = { _typename: "any" }; + for (var k=0;k<names.length;++k) { + var p = str.indexOf(":", lastp+1); + obj[names[k]] = parseInt(str.substr(lastp+1, (p>lastp) ? p-lastp-1 : undefined)); + lastp = p; + } + return obj; + } + + painter.Redraw = function() { + + var obj = this.GetObject(), func = this.AxisToSvgFunc(false); + + if (!obj || !obj.fOper || !func) return; + + var indx = 0, attr = {}, lastpath = null, lastkind = "none", d = "", + oper, k, npoints, n, arr = obj.fOper.split(";"); + + function check_attributes(painter, kind) { + if (kind == lastkind) return; + + if (lastpath) { + lastpath.attr("d", d); // flush previous + d = ""; lastpath = null; lastkind = "none"; + } + + if (!kind) return; + + lastkind = kind; + lastpath = painter.draw_g.append("svg:path"); + switch (kind) { + case "f": lastpath.call(painter.fillatt.func).attr('stroke', 'none'); break; + case "l": lastpath.call(painter.lineatt.func).attr('fill', 'none'); break; + case "m": lastpath.call(painter.markeratt.func); break; + } + } + + this.CreateG(); + + for (k=0;k<arr.length;++k) { + oper = arr[k][0]; + switch (oper) { + case "z": + this.createAttLine({ attr: this.ReadAttr(arr[k], ["fLineColor", "fLineStyle", "fLineWidth"]), force: true }); + check_attributes(); + continue; + case "y": + this.createAttFill({ attr: this.ReadAttr(arr[k], ["fFillColor", "fFillStyle"]), force: true }); + check_attributes(); + continue; + case "x": + this.createAttMarker({ attr: this.ReadAttr(arr[k], ["fMarkerColor", "fMarkerStyle", "fMarkerSize"]), force: true }) + check_attributes(); + continue; + case "o": + attr = this.ReadAttr(arr[k], ["fTextColor", "fTextFont", "fTextSize", "fTextAlign", "fTextAngle" ]); + if (attr.fTextSize < 0) attr.fTextSize *= -0.001; + check_attributes(); + continue; + case "r": + case "b": { + + check_attributes(this, (oper == "b") ? "f" : "l"); + + var x1 = func.x(obj.fBuf[indx++]), + y1 = func.y(obj.fBuf[indx++]), + x2 = func.x(obj.fBuf[indx++]), + y2 = func.y(obj.fBuf[indx++]); + + d += "M"+x1+","+y1+"h"+(x2-x1)+"v"+(y2-y1)+"h"+(x1-x2)+"z"; + + continue; + } + case "l": + case "f": { + + check_attributes(this, oper); + + npoints = parseInt(arr[k].substr(1)); + + for (n=0;n<npoints;++n) + d += ((n>0) ? "L" : "M") + + func.x(obj.fBuf[indx++]) + "," + func.y(obj.fBuf[indx++]); + + if (oper == "f") d+="Z"; + + continue; + } + + case "m": { + + check_attributes(this, oper); + + npoints = parseInt(arr[k].substr(1)); + + this.markeratt.reset_pos(); + for (n=0;n<npoints;++n) + d += this.markeratt.create(func.x(obj.fBuf[indx++]), func.y(obj.fBuf[indx++])); + + continue; + } + + case "h": + case "t": { + if (attr.fTextSize) { + + check_attributes(); + + var height = (attr.fTextSize > 1) ? attr.fTextSize : this.pad_height() * attr.fTextSize; + + var group = this.draw_g.append("svg:g"); + + this.StartTextDrawing(attr.fTextFont, height, group); + + var angle = attr.fTextAngle; + if (angle >= 360) angle -= Math.floor(angle/360) * 360; + + var txt = arr[k].substr(1); + + if (oper == "h") { + var res = ""; + for (n=0;n<txt.length;n+=2) + res += String.fromCharCode(parseInt(txt.substr(n,2), 16)); + txt = res; + } + + // todo - correct support of angle + this.DrawText({ align: attr.fTextAlign, + x: func.x(obj.fBuf[indx++]), + y: func.y(obj.fBuf[indx++]), + rotate: -angle, + text: txt, + color: JSROOT.Painter.root_colors[attr.fTextColor], latex: 0, draw_g: group }); + + this.FinishTextDrawing(group); + } + continue; + } + + default: + console.log('unsupported operation ' + oper); + } + } + + check_attributes(); + } + + painter.SetDivId(divid); + + painter.Redraw(); + + return painter.DrawingReady(); + } + + JSROOT.Painter.drawASImage = function(divid, obj, opt) { + var painter = new JSROOT.TBasePainter(); + painter.SetDivId(divid, -1); + + var main = painter.select_main(); // this is d3 selection of main element for image drawing + + // from here one should insert PNG image + + // this is example how external image can be inserted + // main.append("img").attr("src","https://root.cern/js/files/img/tf1.png"); + + // this is potential example how image can be generated + // one could use TASImage member like obj.fPngBuf + // main.append("img").attr("src","data:image/png;base64,xxxxxxxxx.."); + + painter.SetDivId(divid); + + return painter.DrawingReady(); + } + + JSROOT.Painter.drawJSImage = function(divid, obj, opt) { + var painter = new JSROOT.TBasePainter(); + painter.SetDivId(divid, -1); + + var main = painter.select_main(); + + // this is example how external image can be inserted + var img = main.append("img").attr("src", obj.fName).attr("title", obj.fTitle || obj.fName); + + if (opt && opt.indexOf("scale")>=0) { + img.style("width","100%").style("height","100%"); + } else if (opt && opt.indexOf("center")>=0) { + main.style("position", "relative"); + img.attr("style", "margin: 0; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);"); + } + + painter.SetDivId(divid); + + return painter.DrawingReady(); + } + + + // ================================================================================================== + + JSROOT.Painter.CreateBranchItem = function(node, branch, tree, parent_branch) { + if (!node || !branch) return false; + + var nb_branches = branch.fBranches ? branch.fBranches.arr.length : 0, + nb_leaves = branch.fLeaves ? branch.fLeaves.arr.length : 0; + + function ClearName(arg) { + var pos = arg.indexOf("["); + if (pos>0) arg = arg.substr(0, pos); + if (parent_branch && arg.indexOf(parent_branch.fName)==0) { + arg = arg.substr(parent_branch.fName.length); + if (arg[0]===".") arg = arg.substr(1); + } + return arg; + } + + branch.$tree = tree; // keep tree pointer, later do it more smart + + var subitem = { + _name : ClearName(branch.fName), + _kind : "ROOT." + branch._typename, + _title : branch.fTitle, + _obj : branch + }; + + if (!node._childs) node._childs = []; + + node._childs.push(subitem); + + if (branch._typename==='TBranchElement') + subitem._title += " from " + branch.fClassName + ";" + branch.fClassVersion; + + if (nb_branches > 0) { + subitem._more = true; + subitem._expand = function(bnode,bobj) { + // really create all sub-branch items + if (!bobj) return false; + + if (!bnode._childs) bnode._childs = []; + + if (bobj.fLeaves && (bobj.fLeaves.arr.length === 1) && + ((bobj.fType === JSROOT.BranchType.kClonesNode) || (bobj.fType === JSROOT.BranchType.kSTLNode))) { + bobj.fLeaves.arr[0].$branch = bobj; + bnode._childs.push({ + _name: "@size", + _title: "container size", + _kind: "ROOT.TLeafElement", + _icon: "img_leaf", + _obj: bobj.fLeaves.arr[0], + _more : false + }); + } + + for (var i=0; i<bobj.fBranches.arr.length; ++i) + JSROOT.Painter.CreateBranchItem(bnode, bobj.fBranches.arr[i], bobj.$tree, bobj); + + var object_class = JSROOT.IO.GetBranchObjectClass(bobj, bobj.$tree, true), + methods = object_class ? JSROOT.getMethods(object_class) : null; + + if (methods && (bobj.fBranches.arr.length>0)) + for (var key in methods) { + if (typeof methods[key] !== 'function') continue; + var s = methods[key].toString(); + if ((s.indexOf("return")>0) && (s.indexOf("function ()")==0)) + bnode._childs.push({ + _name: key+"()", + _title: "function " + key + " of class " + object_class, + _kind: "ROOT.TBranchFunc", // fictional class, only for drawing + _obj: { _typename: "TBranchFunc", branch: bobj, func: key }, + _more : false + }); + + } + + return true; + } + return true; + } else if (nb_leaves === 1) { + subitem._icon = "img_leaf"; + subitem._more = false; + } else if (nb_leaves > 1) { + subitem._childs = []; + for (var j = 0; j < nb_leaves; ++j) { + branch.fLeaves.arr[j].$branch = branch; // keep branch pointer for drawing + var leafitem = { + _name : ClearName(branch.fLeaves.arr[j].fName), + _kind : "ROOT." + branch.fLeaves.arr[j]._typename, + _obj: branch.fLeaves.arr[j] + } + subitem._childs.push(leafitem); + } + } + + return true; + } + + JSROOT.Painter.TreeHierarchy = function(node, obj) { + if (obj._typename != 'TTree' && obj._typename != 'TNtuple' && obj._typename != 'TNtupleD' ) return false; + + node._childs = []; + node._tree = obj; // set reference, will be used later by TTree::Draw + + for (var i=0; i<obj.fBranches.arr.length; ++i) + JSROOT.Painter.CreateBranchItem(node, obj.fBranches.arr[i], obj); + + return true; + } + + /** @summary function called from JSROOT.draw() + * @desc just envelope for real TTree::Draw method which do the main job + * Can be also used for the branch and leaf object + * @private */ + JSROOT.Painter.drawTree = function(divid, obj, opt) { + + var painter = new JSROOT.TObjectPainter(obj), + tree = obj, args = opt; + + if (obj._typename == "TBranchFunc") { + // fictional object, created only in browser + args = { expr: "." + obj.func + "()", branch: obj.branch }; + if (opt && opt.indexOf("dump")==0) args.expr += ">>" + opt; else + if (opt) args.expr += opt; + tree = obj.branch.$tree; + } else if (obj.$branch) { + // this is drawing of the single leaf from the branch + args = { expr: "." + obj.fName + (opt || ""), branch: obj.$branch }; + if ((args.branch.fType === JSROOT.BranchType.kClonesNode) || (args.branch.fType === JSROOT.BranchType.kSTLNode)) { + // special case of size + args.expr = opt; + args.direct_branch = true; + } + + tree = obj.$branch.$tree; + } else if (obj.$tree) { + // this is drawing of the branch + + // if generic object tried to be drawn without specifying any options, it will be just dump + if (!opt && obj.fStreamerType && (obj.fStreamerType !== JSROOT.IO.kTString) && + (obj.fStreamerType >= JSROOT.IO.kObject) && (obj.fStreamerType <= JSROOT.IO.kAnyP)) opt = "dump"; + + args = { expr: opt, branch: obj }; + tree = obj.$tree; + } else { + + if ((args==='player') || !args) { + JSROOT.AssertPrerequisites("jq2d", function() { + JSROOT.CreateTreePlayer(painter); + painter.ConfigureTree(tree); + painter.Show(divid); + painter.DrawingReady(); + }); + return painter; + } + + if (typeof args === 'string') args = { expr: args }; + } + + if (!tree) { + console.error('No TTree object available for TTree::Draw'); + return painter.DrawingReady(); + } + + var callback = painter.DrawingReady.bind(painter); + painter._return_res_painter = true; // indicate that TTree::Draw painter returns not itself but drawing of result object + + JSROOT.cleanup(divid); + + tree.Draw(args, function(histo, hopt, intermediate) { + + var drawid = ""; + + if (!args.player) drawid = divid; else + if (args.create_player === 2) drawid = painter.drawid; + + if (drawid) + return JSROOT.redraw(drawid, histo, hopt, intermediate ? null : callback); + + if (args.create_player === 1) { args.player_intermediate = intermediate; return; } + + // redirect drawing to the player + args.player_create = 1; + args.player_intermediate = intermediate; + JSROOT.AssertPrerequisites("jq2d", function() { + JSROOT.CreateTreePlayer(painter); + painter.ConfigureTree(tree); + painter.Show(divid, args); + args.create_player = 2; + JSROOT.redraw(painter.drawid, histo, hopt, args.player_intermediate ? null : callback); + painter.SetItemName("TreePlayer"); // item name used by MDI when process resize + }); + }); + + return painter; + } + + // ================================================================================================== + + + JSROOT.Painter.drawText = drawText; + JSROOT.Painter.drawLine = drawLine; + JSROOT.Painter.drawPolyLine = drawPolyLine; + JSROOT.Painter.drawArrow = drawArrow; + JSROOT.Painter.drawEllipse = drawEllipse; + JSROOT.Painter.drawPie = drawPie; + JSROOT.Painter.drawBox = drawBox; + JSROOT.Painter.drawMarker = drawMarker; + JSROOT.Painter.drawPolyMarker = drawPolyMarker; + JSROOT.Painter.drawWebPainting = drawWebPainting; + JSROOT.Painter.drawRooPlot = drawRooPlot; + JSROOT.Painter.drawGraph = drawGraph; + JSROOT.Painter.drawFunction = drawFunction; + JSROOT.Painter.drawGraphPolar = drawGraphPolar; + JSROOT.Painter.drawGraphPolargram = drawGraphPolargram; + + JSROOT.TF1Painter = TF1Painter; + JSROOT.TGraphPainter = TGraphPainter; + JSROOT.TGraphPolarPainter = TGraphPolarPainter; + JSROOT.TMultiGraphPainter = TMultiGraphPainter; + JSROOT.TSplinePainter = TSplinePainter; + + return JSROOT; + +})); diff --git a/js/scripts/JSRootPainter.openui5.js b/js/scripts/JSRootPainter.openui5.js new file mode 100644 index 00000000000..3a89a1c3d5e --- /dev/null +++ b/js/scripts/JSRootPainter.openui5.js @@ -0,0 +1,525 @@ +/// @file JSRootPainter.openui5.js +/// Part of JavaScript ROOT graphics, dependent from openui5 functionality +/// Openui5 loaded directly in the script + +(function( factory ) { + if ( typeof define === "function" && define.amd ) { + define( ['jquery', 'jquery-ui', 'd3', 'JSRootPainter', 'JSRootPainter.hierarchy', 'JSRootPainter.jquery' ], factory ); + } else { + + if (typeof jQuery == 'undefined') + throw new Error('jQuery not defined', 'JSRootPainter.openui5.js'); + + if (typeof jQuery.ui == 'undefined') + throw new Error('jQuery-ui not defined','JSRootPainter.openui5.js'); + + if (typeof d3 != 'object') + throw new Error('This extension requires d3.v3.js', 'JSRootPainter.openui5.js'); + + if (typeof JSROOT == 'undefined') + throw new Error('JSROOT is not defined', 'JSRootPainter.openui5.js'); + + if (typeof JSROOT.Painter != 'object') + throw new Error('JSROOT.Painter not defined', 'JSRootPainter.openui5.js'); + + factory(jQuery, jQuery.ui, d3, JSROOT); + } +} (function($, myui, d3, JSROOT) { + + "use strict"; + + JSROOT.sources.push("openui5"); + + var load_callback = JSROOT.complete_script_load; + delete JSROOT.complete_script_load; // normal callback is intercepted - we need to instantiate openui5 + + JSROOT.completeUI5Loading = function() { + console.log('complete ui5 loading'); + JSROOT.sap = sap; + + // var cust_style = document.createElement("link"); + // cust_style.setAttribute("rel", "stylesheet"); + // cust_style.setAttribute("type", "text/css"); + // cust_style.setAttribute("href", JSROOT.source_dir + "openui5/custom.css"); + // document.getElementsByTagName("head")[0].appendChild(cust_style); + + JSROOT.CallBack(load_callback); + load_callback = null; + } + + function TryOpenOpenUI(sources) { + + // where to take openui5 sources + var src = sources.shift(); + + if ((src.indexOf("roothandler")==0) && (src.indexOf("://")<0)) src = src.replace(/\:\//g,"://"); + + var element = document.createElement("script"); + element.setAttribute('type', "text/javascript"); + element.setAttribute('id', "sap-ui-bootstrap"); + // use nojQuery while we are already load jquery and jquery-ui, later one can use directly sap-ui-core.js + + // this is location of openui5 scripts when working with THttpServer or when scripts are installed inside JSROOT + element.setAttribute('src', src + "resources/sap-ui-core-nojQuery.js"); // latest openui5 version + + element.setAttribute('data-sap-ui-libs', JSROOT.openui5libs || "sap.m, sap.ui.layout, sap.ui.unified, sap.ui.commons"); + + element.setAttribute('data-sap-ui-theme', 'sap_belize'); + element.setAttribute('data-sap-ui-compatVersion', 'edge'); + // element.setAttribute('data-sap-ui-bindingSyntax', 'complex'); + + element.setAttribute('data-sap-ui-preload', 'async'); // '' to disable Component-preload.js + + // configure path for openui5 scripts + element.setAttribute('data-sap-ui-resourceroots', '{ "sap.ui.jsroot": "' + JSROOT.source_dir + 'openui5/" }'); + + element.setAttribute('data-sap-ui-evt-oninit', "JSROOT.completeUI5Loading()"); + + element.onerror = function() { + // remove failed element + element.parentNode.removeChild(element); + // and try next + TryOpenOpenUI(sources); + } + + element.onload = function() { + console.log('Load openui5 from ' + src); + } + + document.getElementsByTagName("head")[0].appendChild(element); + } + + var sources = [], openui5_dflt = "https://openui5.hana.ondemand.com/", openui5_jsroot = JSROOT.source_dir + "openui5dist/"; + + if (typeof JSROOT.openui5src == 'string') { + switch (JSROOT.openui5src) { + case "nodefault": openui5_dflt = ""; break; + case "default": sources.push(openui5_dflt); openui5_dflt = ""; break; + case "nojsroot": openui5_jsroot = ""; break; + case "jsroot": sources.push(openui5_jsroot); openui5_jsroot = ""; break; + default: sources.push(JSROOT.openui5src); break; + } + + } + + if (openui5_jsroot && (sources.indexOf(openui5_jsroot)<0)) sources.push(openui5_jsroot); + if (openui5_dflt && (sources.indexOf(openui5_dflt)<0)) sources.push(openui5_dflt); + + TryOpenOpenUI(sources); + + // function allows to create menu with openui + // for the moment deactivated - can be used later + JSROOT.Painter.createMenuNew = function(painter, maincallback) { + + var menu = { painter: painter, element: null, cnt: 1, stack: [], items: [], separ: false }; + + // this is slightly modified version of original MenuItem.render function. + // need to be updated with any further changes + function RenderCustomItem(rm, oItem, oMenu, oInfo) { + var oSubMenu = oItem.getSubmenu(); + rm.write("<li "); + + var sClass = "sapUiMnuItm"; + if (oInfo.iItemNo == 1) { + sClass += " sapUiMnuItmFirst"; + } else if (oInfo.iItemNo == oInfo.iTotalItems) { + sClass += " sapUiMnuItmLast"; + } + if (!oMenu.checkEnabled(oItem)) { + sClass += " sapUiMnuItmDsbl"; + } + if (oItem.getStartsSection()) { + sClass += " sapUiMnuItmSepBefore"; + } + + rm.writeAttribute("class", sClass); + if (oItem.getTooltip_AsString()) { + rm.writeAttributeEscaped("title", oItem.getTooltip_AsString()); + } + rm.writeElementData(oItem); + + // ARIA + if (oInfo.bAccessible) { + rm.writeAccessibilityState(oItem, { + role: "menuitem", + disabled: !oMenu.checkEnabled(oItem), + posinset: oInfo.iItemNo, + setsize: oInfo.iTotalItems, + labelledby: {value: /*oMenu.getId() + "-label " + */this.getId() + "-txt " + this.getId() + "-scuttxt", append: true} + }); + if (oSubMenu) { + rm.writeAttribute("aria-haspopup", true); + rm.writeAttribute("aria-owns", oSubMenu.getId()); + } + } + + // Left border + rm.write("><div class=\"sapUiMnuItmL\"></div>"); + + // icon/check column + rm.write("<div class=\"sapUiMnuItmIco\">"); + if (oItem.getIcon()) { + rm.writeIcon(oItem.getIcon(), null, {title: null}); + } + rm.write("</div>"); + + // Text column + rm.write("<div id=\"" + this.getId() + "-txt\" class=\"sapUiMnuItmTxt\">"); + rm.write(oItem.custom_html); + rm.write("</div>"); + + // Shortcut column + rm.write("<div id=\"" + this.getId() + "-scuttxt\" class=\"sapUiMnuItmSCut\"></div>"); + + // Submenu column + rm.write("<div class=\"sapUiMnuItmSbMnu\">"); + if (oSubMenu) { + rm.write("<div class=\"sapUiIconMirrorInRTL\"></div>"); + } + rm.write("</div>"); + + // Right border + rm.write("<div class=\"sapUiMnuItmR\"></div>"); + + rm.write("</li>"); + } + + JSROOT.sap.ui.define([ 'sap/ui/unified/Menu', 'sap/ui/unified/MenuItem', 'sap/ui/unified/MenuItemBase' ], + function(sapMenu, sapMenuItem, sapMenuItemBase) { + + menu.add = function(name, arg, func) { + if (name == "separator") { this.separ = true; return; } + + if (name.indexOf("header:")==0) + return this.items.push(new sapMenuItem("", { text: name.substr(7), enabled: false })); + + if (name=="endsub:") { + var last = this.stack.pop(); + last._item.setSubmenu(new sapMenu("", { items: this.items })); + this.items = last._items; + return; + } + + var issub = false, checked = null; + if (name.indexOf("sub:")==0) { + name = name.substr(4); + issub = true; + } + + if (typeof arg == 'function') { func = arg; arg = name; } + + if (name.indexOf("chk:")==0) { name = name.substr(4); checked = true; } else + if (name.indexOf("unk:")==0) { name = name.substr(4); checked = false; } + + var item = new sapMenuItem("", { }); + + if (!issub && (name.indexOf("<svg")==0)) { + item.custom_html = name; + item.render = RenderCustomItem; + } else { + item.setText(name); + if (this.separ) item.setStartsSection(true); + this.separ = false; + } + + if (checked) item.setIcon("sap-icon://accept"); + + this.items.push(item); + + if (issub) { + this.stack.push({ _items: this.items, _item: item }); + this.items = []; + } + + if (typeof func == 'function') { + item.menu_func = func; // keep call-back function + item.menu_arg = arg; // keep call-back argument + } + + this.cnt++; + } + + menu.addchk = function(flag, name, arg, func) { + return this.add((flag ? "chk:" : "unk:") + name, arg, func); + } + + menu.size = function() { return this.cnt-1; } + + menu.addDrawMenu = function(menu_name, opts, call_back) { + if (!opts) opts = []; + if (opts.length==0) opts.push(""); + + var without_sub = false; + if (menu_name.indexOf("nosub:")==0) { + without_sub = true; + menu_name = menu_name.substr(6); + } + + if (opts.length === 1) { + if (opts[0]==='inspect') menu_name = menu_name.replace("Draw", "Inspect"); + return this.add(menu_name, opts[0], call_back); + } + + if (!without_sub) this.add("sub:" + menu_name, opts[0], call_back); + + for (var i=0;i<opts.length;++i) { + var name = opts[i]; + if (name=="") name = '<dflt>'; + + var group = i+1; + if ((opts.length>5) && (name.length>0)) { + // check if there are similar options, which can be grouped once again + while ((group<opts.length) && (opts[group].indexOf(name)==0)) group++; + } + + if (without_sub) name = menu_name + " " + name; + + if (group < i+2) { + this.add(name, opts[i], call_back); + } else { + this.add("sub:" + name, opts[i], call_back); + for (var k=i+1;k<group;++k) + this.add(opts[k], opts[k], call_back); + this.add("endsub:"); + i = group-1; + } + } + if (!without_sub) this.add("endsub:"); + } + + menu.remove = function() { + if (this.remove_bind) { + document.body.removeEventListener('click', this.remove_bind); + this.remove_bind = null; + } + if (this.element) { + this.element.destroy(); + if (this.close_callback) this.close_callback(); + } + this.element = null; + } + + menu.remove_bind = menu.remove.bind(menu); + + menu.show = function(event, close_callback) { + this.remove(); + + if (typeof close_callback == 'function') this.close_callback = close_callback; + + var old = sap.ui.getCore().byId("root_context_menu"); + if (old) old.destroy(); + + document.body.addEventListener('click', this.remove_bind); + + this.element = new sapMenu("root_context_menu", { items: this.items }); + + // this.element.attachClosed({}, this.remove, this); + + this.element.attachItemSelect(null, this.menu_item_select, this); + + var eDock = sap.ui.core.Popup.Dock; + // var oButton = oEvent.getSource(); + this.element.open(false, null, eDock.BeginTop, eDock.BeginTop, null, event.clientX + " " + event.clientY); + } + + menu.menu_item_select = function(oEvent) { + var item = oEvent.getParameter("item"); + if (!item || !item.menu_func) return; + // console.log('select item arg', item.menu_arg); + // console.log('select item', item.getText()); + if (this.painter) + item.menu_func.bind(this.painter)(item.menu_arg); + else + item.menu_func(item.menu_arg); + } + + JSROOT.CallBack(maincallback, menu); + }); + + return menu; + } + + JSROOT.TObjectPainter.prototype.ShowInpsector = function() { + var handle = {}; // should be controller? + handle.closeObjectInspector = function() { + this.dialog.close(); + this.dialog.destroy(); + } + handle.dialog = JSROOT.sap.ui.xmlfragment("sap.ui.jsroot.view.Inspector", handle); + + // FIXME: global id is used, should find better solution later + var view = sap.ui.getCore().byId("object_inspector"); + view.getController().setObject(this.GetObject()); + + handle.dialog.open(); + } + + // =================================================================================================== + + JSROOT.TCanvasPainter.prototype.ShowGed = function(objpainter) { + // function used to activate GED + + d3.select("#ged_placeholder").text(""); + + var panelid = "CanvasGedId"; + + var oModel = new JSROOT.sap.ui.model.json.JSONModel({ + handle: null + }); + + sap.ui.getCore().setModel(oModel, panelid); + + var ged = sap.ui.getCore().byId(panelid); + + if (!ged) + ged = JSROOT.sap.ui.xmlview({ + id: panelid, + viewName: "sap.ui.jsroot.view.Ged" + // layoutData: oLd, + // height: "100%" + }); + + ged.placeAt("ged_placeholder"); + + // should be moved into Ged controller - it must be able to detect canvas painter itself + this.RegisterForPadEvents(ged.getController().padEventsReceiver.bind(ged.getController())); + + this.SelectObjectPainter(objpainter); + } + + JSROOT.TCanvasPainter.prototype.CleanupGed = function() { + + // dettach pad events receiver + this.RegisterForPadEvents(null); + + sap.ui.getCore().byId("CanvasGedId").getController().cleanupGed(); + } + + JSROOT.TCanvasPainter.prototype.openuiHasGed = function() { + var main = JSROOT.sap.ui.getCore().byId("TopCanvasId"); + return main ? main.getController().isGedEditor() : false; + } + + JSROOT.TCanvasPainter.prototype.openuiActivateGed = function(painter, kind, mode) { + // function used to activate GED in full canvas + + var main = JSROOT.sap.ui.getCore().byId("TopCanvasId"); + if (main) main.getController().showGeEditor(true); + + this.SelectObjectPainter(painter); + + if (typeof this.ProcessChanges == 'function') + this.ProcessChanges("sbits", this); + } + + JSROOT.TCanvasPainter.prototype.ActivateFitPanel = function(painter) { + // function used to activate FitPanel + + if (!this.use_openui) return; // not supported in reduced mode + var main = JSROOT.sap.ui.getCore().byId("TopCanvasId"); + if (main) main.getController().showLeftArea("FitPanel"); + } + + /* + JSROOT.TCanvasPainter.prototype.SelectObjectPainter = function(objpainter) { + var ged = null; + if (this.use_openui) { + var main = JSROOT.sap.ui.getCore().byId("TopCanvasId") + ged = main.getController().getLeftController("Ged"); + } else { + var main = JSROOT.sap.ui.getCore().byId("CanvasGedId"); + if (main) ged = main.getController(); + } + if (ged) ged.onObjectSelect(this, objpainter); + } + + JSROOT.TCanvasPainter.prototype.ProcessPadRedraw = function(padpainter) { + var ged = null; + if (this.use_openui) { + var main = JSROOT.sap.ui.getCore().byId("TopCanvasId") + ged = main.getController().getLeftController("Ged"); + } else { + var main = JSROOT.sap.ui.getCore().byId("CanvasGedId"); + if (main) ged = main.getController(); + } + if (ged) ged.onPadRedraw(this, padpainter); + } + */ + + JSROOT.TCanvasPainter.prototype.openuiHasEventStatus = function() { + var main = JSROOT.sap.ui.getCore().byId("TopCanvasId"); + return main ? main.getController().isStatusShown() : false; + } + + JSROOT.TCanvasPainter.prototype.openuiToggleEventStatus = function() { + var main = JSROOT.sap.ui.getCore().byId("TopCanvasId"); + if (main) main.getController().toggleShowStatus(); + } + + JSROOT.TCanvasPainter.prototype.fullShowStatus = function(lbl1,lbl2,lbl3,lbl4) { + var main = JSROOT.sap.ui.getCore().byId("TopCanvasId"); + if (main) main.getController().ShowCanvasStatus(lbl1,lbl2,lbl3,lbl4); + } + + JSROOT.TCanvasPainter.prototype.ShowUI5ProjectionArea = function(kind, call_back) { + var main = JSROOT.sap.ui.getCore().byId("TopCanvasId"); + if (main) main.getController().showProjectionArea(kind, call_back); + } + + JSROOT.TCanvasPainter.prototype.DrawInUI5ProjectionArea = function(obj, opt, call_back) { + var main = JSROOT.sap.ui.getCore().byId("TopCanvasId"); + if (main) main.getController().drawInProjectionArea(obj, opt, call_back); + } + + JSROOT.TCanvasPainter.prototype.ShowMessage = function(msg) { + if (!this.use_openui) + return JSROOT.progress(msg, 7000); + var main = JSROOT.sap.ui.getCore().byId("TopCanvasId"); + if (main) main.getController().showMessage(msg); + } + + JSROOT.TCanvasPainter.prototype.fullShowSection = function(that, on) { + var main = JSROOT.sap.ui.getCore().byId("TopCanvasId"); + if (main) main.getController().showSection(that, on); + } + + JSROOT.TCanvasPainter.prototype.MethodsDialog = function(painter, method, menu_obj_id) { + + var main = JSROOT.sap.ui.getCore().byId("TopCanvasId"); + if (!main) return; + + var pthis = this; + + method.fClassName = painter.GetClassName(); + // TODO: deliver class name together with menu items + if ((menu_obj_id.indexOf("#x")>0) || (menu_obj_id.indexOf("#y")>0) || (menu_obj_id.indexOf("#z")>0)) method.fClassName = "TAxis"; + + main.getController().showMethodsDialog(method, function(args) { + + if (painter.ExecuteMenuCommand(method, args)) return; + + var exec = method.fExec; + if (args) exec = exec.substr(0,exec.length-1) + args + ')'; + + // invoked only when user press Ok button + console.log('execute method for object ' + menu_obj_id + ' exec= ' + exec); + + pthis.SendWebsocket('OBJEXEC:' + menu_obj_id + ":" + exec); + }); + } + + // ==================================================================================== + + if (JSROOT.v7 && JSROOT.v7.TCanvasPainter) + JSROOT.v7.TCanvasPainter.prototype.ActivatePanel = function(name, handle, callback) { + // function used to activate FitPanel + + var main = JSROOT.sap.ui.getCore().byId("TopCanvasId"); + if (!main) return JSROOT.CallBack(callback, false); + main.getController().showPanelInLeftArea(name, handle, callback); + } + + return JSROOT; + +})); + diff --git a/js/scripts/JSRootPainter.v6.js b/js/scripts/JSRootPainter.v6.js new file mode 100644 index 00000000000..ac778c4e37b --- /dev/null +++ b/js/scripts/JSRootPainter.v6.js @@ -0,0 +1,4903 @@ +/// @file JSRootPainter.v6.js +/// JavaScript ROOT graphics for main ROOT6 classes + +(function( factory ) { + if ( typeof define === "function" && define.amd ) { + define( ['JSRootPainter', 'd3'], factory ); + } else + if (typeof exports === 'object' && typeof module !== 'undefined') { + factory(require("./JSRootCore.js"), require("./d3.min.js")); + } else { + + if (typeof d3 != 'object') + throw new Error('This extension requires d3.js', 'JSRootPainter.v6.js'); + + if (typeof JSROOT == 'undefined') + throw new Error('JSROOT is not defined', 'JSRootPainter.v6.js'); + + if (typeof JSROOT.Painter != 'object') + throw new Error('JSROOT.Painter not defined', 'JSRootPainter.v6.js'); + + factory(JSROOT, d3); + } +} (function(JSROOT, d3) { + + "use strict"; + + JSROOT.sources.push("v6"); + + // identifier used in TWebCanvas painter + JSROOT.WebSnapIds = { kNone: 0, kObject: 1, kSVG: 2, kSubPad: 3, kColors: 4, kStyle: 5 }; + + // ======================================================================= + + + /** + * @summary Painter for TAxis/TGaxis objects. + * + * @constructor + * @memberof JSROOT + * @augments JSROOT.TObjectPainter + * @param {object} axis - object to draw + * @param {boolean} embedded - if true, painter used in other objects painters + */ + + function TAxisPainter(axis, embedded) { + JSROOT.TObjectPainter.call(this, axis); + + this.embedded = embedded; // indicate that painter embedded into the histo painter + + this.name = "yaxis"; + this.kind = "normal"; + this.func = null; + this.order = 0; // scaling order for axis labels + + this.full_min = 0; + this.full_max = 1; + this.scale_min = 0; + this.scale_max = 1; + this.ticks = []; // list of major ticks + this.invert_side = false; + this.lbls_both_sides = false; // draw labels on both sides + } + + TAxisPainter.prototype = Object.create(JSROOT.TObjectPainter.prototype); + + TAxisPainter.prototype.Cleanup = function() { + + this.ticks = []; + this.func = null; + delete this.format; + + JSROOT.TObjectPainter.prototype.Cleanup.call(this); + } + + TAxisPainter.prototype.SetAxisConfig = function(name, kind, func, min, max, smin, smax) { + this.name = name; + this.kind = kind; + this.func = func; + + this.full_min = min; + this.full_max = max; + this.scale_min = smin; + this.scale_max = smax; + } + + TAxisPainter.prototype.format10Exp = function(order, value) { + var res = ""; + if (value) { + value = Math.round(value/Math.pow(10,order)); + if ((value!=0) && (value!=1)) res = value.toString() + (JSROOT.gStyle.Latex ? "#times" : "x"); + } + res += "10"; + if (JSROOT.gStyle.Latex > 1) return res + "^{" + order + "}"; + var superscript_symbols = { + '0': '\u2070', '1': '\xB9', '2': '\xB2', '3': '\xB3', '4': '\u2074', '5': '\u2075', + '6': '\u2076', '7': '\u2077', '8': '\u2078', '9': '\u2079', '-': '\u207B' + }; + var str = order.toString(); + for (var n=0;n<str.length;++n) res += superscript_symbols[str[n]]; + return res; + } + + TAxisPainter.prototype.CreateFormatFuncs = function() { + + var axis = this.GetObject(), + is_gaxis = (axis && axis._typename === 'TGaxis'); + + delete this.format;// remove formatting func + + var ndiv = 508; + if (is_gaxis) ndiv = axis.fNdiv; else + if (axis) ndiv = Math.max(axis.fNdivisions, 4); + + this.nticks = ndiv % 100; + this.nticks2 = (ndiv % 10000 - this.nticks) / 100; + this.nticks3 = Math.floor(ndiv/10000); + + if (axis && !is_gaxis && (this.nticks > 7)) this.nticks = 7; + + var gr_range = Math.abs(this.func.range()[1] - this.func.range()[0]); + if (gr_range<=0) gr_range = 100; + + if (this.kind == 'time') { + if (this.nticks > 8) this.nticks = 8; + + var scale_range = this.scale_max - this.scale_min, + tf1 = JSROOT.Painter.getTimeFormat(axis), + tf2 = JSROOT.Painter.chooseTimeFormat(scale_range / gr_range, false); + + if ((tf1.length == 0) || (scale_range < 0.1 * (this.full_max - this.full_min))) + tf1 = JSROOT.Painter.chooseTimeFormat(scale_range / this.nticks, true); + + this.tfunc1 = this.tfunc2 = d3.timeFormat(tf1); + if (tf2!==tf1) + this.tfunc2 = d3.timeFormat(tf2); + + this.format = function(d, asticks) { + return asticks ? this.tfunc1(d) : this.tfunc2(d); + } + + } else if (this.kind == 'log') { + if (this.nticks2 > 1) { + this.nticks *= this.nticks2; // all log ticks (major or minor) created centrally + this.nticks2 = 1; + } + this.noexp = axis ? axis.TestBit(JSROOT.EAxisBits.kNoExponent) : false; + if ((this.scale_max < 300) && (this.scale_min > 0.3)) this.noexp = true; + this.moreloglabels = axis ? axis.TestBit(JSROOT.EAxisBits.kMoreLogLabels) : false; + + this.format = function(d, asticks, notickexp_fmt) { + var val = parseFloat(d), rnd = Math.round(val); + if (!asticks) + return ((rnd === val) && (Math.abs(rnd)<1e9)) ? rnd.toString() : JSROOT.FFormat(val, notickexp_fmt || JSROOT.gStyle.fStatFormat); + + if (val <= 0) return null; + var vlog = JSROOT.log10(val); + if (this.moreloglabels || (Math.abs(vlog - Math.round(vlog))<0.001)) { + if (!this.noexp && !notickexp_fmt) + return this.format10Exp(Math.floor(vlog+0.01), val); + + return (vlog<0) ? val.toFixed(Math.round(-vlog+0.5)) : val.toFixed(0); + } + return null; + } + } else if (this.kind == 'labels') { + this.nticks = 50; // for text output allow max 50 names + var scale_range = this.scale_max - this.scale_min; + if (this.nticks > scale_range) + this.nticks = Math.round(scale_range); + + this.regular_labels = true; + + if (axis && axis.fNbins && axis.fLabels) { + if ((axis.fNbins != Math.round(axis.fXmax - axis.fXmin)) || + (axis.fXmin != 0) || (axis.fXmax != axis.fNbins)) { + this.regular_labels = false; + } + } + + this.nticks2 = 1; + + this.axis = axis; + + this.format = function(d) { + var indx = parseFloat(d); + if (!this.regular_labels) + indx = (indx - this.axis.fXmin)/(this.axis.fXmax - this.axis.fXmin) * this.axis.fNbins; + indx = Math.round(indx); + if ((indx<0) || (indx>=this.axis.fNbins)) return null; + for (var i = 0; i < this.axis.fLabels.arr.length; ++i) { + var tstr = this.axis.fLabels.arr[i]; + if (tstr.fUniqueID === indx+1) return tstr.fString; + } + return null; + } + } else { + + this.order = 0; + this.ndig = 0; + + this.format = function(d, asticks, fmt) { + var val = parseFloat(d); + if (asticks && this.order) val = val / Math.pow(10, this.order); + + if (val === Math.round(val)) + return (Math.abs(val)<1e9) ? val.toFixed(0) : val.toExponential(4); + + if (asticks) return (this.ndig>10) ? val.toExponential(this.ndig-11) : val.toFixed(this.ndig); + + return JSROOT.FFormat(val, fmt || JSROOT.gStyle.fStatFormat); + } + } + } + + TAxisPainter.prototype.ProduceTicks = function(ndiv, ndiv2) { + if (!this.noticksopt) return this.func.ticks(ndiv * (ndiv2 || 1)); + + if (ndiv2) ndiv = (ndiv-1) * ndiv2; + var dom = this.func.domain(), ticks = []; + for (var n=0;n<=ndiv;++n) + ticks.push((dom[0]*(ndiv-n) + dom[1]*n)/ndiv); + return ticks; + } + + TAxisPainter.prototype.CreateTicks = function(only_major_as_array, optionNoexp, optionNoopt, optionInt) { + // function used to create array with minor/middle/major ticks + + if (optionNoopt && this.nticks && (this.kind == "normal")) this.noticksopt = true; + + var handle = { nminor: 0, nmiddle: 0, nmajor: 0, func: this.func }; + + handle.minor = handle.middle = handle.major = this.ProduceTicks(this.nticks); + + if (only_major_as_array) { + var res = handle.major, delta = (this.scale_max - this.scale_min)*1e-5; + if (res[0] > this.scale_min + delta) res.unshift(this.scale_min); + if (res[res.length-1] < this.scale_max - delta) res.push(this.scale_max); + return res; + } + + if ((this.kind == 'labels') && !this.regular_labels) { + handle.lbl_pos = []; + for (var n=0;n<this.axis.fNbins;++n) { + var x = this.axis.fXmin + n / this.axis.fNbins * (this.axis.fXmax - this.axis.fXmin); + if ((x >= this.scale_min) && (x < this.scale_max)) handle.lbl_pos.push(x); + } + } + + if (this.nticks2 > 1) { + handle.minor = handle.middle = this.ProduceTicks(handle.major.length, this.nticks2); + + var gr_range = Math.abs(this.func.range()[1] - this.func.range()[0]); + + // avoid black filling by middle-size + if ((handle.middle.length <= handle.major.length) || (handle.middle.length > gr_range/3.5)) { + handle.minor = handle.middle = handle.major; + } else + if ((this.nticks3 > 1) && (this.kind !== 'log')) { + handle.minor = this.ProduceTicks(handle.middle.length, this.nticks3); + if ((handle.minor.length <= handle.middle.length) || (handle.minor.length > gr_range/1.7)) handle.minor = handle.middle; + } + } + + handle.reset = function() { + this.nminor = this.nmiddle = this.nmajor = 0; + } + + handle.next = function(doround) { + if (this.nminor >= this.minor.length) return false; + + this.tick = this.minor[this.nminor++]; + this.grpos = this.func(this.tick); + if (doround) this.grpos = Math.round(this.grpos); + this.kind = 3; + + if ((this.nmiddle < this.middle.length) && (Math.abs(this.grpos - this.func(this.middle[this.nmiddle])) < 1)) { + this.nmiddle++; + this.kind = 2; + } + + if ((this.nmajor < this.major.length) && (Math.abs(this.grpos - this.func(this.major[this.nmajor])) < 1) ) { + this.nmajor++; + this.kind = 1; + } + return true; + } + + handle.last_major = function() { + return (this.kind !== 1) ? false : this.nmajor == this.major.length; + } + + handle.next_major_grpos = function() { + if (this.nmajor >= this.major.length) return null; + return this.func(this.major[this.nmajor]); + } + + this.order = 0; + this.ndig = 0; + + // at the moment when drawing labels, we can try to find most optimal text representation for them + + if ((this.kind == "normal") && (handle.major.length > 0)) { + + var maxorder = 0, minorder = 0, exclorder3 = false; + + if (!optionNoexp) { + var maxtick = Math.max(Math.abs(handle.major[0]),Math.abs(handle.major[handle.major.length-1])), + mintick = Math.min(Math.abs(handle.major[0]),Math.abs(handle.major[handle.major.length-1])), + ord1 = (maxtick > 0) ? Math.round(JSROOT.log10(maxtick)/3)*3 : 0, + ord2 = (mintick > 0) ? Math.round(JSROOT.log10(mintick)/3)*3 : 0; + + exclorder3 = (maxtick < 2e4); // do not show 10^3 for values below 20000 + + if (maxtick || mintick) { + maxorder = Math.max(ord1,ord2) + 3; + minorder = Math.min(ord1,ord2) - 3; + } + } + + // now try to find best combination of order and ndig for labels + + var bestorder = 0, bestndig = this.ndig, bestlen = 1e10; + + for (var order = minorder; order <= maxorder; order+=3) { + if (exclorder3 && (order===3)) continue; + this.order = order; + this.ndig = 0; + var lbls = [], indx = 0, totallen = 0; + while (indx<handle.major.length) { + var lbl = this.format(handle.major[indx], true); + if (lbls.indexOf(lbl)<0) { + lbls.push(lbl); + totallen += lbl.length; + indx++; + continue; + } + if (++this.ndig > 15) break; // not too many digits, anyway it will be exponential + lbls = []; indx = 0; totallen = 0; + } + + // for order==0 we should virtually remove "0." and extra label on top + if (!order && (this.ndig<4)) totallen-=(handle.major.length*2+3); + + if (totallen < bestlen) { + bestlen = totallen; + bestorder = this.order; + bestndig = this.ndig; + } + } + + this.order = bestorder; + this.ndig = bestndig; + + if (optionInt) { + if (this.order) console.warn('Axis painter - integer labels are configured, but axis order ' + this.order + ' is preferable'); + if (this.ndig) console.warn('Axis painter - integer labels are configured, but ' + this.ndig + ' decimal digits are required'); + this.ndig = 0; + this.order = 0; + } + } + + return handle; + } + + TAxisPainter.prototype.IsCenterLabels = function() { + if (this.kind === 'labels') return true; + if (this.kind === 'log') return false; + var axis = this.GetObject(); + return axis && axis.TestBit(JSROOT.EAxisBits.kCenterLabels); + } + + TAxisPainter.prototype.AddTitleDrag = function(title_g, vertical, offset_k, reverse, axis_length) { + if (!JSROOT.gStyle.MoveResize) return; + + var pthis = this, drag_rect = null, prefix = "", drag_move, + acc_x, acc_y, new_x, new_y, sign_0, center_0, alt_pos; + if (JSROOT._test_d3_ === 3) { + prefix = "drag"; + drag_move = d3.behavior.drag().origin(Object); + } else { + drag_move = d3.drag().subject(Object); + } + + drag_move + .on(prefix+"start", function() { + + d3.event.sourceEvent.preventDefault(); + d3.event.sourceEvent.stopPropagation(); + + var box = title_g.node().getBBox(), // check that elements visible, request precise value + axis = pthis.GetObject(); + + new_x = acc_x = title_g.property('shift_x'); + new_y = acc_y = title_g.property('shift_y'); + + sign_0 = vertical ? (acc_x>0) : (acc_y>0); // sign should remain + + if (axis.TestBit(JSROOT.EAxisBits.kCenterTitle)) + alt_pos = (reverse === vertical) ? axis_length : 0; + else + alt_pos = Math.round(axis_length/2); + + drag_rect = title_g.append("rect") + .classed("zoom", true) + .attr("x", box.x) + .attr("y", box.y) + .attr("width", box.width) + .attr("height", box.height) + .style("cursor", "move"); +// .style("pointer-events","none"); // let forward double click to underlying elements + }).on("drag", function() { + if (!drag_rect) return; + + d3.event.sourceEvent.preventDefault(); + d3.event.sourceEvent.stopPropagation(); + + acc_x += d3.event.dx; + acc_y += d3.event.dy; + + var set_x = title_g.property('shift_x'), + set_y = title_g.property('shift_y'); + + if (vertical) { + set_x = acc_x; + if (Math.abs(acc_y - set_y) > Math.abs(acc_y - alt_pos)) set_y = alt_pos; + } else { + set_y = acc_y; + if (Math.abs(acc_x - set_x) > Math.abs(acc_x - alt_pos)) set_x = alt_pos; + } + + if (sign_0 === (vertical ? (set_x>0) : (set_y>0))) { + new_x = set_x; new_y = set_y; + title_g.attr('transform', 'translate(' + new_x + ',' + new_y + ')'); + } + + }).on(prefix+"end", function() { + if (!drag_rect) return; + + d3.event.sourceEvent.preventDefault(); + d3.event.sourceEvent.stopPropagation(); + + title_g.property('shift_x', new_x) + .property('shift_y', new_y); + + var axis = pthis.GetObject(); + + axis.fTitleOffset = (vertical ? new_x : new_y) / offset_k; + if ((vertical ? new_y : new_x) === alt_pos) axis.InvertBit(JSROOT.EAxisBits.kCenterTitle); + + drag_rect.remove(); + drag_rect = null; + }); + + title_g.style("cursor", "move").call(drag_move); + } + + TAxisPainter.prototype.DrawAxis = function(vertical, layer, w, h, transform, reverse, second_shift, disable_axis_drawing, max_text_width) { + // function draws TAxis or TGaxis object + + var axis = this.GetObject(), chOpt = "", + is_gaxis = (axis && axis._typename === 'TGaxis'), + axis_g = layer, tickSize = 0.03, + scaling_size = 100, draw_lines = true, + pad_w = this.pad_width() || 10, + pad_h = this.pad_height() || 10; + + this.vertical = vertical; + + function myXor(a,b) { return ( a && !b ) || (!a && b); } + + // shift for second ticks set (if any) + if (!second_shift) second_shift = 0; else + if (this.invert_side) second_shift = -second_shift; + + if (is_gaxis) { + this.createAttLine({ attr: axis }); + draw_lines = axis.fLineColor != 0; + chOpt = axis.fChopt; + tickSize = axis.fTickSize; + scaling_size = (vertical ? 1.7*h : 0.6*w); + } else { + this.createAttLine({ color: axis.fAxisColor, width: 1, style: 1 }); + chOpt = myXor(vertical, this.invert_side) ? "-S" : "+S"; + tickSize = axis.fTickLength; + scaling_size = (vertical ? pad_w : pad_h); + } + + if (!is_gaxis || (this.name === "zaxis")) { + axis_g = layer.select("." + this.name + "_container"); + if (axis_g.empty()) + axis_g = layer.append("svg:g").attr("class",this.name + "_container"); + else + axis_g.selectAll("*").remove(); + } + + if (!disable_axis_drawing && draw_lines) + axis_g.append("svg:line") + .attr("x1",0).attr("y1",0) + .attr("x2",vertical ? 0 : w) + .attr("y2", vertical ? h : 0) + .call(this.lineatt.func); + + axis_g.attr("transform", transform || null); + + var side = 1, ticks_plusminus = 0, + text_scaling_size = Math.min(pad_w, pad_h), + optionPlus = (chOpt.indexOf("+")>=0), + optionMinus = (chOpt.indexOf("-")>=0), + optionSize = (chOpt.indexOf("S")>=0), + optionY = (chOpt.indexOf("Y")>=0), + optionUp = (chOpt.indexOf("0")>=0), + optionDown = (chOpt.indexOf("O")>=0), + optionUnlab = (chOpt.indexOf("U")>=0), // no labels + optionNoopt = (chOpt.indexOf("N")>=0), // no ticks position optimization + optionInt = (chOpt.indexOf("I")>=0), // integer labels + optionNoexp = axis.TestBit(JSROOT.EAxisBits.kNoExponent); + + if (is_gaxis && axis.TestBit(JSROOT.EAxisBits.kTickPlus)) optionPlus = true; + if (is_gaxis && axis.TestBit(JSROOT.EAxisBits.kTickMinus)) optionMinus = true; + + if (optionPlus && optionMinus) { side = 1; ticks_plusminus = 1; } else + if (optionMinus) { side = myXor(reverse,vertical) ? 1 : -1; } else + if (optionPlus) { side = myXor(reverse,vertical) ? -1 : 1; } + + tickSize = Math.round((optionSize ? tickSize : 0.03) * scaling_size); + + if (this.max_tick_size && (tickSize > this.max_tick_size)) tickSize = this.max_tick_size; + + this.CreateFormatFuncs(); + + var res = "", res2 = "", lastpos = 0, lasth = 0; + + // first draw ticks + + this.ticks = []; + + var handle = this.CreateTicks(false, optionNoexp, optionNoopt, optionInt); + + while (handle.next(true)) { + + var h1 = Math.round(tickSize/4), h2 = 0; + + if (handle.kind < 3) + h1 = Math.round(tickSize/2); + + if (handle.kind == 1) { + // if not showing labels, not show large tick + if (!('format' in this) || (this.format(handle.tick,true)!==null)) h1 = tickSize; + this.ticks.push(handle.grpos); // keep graphical positions of major ticks + } + + if (ticks_plusminus > 0) h2 = -h1; else + if (side < 0) { h2 = -h1; h1 = 0; } else { h2 = 0; } + + if (res.length == 0) { + res = vertical ? ("M"+h1+","+handle.grpos) : ("M"+handle.grpos+","+(-h1)); + res2 = vertical ? ("M"+(second_shift-h1)+","+handle.grpos) : ("M"+handle.grpos+","+(second_shift+h1)); + } else { + res += vertical ? ("m"+(h1-lasth)+","+(handle.grpos-lastpos)) : ("m"+(handle.grpos-lastpos)+","+(lasth-h1)); + res2 += vertical ? ("m"+(lasth-h1)+","+(handle.grpos-lastpos)) : ("m"+(handle.grpos-lastpos)+","+(h1-lasth)); + } + + res += vertical ? ("h"+ (h2-h1)) : ("v"+ (h1-h2)); + res2 += vertical ? ("h"+ (h1-h2)) : ("v"+ (h2-h1)); + + lastpos = handle.grpos; + lasth = h2; + } + + if ((res.length > 0) && !disable_axis_drawing && draw_lines) + axis_g.append("svg:path").attr("d", res).call(this.lineatt.func); + + if ((second_shift!==0) && (res2.length>0) && !disable_axis_drawing && draw_lines) + axis_g.append("svg:path").attr("d", res2).call(this.lineatt.func); + + var labelsize = Math.round( (axis.fLabelSize < 1) ? axis.fLabelSize * text_scaling_size : axis.fLabelSize); + if ((labelsize <= 0) || (Math.abs(axis.fLabelOffset) > 1.1)) optionUnlab = true; // disable labels when size not specified + + // draw labels (sometime on both sides) + if (!disable_axis_drawing && !optionUnlab) { + + var label_color = this.get_color(axis.fLabelColor), + labeloffset = Math.round(Math.abs(axis.fLabelOffset)*text_scaling_size), + center_lbls = this.IsCenterLabels(), + rotate_lbls = axis.TestBit(JSROOT.EAxisBits.kLabelsVert), + textscale = 1, maxtextlen = 0, lbls_tilt = false, labelfont = null, + label_g = [ axis_g.append("svg:g").attr("class","axis_labels") ], + lbl_pos = handle.lbl_pos || handle.major; + + if (this.lbls_both_sides) + label_g.push(axis_g.append("svg:g").attr("class","axis_labels").attr("transform", vertical ? "translate(" + w + ",0)" : "translate(0," + (-h) + ")")); + + for (var lcnt = 0; lcnt < label_g.length; ++lcnt) { + + if (lcnt > 0) side = -side; + + var lastpos = 0, + fix_coord = vertical ? -labeloffset*side : (labeloffset+2)*side + ticks_plusminus*tickSize; + + labelfont = JSROOT.Painter.getFontDetails(axis.fLabelFont, labelsize); + + this.StartTextDrawing(labelfont, 'font', label_g[lcnt]); + + for (var nmajor=0;nmajor<lbl_pos.length;++nmajor) { + + var lbl = this.format(lbl_pos[nmajor], true); + if (lbl === null) continue; + + var pos = Math.round(this.func(lbl_pos[nmajor])), + gap_before = (nmajor>0) ? Math.abs(Math.round(pos - this.func(lbl_pos[nmajor-1]))) : 0, + gap_after = (nmajor<lbl_pos.length-1) ? Math.abs(Math.round(this.func(lbl_pos[nmajor+1])-pos)) : 0; + + if (center_lbls) { + var gap = gap_after || gap_before; + pos = Math.round(pos - (vertical ? 0.5*gap : -0.5*gap)); + if ((pos < -5) || (pos > (vertical ? h : w) + 5)) continue; + } + + var arg = { text: lbl, color: label_color, latex: 1, draw_g: label_g[lcnt] }; + + maxtextlen = Math.max(maxtextlen, lbl.length); + + if (vertical) { + arg.x = fix_coord; + arg.y = pos; + arg.align = rotate_lbls ? ((side<0) ? 23 : 20) : ((side<0) ? 12 : 32); + } else { + arg.x = pos; + arg.y = fix_coord; + arg.align = rotate_lbls ? ((side<0) ? 12 : 32) : ((side<0) ? 20 : 23); + } + + if (rotate_lbls) arg.rotate = 270; + + var textwidth = this.DrawText(arg); + + if (textwidth && ((!vertical && !rotate_lbls) || (vertical && rotate_lbls)) && (this.kind != 'log')) { + var maxwidth = gap_before*0.45 + gap_after*0.45; + if (!gap_before) maxwidth = 0.9*gap_after; else + if (!gap_after) maxwidth = 0.9*gap_before; + textscale = Math.min(textscale, maxwidth / textwidth); + } else if (vertical && max_text_width && !lcnt && (max_text_width - labeloffset > 20) && (textwidth > max_text_width - labeloffset)) { + textscale = Math.min(textscale, (max_text_width - labeloffset) / textwidth); + } + + if (lastpos && (pos!=lastpos) && ((vertical && !rotate_lbls) || (!vertical && rotate_lbls))) { + var axis_step = Math.abs(pos-lastpos); + textscale = Math.min(textscale, 0.9*axis_step/labelsize); + } + + lastpos = pos; + } + + if (this.order) + this.DrawText({ color: label_color, + x: vertical ? side*5 : w+5, + y: this.has_obstacle ? fix_coord : (vertical ? -3 : -3*side), + align: vertical ? ((side<0) ? 30 : 10) : ( myXor(this.has_obstacle, (side<0)) ? 13 : 10 ), + latex: 1, + text: '#times' + this.format10Exp(this.order), + draw_g: label_g[lcnt] + }); + } + + if ((textscale > 0.01) && (textscale < 0.7) && !vertical && !rotate_lbls && (maxtextlen > 5) && !this.lbls_both_sides) { + lbls_tilt = true; + textscale *= 3; + } + + for (var lcnt = 0; lcnt < label_g.length; ++lcnt) { + if ((textscale > 0.01) && (textscale < 1)) + this.TextScaleFactor(1/textscale, label_g[lcnt]); + + this.FinishTextDrawing(label_g[lcnt]); + if (lbls_tilt) + label_g[lcnt].selectAll("text").each(function() { + var txt = d3.select(this), tr = txt.attr("transform"); + txt.attr("transform", tr + " rotate(25)").style("text-anchor", "start"); + }); + } + + if (label_g.length > 1) side = -side; + + if (labelfont) labelsize = labelfont.size; // use real font size + } + + if (JSROOT.gStyle.Zooming && !this.disable_zooming) { + var r = axis_g.append("svg:rect") + .attr("class", "axis_zoom") + .style("opacity", "0") + .style("cursor", "crosshair"); + + if (vertical) + r.attr("x", (side>0) ? (-2*labelsize - 3) : 3) + .attr("y", 0) + .attr("width", 2*labelsize + 3) + .attr("height", h) + else + r.attr("x", 0).attr("y", (side>0) ? 0 : -labelsize - 3) + .attr("width", w).attr("height", labelsize + 3); + } + + if ((axis.fTitle.length > 0) && !disable_axis_drawing) { + var title_g = axis_g.append("svg:g").attr("class", "axis_title"), + title_fontsize = (axis.fTitleSize >= 1) ? axis.fTitleSize : Math.round(axis.fTitleSize * text_scaling_size), + title_offest_k = 1.6*(axis.fTitleSize<1 ? axis.fTitleSize : axis.fTitleSize/(this.pad_height("") || 10)), + center = axis.TestBit(JSROOT.EAxisBits.kCenterTitle), + rotate = axis.TestBit(JSROOT.EAxisBits.kRotateTitle) ? -1 : 1, + title_color = this.get_color(is_gaxis ? axis.fTextColor : axis.fTitleColor), + shift_x = 0, shift_y = 0; + + this.StartTextDrawing(axis.fTitleFont, title_fontsize, title_g); + + var myxor = ((rotate<0) && !reverse) || ((rotate>=0) && reverse); + + if (vertical) { + title_offest_k *= -side*pad_w; + + shift_x = Math.round(title_offest_k*axis.fTitleOffset); + + if ((this.name == "zaxis") && is_gaxis && ('getBoundingClientRect' in axis_g.node())) { + // special handling for color palette labels - draw them always on right side + var rect = axis_g.node().getBoundingClientRect(); + if (shift_x < rect.width - tickSize) shift_x = Math.round(rect.width - tickSize); + } + + shift_y = Math.round(center ? h/2 : (reverse ? h : 0)); + + this.DrawText({ align: (center ? "middle" : (myxor ? "begin" : "end" )) + ";middle", + rotate: (rotate<0) ? 90 : 270, + text: axis.fTitle, color: title_color, draw_g: title_g }); + } else { + title_offest_k *= side*pad_h; + + shift_x = Math.round(center ? w/2 : (reverse ? 0 : w)); + shift_y = Math.round(title_offest_k*axis.fTitleOffset); + this.DrawText({ align: (center ? 'middle' : (myxor ? 'begin' : 'end')) + ";middle", + rotate: (rotate<0) ? 180 : 0, + text: axis.fTitle, color: title_color, draw_g: title_g }); + } + + var axis_rect = null; + if (vertical && (axis.fTitleOffset == 0) && ('getBoundingClientRect' in axis_g.node())) + axis_rect = axis_g.node().getBoundingClientRect(); + + this.FinishTextDrawing(title_g, function() { + if (axis_rect) { + var title_rect = title_g.node().getBoundingClientRect(); + shift_x = (side>0) ? Math.round(axis_rect.left - title_rect.right - title_fontsize*0.3) : + Math.round(axis_rect.right - title_rect.left + title_fontsize*0.3); + } + + title_g.attr('transform', 'translate(' + shift_x + ',' + shift_y + ')') + .property('shift_x', shift_x) + .property('shift_y', shift_y); + }); + + + this.AddTitleDrag(title_g, vertical, title_offest_k, reverse, vertical ? h : w); + } + + this.position = 0; + + if (!disable_axis_drawing && ('getBoundingClientRect' in axis_g.node())) { + var rect1 = axis_g.node().getBoundingClientRect(), + rect2 = this.svg_pad().node().getBoundingClientRect(); + + this.position = rect1.left - rect2.left; // use to control left position of Y scale + } + } + + TAxisPainter.prototype.Redraw = function() { + + var gaxis = this.GetObject(), + x1 = this.AxisToSvg("x", gaxis.fX1, "pad"), + y1 = this.AxisToSvg("y", gaxis.fY1, "pad"), + x2 = this.AxisToSvg("x", gaxis.fX2, "pad"), + y2 = this.AxisToSvg("y", gaxis.fY2, "pad"), + w = x2 - x1, h = y1 - y2, + vertical = Math.abs(w) < Math.abs(h), + func = null, reverse = false, kind = "normal", + min = gaxis.fWmin, max = gaxis.fWmax, + domain_min = min, domain_max = max; + + if (gaxis.fChopt.indexOf("t")>=0) { + func = d3.scaleTime(); + kind = "time"; + this.toffset = JSROOT.Painter.getTimeOffset(gaxis); + domain_min = new Date(this.toffset + min*1000); + domain_max = new Date(this.toffset + max*1000); + } else if (gaxis.fChopt.indexOf("G")>=0) { + func = d3.scaleLog(); + kind = "log"; + } else { + func = d3.scaleLinear(); + kind = "normal"; + } + + func.domain([domain_min, domain_max]); + + if (vertical) { + if (h > 0) { + func.range([h,0]); + } else { + var d = y1; y1 = y2; y2 = d; + h = -h; reverse = true; + func.range([0,h]); + } + } else { + if (w > 0) { + func.range([0,w]); + } else { + var d = x1; x1 = x2; x2 = d; + w = -w; reverse = true; + func.range([w,0]); + } + } + + this.SetAxisConfig(vertical ? "yaxis" : "xaxis", kind, func, min, max, min, max); + + this.CreateG(); + + this.DrawAxis(vertical, this.draw_g, w, h, "translate(" + x1 + "," + y2 +")", reverse); + } + + JSROOT.Painter.drawGaxis = function(divid, obj, opt) { + var painter = new JSROOT.TAxisPainter(obj, false); + + painter.SetDivId(divid); + + painter.disable_zooming = true; + + painter.Redraw(); + + return painter.DrawingReady(); + } + + // =============================================== + + /** + * @summary Painter for TFrame object. + * + * @constructor + * @memberof JSROOT + * @augments JSROOT.TObjectPainter + * @param {object} tframe - TFrame object to draw + */ + + function TFramePainter(tframe) { + if (tframe && tframe.$dummy) tframe = null; + JSROOT.TooltipHandler.call(this, tframe); + this.zoom_kind = 0; + this.mode3d = false; + this.shrink_frame_left = 0.; + this.x_kind = 'normal'; // 'normal', 'log', 'time', 'labels' + this.y_kind = 'normal'; // 'normal', 'log', 'time', 'labels' + this.xmin = this.xmax = 0; // no scale specified, wait for objects drawing + this.ymin = this.ymax = 0; // no scale specified, wait for objects drawing + this.ranges_set = false; + this.axes_drawn = false; + this.keys_handler = null; + this.projection = 0; // different projections + } + + TFramePainter.prototype = Object.create(JSROOT.TooltipHandler.prototype); + + /** @summary Returns frame painter - object itself + * @private */ + TFramePainter.prototype.frame_painter = function() { + return this; + } + + /** @summary Set active flag for frame - can block some events + * @private */ + TFramePainter.prototype.SetActive = function(on) { + // do nothing here - key handler is handled differently + } + + TFramePainter.prototype.GetTipName = function(append) { + var res = JSROOT.TooltipHandler.prototype.GetTipName.call(this) || "TFrame"; + if (append) res+=append; + return res; + } + + TFramePainter.prototype.Shrink = function(shrink_left, shrink_right) { + this.fX1NDC += shrink_left; + this.fX2NDC -= shrink_right; + } + + TFramePainter.prototype.SetLastEventPos = function(pnt) { + // set position of last context menu event, can be + this.fLastEventPnt = pnt; + } + + TFramePainter.prototype.GetLastEventPos = function() { + // return position of last event + return this.fLastEventPnt; + } + + TFramePainter.prototype.ProjectAitoff2xy = function(l, b) { + var DegToRad = Math.PI/180, + alpha2 = (l/2)*DegToRad, + delta = b*DegToRad, + r2 = Math.sqrt(2), + f = 2*r2/Math.PI, + cdec = Math.cos(delta), + denom = Math.sqrt(1. + cdec*Math.cos(alpha2)), + res = { + x: cdec*Math.sin(alpha2)*2.*r2/denom/f/DegToRad, + y: Math.sin(delta)*r2/denom/f/DegToRad + }; + // x *= -1.; // for a skymap swap left<->right + return res; + } + + TFramePainter.prototype.ProjectMercator2xy = function(l, b) { + var aid = Math.tan((Math.PI/2 + b/180*Math.PI)/2); + return { x: l, y: Math.log(aid) }; + } + + TFramePainter.prototype.ProjectSinusoidal2xy = function(l, b) { + return { x: l*Math.cos(b/180*Math.PI), y: b }; + } + + TFramePainter.prototype.ProjectParabolic2xy = function(l, b) { + return { + x: l*(2.*Math.cos(2*b/180*Math.PI/3) - 1), + y: 180*Math.sin(b/180*Math.PI/3) + }; + } + + TFramePainter.prototype.RecalculateRange = function(Proj) { + // not yet used, could be useful in the future + + this.projection = Proj || 0; + + if (!this.projection) return; + + var pnts = []; // all extremes which used to find + if (this.projection == 1) { + // TODO : check x range not lower than -180 and not higher than 180 + pnts.push(this.ProjectAitoff2xy(this.scale_xmin, this.scale_ymin)); + pnts.push(this.ProjectAitoff2xy(this.scale_xmin, this.scale_ymax)); + pnts.push(this.ProjectAitoff2xy(this.scale_xmax, this.scale_ymax)); + pnts.push(this.ProjectAitoff2xy(this.scale_xmax, this.scale_ymin)); + if (this.scale_ymin<0 && this.scale_ymax>0) { + // there is an 'equator', check its range in the plot.. + pnts.push(this.ProjectAitoff2xy(this.scale_xmin*0.9999, 0)); + pnts.push(this.ProjectAitoff2xy(this.scale_xmax*0.9999, 0)); + } + if (this.scale_xmin<0 && this.scale_xmax>0) { + pnts.push(this.ProjectAitoff2xy(0, this.scale_ymin)); + pnts.push(this.ProjectAitoff2xy(0, this.scale_ymax)); + } + } else if (this.projection == 2) { + if (this.scale_ymin <= -90 || this.scale_ymax >=90) { + console.warn("Mercator Projection", "Latitude out of range", this.scale_ymin, this.scale_ymax); + this.projection = 0; + return; + } + pnts.push(this.ProjectMercator2xy(this.scale_xmin, this.scale_ymin)); + pnts.push(this.ProjectMercator2xy(this.scale_xmax, this.scale_ymax)); + + } else if (this.projection == 3) { + pnts.push(this.ProjectSinusoidal2xy(this.scale_xmin, this.scale_ymin)); + pnts.push(this.ProjectSinusoidal2xy(this.scale_xmin, this.scale_ymax)); + pnts.push(this.ProjectSinusoidal2xy(this.scale_xmax, this.scale_ymax)); + pnts.push(this.ProjectSinusoidal2xy(this.scale_xmax, this.scale_ymin)); + if (this.scale_ymin<0 && this.scale_ymax>0) { + pnts.push(this.ProjectSinusoidal2xy(this.scale_xmin, 0)); + pnts.push(this.ProjectSinusoidal2xy(this.scale_xmax, 0)); + } + if (this.scale_xmin<0 && this.scale_xmax>0) { + pnts.push(this.ProjectSinusoidal2xy(0, this.scale_ymin)); + pnts.push(this.ProjectSinusoidal2xy(0, this.scale_ymax)); + } + } else if (this.projection == 4) { + pnts.push(this.ProjectParabolic2xy(this.scale_xmin, this.scale_ymin)); + pnts.push(this.ProjectParabolic2xy(this.scale_xmin, this.scale_ymax)); + pnts.push(this.ProjectParabolic2xy(this.scale_xmax, this.scale_ymax)); + pnts.push(this.ProjectParabolic2xy(this.scale_xmax, this.scale_ymin)); + if (this.scale_ymin<0 && this.scale_ymax>0) { + pnts.push(this.ProjectParabolic2xy(this.scale_xmin, 0)); + pnts.push(this.ProjectParabolic2xy(this.scale_xmax, 0)); + } + if (this.scale_xmin<0 && this.scale_xmax>0) { + pnts.push(this.ProjectParabolic2xy(0, this.scale_ymin)); + pnts.push(this.ProjectParabolic2xy(0, this.scale_ymax)); + } + } + + this.original_xmin = this.scale_xmin; + this.original_xmax = this.scale_xmax; + this.original_ymin = this.scale_ymin; + this.original_ymax = this.scale_ymax; + + this.scale_xmin = this.scale_xmax = pnts[0].x; + this.scale_ymin = this.scale_ymax = pnts[0].y; + + for (var n=1;n<pnts.length;++n) { + this.scale_xmin = Math.min(this.scale_xmin, pnts[n].x); + this.scale_xmax = Math.max(this.scale_xmax, pnts[n].x); + this.scale_ymin = Math.min(this.scale_ymin, pnts[n].y); + this.scale_ymax = Math.max(this.scale_ymax, pnts[n].y); + } + } + + TFramePainter.prototype.SetAxesRanges = function(xaxis, xmin, xmax, yaxis, ymin, ymax, zaxis, zmin, zmax) { + // if (this.axes_drawn) return; + + this.ranges_set = true; + + this.xaxis = xaxis; + this.xmin = xmin; + this.xmax = xmax; + + this.yaxis = yaxis; + this.ymin = ymin; + this.ymax = ymax; + + this.zaxis = zaxis; + this.zmin = zmin; + this.zmax = zmax; + } + + TFramePainter.prototype.GetAxis = function(name) { + switch(name) { + case "x": return this.xaxis; + case "y": return this.yaxis; + case "z": return this.zaxis; + } + return null; + } + + TFramePainter.prototype.CheckAxisZoom = function(name) { + var axis = this.GetAxis(name); + if (axis && axis.TestBit(JSROOT.EAxisBits.kAxisRange)) { + if ((axis.fFirst !== axis.fLast) && ((axis.fFirst > 1) || (axis.fLast < axis.fNbins))) { + this['zoom_' + name + 'min'] = axis.fFirst > 1 ? axis.GetBinLowEdge(axis.fFirst) : axis.fXmin; + this['zoom_' + name + 'max'] = axis.fLast < axis.fNbins ? axis.GetBinLowEdge(axis.fLast+1) : axis.fXmax; + // reset user range for main painter + axis.InvertBit(JSROOT.EAxisBits.kAxisRange); + axis.fFirst = 1; axis.fLast = axis.fNbins + } + } + } + + TFramePainter.prototype.CheckPadUserRange = function(pad, name) { + if (!pad) return; + + // seems to be, not allways user range calculated + var umin = pad['fU' + name + 'min'], + umax = pad['fU' + name + 'max'], + eps = 1e-7; + + if (name == "x") { + if ((Math.abs(pad.fX1) > eps) || (Math.abs(pad.fX2-1) > eps)) { + var dx = pad.fX2 - pad.fX1; + umin = pad.fX1 + dx*pad.fLeftMargin; + umax = pad.fX2 - dx*pad.fRightMargin; + } + } else { + if ((Math.abs(pad.fY1) > eps) || (Math.abs(pad.fY2-1) > eps)) { + var dy = pad.fY2 - pad.fY1; + umin = pad.fY1 + dy*pad.fBottomMargin; + umax = pad.fY2 - dy*pad.fTopMargin; + } + } + + if ((umin>=umax) || (Math.abs(umin)<eps && Math.abs(umax-1)<eps)) return; + + if (pad['fLog' + name] > 0) { + umin = Math.exp(umin * Math.log(10)); + umax = Math.exp(umax * Math.log(10)); + } + + var aname = name; + if (this.swap_xy) aname = (name=="x") ? "y" : "x"; + var smin = 'scale_' + aname + 'min', + smax = 'scale_' + aname + 'max'; + + var eps = (this[smax] - this[smin]) * 1e-7; + + if ((Math.abs(umin - this[smin]) > eps) || (Math.abs(umax - this[smax]) > eps)) { + this["zoom_" + aname + "min"] = umin; + this["zoom_" + aname + "max"] = umax; + } + } + + TFramePainter.prototype.CreateXY = function(opts) { + + this.CleanXY(); // remove all previous configurations + + if (!opts) opts = {}; + + this.swap_xy = opts.swap_xy || false; + this.reverse_x = opts.reverse_x || false; + this.reverse_y = opts.reverse_y || false; + + this.logx = this.logy = false; + + var w = this.frame_width(), h = this.frame_height(), pad = this.root_pad(); + + this.scale_xmin = this.xmin; + this.scale_xmax = this.xmax; + + this.scale_ymin = this.ymin; + this.scale_ymax = this.ymax; + + if (opts.extra_y_space) { + var log_scale = this.swap_xy ? pad.fLogx : pad.fLogy; + if (log_scale && (this.scale_ymax > 0)) + this.scale_ymax = Math.exp(Math.log(this.scale_ymax)*1.1); + else + this.scale_ymax += (this.scale_ymax - this.scale_ymin) * 0.1; + } + + if (opts.check_pad_range) { + // take zooming out of pad or axis attributes + + this.zoom_xmin = this.zoom_xmax = 0; + this.zoom_ymin = this.zoom_ymax = 0; + this.zoom_zmin = this.zoom_zmax = 0; + + this.CheckAxisZoom('x'); + if (opts.ndim && (opts.ndim > 1)) this.CheckAxisZoom('y'); + if (opts.ndim && (opts.ndim > 2)) this.CheckAxisZoom('z'); + + if (opts.check_pad_range === "pad_range") { + var canp = this.canv_painter(); + // ignore range set in the online canvas + if (!canp || !canp.online_canvas) { + this.CheckPadUserRange(pad, 'x'); + this.CheckPadUserRange(pad, 'y'); + } + } + } + + if ((this.zoom_ymin == this.zoom_ymax) && (opts.zoom_ymin != opts.zoom_ymax) && !this.zoom_changed_interactive) { + this.zoom_ymin = opts.zoom_ymin; + this.zoom_ymax = opts.zoom_ymax; + } + + if (this.zoom_xmin != this.zoom_xmax) { + this.scale_xmin = this.zoom_xmin; + this.scale_xmax = this.zoom_xmax; + } + + if (this.zoom_ymin != this.zoom_ymax) { + this.scale_ymin = this.zoom_ymin; + this.scale_ymax = this.zoom_ymax; + } + + // projection should be assigned + this.RecalculateRange(opts.Proj); + + if (this.xaxis.fTimeDisplay) { + this.x_kind = 'time'; + this.timeoffsetx = JSROOT.Painter.getTimeOffset(this.xaxis); + this.ConvertX = function(x) { return new Date(this.timeoffsetx + x*1000); }; + this.RevertX = function(grx) { return (this.x.invert(grx) - this.timeoffsetx) / 1000; }; + } else { + this.x_kind = !this.xaxis.fLabels ? 'normal' : 'labels'; + this.ConvertX = function(x) { return x; }; + this.RevertX = function(grx) { return this.x.invert(grx); }; + } + + if (this.x_kind == 'time') { + this.x = d3.scaleTime(); + } else + if (this.swap_xy ? pad.fLogy : pad.fLogx) { + this.logx = true; + + if (this.scale_xmax <= 0) this.scale_xmax = 0; + + if ((this.scale_xmin <= 0) && this.xaxis && !this.swap_xy) + for (var i=0;i<this.xaxis.fNbins;++i) { + this.scale_xmin = Math.max(this.scale_xmin, this.xaxis.GetBinLowEdge(i+1)); + if (this.scale_xmin>0) break; + } + + if ((this.scale_xmin <= 0) || (this.scale_xmin >= this.scale_xmax)) + this.scale_xmin = this.scale_xmax * 0.0001; + + this.x = d3.scaleLog(); + } else { + this.x = d3.scaleLinear(); + } + + var gr_range_x = this.reverse_x ? [ w, 0 ] : [ 0, w ], + gr_range_y = this.reverse_y ? [ 0, h ] : [ h, 0 ]; + + this.x.domain([this.ConvertX(this.scale_xmin), this.ConvertX(this.scale_xmax)]) + .range(this.swap_xy ? gr_range_y : gr_range_x); + + if (this.x_kind == 'time') { + // we emulate scale functionality + this.grx = function(val) { return this.x(this.ConvertX(val)); } + } else + if (this.logx) { + this.grx = function(val) { return (val < this.scale_xmin) ? (this.swap_xy ? this.x.range()[0]+5 : -5) : this.x(val); } + } else { + this.grx = this.x; + } + + if (this.yaxis.fTimeDisplay) { + this.y_kind = 'time'; + this.timeoffsety = JSROOT.Painter.getTimeOffset(this.yaxis); + this.ConvertY = function(y) { return new Date(this.timeoffsety + y*1000); }; + this.RevertY = function(gry) { return (this.y.invert(gry) - this.timeoffsety) / 1000; }; + } else { + this.y_kind = !this.yaxis.fLabels ? 'normal' : 'labels'; + this.ConvertY = function(y) { return y; }; + this.RevertY = function(gry) { return this.y.invert(gry); }; + } + + if (this.swap_xy ? pad.fLogx : pad.fLogy) { + this.logy = true; + if (this.scale_ymax <= 0) + this.scale_ymax = 1; + else + if ((this.zoom_ymin === this.zoom_ymax) && (opts.ndim==1) && this.draw_content) + this.scale_ymax*=1.8; + + // this is for 2/3 dim histograms - find first non-negative bin + if ((this.scale_ymin <= 0) && this.yaxis && (opts.ndim>1) && !this.swap_xy) + for (var i=0;i<this.yaxis.fNbins;++i) { + this.scale_ymin = Math.max(this.scale_ymin, this.yaxis.GetBinLowEdge(i+1)); + if (this.scale_ymin>0) break; + } + + if ((this.scale_ymin <= 0) && (opts.ymin_nz) && (opts.ymin_nz < 1e-2*this.ymax)) + this.scale_ymin = 0.3 * opts.ymin_nz; + + if ((this.scale_ymin <= 0) || (this.scale_ymin >= this.scale_ymax)) + this.scale_ymin = 3e-4 * this.scale_ymax; + + this.y = d3.scaleLog(); + } else if (this.y_kind == 'time') { + this.y = d3.scaleTime(); + } else { + this.y = d3.scaleLinear() + } + + this.y.domain([ this.ConvertY(this.scale_ymin), this.ConvertY(this.scale_ymax) ]) + .range(this.swap_xy ? gr_range_x : gr_range_y); + + if (this.y_kind == 'time') { + // we emulate scale functionality + this.gry = function(val) { return this.y(this.ConvertY(val)); } + } else if (this.logy) { + // make protection for log + this.gry = function(val) { return (val < this.scale_ymin) ? (this.swap_xy ? -5 : this.y.range()[0]+5) : this.y(val); } + } else { + this.gry = this.y; + } + + this.SetRootPadRange(pad); + } + + /** Set selected range back to TPad object */ + TFramePainter.prototype.SetRootPadRange = function(pad, is3d) { + if (!pad || !this.ranges_set) return; + + if (is3d) { + // this is fake values, algorithm should be copied from TView3D class of ROOT + // pad.fLogx = pad.fLogy = 0; + pad.fUxmin = pad.fUymin = -0.9; + pad.fUxmax = pad.fUymax = 0.9; + } else { + pad.fLogx = (this.swap_xy ? this.logy : this.logx) ? 1 : 0; + pad.fUxmin = pad.fLogx ? JSROOT.log10(this.scale_xmin) : this.scale_xmin; + pad.fUxmax = pad.fLogx ? JSROOT.log10(this.scale_xmax) : this.scale_xmax; + pad.fLogy = (this.swap_xy ? this.logx : this.logy) ? 1 : 0; + pad.fUymin = pad.fLogy ? JSROOT.log10(this.scale_ymin) : this.scale_ymin; + pad.fUymax = pad.fLogy ? JSROOT.log10(this.scale_ymax) : this.scale_ymax; + } + + var rx = pad.fUxmax - pad.fUxmin, + mx = 1 - pad.fLeftMargin - pad.fRightMargin, + ry = pad.fUymax - pad.fUymin, + my = 1 - pad.fBottomMargin - pad.fTopMargin; + + if (mx <= 0) mx = 0.01; // to prevent overflow + if (my <= 0) my = 0.01; + + pad.fX1 = pad.fUxmin - rx/mx*pad.fLeftMargin; + pad.fX2 = pad.fUxmax + rx/mx*pad.fRightMargin; + pad.fY1 = pad.fUymin - ry/my*pad.fBottomMargin; + pad.fY2 = pad.fUymax + ry/my*pad.fTopMargin; + } + + + TFramePainter.prototype.DrawGrids = function() { + // grid can only be drawn by first painter + + var layer = this.svg_frame().select(".grid_layer"); + + layer.selectAll(".xgrid").remove(); + layer.selectAll(".ygrid").remove(); + + var pad = this.root_pad(), + h = this.frame_height(), + w = this.frame_width(), + grid, grid_style = JSROOT.gStyle.fGridStyle; + + if ((grid_style < 0) || (grid_style >= JSROOT.Painter.root_line_styles.length)) grid_style = 11; + + // add a grid on x axis, if the option is set + if (pad && pad.fGridx && this.x_handle) { + grid = ""; + for (var n=0;n<this.x_handle.ticks.length;++n) + if (this.swap_xy) + grid += "M0,"+this.x_handle.ticks[n]+"h"+w; + else + grid += "M"+this.x_handle.ticks[n]+",0v"+h; + + var colid = (JSROOT.gStyle.fGridColor > 0) ? JSROOT.gStyle.fGridColor : (this.GetAxis("x") ? this.GetAxis("x").fAxisColor : 1), + grid_color = this.get_color(colid) || "black"; + + if (grid.length > 0) + layer.append("svg:path") + .attr("class", "xgrid") + .attr("d", grid) + .style('stroke',grid_color).style("stroke-width",JSROOT.gStyle.fGridWidth) + .style("stroke-dasharray", JSROOT.Painter.root_line_styles[grid_style]); + } + + // add a grid on y axis, if the option is set + if (pad && pad.fGridy && this.y_handle) { + grid = ""; + for (var n=0;n<this.y_handle.ticks.length;++n) + if (this.swap_xy) + grid += "M"+this.y_handle.ticks[n]+",0v"+h; + else + grid += "M0,"+this.y_handle.ticks[n]+"h"+w; + + var colid = (JSROOT.gStyle.fGridColor > 0) ? JSROOT.gStyle.fGridColor : (this.GetAxis("y") ? this.GetAxis("y").fAxisColor : 1), + grid_color = this.get_color(colid) || "black"; + + if (grid.length > 0) + layer.append("svg:path") + .attr("class", "ygrid") + .attr("d", grid) + .style('stroke',grid_color).style("stroke-width",JSROOT.gStyle.fGridWidth) + .style("stroke-dasharray", JSROOT.Painter.root_line_styles[grid_style]); + } + } + + TFramePainter.prototype.AxisAsText = function(axis, value) { + if (axis == "x") { + if (this.x_kind == 'time') + value = this.ConvertX(value); + if (this.x_handle && ('format' in this.x_handle)) + return this.x_handle.format(value, false, JSROOT.gStyle.XValuesFormat); + } else if (axis == "y") { + if (this.y_kind == 'time') + value = this.ConvertY(value); + if (this.y_handle && ('format' in this.y_handle)) + return this.y_handle.format(value, false, false, JSROOT.gStyle.YValuesFormat); + } else { + if (this.z_handle && ('format' in this.z_handle)) + return this.z_handle.format(value, false, false, JSROOT.gStyle.ZValuesFormat); + } + + return value.toPrecision(4); + } + + TFramePainter.prototype.DrawAxes = function(shrink_forbidden, disable_axis_draw, AxisPos, has_x_obstacle) { + // axes can be drawn only for main histogram + + // if (this.axes_drawn) return true; + + this.CleanupAxes(); + + if ((this.xmin==this.xmax) || (this.ymin==this.ymax)) return false; + + if (AxisPos === undefined) AxisPos = 0; + + var layer = this.svg_frame().select(".axis_layer"), + w = this.frame_width(), + h = this.frame_height(), + pad = this.root_pad(); + + this.x_handle = new JSROOT.TAxisPainter(this.xaxis, true); + this.x_handle.SetDivId(this.divid, -1); + this.x_handle.pad_name = this.pad_name; + + this.x_handle.SetAxisConfig("xaxis", + (this.logx && (this.x_kind !== "time")) ? "log" : this.x_kind, + this.x, this.xmin, this.xmax, this.scale_xmin, this.scale_xmax); + this.x_handle.invert_side = (AxisPos >= 10); + this.x_handle.lbls_both_sides = !this.x_handle.invert_side && (pad.fTickx > 1); // labels on both sides + this.x_handle.has_obstacle = has_x_obstacle; + + this.y_handle = new JSROOT.TAxisPainter(this.yaxis, true); + this.y_handle.SetDivId(this.divid, -1); + this.y_handle.pad_name = this.pad_name; + + this.y_handle.SetAxisConfig("yaxis", + (this.logy && this.y_kind !== "time") ? "log" : this.y_kind, + this.y, this.ymin, this.ymax, this.scale_ymin, this.scale_ymax); + this.y_handle.invert_side = ((AxisPos % 10) === 1); + this.y_handle.lbls_both_sides = !this.y_handle.invert_side && (pad.fTicky > 1); // labels on both sides + + var draw_horiz = this.swap_xy ? this.y_handle : this.x_handle, + draw_vertical = this.swap_xy ? this.x_handle : this.y_handle; + + if (!disable_axis_draw) { + var pp = this.pad_painter(); + if (pp && pp._fast_drawing) disable_axis_draw = true; + } + + if (!disable_axis_draw) { + draw_horiz.DrawAxis(false, layer, w, h, + draw_horiz.invert_side ? undefined : "translate(0," + h + ")", + false, pad.fTickx ? -h : 0, disable_axis_draw); + + draw_vertical.DrawAxis(true, layer, w, h, + draw_vertical.invert_side ? "translate(" + w + ",0)" : undefined, + false, pad.fTicky ? w : 0, disable_axis_draw, + draw_vertical.invert_side ? 0 : this.frame_x()); + + this.DrawGrids(); + } + + if (!shrink_forbidden && JSROOT.gStyle.CanAdjustFrame && !disable_axis_draw) { + + var shrink = 0., ypos = draw_vertical.position; + + if ((-0.2*w < ypos) && (ypos < 0)) { + shrink = -ypos/w + 0.001; + this.shrink_frame_left += shrink; + } else if ((ypos>0) && (ypos<0.3*w) && (this.shrink_frame_left > 0) && (ypos/w > this.shrink_frame_left)) { + shrink = -this.shrink_frame_left; + this.shrink_frame_left = 0.; + } + + if (shrink != 0) { + this.Shrink(shrink, 0); + this.Redraw(); + this.DrawAxes(true); + } + } + + this.axes_drawn = true; + + return true; + } + + TFramePainter.prototype.UpdateAttributes = function(force) { + var pad = this.root_pad(), + tframe = this.GetObject(); + + if ((this.fX1NDC === undefined) || (force && !this.modified_NDC)) { + if (!pad || (pad.fLeftMargin===undefined)) { + JSROOT.extend(this, JSROOT.gStyle.FrameNDC); + } else { + JSROOT.extend(this, { + fX1NDC: pad.fLeftMargin, + fX2NDC: 1 - pad.fRightMargin, + fY1NDC: pad.fBottomMargin, + fY2NDC: 1 - pad.fTopMargin + }); + } + } + + if (this.fillatt === undefined) { + if (tframe) this.createAttFill({ attr: tframe }); + else if (pad && pad.fFrameFillColor) this.createAttFill({ pattern: pad.fFrameFillStyle, color: pad.fFrameFillColor }); + else if (pad) this.createAttFill({ attr: pad }); + else this.createAttFill({ pattern: 1001, color: 0}); + + // force white color for the canvas frame + if (!tframe && this.fillatt.empty() && this.pad_painter() && this.pad_painter().iscan) + this.fillatt.SetSolidColor('white'); + } + + if (!tframe && pad && (pad.fFrameLineColor!==undefined)) + this.createAttLine({ color: pad.fFrameLineColor, width: pad.fFrameLineWidth, style: pad.fFrameLineStyle }); + else + this.createAttLine({ attr: tframe, color: 'black' }); + } + + TFramePainter.prototype.SizeChanged = function() { + // function called at the end of resize of frame + // One should apply changes to the pad + + var pad = this.root_pad(); + + if (pad) { + pad.fLeftMargin = this.fX1NDC; + pad.fRightMargin = 1 - this.fX2NDC; + pad.fBottomMargin = this.fY1NDC; + pad.fTopMargin = 1 - this.fY2NDC; + this.SetRootPadRange(pad); + } + + this.RedrawPad(); + } + + TFramePainter.prototype.CleanXY = function() { + // remove all kinds of X/Y function for axes transformation + delete this.x; delete this.grx; + delete this.ConvertX; delete this.RevertX; + delete this.y; delete this.gry; + delete this.ConvertY; delete this.RevertY; + delete this.z; delete this.grz; + } + + TFramePainter.prototype.CleanupAxes = function() { + // remove all axes drawings + if (this.x_handle) { + this.x_handle.Cleanup(); + delete this.x_handle; + } + + if (this.y_handle) { + this.y_handle.Cleanup(); + delete this.y_handle; + } + + if (this.z_handle) { + this.z_handle.Cleanup(); + delete this.z_handle; + } + if (this.draw_g) { + this.draw_g.select(".grid_layer").selectAll("*").remove(); + this.draw_g.select(".axis_layer").selectAll("*").remove(); + } + this.axes_drawn = false; + } + + TFramePainter.prototype.CleanFrameDrawings = function() { + + // cleanup all 3D drawings if any + if (typeof this.Create3DScene === 'function') + this.Create3DScene(-1); + + this.CleanupAxes(); + this.CleanXY(); + + this.ranges_set = false; + + this.xmin = this.xmax = 0; + this.ymin = this.ymax = 0; + this.zmin = this.zmax = 0; + + this.zoom_xmin = this.zoom_xmax = 0; + this.zoom_ymin = this.zoom_ymax = 0; + this.zoom_zmin = this.zoom_zmax = 0; + + this.scale_xmin = this.scale_xmax = 0; + this.scale_ymin = this.scale_ymax = 0; + this.scale_zmin = this.scale_zmax = 0; + + if (this.draw_g) { + this.draw_g.select(".main_layer").selectAll("*").remove(); + this.draw_g.select(".upper_layer").selectAll("*").remove(); + } + + this.xaxis = null; + this.yaxis = null; + this.zaxis = null; + + if (this.draw_g) { + this.draw_g.selectAll("*").remove(); + this.draw_g.on("mousedown", null) + .on("dblclick", null) + .on("wheel", null) + .on("contextmenu", null) + .property('interactive_set', null); + this.draw_g.remove(); + } + + this.draw_g = null; + + if (this.keys_handler) { + window.removeEventListener('keydown', this.keys_handler, false); + this.keys_handler = null; + } + } + + TFramePainter.prototype.Cleanup = function() { + this.CleanFrameDrawings(); + delete this._click_handler; + delete this._dblclick_handler; + + JSROOT.TooltipHandler.prototype.Cleanup.call(this); + } + + TFramePainter.prototype.Redraw = function() { + + var pp = this.pad_painter(); + if (pp) pp.frame_painter_ref = this; // keep direct reference to the frame painter + + if (this.mode3d) return; // no need to create any elements in 3d mode + + // first update all attributes from objects + this.UpdateAttributes(); + + var width = this.pad_width(), + height = this.pad_height(), + lm = Math.round(width * this.fX1NDC), + w = Math.round(width * (this.fX2NDC - this.fX1NDC)), + tm = Math.round(height * (1 - this.fY2NDC)), + h = Math.round(height * (this.fY2NDC - this.fY1NDC)), + rotate = false, fixpos = false; + + if (pp && pp.options) { + if (pp.options.RotateFrame) rotate = true; + if (pp.options.FixFrame) fixpos = true; + } + + // this is svg:g object - container for every other items belonging to frame + this.draw_g = this.svg_layer("primitives_layer").select(".root_frame"); + + var top_rect, main_svg; + + if (this.draw_g.empty()) { + + var layer = this.svg_layer("primitives_layer"); + + this.draw_g = layer.append("svg:g").attr("class", "root_frame"); + + this.draw_g.append("svg:title").text(""); + + top_rect = this.draw_g.append("svg:rect"); + + // append for the moment three layers - for drawing and axis + this.draw_g.append('svg:g').attr('class','grid_layer'); + + main_svg = this.draw_g.append('svg:svg') + .attr('class','main_layer') + .attr("x", 0) + .attr("y", 0) + .attr('overflow', 'hidden'); + + this.draw_g.append('svg:g').attr('class','axis_layer'); + this.draw_g.append('svg:g').attr('class','upper_layer'); + } else { + top_rect = this.draw_g.select("rect"); + main_svg = this.draw_g.select(".main_layer"); + } + + this.axes_drawn = false; + + var trans = "translate(" + lm + "," + tm + ")"; + if (rotate) { + trans += " rotate(-90) " + "translate(" + -h + ",0)"; + var d = w; w = h; h = d; + } + + this._frame_x = lm; + this._frame_y = tm; + this._frame_width = w; + this._frame_height = h; + + this.draw_g.attr("transform", trans); + + top_rect.attr("x", 0) + .attr("y", 0) + .attr("width", w) + .attr("height", h) + .call(this.fillatt.func) + .call(this.lineatt.func); + + main_svg.attr("width", w) + .attr("height", h) + .attr("viewBox", "0 0 " + w + " " + h); + + var tooltip_rect = this.draw_g.select(".interactive_rect"); + + if (JSROOT.BatchMode) return tooltip_rect.remove(); + + this.draw_g.attr("x", lm) + .attr("y", tm) + .attr("width", w) + .attr("height", h); + + if (!rotate && !fixpos) + this.AddDrag({ obj: this, only_resize: true, minwidth: 20, minheight: 20, + redraw: this.SizeChanged.bind(this) }); + + if (tooltip_rect.empty()) + tooltip_rect = + this.draw_g + .append("rect") + .attr("class","interactive_rect") + .style('opacity',0) + .style('fill',"none") + .style("pointer-events","visibleFill") + .property('handlers_set', 0); + + var handlers_set = (pp && pp._fast_drawing) ? 0 : 1; + + if (tooltip_rect.property('handlers_set') != handlers_set) { + var close_handler = handlers_set ? this.ProcessTooltipEvent.bind(this, null) : null, + mouse_handler = handlers_set ? this.ProcessTooltipEvent.bind(this, { handler: true, touch: false }) : null; + + tooltip_rect.property('handlers_set', handlers_set) + .on('mouseenter', mouse_handler) + .on('mousemove', mouse_handler) + .on('mouseleave', close_handler); + + if (JSROOT.touches) { + var touch_handler = handlers_set ? this.ProcessTooltipEvent.bind(this, { handler: true, touch: true }) : null; + + tooltip_rect.on("touchstart", touch_handler) + .on("touchmove", touch_handler) + .on("touchend", close_handler) + .on("touchcancel", close_handler); + } + } + + tooltip_rect.attr("x", 0) + .attr("y", 0) + .attr("width", w) + .attr("height", h); + + var hintsg = this.hints_layer().select(".objects_hints"); + // if tooltips were visible before, try to reconstruct them after short timeout + if (!hintsg.empty() && this.IsTooltipAllowed() && (hintsg.property("hints_pad") == this.pad_name)) + setTimeout(this.ProcessTooltipEvent.bind(this, hintsg.property('last_point')), 10); + } + + TFramePainter.prototype.ToggleLog = function(axis) { + var pad = this.root_pad(); + if (!pad) return; + + // do not allow log scale for labels + if (!pad["fLog" + axis]) { + var kind = this[axis+"_kind"]; + if (this.swap_xy && axis==="x") kind = this.y_kind; else + if (this.swap_xy && axis==="y") kind = this.x_kind; + if (kind === "labels") return; + } + + // directly change attribute in the pad + pad["fLog" + axis] = pad["fLog" + axis] ? 0 : 1; + + this.RedrawPad(); + + var canp = this.canv_painter(); + if (canp) canp.ProcessChanges("log"+axis, this.pad_painter()); + } + + TFramePainter.prototype.FillContextMenu = function(menu, kind, obj) { + // fill context menu for the frame + // it could be appended to the histogram menus + + var main = this.main_painter(), pad = this.root_pad(); + + if ((kind=="x") || (kind=="y") || (kind=="z")) { + var faxis = obj || this[kind+'axis']; + menu.add("header: " + kind.toUpperCase() + " axis"); + menu.add("Unzoom", this.Unzoom.bind(this, kind)); + menu.addchk(pad["fLog" + kind], "SetLog"+kind, this.ToggleLog.bind(this, kind) ); + menu.addchk(faxis.TestBit(JSROOT.EAxisBits.kMoreLogLabels), "More log", + function() { faxis.InvertBit(JSROOT.EAxisBits.kMoreLogLabels); this.RedrawPad(); }); + menu.addchk(faxis.TestBit(JSROOT.EAxisBits.kNoExponent), "No exponent", + function() { faxis.InvertBit(JSROOT.EAxisBits.kNoExponent); this.RedrawPad(); }); + + if ((kind === "z") && main && main.options && main.options.Zscale) + if (typeof main.FillPaletteMenu == 'function') main.FillPaletteMenu(menu); + + if (faxis) { + menu.add("sub:Labels"); + menu.addchk(faxis.TestBit(JSROOT.EAxisBits.kCenterLabels), "Center", + function() { faxis.InvertBit(JSROOT.EAxisBits.kCenterLabels); this.RedrawPad(); }); + menu.addchk(faxis.TestBit(JSROOT.EAxisBits.kLabelsVert), "Rotate", + function() { faxis.InvertBit(JSROOT.EAxisBits.kLabelsVert); this.RedrawPad(); }); + this.AddColorMenuEntry(menu, "Color", faxis.fLabelColor, + function(arg) { faxis.fLabelColor = parseInt(arg); this.RedrawPad(); }); + this.AddSizeMenuEntry(menu,"Offset", 0, 0.1, 0.01, faxis.fLabelOffset, + function(arg) { faxis.fLabelOffset = parseFloat(arg); this.RedrawPad(); } ); + this.AddSizeMenuEntry(menu,"Size", 0.02, 0.11, 0.01, faxis.fLabelSize, + function(arg) { faxis.fLabelSize = parseFloat(arg); this.RedrawPad(); } ); + menu.add("endsub:"); + menu.add("sub:Title"); + menu.add("SetTitle", function() { + var t = prompt("Enter axis title", faxis.fTitle); + if (t!==null) { faxis.fTitle = t; this.RedrawPad(); } + }); + menu.addchk(faxis.TestBit(JSROOT.EAxisBits.kCenterTitle), "Center", + function() { faxis.InvertBit(JSROOT.EAxisBits.kCenterTitle); this.RedrawPad(); }); + menu.addchk(faxis.TestBit(JSROOT.EAxisBits.kRotateTitle), "Rotate", + function() { faxis.InvertBit(JSROOT.EAxisBits.kRotateTitle); this.RedrawPad(); }); + this.AddColorMenuEntry(menu, "Color", faxis.fTitleColor, + function(arg) { faxis.fTitleColor = parseInt(arg); this.RedrawPad(); }); + this.AddSizeMenuEntry(menu,"Offset", 0, 3, 0.2, faxis.fTitleOffset, + function(arg) { faxis.fTitleOffset = parseFloat(arg); this.RedrawPad(); } ); + this.AddSizeMenuEntry(menu,"Size", 0.02, 0.11, 0.01, faxis.fTitleSize, + function(arg) { faxis.fTitleSize = parseFloat(arg); this.RedrawPad(); } ); + menu.add("endsub:"); + menu.add("sub:Ticks"); + if (faxis._typename == "TGaxis") { + this.AddColorMenuEntry(menu, "Color", faxis.fLineColor, + function(arg) { faxis.fLineColor = parseInt(arg); this.RedrawPad(); }); + this.AddSizeMenuEntry(menu,"Size", -0.05, 0.055, 0.01, faxis.fTickSize, + function(arg) { faxis.fTickSize = parseFloat(arg); this.RedrawPad(); } ); + } else { + this.AddColorMenuEntry(menu, "Color", faxis.fAxisColor, + function(arg) { faxis.fAxisColor = parseInt(arg); this.RedrawPad(); }); + this.AddSizeMenuEntry(menu,"Size", -0.05, 0.055, 0.01, faxis.fTickLength, + function(arg) { faxis.fTickLength = parseFloat(arg); this.RedrawPad(); } ); + } + menu.add("endsub:"); + } + return true; + } + + var alone = menu.size() == 0; + + if (alone) + menu.add("header:Frame"); + else + menu.add("separator"); + + if (this.zoom_xmin !== this.zoom_xmax) + menu.add("Unzoom X", this.Unzoom.bind(this,"x")); + if (this.zoom_ymin !== this.zoom_ymax) + menu.add("Unzoom Y", this.Unzoom.bind(this,"y")); + if (this.zoom_zmin !== this.zoom_zmax) + menu.add("Unzoom Z", this.Unzoom.bind(this,"z")); + menu.add("Unzoom all", this.Unzoom.bind(this,"xyz")); + + if (pad) { + menu.addchk(pad.fLogx, "SetLogx", this.ToggleLog.bind(this,"x")); + + menu.addchk(pad.fLogy, "SetLogy", this.ToggleLog.bind(this,"y")); + + if (main && (typeof main.Dimension === 'function') && (main.Dimension() > 1)) + menu.addchk(pad.fLogz, "SetLogz", this.ToggleLog.bind(this,"z")); + menu.add("separator"); + } + + menu.addchk(this.IsTooltipAllowed(), "Show tooltips", function() { + this.SetTooltipAllowed("toggle"); + }); + this.FillAttContextMenu(menu,alone ? "" : "Frame "); + menu.add("separator"); + menu.add("Save as frame.png", function() { this.pad_painter().SaveAs("png", 'frame', 'frame.png'); }); + menu.add("Save as frame.svg", function() { this.pad_painter().SaveAs("svg", 'frame', 'frame.svg'); }); + + return true; + } + + TFramePainter.prototype.GetFrameRect = function() { + // returns frame rectangle plus extra info for hint display + + return { + x: this.frame_x(), + y: this.frame_y(), + width: this.frame_width(), + height: this.frame_height(), + transform: this.draw_g ? this.draw_g.attr("transform") : "", + hint_delta_x: 0, + hint_delta_y: 0 + } + } + + TFramePainter.prototype.ProcessFrameClick = function(pnt, dblckick) { + // function called when frame is clicked and object selection can be performed + // such event can be used to select + + var pp = this.pad_painter(); + if (!pp) return; + + pnt.painters = true; // provide painters reference in the hints + pnt.disabled = true; // do not invoke graphics + + // collect tooltips from pad painter - it has list of all drawn objects + var hints = pp.GetTooltips(pnt), exact = null; + for (var k=0; (k<hints.length) && !exact; ++k) + if (hints[k] && hints[k].exact) exact = hints[k]; + //if (exact) console.log('Click exact', pnt, exact.painter.GetTipName()); + // else console.log('Click frame', pnt); + + var res; + + if (exact) { + var handler = dblckick ? this._dblclick_handler : this._click_handler; + if (handler) res = handler(exact.user_info, pnt); + } + + if (!dblckick) + pp.SelectObjectPainter(exact ? exact.painter : this, + { x: pnt.x + (this._frame_x || 0), y: pnt.y + (this._frame_y || 0) }); + + return res; + } + + TFramePainter.prototype.AddKeysHandler = function() { + if (this.keys_handler || JSROOT.BatchMode || (typeof window == 'undefined')) return; + + this.keys_handler = this.ProcessKeyPress.bind(this); + + window.addEventListener('keydown', this.keys_handler, false); + } + + TFramePainter.prototype.ProcessKeyPress = function(evnt) { + + var main = this.select_main(); + if (main.empty()) return; + + var key = ""; + switch (evnt.keyCode) { + case 33: key = "PageUp"; break; + case 34: key = "PageDown"; break; + case 37: key = "ArrowLeft"; break; + case 38: key = "ArrowUp"; break; + case 39: key = "ArrowRight"; break; + case 40: key = "ArrowDown"; break; + case 42: key = "PrintScreen"; break; + case 106: key = "*"; break; + default: return false; + } + + var pp = this.pad_painter(); + if (JSROOT.Painter.GetActivePad() !== pp) return; + + if (evnt.shiftKey) key = "Shift " + key; + if (evnt.altKey) key = "Alt " + key; + if (evnt.ctrlKey) key = "Ctrl " + key; + + var zoom = { name: "x", dleft: 0, dright: 0 }; + + switch (key) { + case "ArrowLeft": zoom.dleft = -1; zoom.dright = 1; break; + case "ArrowRight": zoom.dleft = 1; zoom.dright = -1; break; + case "Ctrl ArrowLeft": zoom.dleft = zoom.dright = -1; break; + case "Ctrl ArrowRight": zoom.dleft = zoom.dright = 1; break; + case "ArrowUp": zoom.name = "y"; zoom.dleft = 1; zoom.dright = -1; break; + case "ArrowDown": zoom.name = "y"; zoom.dleft = -1; zoom.dright = 1; break; + case "Ctrl ArrowUp": zoom.name = "y"; zoom.dleft = zoom.dright = 1; break; + case "Ctrl ArrowDown": zoom.name = "y"; zoom.dleft = zoom.dright = -1; break; + } + + if (zoom.dleft || zoom.dright) { + if (!JSROOT.gStyle.Zooming) return false; + // in 3dmode with orbit control ignore simple arrows + if (this.mode3d && (key.indexOf("Ctrl")!==0)) return false; + this.AnalyzeMouseWheelEvent(null, zoom, 0.5); + this.Zoom(zoom.name, zoom.min, zoom.max); + if (zoom.changed) this.zoom_changed_interactive = 2; + evnt.stopPropagation(); + evnt.preventDefault(); + } else { + var func = pp ? pp.FindButton(key) : ""; + if (func) { + pp.PadButtonClick(func); + evnt.stopPropagation(); + evnt.preventDefault(); + } + } + + return true; // just process any key press + } + + TFramePainter.prototype.FindAlternativeClickHandler = function(pos) { + var pp = this.pad_painter(); + if (!pp) return false; + + var pnt = { x: pos[0], y: pos[1], painters: true, disabled: true, click_handler: true }; + + var hints = pp.GetTooltips(pnt); + for (var k=0;k<hints.length;++k) + if (hints[k] && (typeof hints[k].click_handler == 'function')) { + hints[k].click_handler(hints[k]); + return true; + } + + return false; + } + + TFramePainter.prototype.clearInteractiveElements = function() { + JSROOT.Painter.closeMenu(); + if (this.zoom_rect) { this.zoom_rect.remove(); this.zoom_rect = null; } + this.zoom_kind = 0; + + // enable tooltip in frame painter + this.SwitchTooltip(true); + } + + TFramePainter.prototype.startRectSel = function() { + // ignore when touch selection is activated + + if (this.zoom_kind > 100) return; + + // ignore all events from non-left button + if ((d3.event.which || d3.event.button) !== 1) return; + + d3.event.preventDefault(); + + var pos = d3.mouse(this.svg_frame().node()); + + if (this.FindAlternativeClickHandler(pos)) return; + + this.clearInteractiveElements(); + this.zoom_origin = pos; + + var w = this.frame_width(), h = this.frame_height(); + + this.zoom_curr = [ Math.max(0, Math.min(w, this.zoom_origin[0])), + Math.max(0, Math.min(h, this.zoom_origin[1])) ]; + + if ((this.zoom_origin[0] < 0) || (this.zoom_origin[0] > w)) { + this.zoom_kind = 3; // only y + this.zoom_origin[0] = 0; + this.zoom_origin[1] = this.zoom_curr[1]; + this.zoom_curr[0] = w; + this.zoom_curr[1] += 1; + } else if ((this.zoom_origin[1] < 0) || (this.zoom_origin[1] > h)) { + this.zoom_kind = 2; // only x + this.zoom_origin[0] = this.zoom_curr[0]; + this.zoom_origin[1] = 0; + this.zoom_curr[0] += 1; + this.zoom_curr[1] = h; + } else { + this.zoom_kind = 1; // x and y + this.zoom_origin[0] = this.zoom_curr[0]; + this.zoom_origin[1] = this.zoom_curr[1]; + } + + d3.select(window).on("mousemove.zoomRect", this.moveRectSel.bind(this)) + .on("mouseup.zoomRect", this.endRectSel.bind(this), true); + + this.zoom_rect = null; + + // disable tooltips in frame painter + this.SwitchTooltip(false); + + d3.event.stopPropagation(); + } + + TFramePainter.prototype.moveRectSel = function() { + + if ((this.zoom_kind == 0) || (this.zoom_kind > 100)) return; + + d3.event.preventDefault(); + var m = d3.mouse(this.svg_frame().node()); + + m[0] = Math.max(0, Math.min(this.frame_width(), m[0])); + m[1] = Math.max(0, Math.min(this.frame_height(), m[1])); + + switch (this.zoom_kind) { + case 1: this.zoom_curr[0] = m[0]; this.zoom_curr[1] = m[1]; break; + case 2: this.zoom_curr[0] = m[0]; break; + case 3: this.zoom_curr[1] = m[1]; break; + } + + if (this.zoom_rect===null) + this.zoom_rect = this.svg_frame() + .append("rect") + .attr("class", "zoom") + .attr("pointer-events","none"); + + this.zoom_rect.attr("x", Math.min(this.zoom_origin[0], this.zoom_curr[0])) + .attr("y", Math.min(this.zoom_origin[1], this.zoom_curr[1])) + .attr("width", Math.abs(this.zoom_curr[0] - this.zoom_origin[0])) + .attr("height", Math.abs(this.zoom_curr[1] - this.zoom_origin[1])); + } + + TFramePainter.prototype.endRectSel = function() { + if ((this.zoom_kind == 0) || (this.zoom_kind > 100)) return; + + d3.event.preventDefault(); + + d3.select(window).on("mousemove.zoomRect", null) + .on("mouseup.zoomRect", null); + + var m = d3.mouse(this.svg_frame().node()), changed = [true, true]; + m[0] = Math.max(0, Math.min(this.frame_width(), m[0])); + m[1] = Math.max(0, Math.min(this.frame_height(), m[1])); + + switch (this.zoom_kind) { + case 1: this.zoom_curr[0] = m[0]; this.zoom_curr[1] = m[1]; break; + case 2: this.zoom_curr[0] = m[0]; changed[1] = false; break; // only X + case 3: this.zoom_curr[1] = m[1]; changed[0] = false; break; // only Y + } + + var xmin, xmax, ymin, ymax, isany = false, + idx = this.swap_xy ? 1 : 0, idy = 1 - idx; + + if (changed[idx] && (Math.abs(this.zoom_curr[idx] - this.zoom_origin[idx]) > 10)) { + xmin = Math.min(this.RevertX(this.zoom_origin[idx]), this.RevertX(this.zoom_curr[idx])); + xmax = Math.max(this.RevertX(this.zoom_origin[idx]), this.RevertX(this.zoom_curr[idx])); + isany = true; + } + + if (changed[idy] && (Math.abs(this.zoom_curr[idy] - this.zoom_origin[idy]) > 10)) { + ymin = Math.min(this.RevertY(this.zoom_origin[idy]), this.RevertY(this.zoom_curr[idy])); + ymax = Math.max(this.RevertY(this.zoom_origin[idy]), this.RevertY(this.zoom_curr[idy])); + isany = true; + } + + var kind = this.zoom_kind, pnt = (kind===1) ? { x: this.zoom_origin[0], y: this.zoom_origin[1] } : null; + + this.clearInteractiveElements(); + + if (isany) { + this.zoom_changed_interactive = 2; + this.Zoom(xmin, xmax, ymin, ymax); + } else { + switch (kind) { + case 1: + var fp = this.frame_painter(); + if (fp) fp.ProcessFrameClick(pnt); + break; + case 2: + var pp = this.pad_painter(); + if (pp) pp.SelectObjectPainter(this.x_handle); + break; + case 3: + var pp = this.pad_painter(); + if (pp) pp.SelectObjectPainter(this.y_handle); + break; + } + } + + this.zoom_kind = 0; + } + + TFramePainter.prototype.mouseDoubleClick = function() { + d3.event.preventDefault(); + var m = d3.mouse(this.svg_frame().node()); + this.clearInteractiveElements(); + + var valid_x = (m[0] >= 0) && (m[0] <= this.frame_width()), + valid_y = (m[1] >= 0) && (m[1] <= this.frame_height()); + + if (valid_x && valid_y && this._dblclick_handler) + if (this.ProcessFrameClick({ x: m[0], y: m[1] }, true)) return; + + var kind = "xyz"; + if (!valid_x) kind = this.swap_xy ? "x" : "y"; else + if (!valid_y) kind = this.swap_xy ? "y" : "x"; + if (this.Unzoom(kind)) return; + + var pp = this.pad_painter(); + if (pp) pp.SelectObjectPainter(pp, { x: m[0]+this.frame_x(), y: m[1]+this.frame_y(), dbl: true }); + } + + TFramePainter.prototype.ConfigureUserClickHandler = function(handler) { + this._click_handler = handler && (typeof handler == 'function') ? handler : null; + } + + TFramePainter.prototype.ConfigureUserDblclickHandler = function(handler) { + this._dblclick_handler = handler && (typeof handler == 'function') ? handler : null; + } + + TFramePainter.prototype.Zoom = function(xmin, xmax, ymin, ymax, zmin, zmax) { + // function can be used for zooming into specified range + // if both limits for each axis 0 (like xmin==xmax==0), axis will be unzoomed + + // disable zooming when axis conversion is enabled + if (this.projection) return false; + + if (xmin==="x") { xmin = xmax; xmax = ymin; ymin = undefined; } else + if (xmin==="y") { ymax = ymin; ymin = xmax; xmin = xmax = undefined; } else + if (xmin==="z") { zmin = xmax; zmax = ymin; xmin = xmax = ymin = undefined; } + + var zoom_x = (xmin !== xmax), zoom_y = (ymin !== ymax), zoom_z = (zmin !== zmax), + unzoom_x = false, unzoom_y = false, unzoom_z = false; + + if (zoom_x) { + var cnt = 0; + if (xmin <= this.xmin) { xmin = this.xmin; cnt++; } + if (xmax >= this.xmax) { xmax = this.xmax; cnt++; } + if (cnt === 2) { zoom_x = false; unzoom_x = true; } + } else { + unzoom_x = (xmin === xmax) && (xmin === 0); + } + + if (zoom_y) { + var cnt = 0; + if (ymin <= this.ymin) { ymin = this.ymin; cnt++; } + if (ymax >= this.ymax) { ymax = this.ymax; cnt++; } + if (cnt === 2) { zoom_y = false; unzoom_y = true; } + } else { + unzoom_y = (ymin === ymax) && (ymin === 0); + } + + if (zoom_z) { + var cnt = 0; + if (zmin <= this.zmin) { zmin = this.zmin; cnt++; } + if (zmax >= this.zmax) { zmax = this.zmax; cnt++; } + if (cnt === 2) { zoom_z = false; unzoom_z = true; } + } else { + unzoom_z = (zmin === zmax) && (zmin === 0); + } + + var changed = false, main = this; + + // first process zooming (if any) + if (zoom_x || zoom_y || zoom_z) + main.ForEachPainter(function(obj) { + if (zoom_x && obj.CanZoomIn("x", xmin, xmax)) { + main.zoom_xmin = xmin; + main.zoom_xmax = xmax; + changed = true; + zoom_x = false; + } + if (zoom_y && obj.CanZoomIn("y", ymin, ymax)) { + main.zoom_ymin = ymin; + main.zoom_ymax = ymax; + changed = true; + zoom_y = false; + } + if (zoom_z && obj.CanZoomIn("z", zmin, zmax)) { + main.zoom_zmin = zmin; + main.zoom_zmax = zmax; + changed = true; + zoom_z = false; + } + }); + + // and process unzoom, if any + if (unzoom_x || unzoom_y || unzoom_z) { + if (unzoom_x) { + if (this.zoom_xmin !== this.zoom_xmax) changed = true; + this.zoom_xmin = this.zoom_xmax = 0; + } + if (unzoom_y) { + if (this.zoom_ymin !== this.zoom_ymax) changed = true; + this.zoom_ymin = this.zoom_ymax = 0; + } + if (unzoom_z) { + if (this.zoom_zmin !== this.zoom_zmax) changed = true; + this.zoom_zmin = this.zoom_zmax = 0; + } + + // first try to unzoom all overlapped objects + if (!changed) { + // than try to unzoom all overlapped objects + var pp = this.pad_painter(); + if (pp && pp.painters) + pp.painters.forEach(function(paint){ + if (paint && (typeof paint.UnzoomUserRange == 'function')) + if (paint.UnzoomUserRange(unzoom_x, unzoom_y, unzoom_z)) changed = true; + }); + } + } + + if (changed) + this.InteractiveRedraw("pad", "zoom"); + + return changed; + } + + TFramePainter.prototype.IsAxisZoomed = function(axis) { + return this['zoom_'+axis+'min'] !== this['zoom_'+axis+'max']; + } + + TFramePainter.prototype.Unzoom = function(dox, doy, doz) { + if (typeof dox === 'undefined') { dox = true; doy = true; doz = true; } else + if (typeof dox === 'string') { doz = dox.indexOf("z")>=0; doy = dox.indexOf("y")>=0; dox = dox.indexOf("x")>=0; } + + var last = this.zoom_changed_interactive; + + if (dox || doy || doz) this.zoom_changed_interactive = 2; + + var changed = this.Zoom(dox ? 0 : undefined, dox ? 0 : undefined, + doy ? 0 : undefined, doy ? 0 : undefined, + doz ? 0 : undefined, doz ? 0 : undefined); + + // if unzooming has no effect, decrease counter + if ((dox || doy || doz) && !changed) + this.zoom_changed_interactive = (!isNaN(last) && (last>0)) ? last - 1 : 0; + + return changed; + } + + TFramePainter.prototype.AnalyzeMouseWheelEvent = function(event, item, dmin, ignore) { + + item.min = item.max = undefined; + item.changed = false; + if (ignore && item.ignore) return; + + var delta = 0, delta_left = 1, delta_right = 1; + + if ('dleft' in item) { delta_left = item.dleft; delta = 1; } + if ('dright' in item) { delta_right = item.dright; delta = 1; } + + if ('delta' in item) { + delta = item.delta; + } else if (event && event.wheelDelta !== undefined ) { + // WebKit / Opera / Explorer 9 + delta = -event.wheelDelta; + } else if (event && event.deltaY !== undefined ) { + // Firefox + delta = event.deltaY; + } else if (event && event.detail !== undefined) { + delta = event.detail; + } + + if (delta===0) return; + delta = (delta<0) ? -0.2 : 0.2; + + delta_left *= delta + delta_right *= delta; + + var lmin = item.min = this["scale_"+item.name+"min"], + lmax = item.max = this["scale_"+item.name+"max"], + gmin = this[item.name+"min"], + gmax = this[item.name+"max"]; + + if ((item.min === item.max) && (delta<0)) { + item.min = gmin; + item.max = gmax; + } + + if (item.min >= item.max) return; + + if ((dmin>0) && (dmin<1)) { + if (this['log'+item.name]) { + var factor = (item.min>0) ? JSROOT.log10(item.max/item.min) : 2; + if (factor>10) factor = 10; else if (factor<0.01) factor = 0.01; + item.min = item.min / Math.pow(10, factor*delta_left*dmin); + item.max = item.max * Math.pow(10, factor*delta_right*(1-dmin)); + } else { + var rx_left = (item.max - item.min), rx_right = rx_left; + if (delta_left>0) rx_left = 1.001 * rx_left / (1-delta_left); + item.min += -delta_left*dmin*rx_left; + + if (delta_right>0) rx_right = 1.001 * rx_right / (1-delta_right); + + item.max -= -delta_right*(1-dmin)*rx_right; + } + if (item.min >= item.max) + item.min = item.max = undefined; + else + if (delta_left !== delta_right) { + // extra check case when moving left or right + if (((item.min < gmin) && (lmin===gmin)) || + ((item.max > gmax) && (lmax==gmax))) + item.min = item.max = undefined; + } + + } else { + item.min = item.max = undefined; + } + + item.changed = ((item.min !== undefined) && (item.max !== undefined)); + } + + TFramePainter.prototype.AllowDefaultYZooming = function() { + // return true if default Y zooming should be enabled + // it is typically for 2-Dim histograms or + // when histogram not draw, defined by other painters + + var pad_painter = this.pad_painter(); + if (pad_painter && pad_painter.painters) + for (var k = 0; k < pad_painter.painters.length; ++k) { + var subpainter = pad_painter.painters[k]; + if (subpainter && (subpainter.wheel_zoomy !== undefined)) + return subpainter.wheel_zoomy; + } + + return false; + } + + TFramePainter.prototype.mouseWheel = function() { + d3.event.stopPropagation(); + + d3.event.preventDefault(); + this.clearInteractiveElements(); + + var itemx = { name: "x", ignore: false }, + itemy = { name: "y", ignore: !this.AllowDefaultYZooming() }, + cur = d3.mouse(this.svg_frame().node()), + w = this.frame_width(), h = this.frame_height(); + + this.AnalyzeMouseWheelEvent(d3.event, this.swap_xy ? itemy : itemx, cur[0] / w, (cur[1] >=0) && (cur[1] <= h)); + + this.AnalyzeMouseWheelEvent(d3.event, this.swap_xy ? itemx : itemy, 1 - cur[1] / h, (cur[0] >= 0) && (cur[0] <= w)); + + this.Zoom(itemx.min, itemx.max, itemy.min, itemy.max); + + if (itemx.changed || itemy.changed) this.zoom_changed_interactive = 2; + } + + TFramePainter.prototype.startTouchZoom = function() { + // in case when zooming was started, block any other kind of events + if (this.zoom_kind != 0) { + d3.event.preventDefault(); + d3.event.stopPropagation(); + return; + } + + var arr = d3.touches(this.svg_frame().node()); + this.touch_cnt+=1; + + // normally double-touch will be handled + // touch with single click used for context menu + if (arr.length == 1) { + // this is touch with single element + + var now = new Date(), diff = now.getTime() - this.last_touch.getTime(); + this.last_touch = now; + + if ((diff < 300) && this.zoom_curr + && (Math.abs(this.zoom_curr[0] - arr[0][0]) < 30) + && (Math.abs(this.zoom_curr[1] - arr[0][1]) < 30)) { + + d3.event.preventDefault(); + d3.event.stopPropagation(); + + this.clearInteractiveElements(); + this.Unzoom("xyz"); + + this.last_touch = new Date(0); + + this.svg_frame().on("touchcancel", null) + .on("touchend", null, true); + } else + if (JSROOT.gStyle.ContextMenu) { + this.zoom_curr = arr[0]; + this.svg_frame().on("touchcancel", this.endTouchSel.bind(this)) + .on("touchend", this.endTouchSel.bind(this)); + d3.event.preventDefault(); + d3.event.stopPropagation(); + } + } + + if ((arr.length != 2) || !JSROOT.gStyle.Zooming || !JSROOT.gStyle.ZoomTouch) return; + + d3.event.preventDefault(); + d3.event.stopPropagation(); + + this.clearInteractiveElements(); + + this.svg_frame().on("touchcancel", null) + .on("touchend", null); + + var pnt1 = arr[0], pnt2 = arr[1], w = this.frame_width(), h = this.frame_height(); + + this.zoom_curr = [ Math.min(pnt1[0], pnt2[0]), Math.min(pnt1[1], pnt2[1]) ]; + this.zoom_origin = [ Math.max(pnt1[0], pnt2[0]), Math.max(pnt1[1], pnt2[1]) ]; + + if ((this.zoom_curr[0] < 0) || (this.zoom_curr[0] > w)) { + this.zoom_kind = 103; // only y + this.zoom_curr[0] = 0; + this.zoom_origin[0] = w; + } else if ((this.zoom_origin[1] > h) || (this.zoom_origin[1] < 0)) { + this.zoom_kind = 102; // only x + this.zoom_curr[1] = 0; + this.zoom_origin[1] = h; + } else { + this.zoom_kind = 101; // x and y + } + + this.SwitchTooltip(false); + + this.zoom_rect = this.svg_frame().append("rect") + .attr("class", "zoom") + .attr("id", "zoomRect") + .attr("x", this.zoom_curr[0]) + .attr("y", this.zoom_curr[1]) + .attr("width", this.zoom_origin[0] - this.zoom_curr[0]) + .attr("height", this.zoom_origin[1] - this.zoom_curr[1]); + + d3.select(window).on("touchmove.zoomRect", this.moveTouchSel.bind(this)) + .on("touchcancel.zoomRect", this.endTouchSel.bind(this)) + .on("touchend.zoomRect", this.endTouchSel.bind(this)); + } + + TFramePainter.prototype.moveTouchSel = function() { + if (this.zoom_kind < 100) return; + + d3.event.preventDefault(); + + var arr = d3.touches(this.svg_frame().node()); + + if (arr.length != 2) + return this.clearInteractiveElements(); + + var pnt1 = arr[0], pnt2 = arr[1]; + + if (this.zoom_kind != 103) { + this.zoom_curr[0] = Math.min(pnt1[0], pnt2[0]); + this.zoom_origin[0] = Math.max(pnt1[0], pnt2[0]); + } + if (this.zoom_kind != 102) { + this.zoom_curr[1] = Math.min(pnt1[1], pnt2[1]); + this.zoom_origin[1] = Math.max(pnt1[1], pnt2[1]); + } + + this.zoom_rect.attr("x", this.zoom_curr[0]) + .attr("y", this.zoom_curr[1]) + .attr("width", this.zoom_origin[0] - this.zoom_curr[0]) + .attr("height", this.zoom_origin[1] - this.zoom_curr[1]); + + if ((this.zoom_origin[0] - this.zoom_curr[0] > 10) + || (this.zoom_origin[1] - this.zoom_curr[1] > 10)) + this.SwitchTooltip(false); + + d3.event.stopPropagation(); + } + + TFramePainter.prototype.endTouchSel = function() { + + this.svg_frame().on("touchcancel", null) + .on("touchend", null); + + if (this.zoom_kind === 0) { + // special case - single touch can ends up with context menu + + d3.event.preventDefault(); + + var now = new Date(); + + var diff = now.getTime() - this.last_touch.getTime(); + + if ((diff > 500) && (diff<2000) && !this.frame_painter().IsTooltipShown()) { + this.ShowContextMenu('main', { clientX: this.zoom_curr[0], clientY: this.zoom_curr[1] }); + this.last_touch = new Date(0); + } else { + this.clearInteractiveElements(); + } + } + + if (this.zoom_kind < 100) return; + + d3.event.preventDefault(); + d3.select(window).on("touchmove.zoomRect", null) + .on("touchend.zoomRect", null) + .on("touchcancel.zoomRect", null); + + var xmin, xmax, ymin, ymax, isany = false, + xid = this.swap_xy ? 1 : 0, yid = 1 - xid, + changed = [true, true]; + if (this.zoom_kind === 102) changed[1] = false; + if (this.zoom_kind === 103) changed[0] = false; + + if (changed[xid] && (Math.abs(this.zoom_curr[xid] - this.zoom_origin[xid]) > 10)) { + xmin = Math.min(this.RevertX(this.zoom_origin[xid]), this.RevertX(this.zoom_curr[xid])); + xmax = Math.max(this.RevertX(this.zoom_origin[xid]), this.RevertX(this.zoom_curr[xid])); + isany = true; + } + + if (changed[yid] && (Math.abs(this.zoom_curr[yid] - this.zoom_origin[yid]) > 10)) { + ymin = Math.min(this.RevertY(this.zoom_origin[yid]), this.RevertY(this.zoom_curr[yid])); + ymax = Math.max(this.RevertY(this.zoom_origin[yid]), this.RevertY(this.zoom_curr[yid])); + isany = true; + } + + this.clearInteractiveElements(); + this.last_touch = new Date(0); + + if (isany) { + this.zoom_changed_interactive = 2; + this.Zoom(xmin, xmax, ymin, ymax); + } + + d3.event.stopPropagation(); + } + + TFramePainter.prototype.ShowContextMenu = function(kind, evnt, obj) { + // ignore context menu when touches zooming is ongoing + if (('zoom_kind' in this) && (this.zoom_kind > 100)) return; + + // this is for debug purposes only, when context menu is where, close is and show normal menu + //if (!evnt && !kind && document.getElementById('root_ctx_menu')) { + // var elem = document.getElementById('root_ctx_menu'); + // elem.parentNode.removeChild(elem); + // return; + //} + + var menu_painter = this, exec_painter = null, frame_corner = false, fp = null; // object used to show context menu + + if (!evnt) { + d3.event.preventDefault(); + d3.event.stopPropagation(); // disable main context menu + evnt = d3.event; + + if (kind === undefined) { + var ms = d3.mouse(this.svg_frame().node()), + tch = d3.touches(this.svg_frame().node()), + pp = this.pad_painter(), + pnt = null, sel = null; + + fp = this; + + if (tch.length === 1) pnt = { x: tch[0][0], y: tch[0][1], touch: true }; else + if (ms.length === 2) pnt = { x: ms[0], y: ms[1], touch: false }; + + if ((pnt !== null) && (pp !== null)) { + pnt.painters = true; // assign painter for every tooltip + var hints = pp.GetTooltips(pnt), bestdist = 1000; + for (var n=0;n<hints.length;++n) + if (hints[n] && hints[n].menu) { + var dist = ('menu_dist' in hints[n]) ? hints[n].menu_dist : 7; + if (dist < bestdist) { sel = hints[n].painter; bestdist = dist; } + } + } + + if (sel) menu_painter = sel; else kind = "frame"; + + if (pnt) frame_corner = (pnt.x>0) && (pnt.x<20) && (pnt.y>0) && (pnt.y<20); + + fp.SetLastEventPos(pnt); + } else if ((kind=="x") || (kind=="y") || (kind=="z")) { + exec_painter = this.main_painter(); // histogram painter delivers items for axis menu + } + } + + // one need to copy event, while after call back event may be changed + menu_painter.ctx_menu_evnt = evnt; + + if (!exec_painter) exec_painter = menu_painter; + + JSROOT.Painter.createMenu(menu_painter, function(menu) { + var domenu = menu.painter.FillContextMenu(menu, kind, obj); + + // fill frame menu by default - or append frame elements when activated in the frame corner + if (fp && (!domenu || (frame_corner && (kind!=="frame")))) + domenu = fp.FillContextMenu(menu); + + if (domenu) + exec_painter.FillObjectExecMenu(menu, kind, function() { + // suppress any running zooming + menu.painter.SwitchTooltip(false); + menu.show(menu.painter.ctx_menu_evnt, menu.painter.SwitchTooltip.bind(menu.painter, true)); + }); + + }); // end menu creation + } + + TFramePainter.prototype.ShowAxisStatus = function(axis_name) { + // method called normally when mouse enter main object element + + var status_func = this.GetShowStatusFunc(); + + if (!status_func) return; + + var taxis = this.histo ? this.histo['f'+axis_name.toUpperCase()+"axis"] : null; + + var hint_name = axis_name, hint_title = "TAxis"; + + if (taxis) { hint_name = taxis.fName; hint_title = taxis.fTitle || "histogram TAxis object"; } + + var m = d3.mouse(this.svg_frame().node()); + + var id = (axis_name=="x") ? 0 : 1; + if (this.swap_xy) id = 1-id; + + var axis_value = (axis_name=="x") ? this.RevertX(m[id]) : this.RevertY(m[id]); + + status_func(hint_name, hint_title, axis_name + " : " + this.AxisAsText(axis_name, axis_value), + m[0].toFixed(0)+","+ m[1].toFixed(0)); + } + + TFramePainter.prototype.AddInteractive = function() { + + if (JSROOT.BatchMode || (!JSROOT.gStyle.Zooming && !JSROOT.gStyle.ContextMenu)) return; + + var pp = this.pad_painter(); + if (pp && pp._fast_drawing) return; + + var svg = this.svg_frame(); + + if (svg.empty()) return; + + var svg_x = svg.selectAll(".xaxis_container"), + svg_y = svg.selectAll(".yaxis_container"); + + if (!svg.property('interactive_set')) { + this.AddKeysHandler(); + + this.last_touch = new Date(0); + this.zoom_kind = 0; // 0 - none, 1 - XY, 2 - only X, 3 - only Y, (+100 for touches) + this.zoom_rect = null; + this.zoom_origin = null; // original point where zooming started + this.zoom_curr = null; // current point for zooming + this.touch_cnt = 0; + } + + if (JSROOT.gStyle.Zooming && !this.projection) { + if (JSROOT.gStyle.ZoomMouse) { + svg.on("mousedown", this.startRectSel.bind(this)); + svg.on("dblclick", this.mouseDoubleClick.bind(this)); + } + if (JSROOT.gStyle.ZoomWheel) { + svg.on("wheel", this.mouseWheel.bind(this)); + } + } + + if (JSROOT.touches && ((JSROOT.gStyle.Zooming && JSROOT.gStyle.ZoomTouch && !this.projection) || JSROOT.gStyle.ContextMenu)) + svg.on("touchstart", this.startTouchZoom.bind(this)); + + if (JSROOT.gStyle.ContextMenu) { + if (JSROOT.touches) { + svg_x.on("touchstart", this.startTouchMenu.bind(this,"x")); + svg_y.on("touchstart", this.startTouchMenu.bind(this,"y")); + } + svg.on("contextmenu", this.ShowContextMenu.bind(this)); + svg_x.on("contextmenu", this.ShowContextMenu.bind(this,"x")); + svg_y.on("contextmenu", this.ShowContextMenu.bind(this,"y")); + } + + svg_x.on("mousemove", this.ShowAxisStatus.bind(this,"x")); + svg_y.on("mousemove", this.ShowAxisStatus.bind(this,"y")); + + svg.property('interactive_set', true); + } + + function drawFrame(divid, obj, opt) { + var p = new TFramePainter(obj); + if (opt == "3d") p.mode3d = true; + p.SetDivId(divid, 2); + p.Redraw(); + return p.DrawingReady(); + } + + // =========================================================================== + + /** + * @summary Painter for TPad object. + * + * @constructor + * @memberof JSROOT + * @augments JSROOT.TObjectPainter + * @param {object} pad - TPad object to draw + * @param {boolean} iscan - if TCanvas object + */ + + function TPadPainter(pad, iscan) { + JSROOT.TObjectPainter.call(this, pad); + this.pad = pad; + this.iscan = iscan; // indicate if working with canvas + this.this_pad_name = ""; + if (!this.iscan && (pad !== null) && ('fName' in pad)) { + this.this_pad_name = pad.fName.replace(" ", "_"); // avoid empty symbol in pad name + var regexp = new RegExp("^[A-Za-z][A-Za-z0-9_]*$"); + if (!regexp.test(this.this_pad_name)) this.this_pad_name = 'jsroot_pad_' + JSROOT.id_counter++; + } + this.painters = []; // complete list of all painters in the pad + this.has_canvas = true; + } + + TPadPainter.prototype = Object.create(JSROOT.TObjectPainter.prototype); + + TPadPainter.prototype.Cleanup = function() { + // cleanup only pad itself, all child elements will be collected and cleanup separately + + for (var k=0;k<this.painters.length;++k) + this.painters[k].Cleanup(); + + var svg_p = this.svg_pad(this.this_pad_name); + if (!svg_p.empty()) { + svg_p.property('pad_painter', null); + svg_p.property('mainpainter', null); + if (!this.iscan) svg_p.remove(); + } + + delete this.frame_painter_ref; + delete this.pads_cache; + delete this.custom_palette; + + this.painters = []; + this.pad = null; + this.this_pad_name = ""; + this.has_canvas = false; + + JSROOT.Painter.SelectActivePad({ pp: this, active: false }); + + JSROOT.TObjectPainter.prototype.Cleanup.call(this); + } + + /** @summary Cleanup primitives from pad - selector lets define which painters to remove + * @private + */ + + TPadPainter.prototype.CleanPrimitives = function(selector) { + if (!selector || (typeof selector !== 'function')) return; + + for (var k = this.painters.length-1; k >= 0; --k) + if (selector(this.painters[k])) { + this.painters[k].Cleanup(); + this.painters.splice(k, 1); + } + } + + /** @summary Generates automatic color for some objects painters + * @private + */ + TPadPainter.prototype.CreateAutoColor = function() { + var pp = this.canv_painter(), + pad = this.root_pad(), + numprimitives = pad && pad.fPrimitves ? pad.fPrimitves.arr.length : 5; + + var pal = this.get_palette(true); + + var indx = this._auto_color || 0; + this._auto_color = indx+1; + + if (pal) { + if (numprimitives<2) numprimitives = 2; + if (indx >= numprimitives) indx = numprimitives - 1; + var palindx = Math.round(indx * (pal.getLength()-3) / (numprimitives-1)); + var colvalue = pal.getColor(palindx); + var colindx = this.add_color(colvalue); + return colindx; + } + + this._auto_color = this._auto_color % 8; + return indx+2; + } + + /// call function for each painter + /// kind == "all" for all objects (default) + /// kind == "pads" only pads and subpads + /// kind == "objects" only for object in current pad + TPadPainter.prototype.ForEachPainterInPad = function(userfunc, kind) { + if (!kind) kind = "all"; + if (kind!="objects") userfunc(this); + for (var k = 0; k < this.painters.length; ++k) { + var sub = this.painters[k]; + if (typeof sub.ForEachPainterInPad === 'function') { + if (kind!="objects") sub.ForEachPainterInPad(userfunc, kind); + } else if (kind != "pads") userfunc(sub); + } + } + + TPadPainter.prototype.ButtonSize = function(fact) { + return Math.round((!fact ? 1 : fact) * (this.iscan || !this.has_canvas ? 16 : 12)); + } + + /// Retrive different event when object selected or pad is redrawn + TPadPainter.prototype.RegisterForPadEvents = function(receiver) { + this.pad_events_receiver = receiver; + } + + /// method redirect call to pad events receiver + TPadPainter.prototype.SelectObjectPainter = function(_painter, pos) { + var istoppad = (this.iscan || !this.has_canvas), + canp = istoppad ? this : this.canv_painter(), + pp = _painter instanceof TPadPainter ? _painter : _painter.pad_painter(); + + if (pos && !istoppad) + this.CalcAbsolutePosition(this.svg_pad(this.this_pad_name), pos); + + JSROOT.Painter.SelectActivePad({ pp: pp, active: true }); + + if (typeof canp.SelectActivePad == "function") + canp.SelectActivePad(pp, _painter, pos); + + if (canp.pad_events_receiver) + canp.pad_events_receiver({ what: "select", padpainter: pp, painter: _painter, position: pos }); + } + + /// method redirect call to pad events receiver + TPadPainter.prototype.InteractiveObjectRedraw = function(_painter) { + var canp = (this.iscan || !this.has_canvas) ? this : this.canv_painter(), + pp = _painter instanceof TPadPainter ? _painter : _painter.pad_painter(); + + if (canp && canp.pad_events_receiver) + canp.pad_events_receiver({ what: "redraw", padpainter: pp, painter: _painter }); + } + + /** @brief Called by framework when pad is supposed to be active and get focus + * @private */ + TPadPainter.prototype.SetActive = function(on) { + var fp = this.frame_painter(); + if (fp && (typeof fp.SetActive == 'function')) fp.SetActive(on); + } + + /** @brief Draw pad active border + * @private */ + TPadPainter.prototype.DrawActiveBorder = function(svg_rect, is_active) { + if (is_active !== undefined) { + if (this.is_active_pad === is_active) return; + this.is_active_pad = is_active; + } + + if (this.is_active_pad === undefined) return; + + if (!svg_rect) + svg_rect = this.iscan ? this.svg_canvas().select(".canvas_fillrect") : + this.svg_pad(this.this_pad_name).select(".root_pad_border"); + + var lineatt = this.is_active_pad ? new JSROOT.TAttLineHandler({ style: 1, width: 1, color: "red" }) : this.lineatt; + + if (!lineatt) lineatt = new JSROOT.TAttLineHandler({ color: "none" }); + + svg_rect.call(lineatt.func); + } + + TPadPainter.prototype.CreateCanvasSvg = function(check_resize, new_size) { + + var factor = null, svg = null, lmt = 5, rect = null, btns; + + if (check_resize > 0) { + + if (this._fixed_size) return (check_resize > 1); // flag used to force re-drawing of all subpads + + svg = this.svg_canvas(); + + if (svg.empty()) return false; + + factor = svg.property('height_factor'); + + rect = this.check_main_resize(check_resize, null, factor); + + if (!rect.changed) return false; + + btns = this.svg_layer("btns_layer"); + + } else { + + var render_to = this.select_main(); + + if (render_to.style('position')=='static') + render_to.style('position','relative'); + + svg = render_to.append("svg") + .attr("class", "jsroot root_canvas") + .property('pad_painter', this) // this is custom property + .property('mainpainter', null) // this is custom property + .property('current_pad', "") // this is custom property + .property('redraw_by_resize', false); // could be enabled to force redraw by each resize + + if (JSROOT.BatchMode) { + svg.attr("xmlns", "http://www.w3.org/2000/svg"); + svg.attr("xmlns:xlink", "http://www.w3.org/1999/xlink"); + } + + svg.append("svg:title").text("ROOT canvas"); + var frect = svg.append("svg:rect").attr("class","canvas_fillrect") + .attr("x",0).attr("y",0); + if (!JSROOT.BatchMode) + frect.style("pointer-events", "visibleFill") + .on("dblclick", this.EnlargePad.bind(this)) + .on("click", this.SelectObjectPainter.bind(this, this)) + .on("mouseenter", this.ShowObjectStatus.bind(this)); + + svg.append("svg:g").attr("class","primitives_layer"); + svg.append("svg:g").attr("class","info_layer"); + btns = svg.append("svg:g").attr("class","btns_layer") + .property('leftside', JSROOT.gStyle.ToolBarSide == 'left') + .property('vertical', JSROOT.gStyle.ToolBarVert); + + if (JSROOT.gStyle.ContextMenu) + svg.select(".canvas_fillrect").on("contextmenu", this.ShowContextMenu.bind(this)); + + factor = 0.66; + if (this.pad && this.pad.fCw && this.pad.fCh && (this.pad.fCw > 0)) { + factor = this.pad.fCh / this.pad.fCw; + if ((factor < 0.1) || (factor > 10)) factor = 0.66; + } + + if (this._fixed_size) { + render_to.style("overflow","auto"); + rect = { width: this.pad.fCw, height: this.pad.fCh }; + } else { + rect = this.check_main_resize(2, new_size, factor); + } + } + + this.createAttFill({ attr: this.pad }); + + if ((rect.width<=lmt) || (rect.height<=lmt)) { + svg.style("display", "none"); + console.warn("Hide canvas while geometry too small w=" + rect.width + " h=" + rect.height); + rect.width = 200; rect.height = 100; // just to complete drawing + } else { + svg.style("display", null); + } + + if (this._fixed_size) { + svg.attr("x", 0) + .attr("y", 0) + .attr("width", rect.width) + .attr("height", rect.height) + .style("position", "absolute"); + } else { + svg.attr("x", 0) + .attr("y", 0) + .style("width", "100%") + .style("height", "100%") + .style("position", "absolute") + .style("left", 0) + .style("top", 0) + .style("right", 0) + .style("bottom", 0); + } + + // console.log('CANVAS SVG width = ' + rect.width + " height = " + rect.height); + + svg.attr("viewBox", "0 0 " + rect.width + " " + rect.height) + .attr("preserveAspectRatio", "none") // we do not preserve relative ratio + .property('height_factor', factor) + .property('draw_x', 0) + .property('draw_y', 0) + .property('draw_width', rect.width) + .property('draw_height', rect.height); + + var fill_rect = svg.select(".canvas_fillrect") + .attr("width", rect.width) + .attr("height", rect.height) + .call(this.fillatt.func); + + this._fast_drawing = JSROOT.gStyle.SmallPad && ((rect.width < JSROOT.gStyle.SmallPad.width) || (rect.height < JSROOT.gStyle.SmallPad.height)); + + this.DrawActiveBorder(fill_rect); + + this.AlignBtns(btns, rect.width, rect.height, svg); + + return true; + } + + TPadPainter.prototype.EnlargePad = function() { + + if (d3.event) { + d3.event.preventDefault(); + d3.event.stopPropagation(); + } + + var svg_can = this.svg_canvas(), + pad_enlarged = svg_can.property("pad_enlarged"); + + if (this.iscan || !this.has_canvas || (!pad_enlarged && !this.HasObjectsToDraw() && !this.painters)) { + if (this._fixed_size) return; // canvas cannot be enlarged in such mode + if (!this.enlarge_main('toggle')) return; + if (this.enlarge_main('state')=='off') svg_can.property("pad_enlarged", null); + } else if (!pad_enlarged) { + this.enlarge_main(true, true); + svg_can.property("pad_enlarged", this.pad); + } else if (pad_enlarged === this.pad) { + this.enlarge_main(false); + svg_can.property("pad_enlarged", null); + } else { + console.error('missmatch with pad double click events'); + } + + var was_fast = this._fast_drawing; + + this.CheckResize({ force: true }); + + if (this._fast_drawing != was_fast) + this.ShowButtons(); + } + + TPadPainter.prototype.CreatePadSvg = function(only_resize) { + // returns true when pad is displayed and all its items should be redrawn + + if (!this.has_canvas) { + this.CreateCanvasSvg(only_resize ? 2 : 0); + return true; + } + + var svg_can = this.svg_canvas(), + width = svg_can.property("draw_width"), + height = svg_can.property("draw_height"), + pad_enlarged = svg_can.property("pad_enlarged"), + pad_visible = !pad_enlarged || (pad_enlarged === this.pad), + w = Math.round(this.pad.fAbsWNDC * width), + h = Math.round(this.pad.fAbsHNDC * height), + x = Math.round(this.pad.fAbsXlowNDC * width), + y = Math.round(height * (1 - this.pad.fAbsYlowNDC)) - h, + svg_pad = null, svg_rect = null, btns = null; + + if (pad_enlarged === this.pad) { w = width; h = height; x = y = 0; } + + if (only_resize) { + svg_pad = this.svg_pad(this.this_pad_name); + svg_rect = svg_pad.select(".root_pad_border"); + btns = this.svg_layer("btns_layer", this.this_pad_name); + } else { + svg_pad = svg_can.select(".primitives_layer") + .append("svg:svg") // here was g before, svg used to blend all drawin outside + .classed("__root_pad_" + this.this_pad_name, true) + .attr("pad", this.this_pad_name) // set extra attribute to mark pad name + .property('pad_painter', this) // this is custom property + .property('mainpainter', null); // this is custom property + svg_rect = svg_pad.append("svg:rect").attr("class", "root_pad_border"); + + svg_pad.append("svg:g").attr("class","primitives_layer"); + btns = svg_pad.append("svg:g").attr("class","btns_layer") + .property('leftside', JSROOT.gStyle.ToolBarSide != 'left') + .property('vertical', JSROOT.gStyle.ToolBarVert); + + if (JSROOT.gStyle.ContextMenu) + svg_rect.on("contextmenu", this.ShowContextMenu.bind(this)); + + if (!JSROOT.BatchMode) + svg_rect.attr("pointer-events", "visibleFill") // get events also for not visible rect + .on("dblclick", this.EnlargePad.bind(this)) + .on("click", this.SelectObjectPainter.bind(this, this)) + .on("mouseenter", this.ShowObjectStatus.bind(this)); + } + + this.createAttFill({ attr: this.pad }); + this.createAttLine({ attr: this.pad, color0: this.pad.fBorderMode == 0 ? 'none' : '' }); + + svg_pad + //.attr("transform", "translate(" + x + "," + y + ")") // is not handled for SVG + .attr("display", pad_visible ? null : "none") + .attr("viewBox", "0 0 " + w + " " + h) // due to svg + .attr("preserveAspectRatio", "none") // due to svg, we do not preserve relative ratio + .attr("x", x) // due to svg + .attr("y", y) // due to svg + .attr("width", w) // due to svg + .attr("height", h) // due to svg + .property('draw_x', x) // this is to make similar with canvas + .property('draw_y', y) + .property('draw_width', w) + .property('draw_height', h); + + svg_rect.attr("x", 0) + .attr("y", 0) + .attr("width", w) + .attr("height", h) + .call(this.fillatt.func) + .call(this.lineatt.func); + + this.DrawActiveBorder(svg_rect); + + this._fast_drawing = JSROOT.gStyle.SmallPad && ((w < JSROOT.gStyle.SmallPad.width) || (h < JSROOT.gStyle.SmallPad.height)); + + if (svg_pad.property('can3d') === 1) + // special case of 3D canvas overlay + this.select_main() + .select(".draw3d_" + this.this_pad_name) + .style('display', pad_visible ? '' : 'none'); + + this.AlignBtns(btns, w, h); + + return pad_visible; + } + + TPadPainter.prototype.CheckSpecial = function(obj) { + + if (!obj || (obj._typename!=="TObjArray")) return false; + + if (obj.name == "ListOfColors") { + + if (this.options && this.options.CreatePalette) { + var arr = []; + for (var n = obj.arr.length - this.options.CreatePalette; n<obj.arr.length; ++n) { + var col = JSROOT.Painter.MakeColorRGB(obj.arr[n]); + if (!col) { console.log('Fail to create color for palette'); arr = null; break; } + arr.push(col); + } + if (arr) this.custom_palette = new JSROOT.ColorPalette(arr); + } + + if (!this.options || this.options.GlobalColors) // set global list of colors + JSROOT.Painter.adoptRootColors(obj); + + // copy existing colors and extend with new values + if (this.options && this.options.LocalColors) + this.root_colors = JSROOT.Painter.extendRootColors(null, obj); + return true; + } + + if (obj.name == "CurrentColorPalette") { + var arr = [], missing = false; + for (var n = 0; n < obj.arr.length; ++n) { + var col = obj.arr[n]; + if (col && (col._typename == 'TColor')) { + arr[n] = JSROOT.Painter.MakeColorRGB(col); + } else { + console.log('Missing color with index ' + n); missing = true; + } + } + if (!this.options || (!missing && !this.options.IgnorePalette)) + this.custom_palette = new JSROOT.ColorPalette(arr); + return true; + } + + return false; + } + + TPadPainter.prototype.CheckSpecialsInPrimitives = function(can) { + var lst = can ? can.fPrimitives : null; + if (!lst) return; + for (var i = 0; i < lst.arr.length; ++i) { + if (this.CheckSpecial(lst.arr[i])) { + lst.arr.splice(i,1); + lst.opt.splice(i,1); + i--; + } + } + } + + TPadPainter.prototype.RemovePrimitive = function(obj) { + if (!this.pad || !this.pad.fPrimitives) return; + var indx = this.pad.fPrimitives.arr.indexOf(obj); + if (indx>=0) this.pad.fPrimitives.RemoveAt(indx); + } + + TPadPainter.prototype.FindPrimitive = function(exact_obj, classname, name) { + if (!this.pad || !this.pad.fPrimitives) return null; + + for (var i=0; i < this.pad.fPrimitives.arr.length; i++) { + var obj = this.pad.fPrimitives.arr[i]; + + if ((exact_obj!==null) && (obj !== exact_obj)) continue; + + if ((classname !== undefined) && (classname !== null)) + if (obj._typename !== classname) continue; + + if ((name !== undefined) && (name !== null)) + if (obj.fName !== name) continue; + + return obj; + } + + return null; + } + + TPadPainter.prototype.HasObjectsToDraw = function() { + // return true if any objects beside sub-pads exists in the pad + + if (!this.pad || !this.pad.fPrimitives) return false; + + for (var n=0;n<this.pad.fPrimitives.arr.length;++n) + if (this.pad.fPrimitives.arr[n] && this.pad.fPrimitives.arr[n]._typename != "TPad") return true; + + return false; + } + + TPadPainter.prototype.DrawPrimitives = function(indx, callback, ppainter) { + + if (indx===0) { + // flag used to prevent immediate pad redraw during normal drawing sequence + this._doing_pad_draw = true; + + if (this.iscan) + this._start_tm = this._lasttm_tm = new Date().getTime(); + + // set number of primitves + this._num_primitives = this.pad && this.pad.fPrimitives ? this.pad.fPrimitives.arr.length : 0; + } + + while (true) { + if (ppainter && (typeof ppainter=='object')) ppainter._primitive = true; // mark painter as belonging to primitives + + if (!this.pad || (indx >= this.pad.fPrimitives.arr.length)) { + delete this._doing_pad_draw; + delete this._current_primitive_indx; + if (this._start_tm) { + var spenttm = new Date().getTime() - this._start_tm; + if (spenttm > 200) console.log("Canvas drawing took " + (spenttm*1e-3).toFixed(2) + "s"); + delete this._start_tm; + delete this._lasttm_tm; + } + + return JSROOT.CallBack(callback); + } + + // handle use to invoke callback only when necessary + var handle = { func: this.DrawPrimitives.bind(this, indx+1, callback) }; + + // set current index + this._current_primitive_indx = indx; + + ppainter = JSROOT.draw(this.divid, this.pad.fPrimitives.arr[indx], this.pad.fPrimitives.opt[indx], handle); + + indx++; + + if (!handle.completed) return; + + if (!JSROOT.BatchMode && this.iscan) { + var curtm = new Date().getTime(); + if (curtm > this._lasttm_tm + 15000) { + this._lasttm_tm = curtm; + ppainter._primitive = true; // mark primitive ourself + return requestAnimationFrame(handle.func); + } + } + } + } + + TPadPainter.prototype.GetTooltips = function(pnt) { + var painters = [], hints = []; + + // first count - how many processors are there + if (this.painters !== null) + this.painters.forEach(function(obj) { + if ('ProcessTooltip' in obj) painters.push(obj); + }); + + if (pnt) pnt.nproc = painters.length; + + painters.forEach(function(obj) { + var hint = obj.ProcessTooltip(pnt); + if (!hint) hint = { user_info: null }; + hints.push(hint); + if (hint && pnt && pnt.painters) hint.painter = obj; + }); + + return hints; + } + + TPadPainter.prototype.FillContextMenu = function(menu) { + + if (this.pad) + menu.add("header: " + this.pad._typename + "::" + this.pad.fName); + else + menu.add("header: Canvas"); + + menu.addchk(this.IsTooltipAllowed(), "Show tooltips", this.SetTooltipAllowed.bind(this, "toggle")); + + if (!this._websocket) { + + function SetPadField(arg) { + this.pad[arg.substr(1)] = parseInt(arg[0]); + var main = this.svg_pad(this.this_pad_name).property('mainpainter'); + if (main && (typeof main.DrawAxes == 'function')) main.DrawAxes(); + var canp = this.canv_painter(); + if (canp) canp.ProcessChanges(arg.substr(1), this.pad_painter()); + } + + menu.addchk(this.pad.fGridx, 'Grid x', (this.pad.fGridx ? '0' : '1') + 'fGridx', SetPadField); + menu.addchk(this.pad.fGridy, 'Grid y', (this.pad.fGridy ? '0' : '1') + 'fGridy', SetPadField); + menu.add("sub:Ticks x"); + menu.addchk(this.pad.fTickx == 0, "normal", "0fTickx", SetPadField); + menu.addchk(this.pad.fTickx == 1, "ticks on both sides", "1fTickx", SetPadField); + menu.addchk(this.pad.fTickx == 2, "labels on both sides", "2fTickx", SetPadField); + menu.add("endsub:"); + menu.add("sub:Ticks y"); + menu.addchk(this.pad.fTicky == 0, "normal", "0fTicky", SetPadField); + menu.addchk(this.pad.fTicky == 1, "ticks on both sides", "1fTicky", SetPadField); + menu.addchk(this.pad.fTicky == 2, "labels on both sides", "2fTicky", SetPadField); + menu.add("endsub:"); + + this.FillAttContextMenu(menu); + } + + menu.add("separator"); + + if (this.ActivateStatusBar) + menu.addchk(this.HasEventStatus(), "Event status", this.ActivateStatusBar.bind(this, 'toggle')); + + if (this.enlarge_main() || (this.has_canvas && this.HasObjectsToDraw())) + menu.addchk((this.enlarge_main('state')=='on'), "Enlarge " + (this.iscan ? "canvas" : "pad"), this.EnlargePad.bind(this)); + + var fname = this.this_pad_name; + if (fname.length===0) fname = this.iscan ? "canvas" : "pad"; + + menu.add("Save as "+ fname+".png", fname+".png", this.SaveAs.bind(this, "png", false)); + menu.add("Save as "+ fname+".svg", fname+".svg", this.SaveAs.bind(this, "svg", false)); + + return true; + } + + TPadPainter.prototype.ShowContextMenu = function(evnt) { + if (!evnt) { + // for debug purposes keep original context menu for small region in top-left corner + var pos = d3.mouse(this.svg_pad(this.this_pad_name).node()); + + if (pos && (pos.length==2) && (pos[0]>0) && (pos[0]<10) && (pos[1]>0) && pos[1]<10) return; + + d3.event.stopPropagation(); // disable main context menu + d3.event.preventDefault(); // disable browser context menu + + // one need to copy event, while after call back event may be changed + evnt = d3.event; + + var fp = this.frame_painter(); + if (fp) fp.SetLastEventPos(); + } + + JSROOT.Painter.createMenu(this, function(menu) { + + menu.painter.FillContextMenu(menu); + + menu.painter.FillObjectExecMenu(menu, "", function() { menu.show(evnt); }); + }); // end menu creation + } + + TPadPainter.prototype.Redraw = function(resize) { + + // prevent redrawing + if (this._doing_pad_draw) return console.log('Prevent redrawing', this.pad.fName); + + var showsubitems = true; + + if (this.iscan) { + this.CreateCanvasSvg(2); + } else { + showsubitems = this.CreatePadSvg(true); + } + + // even sub-pad is not visible, we should redraw sub-sub-pads to hide them as well + for (var i = 0; i < this.painters.length; ++i) { + var sub = this.painters[i]; + if (showsubitems || sub.this_pad_name) sub.Redraw(resize); + } + } + + TPadPainter.prototype.NumDrawnSubpads = function() { + if (this.painters === undefined) return 0; + + var num = 0; + + for (var i = 0; i < this.painters.length; ++i) { + var obj = this.painters[i].GetObject(); + if (obj && (obj._typename === "TPad")) num++; + } + + return num; + } + + TPadPainter.prototype.RedrawByResize = function() { + if (this.access_3d_kind() === 1) return true; + + for (var i = 0; i < this.painters.length; ++i) + if (typeof this.painters[i].RedrawByResize === 'function') + if (this.painters[i].RedrawByResize()) return true; + + return false; + } + + TPadPainter.prototype.CheckCanvasResize = function(size, force) { + + if (!this.iscan && this.has_canvas) return false; + + if ((size === true) || (size === false)) { force = size; size = null; } + + if (size && (typeof size === 'object') && size.force) force = true; + + if (!force) force = this.RedrawByResize(); + + var changed = this.CreateCanvasSvg(force ? 2 : 1, size); + + // if canvas changed, redraw all its subitems. + // If redrawing was forced for canvas, same applied for sub-elements + if (changed) + for (var i = 0; i < this.painters.length; ++i) + this.painters[i].Redraw(force ? false : true); + + return changed; + } + + TPadPainter.prototype.UpdateObject = function(obj) { + if (!obj) return false; + + this.pad.fBits = obj.fBits; + this.pad.fTitle = obj.fTitle; + + this.pad.fGridx = obj.fGridx; + this.pad.fGridy = obj.fGridy; + this.pad.fTickx = obj.fTickx; + this.pad.fTicky = obj.fTicky; + this.pad.fLogx = obj.fLogx; + this.pad.fLogy = obj.fLogy; + this.pad.fLogz = obj.fLogz; + + this.pad.fUxmin = obj.fUxmin; + this.pad.fUxmax = obj.fUxmax; + this.pad.fUymin = obj.fUymin; + this.pad.fUymax = obj.fUymax; + + this.pad.fX1 = obj.fX1; + this.pad.fX2 = obj.fX2; + this.pad.fY1 = obj.fY1; + this.pad.fY2 = obj.fY2; + + this.pad.fLeftMargin = obj.fLeftMargin; + this.pad.fRightMargin = obj.fRightMargin; + this.pad.fBottomMargin = obj.fBottomMargin + this.pad.fTopMargin = obj.fTopMargin; + + this.pad.fFillColor = obj.fFillColor; + this.pad.fFillStyle = obj.fFillStyle; + this.pad.fLineColor = obj.fLineColor; + this.pad.fLineStyle = obj.fLineStyle; + this.pad.fLineWidth = obj.fLineWidth; + + this.pad.fPhi = obj.fPhi; + this.pad.fTheta = obj.fTheta; + + if (this.iscan) this.CheckSpecialsInPrimitives(obj); + + var fp = this.frame_painter(); + if (fp) fp.UpdateAttributes(!fp.modified_NDC); + + if (!obj.fPrimitives) return false; + + var isany = false, p = 0; + for (var n = 0; n < obj.fPrimitives.arr.length; ++n) { + while (p < this.painters.length) { + var pp = this.painters[p++]; + if (!pp._primitive) continue; + if (pp.UpdateObject(obj.fPrimitives.arr[n])) isany = true; + break; + } + } + + return isany; + } + + TPadPainter.prototype.DrawNextSnap = function(lst, indx, call_back, objpainter) { + // function called when drawing next snapshot from the list + // it is also used as callback for drawing of previous snap + + if (indx === -1) { + // flag used to prevent immediate pad redraw during first draw + this._doing_pad_draw = true; + this._snaps_map = {}; // to control how much snaps are drawn + this._num_primitives = lst ? lst.length : 0; + } + + while (true) { + + if (objpainter && lst && lst[indx] && (objpainter.snapid === undefined)) { + // keep snap id in painter, will be used for the + if (this.painters.indexOf(objpainter)<0) this.painters.push(objpainter); + objpainter.snapid = lst[indx].fObjectID; + } + + objpainter = null; + + ++indx; // change to the next snap + + if (!lst || indx >= lst.length) { + delete this._doing_pad_draw; + delete this._snaps_map; + delete this._current_primitive_indx; + return JSROOT.CallBack(call_back, this); + } + + var snap = lst[indx], + snapid = snap.fObjectID, + cnt = this._snaps_map[snapid]; + + if (cnt) cnt++; else cnt=1; + this._snaps_map[snapid] = cnt; // check how many objects with same snapid drawn, use them again + + this._current_primitive_indx = indx; + + // first appropriate painter for the object + // if same object drawn twice, two painters will exists + for (var k=0; k<this.painters.length; ++k) { + if (this.painters[k].snapid === snapid) + if (--cnt === 0) { objpainter = this.painters[k]; break; } + } + + // function which should be called when drawing of next item finished + var draw_callback = this.DrawNextSnap.bind(this, lst, indx, call_back); + + if (objpainter) { + + if (snap.fKind === JSROOT.WebSnapIds.kObject) { // object itself + if (objpainter.UpdateObject(snap.fSnapshot, snap.fOption)) objpainter.Redraw(); + continue; // call next + } + + if (snap.fKind === JSROOT.WebSnapIds.kSVG) { // update SVG + if (objpainter.UpdateObject(snap.fSnapshot)) objpainter.Redraw(); + continue; // call next + } + + if (snap.fKind === JSROOT.WebSnapIds.kSubPad) { // subpad + return objpainter.RedrawPadSnap(snap, draw_callback); + } + + continue; // call next + } + + // gStyle object + if (snap.fKind === JSROOT.WebSnapIds.kStyle) { + JSROOT.extend(JSROOT.gStyle, snap.fSnapshot); + continue; + } + + // list of colors + if (snap.fKind === JSROOT.WebSnapIds.kColors) { + + var ListOfColors = [], arr = snap.fSnapshot.fOper.split(";"); + for (var n=0;n<arr.length;++n) { + var name = arr[n], p = name.indexOf(":"); + if (p>0) { + ListOfColors[parseInt(name.substr(0,p))] = "rgb(" + name.substr(p+1) + ")"; + } else { + p = name.indexOf("="); + ListOfColors[parseInt(name.substr(0,p))] = "rgba(" + name.substr(p+1) + ")"; + } + } + + // set global list of colors + if (!this.options || this.options.GlobalColors) + JSROOT.Painter.adoptRootColors(ListOfColors); + + // copy existing colors and extend with new values + if (this.options && this.options.LocalColors) + this.root_colors = JSROOT.Painter.extendRootColors(null, ListOfColors); + + // set palette + if (snap.fSnapshot.fBuf && (!this.options || !this.options.IgnorePalette)) { + var palette = []; + for (var n=0;n<snap.fSnapshot.fBuf.length;++n) + palette[n] = ListOfColors[Math.round(snap.fSnapshot.fBuf[n])]; + + this.custom_palette = new JSROOT.ColorPalette(palette); + } + + continue; + } + + if (snap.fKind === JSROOT.WebSnapIds.kSubPad) { // subpad + + var subpad = snap.fSnapshot; + + subpad.fPrimitives = null; // clear primitives, they just because of I/O + + var padpainter = new TPadPainter(subpad, false); + padpainter.DecodeOptions(snap.fOption); + padpainter.SetDivId(this.divid); // pad painter will be registered in the canvas painters list + padpainter.snapid = snap.fObjectID; + + padpainter.CreatePadSvg(); + + if (padpainter.MatchObjectType("TPad") && snap.fPrimitives.length > 0) { + padpainter.AddButton(JSROOT.ToolbarIcons.camera, "Create PNG", "PadSnapShot"); + padpainter.AddButton(JSROOT.ToolbarIcons.circle, "Enlarge pad", "EnlargePad"); + + if (JSROOT.gStyle.ContextMenu) + padpainter.AddButton(JSROOT.ToolbarIcons.question, "Access context menus", "PadContextMenus"); + } + + // we select current pad, where all drawing is performed + var prev_name = padpainter.CurrentPadName(padpainter.this_pad_name); + padpainter.DrawNextSnap(snap.fPrimitives, -1, function() { + padpainter.CurrentPadName(prev_name); + draw_callback(padpainter); + }); + return; + } + + var handle = { func: draw_callback }; + + // here the case of normal drawing, can be improved + if (snap.fKind === JSROOT.WebSnapIds.kObject) + objpainter = JSROOT.draw(this.divid, snap.fSnapshot, snap.fOption, handle); + + if (snap.fKind === JSROOT.WebSnapIds.kSVG) + objpainter = JSROOT.draw(this.divid, snap.fSnapshot, snap.fOption, handle); + + if (!handle.completed) return; // if callback will be invoked, break while loop + } + } + + TPadPainter.prototype.FindSnap = function(snapid) { + + if (this.snapid === snapid) return this; + + if (!this.painters) return null; + + for (var k=0;k<this.painters.length;++k) { + var sub = this.painters[k]; + + if (typeof sub.FindSnap === 'function') sub = sub.FindSnap(snapid); + else if (sub.snapid !== snapid) sub = null; + + if (sub) return sub; + } + + return null; + } + + TPadPainter.prototype.AddOnlineButtons = function() { + this.AddButton(JSROOT.ToolbarIcons.camera, "Create PNG", "CanvasSnapShot", "Ctrl PrintScreen"); + if (JSROOT.gStyle.ContextMenu) + this.AddButton(JSROOT.ToolbarIcons.question, "Access context menus", "PadContextMenus"); + + if (this.enlarge_main('verify')) + this.AddButton(JSROOT.ToolbarIcons.circle, "Enlarge canvas", "EnlargePad"); + + if (this.brlayout) { + this.AddButton(JSROOT.ToolbarIcons.diamand, "Toggle Ged", "ToggleGed"); + this.AddButton(JSROOT.ToolbarIcons.three_circles, "Toggle Status", "ToggleStatus"); + } + } + + TPadPainter.prototype.RedrawPadSnap = function(snap, call_back) { + // for the canvas snapshot contains list of objects + // as first entry, graphical properties of canvas itself is provided + // in ROOT6 it also includes primitives, but we ignore them + + if (!snap || !snap.fPrimitives) return; + + this.is_active_pad = !!snap.fActive; // enforce boolean flag + + var first = snap.fSnapshot; + first.fPrimitives = null; // primitives are not interesting, they are disabled in IO + + if (this.snapid === undefined) { + // first time getting snap, create all gui elements first + + this.snapid = snap.fObjectID; + + this.draw_object = first; + this.pad = first; + // this._fixed_size = true; + + // if canvas size not specified in batch mode, temporary use 900x700 size + if (this.batch_mode && (!first.fCw || !first.fCh)) { first.fCw = 900; first.fCh = 700; } + + // case of ROOT7 with always dummy TPad as first entry + if (!first.fCw || !first.fCh) this._fixed_size = false; + + if (JSROOT.BrowserLayout && !this.batch_mode && !this.use_openui && !this.brlayout) { + var mainid = this.divid; + if (mainid && (typeof mainid == 'object')) + mainid = d3.select(mainid).attr("id"); + if (mainid && (typeof mainid == "string")) { + this.brlayout = new JSROOT.BrowserLayout(mainid, null, this); + this.brlayout.Create(mainid, true); + // this.brlayout.ToggleBrowserKind("float"); + this.SetDivId(this.brlayout.drawing_divid(), -1); // assign id for drawing + JSROOT.RegisterForResize(this.brlayout); + } + } + + this.CreateCanvasSvg(0); + this.SetDivId(this.divid); // now add to painters list + if (!this.batch_mode) + this.AddOnlineButtons(); + + this.DrawNextSnap(snap.fPrimitives, -1, call_back); + return; + } + + this.UpdateObject(first); // update only object attributes + + // apply all changes in the object (pad or canvas) + if (this.iscan) { + this.CreateCanvasSvg(2); + } else { + this.CreatePadSvg(true); + } + + var isanyfound = false, isanyremove = false; + + // find and remove painters which no longer exists in the list + for (var k=0;k<this.painters.length;++k) { + var sub = this.painters[k]; + if (sub.snapid===undefined) continue; // look only for painters with snapid + + for (var i=0;i<snap.fPrimitives.length;++i) + if (snap.fPrimitives[i].fObjectID === sub.snapid) { sub = null; isanyfound = true; break; } + + if (sub) { + // console.log('Remove painter' + k + ' from ' + this.painters.length + ' ' + sub.GetObject()._typename); + // remove painter which does not found in the list of snaps + this.painters.splice(k--,1); + sub.Cleanup(); // cleanup such painter + isanyremove = true; + } + } + + if (isanyremove) { + delete this.pads_cache; + } + + if (!isanyfound) { + var svg_p = this.svg_pad(this.this_pad_name), + fp = this.frame_painter(); + if (svg_p && !svg_p.empty()) + svg_p.property('mainpainter', null); + for (var k=0;k<this.painters.length;++k) + if (fp !== this.painters[k]) + this.painters[k].Cleanup(); + this.painters = []; + if (fp) { + this.painters.push(fp); + fp.CleanFrameDrawings(); + } + this.RemoveButtons(); + this.AddOnlineButtons(); + } + + var padpainter = this, + prev_name = padpainter.CurrentPadName(padpainter.this_pad_name); + + padpainter.DrawNextSnap(snap.fPrimitives, -1, function() { + padpainter.CurrentPadName(prev_name); + JSROOT.CallBack(call_back, padpainter); + }); + } + + TPadPainter.prototype.CreateImage = function(format, call_back) { + if (format=="pdf") { + // use https://github.com/MrRio/jsPDF in the future here + JSROOT.CallBack(call_back, btoa("dummy PDF file")); + } else if ((format=="png") || (format=="jpeg") || (format=="svg")) { + this.ProduceImage(true, format, function(res) { + if ((format=="svg") || !res) + return JSROOT.CallBack(call_back, res); + var separ = res.indexOf("base64,"); + JSROOT.CallBack(call_back, (separ>0) ? res.substr(separ+7) : ""); + }); + } else { + JSROOT.CallBack(call_back, ""); + } + } + + TPadPainter.prototype.GetAllRanges = function(arg) { + var is_top = (arg === undefined), elem = null; + if (is_top) arg = []; + + if (this.snapid) { + elem = { _typename: "TWebPadRange", snapid: this.snapid.toString(), + active: !!this.is_active_pad, + bits: 0, primitives: [], + logx: this.pad.fLogx, logy: this.pad.fLogy, logz: this.pad.fLogz, + gridx: this.pad.fGridx, gridy: this.pad.fGridy, + tickx: this.pad.fTickx, ticky: this.pad.fTicky, + mleft: this.pad.fLeftMargin, mright: this.pad.fRightMargin, + mtop: this.pad.fTopMargin, mbottom: this.pad.fBottomMargin }; + + if (this.iscan) elem.bits = this.GetStatusBits(); + + if (this.GetPadRanges(elem)) + arg.push(elem); + else + console.log('fail to get ranges for pad ' + this.pad.fName); + } + + for (var k=0;k<this.painters.length;++k) { + var sub = this.painters[k]; + if (typeof sub.GetAllRanges == "function") + sub.GetAllRanges(arg); + else if (sub.snapid) + elem.primitives.push({ _typename: "TWebObjectOptions", snapid: sub.snapid.toString(), opt: sub.OptionsAsString() }); + } + + if (is_top) return JSROOT.toJSON(arg); + } + + TPadPainter.prototype.GetPadRanges = function(r) { + // function returns actual ranges in the pad, which can be applied to the server + + if (!r) return false; + + var main = this.frame_painter_ref, + p = this.svg_pad(this.this_pad_name); + + r.ranges = main && main.ranges_set ? true : false; // indicate that ranges are assigned + + r.ux1 = r.px1 = r.ranges ? main.scale_xmin : 0; // need to initialize for JSON reader + r.uy1 = r.py1 = r.ranges ? main.scale_ymin : 0; + r.ux2 = r.px2 = r.ranges ? main.scale_xmax : 0; + r.uy2 = r.py2 = r.ranges ? main.scale_ymax : 0; + + if (!r.ranges || p.empty()) return true; + + // calculate user range for full pad + var same = function(x) { return x; }, + exp10 = function(x) { return Math.pow(10, x); }, + func = main.logx ? JSROOT.log10 : same, + func2 = main.logx ? exp10 : same, + k = (func(main.scale_xmax) - func(main.scale_xmin))/p.property("draw_width"), + x1 = func(main.scale_xmin) - k*p.property("draw_x"), + x2 = x1 + k*p.property("draw_width"); + + // method checks if new value v1 close to the old value v0 + function match(v1, v0, range) { + return (Math.abs(v0-v1)<Math.abs(range)*1e-10) ? v0 : v1; + } + + r.ux1 = match( func2(x1), r.ux1, r.px2-r.px1); + r.ux2 = match( func2(x2), r.ux2, r.px2-r.px1); + + func = main.logy ? JSROOT.log10 : same; + func2 = main.logy ? exp10 : same; + + k = (func(main.scale_ymax) - func(main.scale_ymin))/p.property("draw_height"); + var y2 = func(main.scale_ymax) + k*p.property("draw_y"), + y1 = y2 - k*p.property("draw_height"); + + r.uy1 = match( func2(y1), r.uy1, r.py2-r.py1); + r.uy2 = match( func2(y2), r.uy2, r.py2-r.py1); + + return true; + } + + TPadPainter.prototype.ItemContextMenu = function(name) { + var rrr = this.svg_pad(this.this_pad_name).node().getBoundingClientRect(); + var evnt = { clientX: rrr.left+10, clientY: rrr.top + 10 }; + + // use timeout to avoid conflict with mouse click and automatic menu close + if (name=="pad") + return setTimeout(this.ShowContextMenu.bind(this, evnt), 50); + + var selp = null, selkind; + + switch(name) { + case "xaxis": + case "yaxis": + case "zaxis": + selp = this.frame_painter_ref; + selkind = name[0]; + break; + case "frame": + selp = this.frame_painter_ref; + break; + default: { + var indx = parseInt(name); + if (!isNaN(indx)) selp = this.painters[indx]; + } + } + + if (!selp || (typeof selp.FillContextMenu !== 'function')) return; + + JSROOT.Painter.createMenu(selp, function(menu) { + if (selp.FillContextMenu(menu, selkind)) + setTimeout(menu.show.bind(menu, evnt), 50); + }); + } + + TPadPainter.prototype.SaveAs = function(kind, full_canvas, filename) { + if (!filename) { + filename = this.this_pad_name; + if (filename.length === 0) filename = this.iscan ? "canvas" : "pad"; + filename += "." + kind; + } + this.ProduceImage(full_canvas, kind, function(imgdata) { + var a = document.createElement('a'); + a.download = filename; + a.href = (kind != "svg") ? imgdata : "data:image/svg+xml;charset=utf-8,"+encodeURIComponent(imgdata); + document.body.appendChild(a); + a.addEventListener("click", function(e) { + a.parentNode.removeChild(a); + }); + a.click(); + }); + } + + TPadPainter.prototype.ProduceImage = function(full_canvas, file_format, call_back) { + + var use_frame = (full_canvas === "frame"); + + var elem = use_frame ? this.svg_frame() : (full_canvas ? this.svg_canvas() : this.svg_pad(this.this_pad_name)); + + if (elem.empty()) return JSROOT.CallBack(call_back); + + var painter = (full_canvas && !use_frame) ? this.canv_painter() : this; + + var items = []; // keep list of replaced elements, which should be moved back at the end + +// document.body.style.cursor = 'wait'; + + if (!use_frame) // do not make transformations for the frame + painter.ForEachPainterInPad(function(pp) { + + // console.log('Check painter pp', pp.this_pad_name); + + var item = { prnt: pp.svg_pad(pp.this_pad_name) }; + items.push(item); + + // remove buttons from each subpad + var btns = pp.svg_layer("btns_layer", pp.this_pad_name); + item.btns_node = btns.node(); + if (item.btns_node) { + item.btns_prnt = item.btns_node.parentNode; + item.btns_next = item.btns_node.nextSibling; + btns.remove(); + } + + var main = pp.frame_painter_ref; + if (!main || (typeof main.Render3D !== 'function')) return; + + var can3d = main.access_3d_kind(); + + if ((can3d !== 1) && (can3d !== 2)) return; + + var sz2 = main.size_for_3d(2); // get size of DOM element as it will be embed + + var sz = (can3d == 2) ? sz : main.size_for_3d(1); + + // console.log('Render 3D', sz2); + + var canvas = main.renderer.domElement; + main.Render3D(0); // WebGL clears buffers, therefore we should render scene and convert immediately + var dataUrl = canvas.toDataURL("image/png"); + + // console.log('canvas width height', canvas.width, canvas.height); + + // console.log('produced png image len = ', dataUrl.length, 'begin', dataUrl.substr(0,100)); + + // remove 3D drawings + + if (can3d == 2) { + item.foreign = item.prnt.select("." + sz2.clname); + item.foreign.remove(); + } + + var svg_frame = main.svg_frame(); + item.frame_node = svg_frame.node(); + if (item.frame_node) { + item.frame_next = item.frame_node.nextSibling; + svg_frame.remove(); + } + + //var origin = main.apply_3d_size(sz3d, true); + //origin.remove(); + + // add svg image + item.img = item.prnt.insert("image",".primitives_layer") // create image object + .attr("x", sz2.x) + .attr("y", sz2.y) + .attr("width", canvas.width) + .attr("height", canvas.height) + .attr("href", dataUrl); + + }, "pads"); + + function reEncode(data) { + data = encodeURIComponent(data); + data = data.replace(/%([0-9A-F]{2})/g, function(match, p1) { + var c = String.fromCharCode('0x'+p1); + return c === '%' ? '%25' : c; + }); + return decodeURIComponent(data); + } + + function reconstruct(res) { + for (var k=0;k<items.length;++k) { + var item = items[k]; + + if (item.img) + item.img.remove(); // delete embed image + + var prim = item.prnt.select(".primitives_layer"); + + if (item.foreign) // reinsert foreign object + item.prnt.node().insertBefore(item.foreign.node(), prim.node()); + + if (item.frame_node) // reinsert frame as first in list of primitives + prim.node().insertBefore(item.frame_node, item.frame_next); + + if (item.btns_node) // reinsert buttons + item.btns_prnt.insertBefore(item.btns_node, item.btns_next); + } + + JSROOT.CallBack(call_back, res); + } + + var width = elem.property('draw_width'), height = elem.property('draw_height'); + if (use_frame) { width = this.frame_width(); height = this.frame_height(); } + + var svg = '<svg width="' + width + '" height="' + height + '" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">' + + elem.node().innerHTML + + '</svg>'; + + if (file_format == "svg") + return reconstruct(svg); // return SVG file as is + + var doctype = '<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">'; + + var image = new Image(); + image.onload = function() { + // if (options.result==="image") return JSROOT.CallBack(call_back, image); + + // console.log('GOT IMAGE', image.width, image.height); + + var canvas = document.createElement('canvas'); + canvas.width = image.width; + canvas.height = image.height; + var context = canvas.getContext('2d'); + context.drawImage(image, 0, 0); + + reconstruct(canvas.toDataURL('image/' + file_format)); + } + + image.onerror = function(arg) { + console.log('IMAGE ERROR', arg); + reconstruct(null); + } + + image.src = 'data:image/svg+xml;base64,' + window.btoa(reEncode(doctype + svg)); + } + + TPadPainter.prototype.PadButtonClick = function(funcname) { + + if (funcname == "CanvasSnapShot") return this.SaveAs("png", true); + + if (funcname == "EnlargePad") return this.EnlargePad(); + + if (funcname == "PadSnapShot") return this.SaveAs("png", false); + + if (funcname == "PadContextMenus") { + + d3.event.preventDefault(); + d3.event.stopPropagation(); + + if (JSROOT.Painter.closeMenu()) return; + + var pthis = this, evnt = d3.event; + + JSROOT.Painter.createMenu(pthis, function(menu) { + menu.add("header:Menus"); + + if (pthis.iscan) + menu.add("Canvas", "pad", pthis.ItemContextMenu); + else + menu.add("Pad", "pad", pthis.ItemContextMenu); + + if (pthis.frame_painter()) + menu.add("Frame", "frame", pthis.ItemContextMenu); + + var main = pthis.main_painter(); + + if (main) { + menu.add("X axis", "xaxis", pthis.ItemContextMenu); + menu.add("Y axis", "yaxis", pthis.ItemContextMenu); + if ((typeof main.Dimension === 'function') && (main.Dimension() > 1)) + menu.add("Z axis", "zaxis", pthis.ItemContextMenu); + } + + if (pthis.painters && (pthis.painters.length>0)) { + menu.add("separator"); + var shown = []; + for (var n=0;n<pthis.painters.length;++n) { + var pp = pthis.painters[n]; + var obj = pp ? pp.GetObject() : null; + if (!obj || (shown.indexOf(obj)>=0)) continue; + + var name = ('_typename' in obj) ? (obj._typename + "::") : ""; + if ('fName' in obj) name += obj.fName; + if (name.length==0) name = "item" + n; + menu.add(name, n, pthis.ItemContextMenu); + } + } + + menu.show(evnt); + }); + + return; + } + + // click automatically goes to all sub-pads + // if any painter indicates that processing completed, it returns true + var done = false; + + for (var i = 0; i < this.painters.length; ++i) { + var pp = this.painters[i]; + + if (typeof pp.PadButtonClick == 'function') + pp.PadButtonClick(funcname); + + if (!done && (typeof pp.ButtonClick == 'function')) + done = pp.ButtonClick(funcname); + } + } + + TPadPainter.prototype.FindButton = function(keyname) { + var group = this.svg_layer("btns_layer", this.this_pad_name), found_func = ""; + if (!group.empty()) + group.selectAll("svg").each(function() { + if (d3.select(this).attr("key") === keyname) + found_func = d3.select(this).attr("name"); + }); + + return found_func; + } + + TPadPainter.prototype.toggleButtonsVisibility = function(action) { + var group = this.svg_layer("btns_layer", this.this_pad_name), + btn = group.select("[name='Toggle']"); + + if (btn.empty()) return; + + var state = btn.property('buttons_state'); + + if (btn.property('timout_handler')) { + if (action!=='timeout') clearTimeout(btn.property('timout_handler')); + btn.property('timout_handler', null); + } + + var is_visible = false; + switch(action) { + case 'enable': is_visible = true; break; + case 'enterbtn': return; // do nothing, just cleanup timeout + case 'timeout': is_visible = false; break; + case 'toggle': + state = !state; + btn.property('buttons_state', state); + is_visible = state; + break; + case 'disable': + case 'leavebtn': + if (!state) btn.property('timout_handler', setTimeout(this.toggleButtonsVisibility.bind(this,'timeout'), 500)); + return; + } + + group.selectAll('svg').each(function() { + if (this===btn.node()) return; + d3.select(this).style('display', is_visible ? "" : "none"); + }); + } + + TPadPainter.prototype.RemoveButtons = function() { + var group = this.svg_layer("btns_layer", this.this_pad_name); + if (!group.empty()) { + group.selectAll("*").remove(); + group.property("nextx", null); + } + } + + TPadPainter.prototype.AddButton = function(_btn, _tooltip, _funcname, _keyname) { + if (!JSROOT.gStyle.ToolBar) return; + + if (!this._buttons) this._buttons = []; + // check if there are duplications + + for (var k=0;k<this._buttons.length;++k) + if (this._buttons[k].funcname == _funcname) return; + + this._buttons.push({ btn: _btn, tooltip: _tooltip, funcname: _funcname, keyname: _keyname }); + + var iscan = this.iscan || !this.has_canvas; + if (!iscan && (_funcname.indexOf("Pad")!=0) && (_funcname !== "EnlargePad")) { + var cp = this.canv_painter(); + if (cp && (cp!==this)) cp.AddButton(_btn, _tooltip, _funcname); + } + } + + TPadPainter.prototype.ShowButtons = function() { + + if (!this._buttons) return; + + var group = this.svg_layer("btns_layer", this.this_pad_name); + if (group.empty()) return; + + // clean all previous buttons + group.selectAll("*").remove(); + + var iscan = this.iscan || !this.has_canvas, ctrl, + x = group.property('leftside') ? this.ButtonSize(1.25) : 0, y = 0; + + if (this._fast_drawing) { + ctrl = JSROOT.ToolbarIcons.CreateSVG(group, JSROOT.ToolbarIcons.circle, this.ButtonSize(), "EnlargePad"); + ctrl.attr("name", "Enlarge").attr("x", 0).attr("y", 0) + // .property("buttons_state", (JSROOT.gStyle.ToolBar!=='popup')) + .on("click", this.PadButtonClick.bind(this, "EnlargePad")); + } else { + ctrl = JSROOT.ToolbarIcons.CreateSVG(group, JSROOT.ToolbarIcons.rect, this.ButtonSize(), "Toggle tool buttons"); + + ctrl.attr("name", "Toggle").attr("x", 0).attr("y", 0) + .property("buttons_state", (JSROOT.gStyle.ToolBar!=='popup')) + .on("click", this.toggleButtonsVisibility.bind(this, 'toggle')) + .on("mouseenter", this.toggleButtonsVisibility.bind(this, 'enable')) + .on("mouseleave", this.toggleButtonsVisibility.bind(this, 'disable')); + + for (var k=0;k<this._buttons.length;++k) { + var item = this._buttons[k]; + + var svg = JSROOT.ToolbarIcons.CreateSVG(group, item.btn, this.ButtonSize(), + item.tooltip + (iscan ? "" : (" on pad " + this.this_pad_name)) + (item.keyname ? " (keyshortcut " + item.keyname + ")" : "")); + + if (group.property('vertical')) + svg.attr("x", y).attr("y", x); + else + svg.attr("x", x).attr("y", y); + + svg.attr("name", item.funcname) + .style('display', (ctrl.property("buttons_state") ? '' : 'none')) + .on("mouseenter", this.toggleButtonsVisibility.bind(this, 'enterbtn')) + .on("mouseleave", this.toggleButtonsVisibility.bind(this, 'leavebtn')); + + if (item.keyname) svg.attr("key", item.keyname); + + svg.on("click", this.PadButtonClick.bind(this, item.funcname)); + + x += this.ButtonSize(1.25); + } + } + + group.property("nextx", x); + + this.AlignBtns(group, this.pad_width(this.this_pad_name), this.pad_height(this.this_pad_name)); + + if (group.property('vertical')) ctrl.attr("y", x); + else if (!group.property('leftside')) ctrl.attr("x", x); + } + + TPadPainter.prototype.AlignBtns = function(btns, width, height, svg) { + var sz0 = this.ButtonSize(1.25), nextx = (btns.property('nextx') || 0) + sz0, btns_x, btns_y; + + if (btns.property('vertical')) { + btns_x = btns.property('leftside') ? 2 : (width - sz0); + btns_y = height - nextx; + } else { + btns_x = btns.property('leftside') ? 2 : (width - nextx); + btns_y = height - sz0; + } + + btns.attr("transform","translate("+btns_x+","+btns_y+")"); + } + + TPadPainter.prototype.DrawingReady = function(res_painter) { + + var main = this.frame_painter_ref; + + if (main && main.mode3d && typeof main.Render3D == 'function') main.Render3D(-2222); + + JSROOT.TObjectPainter.prototype.DrawingReady.call(this, res_painter); + } + + TPadPainter.prototype.DecodeOptions = function(opt) { + var pad = this.GetObject(); + if (!pad) return; + + var d = new JSROOT.DrawOptions(opt); + + if (d.check('WEBSOCKET')) this.OpenWebsocket(); + if (!this.options) this.options = {}; + + JSROOT.extend(this.options, { GlobalColors: true, LocalColors: false, CreatePalette: 0, IgnorePalette: false, RotateFrame: false, FixFrame: false }); + + if (d.check('NOCOLORS') || d.check('NOCOL')) this.options.GlobalColors = this.options.LocalColors = false; + if (d.check('LCOLORS') || d.check('LCOL')) { this.options.GlobalColors = false; this.options.LocalColors = true; } + if (d.check('NOPALETTE') || d.check('NOPAL')) this.options.IgnorePalette = true; + if (d.check('ROTATE')) this.options.RotateFrame = true; + if (d.check('FIXFRAME')) this.options.FixFrame = true; + + if (d.check("CP",true)) this.options.CreatePalette = d.partAsInt(0,0); + + if (d.check('WHITE')) pad.fFillColor = 0; + if (d.check('LOGX')) { pad.fLogx = 1; pad.fUxmin = 0; pad.fUxmax = 1; pad.fX1 = 0; pad.fX2 = 1; } + if (d.check('LOGY')) { pad.fLogy = 1; pad.fUymin = 0; pad.fUymax = 1; pad.fY1 = 0; pad.fY2 = 1; } + if (d.check('LOGZ')) pad.fLogz = 1; + if (d.check('LOG')) pad.fLogx = pad.fLogy = pad.fLogz = 1; + if (d.check('GRIDX')) pad.fGridx = 1; + if (d.check('GRIDY')) pad.fGridy = 1; + if (d.check('GRID')) pad.fGridx = pad.fGridy = 1; + if (d.check('TICKX')) pad.fTickx = 1; + if (d.check('TICKY')) pad.fTicky = 1; + if (d.check('TICK')) pad.fTickx = pad.fTicky = 1; + + this.OptionsStore(opt); + } + + function drawPad(divid, pad, opt) { + var painter = new TPadPainter(pad, false); + painter.DecodeOptions(opt); + + painter.SetDivId(divid); // pad painter will be registered in the canvas painters list + + if (painter.svg_canvas().empty()) { + painter.has_canvas = false; + painter.this_pad_name = ""; + } + + painter.CreatePadSvg(); + + if (painter.MatchObjectType("TPad") && (!painter.has_canvas || painter.HasObjectsToDraw())) { + painter.AddButton(JSROOT.ToolbarIcons.camera, "Create PNG", "PadSnapShot"); + + if ((painter.has_canvas && painter.HasObjectsToDraw()) || painter.enlarge_main('verify')) + painter.AddButton(JSROOT.ToolbarIcons.circle, "Enlarge pad", "EnlargePad"); + + if (JSROOT.gStyle.ContextMenu) + painter.AddButton(JSROOT.ToolbarIcons.question, "Access context menus", "PadContextMenus"); + } + + // we select current pad, where all drawing is performed + var prev_name = painter.has_canvas ? painter.CurrentPadName(painter.this_pad_name) : undefined; + + // set active pad + JSROOT.Painter.SelectActivePad({ pp: painter, active: true }); + + // flag used to prevent immediate pad redraw during first draw + painter.DrawPrimitives(0, function() { + painter.ShowButtons(); + // we restore previous pad name + painter.CurrentPadName(prev_name); + painter.DrawingReady(); + }); + + return painter; + } + + // ========================================================================================== + + /** + * @summary Painter for TCanvas object. + * + * @constructor + * @memberof JSROOT + * @augments JSROOT.TPadPainter + * @param {object} canvas - TCanvas object to draw + */ + + function TCanvasPainter(canvas) { + TPadPainter.call(this, canvas, true); + this._websocket = null; + this.tooltip_allowed = (JSROOT.gStyle.Tooltip > 0); + } + + TCanvasPainter.prototype = Object.create(TPadPainter.prototype); + + TCanvasPainter.prototype.ChangeLayout = function(layout_kind, call_back) { + var current = this.get_layout_kind(); + if (current == layout_kind) return JSROOT.CallBack(call_back, true); + + var origin = this.select_main('origin'), + sidebar = origin.select('.side_panel'), + main = this.select_main(), lst = []; + + while (main.node().firstChild) + lst.push(main.node().removeChild(main.node().firstChild)); + + if (!sidebar.empty()) JSROOT.cleanup(sidebar.node()); + + this.set_layout_kind("simple"); // restore defaults + origin.html(""); // cleanup origin + + if (layout_kind == 'simple') { + main = origin; + for (var k=0;k<lst.length;++k) + main.node().appendChild(lst[k]); + this.set_layout_kind(layout_kind); + // JSROOT.resize(main.node()); + return JSROOT.CallBack(call_back, true); + } + + var pthis = this; + + JSROOT.AssertPrerequisites("jq2d", function() { + + var grid = new JSROOT.GridDisplay(origin.node(), layout_kind); + + if (layout_kind.indexOf("vert")==0) { + main = d3.select(grid.GetFrame(0)); + sidebar = d3.select(grid.GetFrame(1)); + } else { + main = d3.select(grid.GetFrame(1)); + sidebar = d3.select(grid.GetFrame(0)); + } + + main.classed("central_panel", true).style('position','relative'); + sidebar.classed("side_panel", true).style('position','relative'); + + // now append all childs to the new main + for (var k=0;k<lst.length;++k) + main.node().appendChild(lst[k]); + + pthis.set_layout_kind(layout_kind, ".central_panel"); + + JSROOT.CallBack(call_back, true); + }); + } + + TCanvasPainter.prototype.ToggleProjection = function(kind, call_back) { + delete this.proj_painter; + + if (kind) this.proj_painter = 1; // just indicator that drawing can be preformed + + if (this.use_openui && this.ShowUI5ProjectionArea) + return this.ShowUI5ProjectionArea(kind, call_back); + + var layout = 'simple'; + + if (kind == "X") layout = 'vert2_31'; else + if (kind == "Y") layout = 'horiz2_13'; + + this.ChangeLayout(layout, call_back); + } + + TCanvasPainter.prototype.DrawProjection = function(kind,hist) { + if (!this.proj_painter) return; // ignore drawing if projection not configured + + if (this.proj_painter === 1) { + + var canv = JSROOT.Create("TCanvas"), + pthis = this, pad = this.root_pad(), + main = this.frame_painter_ref, drawopt; + + if (kind == "X") { + canv.fLeftMargin = pad.fLeftMargin; + canv.fRightMargin = pad.fRightMargin; + canv.fLogx = main.logx ? 1 : 0; + canv.fUxmin = main.logx ? JSROOT.log10(main.scale_xmin) : main.scale_xmin; + canv.fUxmax = main.logx ? JSROOT.log10(main.scale_xmax) : main.scale_xmax; + drawopt = "fixframe"; + } else { + canv.fBottomMargin = pad.fBottomMargin; + canv.fTopMargin = pad.fTopMargin; + canv.fLogx = main.logy ? 1 : 0; + canv.fUxmin = main.logy ? JSROOT.log10(main.scale_ymin) : main.scale_ymin; + canv.fUxmax = main.logy ? JSROOT.log10(main.scale_ymax) : main.scale_ymax; + drawopt = "rotate"; + } + + canv.fPrimitives.Add(hist, "hist"); + + if (this.use_openui && this.DrawInUI5ProjectionArea) { + // copy frame attributes + this.DrawInUI5ProjectionArea(canv, drawopt, function(painter) { pthis.proj_painter = painter; }) + } else { + this.DrawInSidePanel(canv, drawopt, function(painter) { pthis.proj_painter = painter; }) + } + } else { + var hp = this.proj_painter.main_painter(); + if (hp) hp.UpdateObject(hist, "hist"); + this.proj_painter.RedrawPad(); + } + } + + TCanvasPainter.prototype.DrawInSidePanel = function(canv, opt, call_back) { + var side = this.select_main('origin').select(".side_panel"); + if (side.empty()) return JSROOT.CallBack(call_back, null); + JSROOT.draw(side.node(), canv, opt, call_back); + } + + TCanvasPainter.prototype.ShowMessage = function(msg) { + JSROOT.progress(msg, 7000); + } + + /// function called when canvas menu item Save is called + TCanvasPainter.prototype.SaveCanvasAsFile = function(fname) { + var pthis = this, pnt = fname.indexOf("."); + this.CreateImage(fname.substr(pnt+1), function(res) { + pthis.SendWebsocket("SAVE:" + fname + ":" + res); + }) + } + + TCanvasPainter.prototype.SendSaveCommand = function(fname) { + this.SendWebsocket("PRODUCE:" + fname); + } + + TCanvasPainter.prototype.WindowBeforeUnloadHanlder = function() { + // when window closed, close socket + this.CloseWebsocket(true); + } + + TCanvasPainter.prototype.SendWebsocket = function(msg) { + if (!this._websocket) return; + if (this._websocket.CanSend()) + this._websocket.Send(msg); + else + console.warn("DROP SEND: " + msg); + } + + TCanvasPainter.prototype.CloseWebsocket = function(force) { + if (this._websocket) { + this._websocket.Close(force); + this._websocket.Cleanup(); + delete this._websocket; + } + } + + TCanvasPainter.prototype.OpenWebsocket = function(socket_kind) { + // create websocket for current object (canvas) + // via websocket one recieved many extra information + + this.CloseWebsocket(); + + this._websocket = new JSROOT.WebWindowHandle(socket_kind); + this._websocket.SetReceiver(this); + this._websocket.Connect(); + } + + TCanvasPainter.prototype.UseWebsocket = function(handle) { + this.CloseWebsocket(); + + this._websocket = handle; + this._websocket.SetReceiver(this); + this._websocket.Connect(); + } + + TCanvasPainter.prototype.OnWebsocketOpened = function(handle) { + // indicate that we are ready to recieve any following commands + } + + TCanvasPainter.prototype.OnWebsocketClosed = function(handle) { + JSROOT.CloseCurrentWindow(); + } + + TCanvasPainter.prototype.OnWebsocketMsg = function(handle, msg) { + console.log("GET MSG len:" + msg.length + " " + msg.substr(0,60)); + + if (msg == "CLOSE") { + this.OnWebsocketClosed(); + this.CloseWebsocket(true); + } else if (msg.substr(0,6)=='SNAP6:') { + // This is snapshot, produced with ROOT6 + + msg = msg.substr(6); + var p1 = msg.indexOf(":"), + snapid = msg.substr(0,p1), + snap = JSROOT.parse(msg.substr(p1+1)), + pthis = this; + + this.RedrawPadSnap(snap, function() { + pthis.CompeteCanvasSnapDrawing(); + var ranges = pthis.GetAllRanges(); + if (ranges) { + // console.log("ranges: " + ranges); + ranges = ":" + ranges; + } + handle.Send("READY6:" + snapid + ranges); // send ready message back when drawing completed + }); + } else if (msg.substr(0,5)=='MENU:') { + // this is menu with exact identifier for object + msg = msg.substr(5); + var p1 = msg.indexOf(":"), + menuid = msg.substr(0,p1), + lst = JSROOT.parse(msg.substr(p1+1)); + // console.log("get MENUS ", typeof lst, 'nitems', lst.length, msg.length-4); + if (typeof this._getmenu_callback == 'function') + this._getmenu_callback(lst, menuid); + } else if (msg.substr(0,4)=='CMD:') { + msg = msg.substr(4); + var p1 = msg.indexOf(":"), + cmdid = msg.substr(0,p1), + cmd = msg.substr(p1+1), + reply = "REPLY:" + cmdid + ":"; + if ((cmd == "SVG") || (cmd == "PNG") || (cmd == "JPEG")) { + this.CreateImage(cmd.toLowerCase(), function(res) { + handle.Send(reply + res); + }); + } else { + console.log('Unrecognized command ' + cmd); + handle.Send(reply); + } + } else if ((msg.substr(0,7)=='DXPROJ:') || (msg.substr(0,7)=='DYPROJ:')) { + var kind = msg[1], + hist = JSROOT.parse(msg.substr(7)); + this.DrawProjection(kind, hist); + } else if (msg.substr(0,5)=='SHOW:') { + var that = msg.substr(5), + on = (that[that.length-1] == '1'); + this.ShowSection(that.substr(0,that.length-2), on); + } else if (msg.substr(0,5) == "EDIT:") { + var obj_painter = this.FindSnap(msg.substr(5)); + console.log('GET EDIT ' + msg.substr(5) + ' found ' + !!obj_painter); + if (obj_painter) { + this.ShowSection("Editor", true); + + if (this.pad_events_receiver) + this.pad_events_receiver({ what: "select", padpainter: this, painter: obj_painter }); + } + + } else { + console.log("unrecognized msg " + msg); + } + } + + TCanvasPainter.prototype.PadButtonClick = function(funcname) { + if (funcname == "ToggleGed") return this.ActivateGed(this, null, "toggle"); + if (funcname == "ToggleStatus") return this.ActivateStatusBar("toggle"); + TPadPainter.prototype.PadButtonClick.call(this, funcname); + } + + TCanvasPainter.prototype.HasEventStatus = function() { + if (this.use_openui) return this.openuiHasEventStatus(); + + return this.brlayout ? this.brlayout.HasStatus() : false; + } + + TCanvasPainter.prototype.ActivateStatusBar = function(state) { + if (this.use_openui) + this.openuiToggleEventStatus(state); + else if (this.brlayout) + this.brlayout.CreateStatusLine(23, state); + + this.ProcessChanges("sbits", this); + } + + TCanvasPainter.prototype.HasGed = function() { + if (this.use_openui) + return this.openuiHasGed(); + + return this.brlayout ? this.brlayout.HasContent() : false; + } + + TCanvasPainter.prototype.RemoveGed = function() { + if (typeof this.CleanupGed == 'function') + this.CleanupGed(); + if (this.brlayout) + this.brlayout.DeleteContent(); + + this.ProcessChanges("sbits", this); + } + + + TCanvasPainter.prototype.ActivateGed = function(objpainter, kind, mode) { + // function used to activate GED + + if (this.use_openui) + return this.openuiActivateGed(objpainter, kind, mode); + + if (!this.brlayout) return; + + if (this.brlayout.HasContent()) { + if ((mode === "toggle") || (mode === false)) + return this.RemoveGed(); + return this.SelectObjectPainter(objpainter); + } + + if (mode === false) return; + + var btns = this.brlayout.CreateBrowserBtns(); + + JSROOT.ToolbarIcons.CreateSVG(btns, JSROOT.ToolbarIcons.diamand, 15, "toggle fix-pos mode") + .style("margin","3px").on("click", this.brlayout.Toggle.bind(this.brlayout, 'fix')); + + JSROOT.ToolbarIcons.CreateSVG(btns, JSROOT.ToolbarIcons.circle, 15, "toggle float mode") + .style("margin","3px").on("click", this.brlayout.Toggle.bind(this.brlayout, 'float')); + + JSROOT.ToolbarIcons.CreateSVG(btns, JSROOT.ToolbarIcons.cross, 15, "delete GED") + .style("margin","3px").on("click", this.RemoveGed.bind(this)); + + // be aware, that jsroot_browser_hierarchy required for flexible layout that element use full browser area + this.brlayout.SetBrowserContent("<div class='jsroot_browser_hierarchy' id='ged_placeholder'>Loading GED ...</div>"); + this.brlayout.SetBrowserTitle("GED"); + this.brlayout.ToggleBrowserKind(kind || "float"); + + var pthis = this; + + JSROOT.AssertPrerequisites('openui5', function() { + pthis.ShowGed(objpainter); + pthis.ProcessChanges("sbits", pthis); + }); + } + + TCanvasPainter.prototype.ShowSection = function(that, on) { + if (this.use_openui) + return this.fullShowSection(that, on); + + console.log('Show section ' + that + ' flag = ' + on); + + switch(that) { + case "Menu": break; + case "StatusBar": this.ActivateStatusBar(on); break; + case "Editor": this.ActivateGed(this, null, !!on); break; + case "ToolBar": break; + case "ToolTips": this.SetTooltipAllowed(on); break; + } + } + + TCanvasPainter.prototype.CompeteCanvasSnapDrawing = function() { + if (!this.pad) return; + + if (document) document.title = this.pad.fTitle; + + if (this._all_sections_showed) return; + this._all_sections_showed = true; + this.ShowSection("Menu", this.pad.TestBit(JSROOT.TCanvasStatusBits.kMenuBar)); + this.ShowSection("StatusBar", this.pad.TestBit(JSROOT.TCanvasStatusBits.kShowEventStatus)); + this.ShowSection("ToolBar", this.pad.TestBit(JSROOT.TCanvasStatusBits.kShowToolBar)); + this.ShowSection("Editor", this.pad.TestBit(JSROOT.TCanvasStatusBits.kShowEditor)); + this.ShowSection("ToolTips", this.pad.TestBit(JSROOT.TCanvasStatusBits.kShowToolTips)); + } + + /// method informs that something was changed in the canvas + /// used to update information on the server (when used with web6gui) + TCanvasPainter.prototype.ProcessChanges = function(kind, source_pad) { + // check if we could send at least one message more - for some meaningful actions + if (!this._websocket || !this._websocket.CanSend(2)) return; + + var msg = (kind == "sbits") ? "STATUSBITS:" + this.GetStatusBits() : "RANGES6:" + this.GetAllRanges(); + + this._websocket.Send(msg); + } + + TCanvasPainter.prototype.SelectActivePad = function(pad_painter, obj_painter, click_pos) { + if ((this.snapid === undefined) || !pad_painter) return; // only interactive canvas + + var arg = null, ischanged = false; + + if ((pad_painter.snapid !== undefined) && this._websocket) + arg = { _typename: "TWebPadClick", padid: pad_painter.snapid.toString(), objid: "", x: -1, y: -1, dbl: false }; + + if (!pad_painter.is_active_pad) { + ischanged = true; + this.ForEachPainterInPad(function(pp) { + pp.DrawActiveBorder(null, pp === pad_painter); + }, "pads"); + } + + if (obj_painter && (obj_painter.snapid!==undefined) && arg) { + ischanged = true; + arg.objid = obj_painter.snapid.toString(); + } + + if (click_pos && arg) { + ischanged = true; + arg.x = Math.round(click_pos.x || 0); + arg.y = Math.round(click_pos.y || 0); + if (click_pos.dbl) arg.dbl = true; + } + + if (arg && ischanged) + this.SendWebsocket("PADCLICKED:" + JSROOT.toJSON(arg)); + } + + TCanvasPainter.prototype.GetStatusBits = function() { + var bits = 0; + if (this.HasEventStatus()) bits |= JSROOT.TCanvasStatusBits.kShowEventStatus; + if (this.HasGed()) bits |= JSROOT.TCanvasStatusBits.kShowEditor; + if (this.IsTooltipAllowed()) bits |= JSROOT.TCanvasStatusBits.kShowToolTips; + if (this.use_openui) bits |= JSROOT.TCanvasStatusBits.kMenuBar; + return bits; + } + + /// produce JSON for TCanvas, which can be used to display canvas once again + TCanvasPainter.prototype.ProduceJSON = function() { + + var canv = this.GetObject(), + fill0 = (canv.fFillStyle == 0); + + if (fill0) canv.fFillStyle = 1001; + + if (!this.normal_canvas) { + + // fill list of primitives from painters + this.ForEachPainterInPad(function(p) { + if (p.$secondary) return; // ignore all secoandry painters + + var subobj = p.GetObject(); + if (subobj && subobj._typename) + canv.fPrimitives.Add(subobj, p.OptionsAsString()); + }, "objects"); + } + + var res = JSROOT.toJSON(canv); + + if (fill0) canv.fFillStyle = 0; + + if (!this.normal_canvas) + canv.fPrimitives.Clear(); + + return res; + } + + function drawCanvas(divid, can, opt) { + var nocanvas = !can; + if (nocanvas) can = JSROOT.Create("TCanvas"); + + var painter = new TCanvasPainter(can); + painter.DecodeOptions(opt); + painter.normal_canvas = !nocanvas; + + painter.SetDivId(divid, -1); // just assign id + painter.CheckSpecialsInPrimitives(can); + painter.CreateCanvasSvg(0); + painter.SetDivId(divid); // now add to painters list + + painter.AddButton(JSROOT.ToolbarIcons.camera, "Create PNG", "CanvasSnapShot", "Ctrl PrintScreen"); + if (JSROOT.gStyle.ContextMenu) + painter.AddButton(JSROOT.ToolbarIcons.question, "Access context menus", "PadContextMenus"); + + if (painter.enlarge_main('verify')) + painter.AddButton(JSROOT.ToolbarIcons.circle, "Enlarge canvas", "EnlargePad"); + + if (nocanvas && opt.indexOf("noframe") < 0) + JSROOT.Painter.drawFrame(divid, null); + + // select global reference - required for keys handling + JSROOT.Painter.SelectActivePad({ pp: painter, active: true }); + + painter.DrawPrimitives(0, function() { painter.ShowButtons(); painter.DrawingReady(); }); + return painter; + } + + function drawPadSnapshot(divid, snap, opt) { + // just for debugging without running web canvas + + var can = JSROOT.Create("TCanvas"); + + var painter = new TCanvasPainter(can); + painter.normal_canvas = false; + + painter.SetDivId(divid, -1); // just assign id + + painter.AddButton(JSROOT.ToolbarIcons.camera, "Create PNG", "CanvasSnapShot", "Ctrl PrintScreen"); + if (JSROOT.gStyle.ContextMenu) + painter.AddButton(JSROOT.ToolbarIcons.question, "Access context menus", "PadContextMenus"); + + if (painter.enlarge_main('verify')) + painter.AddButton(JSROOT.ToolbarIcons.circle, "Enlarge canvas", "EnlargePad"); + + // JSROOT.Painter.drawFrame(divid, null); + + painter.RedrawPadSnap(snap, function() { painter.ShowButtons(); painter.DrawingReady(); }); + + return painter; + } + + JSROOT.TAxisPainter = TAxisPainter; + JSROOT.TFramePainter = TFramePainter; + JSROOT.TPadPainter = TPadPainter; + JSROOT.TCanvasPainter = TCanvasPainter; + + JSROOT.Painter.drawFrame = drawFrame; + JSROOT.Painter.drawPad = drawPad; + JSROOT.Painter.drawCanvas = drawCanvas; + JSROOT.Painter.drawPadSnapshot = drawPadSnapshot; + + return JSROOT; + +})); \ No newline at end of file diff --git a/js/scripts/JSRootPainter.v7.js b/js/scripts/JSRootPainter.v7.js new file mode 100644 index 00000000000..bccf74b0cd5 --- /dev/null +++ b/js/scripts/JSRootPainter.v7.js @@ -0,0 +1,4316 @@ +/// @file JSRootPainter.v7.js +/// JavaScript ROOT graphics for ROOT v7 classes + +(function( factory ) { + if ( typeof define === "function" && define.amd ) { + define( ['JSRootPainter', 'd3'], factory ); + } else + if (typeof exports === 'object' && typeof module !== 'undefined') { + factory(require("./JSRootCore.js"), require("./d3.min.js")); + } else { + + if (typeof d3 != 'object') + throw new Error('This extension requires d3.js', 'JSRootPainter.v7.js'); + + if (typeof JSROOT == 'undefined') + throw new Error('JSROOT is not defined', 'JSRootPainter.v7.js'); + + if (typeof JSROOT.Painter != 'object') + throw new Error('JSROOT.Painter not defined', 'JSRootPainter.v7.js'); + + factory(JSROOT, d3); + } +} (function(JSROOT, d3) { + + "use strict"; + + JSROOT.sources.push("v7"); + + JSROOT.v7 = {}; // placeholder for all v7-relevant code + + JSROOT.TObjectPainter.prototype.GetCoordinate = function(pnt) { + var res = { x: 0, y: 0 }; + + if (!pnt) return res; + + var w = this.pad_width(), + h = this.pad_height(), + pp = this.pad_painter(); + + function CalcCoord(val, coord, grsize) { + var res = val.fNormal.fVal * grsize + val.fPixel.fVal; + + if (val.fUser.fVal) + res += (val.fUser.fVal - coord.fBegin) / (coord.fEnd - coord.fBegin) * grsize; + + return res; + } + + if (!pp.pad_frame) { + res.x = pnt.fHoriz.fNormal.fVal*w; + res.y = h - pnt.fVert.fNormal.fVal*h; + } else { + res.x = CalcCoord(pnt.fHoriz, pp.pad_frame.fUserCoord[0], w); + res.y = h - CalcCoord(pnt.fVert, pp.pad_frame.fUserCoord[1], h); + } + return res; + } + + function TAxisPainter(axis, embedded) { + JSROOT.TObjectPainter.call(this, axis); + + this.embedded = embedded; // indicate that painter embedded into the histo painter + + this.name = "yaxis"; + this.kind = "normal"; + this.func = null; + this.order = 0; // scaling order for axis labels + + this.full_min = 0; + this.full_max = 1; + this.scale_min = 0; + this.scale_max = 1; + this.ticks = []; // list of major ticks + this.invert_side = false; + this.lbls_both_sides = false; // draw labels on both sides + } + + TAxisPainter.prototype = Object.create(JSROOT.TObjectPainter.prototype); + + TAxisPainter.prototype.Cleanup = function() { + + this.ticks = []; + this.func = null; + delete this.format; + + JSROOT.TObjectPainter.prototype.Cleanup.call(this); + } + + TAxisPainter.prototype.SetAxisConfig = function(name, kind, func, min, max, smin, smax) { + this.name = name; + this.kind = kind; + this.func = func; + + this.full_min = min; + this.full_max = max; + this.scale_min = smin; + this.scale_max = smax; + } + + TAxisPainter.prototype.format10Exp = function(order, value) { + var res = ""; + if (value) { + value = Math.round(value/Math.pow(10,order)); + if ((value!=0) && (value!=1)) res = value.toString() + (JSROOT.gStyle.Latex ? "#times" : "x"); + } + res += "10"; + if (JSROOT.gStyle.Latex > 1) return res + "^{" + order + "}"; + var superscript_symbols = { + '0': '\u2070', '1': '\xB9', '2': '\xB2', '3': '\xB3', '4': '\u2074', '5': '\u2075', + '6': '\u2076', '7': '\u2077', '8': '\u2078', '9': '\u2079', '-': '\u207B' + }; + var str = order.toString(); + for (var n=0;n<str.length;++n) res += superscript_symbols[str[n]]; + return res; + } + + TAxisPainter.prototype.CreateFormatFuncs = function() { + + var axis = this.GetObject(), + is_gaxis = (axis && axis._typename === 'TGaxis'); + + delete this.format;// remove formatting func + + var ndiv = 508; + if (is_gaxis) ndiv = axis.fNdiv; else + if (axis) ndiv = Math.max(axis.fNdivisions, 4); + + this.nticks = ndiv % 100; + this.nticks2 = (ndiv % 10000 - this.nticks) / 100; + this.nticks3 = Math.floor(ndiv/10000); + + if (axis && !is_gaxis && (this.nticks > 7)) this.nticks = 7; + + var gr_range = Math.abs(this.func.range()[1] - this.func.range()[0]); + if (gr_range<=0) gr_range = 100; + + if (this.kind == 'time') { + if (this.nticks > 8) this.nticks = 8; + + var scale_range = this.scale_max - this.scale_min, + tf1 = JSROOT.Painter.getTimeFormat(axis), + tf2 = JSROOT.Painter.chooseTimeFormat(scale_range / gr_range, false); + + if ((tf1.length == 0) || (scale_range < 0.1 * (this.full_max - this.full_min))) + tf1 = JSROOT.Painter.chooseTimeFormat(scale_range / this.nticks, true); + + this.tfunc1 = this.tfunc2 = d3.timeFormat(tf1); + if (tf2!==tf1) + this.tfunc2 = d3.timeFormat(tf2); + + this.format = function(d, asticks) { + return asticks ? this.tfunc1(d) : this.tfunc2(d); + } + + } else if (this.kind == 'log') { + if (this.nticks2 > 1) { + this.nticks *= this.nticks2; // all log ticks (major or minor) created centrally + this.nticks2 = 1; + } + this.noexp = axis ? axis.TestBit(JSROOT.EAxisBits.kNoExponent) : false; + if ((this.scale_max < 300) && (this.scale_min > 0.3)) this.noexp = true; + this.moreloglabels = axis ? axis.TestBit(JSROOT.EAxisBits.kMoreLogLabels) : false; + + this.format = function(d, asticks, notickexp_fmt) { + var val = parseFloat(d), rnd = Math.round(val); + if (!asticks) + return ((rnd === val) && (Math.abs(rnd)<1e9)) ? rnd.toString() : JSROOT.FFormat(val, notickexp_fmt || JSROOT.gStyle.fStatFormat); + + if (val <= 0) return null; + var vlog = JSROOT.log10(val); + if (this.moreloglabels || (Math.abs(vlog - Math.round(vlog))<0.001)) { + if (!this.noexp && !notickexp_fmt) + return this.format10Exp(Math.floor(vlog+0.01), val); + + return (vlog<0) ? val.toFixed(Math.round(-vlog+0.5)) : val.toFixed(0); + } + return null; + } + } else if (this.kind == 'labels') { + this.nticks = 50; // for text output allow max 50 names + var scale_range = this.scale_max - this.scale_min; + if (this.nticks > scale_range) + this.nticks = Math.round(scale_range); + this.nticks2 = 1; + + this.regular_labels = true; + + if (axis && axis.fNbins && axis.fLabels) { + if ((axis.fNbins != Math.round(axis.fXmax - axis.fXmin)) || + (axis.fXmin != 0) || (axis.fXmax != axis.fNbins)) { + this.regular_labels = false; + } + } + + this.axis = axis; + + this.format = function(d) { + var indx = parseFloat(d); + if (!this.regular_labels) + indx = (indx - this.axis.fXmin)/(this.axis.fXmax - this.axis.fXmin) * this.axis.fNbins; + indx = Math.round(indx); + if ((indx<0) || (indx>=this.axis.fNbins)) return null; + for (var i = 0; i < this.axis.fLabels.arr.length; ++i) { + var tstr = this.axis.fLabels.arr[i]; + if (tstr.fUniqueID === indx+1) return tstr.fString; + } + return null; + } + } else { + + this.order = 0; + this.ndig = 0; + + this.format = function(d, asticks, fmt) { + var val = parseFloat(d); + if (asticks && this.order) val = val / Math.pow(10, this.order); + + if (val === Math.round(val)) + return (Math.abs(val)<1e9) ? val.toFixed(0) : val.toExponential(4); + + if (asticks) return (this.ndig>10) ? val.toExponential(this.ndig-11) : val.toFixed(this.ndig); + + return JSROOT.FFormat(val, fmt || JSROOT.gStyle.fStatFormat); + } + } + } + + TAxisPainter.prototype.ProduceTicks = function(ndiv, ndiv2) { + if (!this.noticksopt) return this.func.ticks(ndiv * (ndiv2 || 1)); + + if (ndiv2) ndiv = (ndiv-1) * ndiv2; + var dom = this.func.domain(), ticks = []; + for (var n=0;n<=ndiv;++n) + ticks.push((dom[0]*(ndiv-n) + dom[1]*n)/ndiv); + return ticks; + } + + TAxisPainter.prototype.CreateTicks = function(only_major_as_array, optionNoexp, optionNoopt, optionInt) { + // function used to create array with minor/middle/major ticks + + if (optionNoopt && this.nticks && (this.kind == "normal")) this.noticksopt = true; + + var handle = { nminor: 0, nmiddle: 0, nmajor: 0, func: this.func }; + + handle.minor = handle.middle = handle.major = this.ProduceTicks(this.nticks); + + if (only_major_as_array) { + var res = handle.major, delta = (this.scale_max - this.scale_min)*1e-5; + if (res[0] > this.scale_min + delta) res.unshift(this.scale_min); + if (res[res.length-1] < this.scale_max - delta) res.push(this.scale_max); + return res; + } + + if ((this.kind == 'labels') && !this.regular_labels) { + handle.lbl_pos = []; + for (var n=0;n<this.axis.fNbins;++n) { + var x = this.axis.fXmin + n / this.axis.fNbins * (this.axis.fXmax - this.axis.fXmin); + if ((x >= this.scale_min) && (x < this.scale_max)) handle.lbl_pos.push(x); + } + } + + if (this.nticks2 > 1) { + handle.minor = handle.middle = this.ProduceTicks(handle.major.length, this.nticks2); + + var gr_range = Math.abs(this.func.range()[1] - this.func.range()[0]); + + // avoid black filling by middle-size + if ((handle.middle.length <= handle.major.length) || (handle.middle.length > gr_range/3.5)) { + handle.minor = handle.middle = handle.major; + } else + if ((this.nticks3 > 1) && (this.kind !== 'log')) { + handle.minor = this.ProduceTicks(handle.middle.length, this.nticks3); + if ((handle.minor.length <= handle.middle.length) || (handle.minor.length > gr_range/1.7)) handle.minor = handle.middle; + } + } + + handle.reset = function() { + this.nminor = this.nmiddle = this.nmajor = 0; + } + + handle.next = function(doround) { + if (this.nminor >= this.minor.length) return false; + + this.tick = this.minor[this.nminor++]; + this.grpos = this.func(this.tick); + if (doround) this.grpos = Math.round(this.grpos); + this.kind = 3; + + if ((this.nmiddle < this.middle.length) && (Math.abs(this.grpos - this.func(this.middle[this.nmiddle])) < 1)) { + this.nmiddle++; + this.kind = 2; + } + + if ((this.nmajor < this.major.length) && (Math.abs(this.grpos - this.func(this.major[this.nmajor])) < 1) ) { + this.nmajor++; + this.kind = 1; + } + return true; + } + + handle.last_major = function() { + return (this.kind !== 1) ? false : this.nmajor == this.major.length; + } + + handle.next_major_grpos = function() { + if (this.nmajor >= this.major.length) return null; + return this.func(this.major[this.nmajor]); + } + + this.order = 0; + this.ndig = 0; + + // at the moment when drawing labels, we can try to find most optimal text representation for them + + if ((this.kind == "normal") && (handle.major.length > 0)) { + + var maxorder = 0, minorder = 0, exclorder3 = false; + + if (!optionNoexp) { + var maxtick = Math.max(Math.abs(handle.major[0]),Math.abs(handle.major[handle.major.length-1])), + mintick = Math.min(Math.abs(handle.major[0]),Math.abs(handle.major[handle.major.length-1])), + ord1 = (maxtick > 0) ? Math.round(JSROOT.log10(maxtick)/3)*3 : 0, + ord2 = (mintick > 0) ? Math.round(JSROOT.log10(mintick)/3)*3 : 0; + + exclorder3 = (maxtick < 2e4); // do not show 10^3 for values below 20000 + + if (maxtick || mintick) { + maxorder = Math.max(ord1,ord2) + 3; + minorder = Math.min(ord1,ord2) - 3; + } + } + + // now try to find best combination of order and ndig for labels + + var bestorder = 0, bestndig = this.ndig, bestlen = 1e10; + + for (var order = minorder; order <= maxorder; order+=3) { + if (exclorder3 && (order===3)) continue; + this.order = order; + this.ndig = 0; + var lbls = [], indx = 0, totallen = 0; + while (indx<handle.major.length) { + var lbl = this.format(handle.major[indx], true); + if (lbls.indexOf(lbl)<0) { + lbls.push(lbl); + totallen += lbl.length; + indx++; + continue; + } + if (++this.ndig > 11) break; // not too many digits, anyway it will be exponential + lbls = []; indx = 0; totallen = 0; + } + + // for order==0 we should virually remove "0." and extra label on top + if (!order && (this.ndig<4)) totallen-=(handle.major.length*2+3); + + if (totallen < bestlen) { + bestlen = totallen; + bestorder = this.order; + bestndig = this.ndig; + } + } + + this.order = bestorder; + this.ndig = bestndig; + + if (optionInt) { + if (this.order) console.warn('Axis painter - integer labels are configured, but axis order ' + this.order + ' is preferable'); + if (this.ndig) console.warn('Axis painter - integer labels are configured, but ' + this.ndig + ' decimal digits are required'); + this.ndig = 0; + this.order = 0; + } + } + + return handle; + } + + TAxisPainter.prototype.IsCenterLabels = function() { + if (this.kind === 'labels') return true; + if (this.kind === 'log') return false; + var axis = this.GetObject(); + return axis && axis.TestBit(JSROOT.EAxisBits.kCenterLabels); + } + + TAxisPainter.prototype.AddTitleDrag = function(title_g, vertical, offset_k, reverse, axis_length) { + if (!JSROOT.gStyle.MoveResize) return; + + var pthis = this, drag_rect = null, prefix = "", drag_move, + acc_x, acc_y, new_x, new_y, sign_0, center_0, alt_pos; + if (JSROOT._test_d3_ === 3) { + prefix = "drag"; + drag_move = d3.behavior.drag().origin(Object); + } else { + drag_move = d3.drag().subject(Object); + } + + drag_move + .on(prefix+"start", function() { + + d3.event.sourceEvent.preventDefault(); + d3.event.sourceEvent.stopPropagation(); + + var box = title_g.node().getBBox(), // check that elements visible, request precise value + axis = pthis.GetObject(); + + new_x = acc_x = title_g.property('shift_x'); + new_y = acc_y = title_g.property('shift_y'); + + sign_0 = vertical ? (acc_x>0) : (acc_y>0); // sign should remain + + if (axis.TestBit(JSROOT.EAxisBits.kCenterTitle)) + alt_pos = (reverse === vertical) ? axis_length : 0; + else + alt_pos = Math.round(axis_length/2); + + drag_rect = title_g.append("rect") + .classed("zoom", true) + .attr("x", box.x) + .attr("y", box.y) + .attr("width", box.width) + .attr("height", box.height) + .style("cursor", "move"); +// .style("pointer-events","none"); // let forward double click to underlying elements + }).on("drag", function() { + if (!drag_rect) return; + + d3.event.sourceEvent.preventDefault(); + d3.event.sourceEvent.stopPropagation(); + + acc_x += d3.event.dx; + acc_y += d3.event.dy; + + var set_x = title_g.property('shift_x'), + set_y = title_g.property('shift_y'); + + if (vertical) { + set_x = acc_x; + if (Math.abs(acc_y - set_y) > Math.abs(acc_y - alt_pos)) set_y = alt_pos; + } else { + set_y = acc_y; + if (Math.abs(acc_x - set_x) > Math.abs(acc_x - alt_pos)) set_x = alt_pos; + } + + if (sign_0 === (vertical ? (set_x>0) : (set_y>0))) { + new_x = set_x; new_y = set_y; + title_g.attr('transform', 'translate(' + new_x + ',' + new_y + ')'); + } + + }).on(prefix+"end", function() { + if (!drag_rect) return; + + d3.event.sourceEvent.preventDefault(); + d3.event.sourceEvent.stopPropagation(); + + title_g.property('shift_x', new_x) + .property('shift_y', new_y); + + var axis = pthis.GetObject(); + + axis.fTitleOffset = (vertical ? new_x : new_y) / offset_k; + if ((vertical ? new_y : new_x) === alt_pos) axis.InvertBit(JSROOT.EAxisBits.kCenterTitle); + + drag_rect.remove(); + drag_rect = null; + }); + + title_g.style("cursor", "move").call(drag_move); + } + + TAxisPainter.prototype.DrawAxis = function(vertical, layer, w, h, transform, reverse, second_shift, disable_axis_drawing, max_text_width) { + // function draws TAxis or TGaxis object + + var axis = this.GetObject(), chOpt = "", + is_gaxis = (axis && axis._typename === 'TGaxis'), + axis_g = layer, tickSize = 0.03, + scaling_size = 100, draw_lines = true, + pad_w = this.pad_width() || 10, + pad_h = this.pad_height() || 10; + + this.vertical = vertical; + + function myXor(a,b) { return ( a && !b ) || (!a && b); } + + // shift for second ticks set (if any) + if (!second_shift) second_shift = 0; else + if (this.invert_side) second_shift = -second_shift; + + if (is_gaxis) { + this.createAttLine({ attr: axis }); + draw_lines = axis.fLineColor != 0; + chOpt = axis.fChopt; + tickSize = axis.fTickSize; + scaling_size = (vertical ? 1.7*h : 0.6*w); + } else { + this.createAttLine({ color: axis.fAxisColor, width: 1, style: 1 }); + chOpt = myXor(vertical, this.invert_side) ? "-S" : "+S"; + tickSize = axis.fTickLength; + scaling_size = (vertical ? pad_w : pad_h); + } + + if (!is_gaxis || (this.name === "zaxis")) { + axis_g = layer.select("." + this.name + "_container"); + if (axis_g.empty()) + axis_g = layer.append("svg:g").attr("class",this.name + "_container"); + else + axis_g.selectAll("*").remove(); + } else { + if (!disable_axis_drawing && draw_lines) + axis_g.append("svg:line") + .attr("x1",0).attr("y1",0) + .attr("x1",vertical ? 0 : w) + .attr("y1", vertical ? h : 0) + .call(this.lineatt.func); + } + + axis_g.attr("transform", transform || null); + + var side = 1, ticks_plusminus = 0, + text_scaling_size = Math.min(pad_w, pad_h), + optionPlus = (chOpt.indexOf("+")>=0), + optionMinus = (chOpt.indexOf("-")>=0), + optionSize = (chOpt.indexOf("S")>=0), + optionY = (chOpt.indexOf("Y")>=0), + optionUp = (chOpt.indexOf("0")>=0), + optionDown = (chOpt.indexOf("O")>=0), + optionUnlab = (chOpt.indexOf("U")>=0), // no labels + optionNoopt = (chOpt.indexOf("N")>=0), // no ticks position optimization + optionInt = (chOpt.indexOf("I")>=0), // integer labels + optionNoexp = axis.TestBit(JSROOT.EAxisBits.kNoExponent); + + if (is_gaxis && axis.TestBit(JSROOT.EAxisBits.kTickPlus)) optionPlus = true; + if (is_gaxis && axis.TestBit(JSROOT.EAxisBits.kTickMinus)) optionMinus = true; + + if (optionPlus && optionMinus) { side = 1; ticks_plusminus = 1; } else + if (optionMinus) { side = myXor(reverse,vertical) ? 1 : -1; } else + if (optionPlus) { side = myXor(reverse,vertical) ? -1 : 1; } + + tickSize = Math.round((optionSize ? tickSize : 0.03) * scaling_size); + + if (this.max_tick_size && (tickSize > this.max_tick_size)) tickSize = this.max_tick_size; + + this.CreateFormatFuncs(); + + var res = "", res2 = "", lastpos = 0, lasth = 0; + + // first draw ticks + + this.ticks = []; + + var handle = this.CreateTicks(false, optionNoexp, optionNoopt, optionInt); + + while (handle.next(true)) { + + var h1 = Math.round(tickSize/4), h2 = 0; + + if (handle.kind < 3) + h1 = Math.round(tickSize/2); + + if (handle.kind == 1) { + // if not showing labels, not show large tick + if (!('format' in this) || (this.format(handle.tick,true)!==null)) h1 = tickSize; + this.ticks.push(handle.grpos); // keep graphical positions of major ticks + } + + if (ticks_plusminus > 0) h2 = -h1; else + if (side < 0) { h2 = -h1; h1 = 0; } else { h2 = 0; } + + if (res.length == 0) { + res = vertical ? ("M"+h1+","+handle.grpos) : ("M"+handle.grpos+","+(-h1)); + res2 = vertical ? ("M"+(second_shift-h1)+","+handle.grpos) : ("M"+handle.grpos+","+(second_shift+h1)); + } else { + res += vertical ? ("m"+(h1-lasth)+","+(handle.grpos-lastpos)) : ("m"+(handle.grpos-lastpos)+","+(lasth-h1)); + res2 += vertical ? ("m"+(lasth-h1)+","+(handle.grpos-lastpos)) : ("m"+(handle.grpos-lastpos)+","+(h1-lasth)); + } + + res += vertical ? ("h"+ (h2-h1)) : ("v"+ (h1-h2)); + res2 += vertical ? ("h"+ (h1-h2)) : ("v"+ (h2-h1)); + + lastpos = handle.grpos; + lasth = h2; + } + + if ((res.length > 0) && !disable_axis_drawing && draw_lines) + axis_g.append("svg:path").attr("d", res).call(this.lineatt.func); + + if ((second_shift!==0) && (res2.length>0) && !disable_axis_drawing && draw_lines) + axis_g.append("svg:path").attr("d", res2).call(this.lineatt.func); + + var labelsize = Math.round( (axis.fLabelSize < 1) ? axis.fLabelSize * text_scaling_size : axis.fLabelSize); + if ((labelsize <= 0) || (Math.abs(axis.fLabelOffset) > 1.1)) optionUnlab = true; // disable labels when size not specified + + // draw labels (on both sides, when needed) + if (!disable_axis_drawing && !optionUnlab) { + + var label_color = this.get_color(axis.fLabelColor), + labeloffset = Math.round(axis.fLabelOffset*text_scaling_size /*+ 0.5*labelsize*/), + center_lbls = this.IsCenterLabels(), + rotate_lbls = axis.TestBit(JSROOT.EAxisBits.kLabelsVert), + textscale = 1, maxtextlen = 0, lbls_tilt = false, labelfont = null, + label_g = [ axis_g.append("svg:g").attr("class","axis_labels") ], + lbl_pos = handle.lbl_pos || handle.major; + + if (this.lbls_both_sides) + label_g.push(axis_g.append("svg:g").attr("class","axis_labels").attr("transform", vertical ? "translate(" + w + ",0)" : "translate(0," + (-h) + ")")); + + for (var lcnt = 0; lcnt < label_g.length; ++lcnt) { + + if (lcnt > 0) side = -side; + + var lastpos = 0, + fix_coord = vertical ? -labeloffset*side : (labeloffset+2)*side + ticks_plusminus*tickSize; + + labelfont = JSROOT.Painter.getFontDetails(axis.fLabelFont, labelsize); + + this.StartTextDrawing(labelfont, 'font', label_g[lcnt]); + + for (var nmajor=0;nmajor<lbl_pos.length;++nmajor) { + + var lbl = this.format(lbl_pos[nmajor], true); + if (lbl === null) continue; + + var pos = Math.round(this.func(lbl_pos[nmajor])), + gap_before = (nmajor>0) ? Math.abs(Math.round(pos - this.func(lbl_pos[nmajor-1]))) : 0, + gap_after = (nmajor<lbl_pos.length-1) ? Math.abs(Math.round(this.func(lbl_pos[nmajor+1])-pos)) : 0; + + if (center_lbls) { + var gap = gap_after || gap_before; + pos = Math.round(pos - (vertical ? 0.5*gap : -0.5*gap)); + if ((pos < -5) || (pos > (vertical ? h : w) + 5)) continue; + } + + var arg = { text: lbl, color: label_color, latex: 1, draw_g: label_g[lcnt] }; + + maxtextlen = Math.max(maxtextlen, lbl.length); + + if (vertical) { + arg.x = fix_coord; + arg.y = pos; + arg.align = rotate_lbls ? ((side<0) ? 23 : 20) : ((side<0) ? 12 : 32); + } else { + arg.x = pos; + arg.y = fix_coord; + arg.align = rotate_lbls ? ((side<0) ? 12 : 32) : ((side<0) ? 20 : 23); + } + + if (rotate_lbls) arg.rotate = 270; + + var textwidth = this.DrawText(arg); + + if (textwidth && ((!vertical && !rotate_lbls) || (vertical && rotate_lbls)) && (this.kind != 'log')) { + var maxwidth = gap_before*0.45 + gap_after*0.45; + if (!gap_before) maxwidth = 0.9*gap_after; else + if (!gap_after) maxwidth = 0.9*gap_before; + textscale = Math.min(textscale, maxwidth / textwidth); + } else if (vertical && max_text_width && !lcnt && (max_text_width - labeloffset > 20) && (textwidth > max_text_width - labeloffset)) { + textscale = Math.min(textscale, (max_text_width - labeloffset) / textwidth); + } + + if (lastpos && (pos!=lastpos) && ((vertical && !rotate_lbls) || (!vertical && rotate_lbls))) { + var axis_step = Math.abs(pos-lastpos); + textscale = Math.min(textscale, 0.9*axis_step/labelsize); + } + + lastpos = pos; + } + + if (this.order) + this.DrawText({ color: label_color, + x: vertical ? side*5 : w+5, + y: this.has_obstacle ? fix_coord : (vertical ? -3 : -3*side), + align: vertical ? ((side<0) ? 30 : 10) : ( myXor(this.has_obstacle, (side<0)) ? 13 : 10 ), + latex: 1, + text: '#times' + this.format10Exp(this.order), + draw_g: label_g[lcnt] + }); + + } + + if ((textscale > 0.01) && (textscale < 0.7) && !vertical && !rotate_lbls && (maxtextlen > 5) && !this.lbls_both_sides) { + lbls_tilt = true; + textscale *= 3; + } + + for (var lcnt = 0; lcnt < label_g.length; ++lcnt) { + if ((textscale > 0.01) && (textscale < 1)) + this.TextScaleFactor(1/textscale, label_g[lcnt]); + + this.FinishTextDrawing(label_g[lcnt]); + if (lbls_tilt) + label_g[lcnt].selectAll("text").each(function() { + var txt = d3.select(this), tr = txt.attr("transform"); + txt.attr("transform", tr + " rotate(25)").style("text-anchor", "start"); + }); + } + + if (label_g.length > 1) side = -side; + + if (labelfont) labelsize = labelfont.size; // use real font size + } + + if (JSROOT.gStyle.Zooming && !this.disable_zooming) { + var r = axis_g.append("svg:rect") + .attr("class", "axis_zoom") + .style("opacity", "0") + .style("cursor", "crosshair"); + + if (vertical) + r.attr("x", (side>0) ? (-2*labelsize - 3) : 3) + .attr("y", 0) + .attr("width", 2*labelsize + 3) + .attr("height", h) + else + r.attr("x", 0).attr("y", (side>0) ? 0 : -labelsize-3) + .attr("width", w).attr("height", labelsize + 3); + } + + if ((axis.fTitle.length > 0) && !disable_axis_drawing) { + var title_g = axis_g.append("svg:g").attr("class", "axis_title"), + title_fontsize = (axis.fTitleSize >= 1) ? axis.fTitleSize : Math.round(axis.fTitleSize * text_scaling_size), + title_offest_k = 1.6*(axis.fTitleSize<1 ? axis.fTitleSize : axis.fTitleSize/(this.pad_height("") || 10)), + center = axis.TestBit(JSROOT.EAxisBits.kCenterTitle), + rotate = axis.TestBit(JSROOT.EAxisBits.kRotateTitle) ? -1 : 1, + title_color = this.get_color(axis.fTitleColor), + shift_x = 0, shift_y = 0; + + this.StartTextDrawing(axis.fTitleFont, title_fontsize, title_g); + + var myxor = ((rotate<0) && !reverse) || ((rotate>=0) && reverse); + + if (vertical) { + title_offest_k *= -side*pad_w; + + shift_x = Math.round(title_offest_k*axis.fTitleOffset); + + if ((this.name == "zaxis") && is_gaxis && ('getBoundingClientRect' in axis_g.node())) { + // special handling for color palette labels - draw them always on right side + var rect = axis_g.node().getBoundingClientRect(); + if (shift_x < rect.width - tickSize) shift_x = Math.round(rect.width - tickSize); + } + + shift_y = Math.round(center ? h/2 : (reverse ? h : 0)); + + this.DrawText({ align: (center ? "middle" : (myxor ? "begin" : "end" )) + ";middle", + rotate: (rotate<0) ? 90 : 270, + text: axis.fTitle, color: title_color, draw_g: title_g }); + } else { + title_offest_k *= side*pad_h; + + shift_x = Math.round(center ? w/2 : (reverse ? 0 : w)); + shift_y = Math.round(title_offest_k*axis.fTitleOffset); + this.DrawText({ align: (center ? 'middle' : (myxor ? 'begin' : 'end')) + ";middle", + rotate: (rotate<0) ? 180 : 0, + text: axis.fTitle, color: title_color, draw_g: title_g }); + } + + var axis_rect = null; + if (vertical && (axis.fTitleOffset == 0) && ('getBoundingClientRect' in axis_g.node())) + axis_rect = axis_g.node().getBoundingClientRect(); + + this.FinishTextDrawing(title_g, function() { + if (axis_rect) { + var title_rect = title_g.node().getBoundingClientRect(); + shift_x = (side>0) ? Math.round(axis_rect.left - title_rect.right - title_fontsize*0.3) : + Math.round(axis_rect.right - title_rect.left + title_fontsize*0.3); + } + + title_g.attr('transform', 'translate(' + shift_x + ',' + shift_y + ')') + .property('shift_x', shift_x) + .property('shift_y', shift_y); + }); + + + this.AddTitleDrag(title_g, vertical, title_offest_k, reverse, vertical ? h : w); + } + + this.position = 0; + + if ('getBoundingClientRect' in axis_g.node()) { + var rect1 = axis_g.node().getBoundingClientRect(), + rect2 = this.svg_pad().node().getBoundingClientRect(); + + this.position = rect1.left - rect2.left; // use to control left position of Y scale + } + } + + TAxisPainter.prototype.Redraw = function() { + + var gaxis = this.GetObject(), + x1 = this.AxisToSvg("x", gaxis.fX1, "pad"), + y1 = this.AxisToSvg("y", gaxis.fY1, "pad"), + x2 = this.AxisToSvg("x", gaxis.fX2, "pad"), + y2 = this.AxisToSvg("y", gaxis.fY2, "pad"), + w = x2 - x1, h = y1 - y2, + vertical = Math.abs(w) < Math.abs(h), + func = null, reverse = false, kind = "normal", + min = gaxis.fWmin, max = gaxis.fWmax, + domain_min = min, domain_max = max; + + if (gaxis.fChopt.indexOf("t")>=0) { + func = d3.scaleTime(); + kind = "time"; + this.toffset = JSROOT.Painter.getTimeOffset(gaxis); + domain_min = new Date(this.toffset + min*1000); + domain_max = new Date(this.toffset + max*1000); + } else if (gaxis.fChopt.indexOf("G")>=0) { + func = d3.scaleLog(); + kind = "log"; + } else { + func = d3.scaleLinear(); + kind = "normal"; + } + + func.domain([domain_min, domain_max]); + + if (vertical) { + if (h > 0) { + func.range([h,0]); + } else { + var d = y1; y1 = y2; y2 = d; + h = -h; reverse = true; + func.range([0,h]); + } + } else { + if (w > 0) { + func.range([0,w]); + } else { + var d = x1; x1 = x2; x2 = d; + w = -w; reverse = true; + func.range([w,0]); + } + } + + this.SetAxisConfig(vertical ? "yaxis" : "xaxis", kind, func, min, max, min, max); + + this.CreateG(); + + this.DrawAxis(vertical, this.draw_g, w, h, "translate(" + x1 + "," + y2 +")", reverse); + } + + // ========================================================================================== + + + function TFramePainter(tframe) { + JSROOT.TooltipHandler.call(this, tframe); + this.mode3d = false; + this.shrink_frame_left = 0.; + this.x_kind = 'normal'; // 'normal', 'log', 'time', 'labels' + this.y_kind = 'normal'; // 'normal', 'log', 'time', 'labels' + this.xmin = this.xmax = 0; // no scale specified, wait for objects drawing + this.ymin = this.ymax = 0; // no scale specified, wait for objects drawing + this.axes_drawn = false; + this.keys_handler = null; + this.mode3d = false; + } + + TFramePainter.prototype = Object.create(JSROOT.TooltipHandler.prototype); + + TFramePainter.prototype.frame_painter = function() { + return this; + } + + /** @summary Set active flag for frame - can block some events + * @private */ + TFramePainter.prototype.SetActive = function(on) { + // do nothing here - key handler is handled differently + } + + TFramePainter.prototype.GetTipName = function(append) { + var res = JSROOT.TooltipHandler.prototype.GetTipName.call(this) || "TFrame"; + if (append) res+=append; + return res; + } + + TFramePainter.prototype.Shrink = function(shrink_left, shrink_right) { + this.fX1NDC += shrink_left; + this.fX2NDC -= shrink_right; + } + + TFramePainter.prototype.SetLastEventPos = function(pnt) { + // set position of last context menu event, can be + this.fLastEventPnt = pnt; + } + + TFramePainter.prototype.GetLastEventPos = function() { + // return position of last event + return this.fLastEventPnt; + } + + TFramePainter.prototype.UpdateAttributes = function(force) { + var tframe = this.GetObject(); + + if ((this.fX1NDC === undefined) || (force && !this.modified_NDC)) { + JSROOT.extend(this, JSROOT.gStyle.FrameNDC); + + if (tframe && tframe.fPos && tframe.fSize) { + this.fX1NDC = tframe.fPos.fHoriz.fNormal.fVal; + this.fX2NDC = this.fX1NDC + tframe.fSize.fHoriz.fNormal.fVal; + this.fY1NDC = tframe.fPos.fVert.fNormal.fVal; + this.fY2NDC = this.fY1NDC + tframe.fSize.fVert.fNormal.fVal; + } + } + + if (this.fillatt === undefined) { + this.createAttFill({ pattern: 1001, color: 0 }); + + var fillcolor = 'white'; + if (tframe && tframe.fFillColor) + fillcolor = this.canv_painter().GetNewColor(tframe.fFillColor, true); + + this.fillatt.SetSolidColor(fillcolor); + } + + this.createAttLine({ color: 'black' }); + } + + TFramePainter.prototype.ProjectAitoff2xy = function(l, b) { + var DegToRad = Math.PI/180, + alpha2 = (l/2)*DegToRad, + delta = b*DegToRad, + r2 = Math.sqrt(2), + f = 2*r2/Math.PI, + cdec = Math.cos(delta), + denom = Math.sqrt(1. + cdec*Math.cos(alpha2)), + res = { + x: cdec*Math.sin(alpha2)*2.*r2/denom/f/DegToRad, + y: Math.sin(delta)*r2/denom/f/DegToRad + }; + // x *= -1.; // for a skymap swap left<->right + return res; + } + + TFramePainter.prototype.ProjectMercator2xy = function(l, b) { + var aid = Math.tan((Math.PI/2 + b/180*Math.PI)/2); + return { x: l, y: Math.log(aid) }; + } + + TFramePainter.prototype.ProjectSinusoidal2xy = function(l, b) { + return { x: l*Math.cos(b/180*Math.PI), y: b }; + } + + TFramePainter.prototype.ProjectParabolic2xy = function(l, b) { + return { + x: l*(2.*Math.cos(2*b/180*Math.PI/3) - 1), + y: 180*Math.sin(b/180*Math.PI/3) + }; + } + + TFramePainter.prototype.RecalculateRange = function(Proj) { + // not yet used, could be useful in the future + + if (!Proj) return; + + var pnts = []; // all extremes which used to find + if (Proj == 1) { + // TODO : check x range not lower than -180 and not higher than 180 + pnts.push(this.ProjectAitoff2xy(this.scale_xmin, this.scale_ymin)); + pnts.push(this.ProjectAitoff2xy(this.scale_xmin, this.scale_ymax)); + pnts.push(this.ProjectAitoff2xy(this.scale_xmax, this.scale_ymax)); + pnts.push(this.ProjectAitoff2xy(this.scale_xmax, this.scale_ymin)); + if (this.scale_ymin<0 && this.scale_ymax>0) { + // there is an 'equator', check its range in the plot.. + pnts.push(this.ProjectAitoff2xy(this.scale_xmin*0.9999, 0)); + pnts.push(this.ProjectAitoff2xy(this.scale_xmax*0.9999, 0)); + } + if (this.scale_xmin<0 && this.scale_xmax>0) { + pnts.push(this.ProjectAitoff2xy(0, this.scale_ymin)); + pnts.push(this.ProjectAitoff2xy(0, this.scale_ymax)); + } + } else if (Proj == 2) { + if (this.scale_ymin <= -90 || this.scale_ymax >=90) { + console.warn("Mercator Projection", "Latitude out of range", this.scale_ymin, this.scale_ymax); + this.options.Proj = 0; + return; + } + pnts.push(this.ProjectMercator2xy(this.scale_xmin, this.scale_ymin)); + pnts.push(this.ProjectMercator2xy(this.scale_xmax, this.scale_ymax)); + + } else if (Proj == 3) { + pnts.push(this.ProjectSinusoidal2xy(this.scale_xmin, this.scale_ymin)); + pnts.push(this.ProjectSinusoidal2xy(this.scale_xmin, this.scale_ymax)); + pnts.push(this.ProjectSinusoidal2xy(this.scale_xmax, this.scale_ymax)); + pnts.push(this.ProjectSinusoidal2xy(this.scale_xmax, this.scale_ymin)); + if (this.scale_ymin<0 && this.scale_ymax>0) { + pnts.push(this.ProjectSinusoidal2xy(this.scale_xmin, 0)); + pnts.push(this.ProjectSinusoidal2xy(this.scale_xmax, 0)); + } + if (this.scale_xmin<0 && this.scale_xmax>0) { + pnts.push(this.ProjectSinusoidal2xy(0, this.scale_ymin)); + pnts.push(this.ProjectSinusoidal2xy(0, this.scale_ymax)); + } + } else if (Proj == 4) { + pnts.push(this.ProjectParabolic2xy(this.scale_xmin, this.scale_ymin)); + pnts.push(this.ProjectParabolic2xy(this.scale_xmin, this.scale_ymax)); + pnts.push(this.ProjectParabolic2xy(this.scale_xmax, this.scale_ymax)); + pnts.push(this.ProjectParabolic2xy(this.scale_xmax, this.scale_ymin)); + if (this.scale_ymin<0 && this.scale_ymax>0) { + pnts.push(this.ProjectParabolic2xy(this.scale_xmin, 0)); + pnts.push(this.ProjectParabolic2xy(this.scale_xmax, 0)); + } + if (this.scale_xmin<0 && this.scale_xmax>0) { + pnts.push(this.ProjectParabolic2xy(0, this.scale_ymin)); + pnts.push(this.ProjectParabolic2xy(0, this.scale_ymax)); + } + } + + this.original_xmin = this.scale_xmin; + this.original_xmax = this.scale_xmax; + this.original_ymin = this.scale_ymin; + this.original_ymax = this.scale_ymax; + + this.scale_xmin = this.scale_xmax = pnts[0].x; + this.scale_ymin = this.scale_ymax = pnts[0].y; + + for (var n=1;n<pnts.length;++n) { + this.scale_xmin = Math.min(this.scale_xmin, pnts[n].x); + this.scale_xmax = Math.max(this.scale_xmax, pnts[n].x); + this.scale_ymin = Math.min(this.scale_ymin, pnts[n].y); + this.scale_ymax = Math.max(this.scale_ymax, pnts[n].y); + } + } + + TFramePainter.prototype.DrawGrids = function() { + // grid can only be drawn by first painter + + var layer = this.svg_frame().select(".grid_layer"); + + layer.selectAll(".xgrid").remove(); + layer.selectAll(".ygrid").remove(); + + var h = this.frame_height(), + w = this.frame_width(), + grid, grid_style = JSROOT.gStyle.fGridStyle, + grid_color = (JSROOT.gStyle.fGridColor > 0) ? this.get_color(JSROOT.gStyle.fGridColor) : "black"; + + if ((grid_style < 0) || (grid_style >= JSROOT.Painter.root_line_styles.length)) grid_style = 11; + + // add a grid on x axis, if the option is set + if (this.x_handle) { + grid = ""; + for (var n=0;n<this.x_handle.ticks.length;++n) + if (this.swap_xy) + grid += "M0,"+this.x_handle.ticks[n]+"h"+w; + else + grid += "M"+this.x_handle.ticks[n]+",0v"+h; + + if (grid.length > 0) + layer.append("svg:path") + .attr("class", "xgrid") + .attr("d", grid) + .style('stroke',grid_color).style("stroke-width",JSROOT.gStyle.fGridWidth) + .style("stroke-dasharray", JSROOT.Painter.root_line_styles[grid_style]); + } + + // add a grid on y axis, if the option is set + if (this.y_handle) { + grid = ""; + for (var n=0;n<this.y_handle.ticks.length;++n) + if (this.swap_xy) + grid += "M"+this.y_handle.ticks[n]+",0v"+h; + else + grid += "M0,"+this.y_handle.ticks[n]+"h"+w; + + if (grid.length > 0) + layer.append("svg:path") + .attr("class", "ygrid") + .attr("d", grid) + .style('stroke',grid_color).style("stroke-width",JSROOT.gStyle.fGridWidth) + .style("stroke-dasharray", JSROOT.Painter.root_line_styles[grid_style]); + } + } + + TFramePainter.prototype.AxisAsText = function(axis, value) { + if (axis == "x") { + if (this.x_kind == 'time') + value = this.ConvertX(value); + if (this.x_handle && ('format' in this.x_handle)) + return this.x_handle.format(value, false, JSROOT.gStyle.XValuesFormat); + } else if (axis == "y") { + if (this.y_kind == 'time') + value = this.ConvertY(value); + if (this.y_handle && ('format' in this.y_handle)) + return this.y_handle.format(value, false, JSROOT.gStyle.YValuesFormat); + } else { + if (this.z_handle && ('format' in this.z_handle)) + return this.z_handle.format(value, false, JSROOT.gStyle.ZValuesFormat); + } + + return value.toPrecision(4); + } + + TFramePainter.prototype.SetAxesRanges = function(xmin, xmax, ymin, ymax) { + if (this.axes_drawn) return; + + if ((this.xmin == this.xmax) && (xmin!==xmax)) { + this.xmin = xmin; + this.xmax = xmax; + } + if ((this.ymin == this.ymax) && (ymin!==ymax)) { + this.ymin = ymin; + this.ymax = ymax; + } + } + + TFramePainter.prototype.DrawAxes = function(shrink_forbidden) { + // axes can be drawn only for main histogram + + if (this.axes_drawn) return true; + + if ((this.xmin==this.xmax) || (this.ymin==this.ymax)) return false; + + this.CleanupAxes(); + this.CleanXY(); + + this.CreateXY(); + + var layer = this.svg_frame().select(".axis_layer"), + w = this.frame_width(), + h = this.frame_height(), + axisx = JSROOT.Create("TAxis"), // temporary object for different attributes + axisy = JSROOT.Create("TAxis"); + + this.x_handle = new JSROOT.TAxisPainter(axisx, true); + this.x_handle.SetDivId(this.divid, -1); + this.x_handle.pad_name = this.pad_name; + + this.x_handle.SetAxisConfig("xaxis", + (this.logx && (this.x_kind !== "time")) ? "log" : this.x_kind, + this.x, this.xmin, this.xmax, this.scale_xmin, this.scale_xmax); + this.x_handle.invert_side = false; + this.x_handle.lbls_both_sides = false; + this.x_handle.has_obstacle = false; + + this.y_handle = new JSROOT.TAxisPainter(axisy, true); + this.y_handle.SetDivId(this.divid, -1); + this.y_handle.pad_name = this.pad_name; + + this.y_handle.SetAxisConfig("yaxis", + (this.logy && this.y_kind !== "time") ? "log" : this.y_kind, + this.y, this.ymin, this.ymax, this.scale_ymin, this.scale_ymax); + this.y_handle.invert_side = false; // ((this.options.AxisPos % 10) === 1) || (pad.fTicky > 1); + this.y_handle.lbls_both_sides = false; + + var draw_horiz = this.swap_xy ? this.y_handle : this.x_handle, + draw_vertical = this.swap_xy ? this.x_handle : this.y_handle, + disable_axis_draw = false, show_second_ticks = false; + + if (!disable_axis_draw) { + var pp = this.pad_painter(); + if (pp && pp._fast_drawing) disable_axis_draw = true; + } + + if (!disable_axis_draw) { + draw_horiz.DrawAxis(false, layer, w, h, + draw_horiz.invert_side ? undefined : "translate(0," + h + ")", + false, show_second_ticks ? -h : 0, disable_axis_draw); + + draw_vertical.DrawAxis(true, layer, w, h, + draw_vertical.invert_side ? "translate(" + w + ",0)" : undefined, + false, show_second_ticks ? w : 0, disable_axis_draw, + draw_vertical.invert_side ? 0 : this.frame_x()); + + this.DrawGrids(); + } + + if (!shrink_forbidden && JSROOT.gStyle.CanAdjustFrame && !disable_axis_draw) { + + var shrink = 0., ypos = draw_vertical.position; + + if ((-0.2*w < ypos) && (ypos < 0)) { + shrink = -ypos/w + 0.001; + this.shrink_frame_left += shrink; + } else if ((ypos>0) && (ypos<0.3*w) && (this.shrink_frame_left > 0) && (ypos/w > this.shrink_frame_left)) { + shrink = -this.shrink_frame_left; + this.shrink_frame_left = 0.; + } + + if (shrink != 0) { + this.Shrink(shrink, 0); + this.Redraw(); + this.DrawAxes(true); + } + } + + this.axes_drawn = true; + + return true; + } + + TFramePainter.prototype.SizeChanged = function() { + // function called at the end of resize of frame + // One should apply changes to the pad + + /* var pad = this.root_pad(); + + if (pad) { + pad.fLeftMargin = this.fX1NDC; + pad.fRightMargin = 1 - this.fX2NDC; + pad.fBottomMargin = this.fY1NDC; + pad.fTopMargin = 1 - this.fY2NDC; + this.SetRootPadRange(pad); + } + */ + + this.RedrawPad(); + } + + TFramePainter.prototype.CleanXY = function() { + // remove all kinds of X/Y function for axes transformation + delete this.x; delete this.grx; + delete this.ConvertX; delete this.RevertX; + delete this.y; delete this.gry; + delete this.ConvertY; delete this.RevertY; + delete this.z; delete this.grz; + } + + TFramePainter.prototype.CleanupAxes = function() { + // remove all axes drawings + if (this.x_handle) { + this.x_handle.Cleanup(); + delete this.x_handle; + } + + if (this.y_handle) { + this.y_handle.Cleanup(); + delete this.y_handle; + } + + if (this.z_handle) { + this.z_handle.Cleanup(); + delete this.z_handle; + } + if (this.draw_g) { + this.draw_g.select(".grid_layer").selectAll("*").remove(); + this.draw_g.select(".axis_layer").selectAll("*").remove(); + } + this.axes_drawn = false; + } + + TFramePainter.prototype.CleanDrawings = function() { + // cleanup all 3D drawings if any + if (typeof this.Create3DScene === 'function') + this.Create3DScene(-1); + + this.CleanupAxes(); + this.CleanXY(); + + this.xmin = this.xmax = 0; + this.ymin = this.ymax = 0; + this.zmin = this.zmax = 0; + + this.zoom_xmin = this.zoom_xmax = 0; + this.zoom_ymin = this.zoom_ymax = 0; + this.zoom_zmin = this.zoom_zmax = 0; + + this.scale_xmin = this.scale_xmax = 0; + this.scale_ymin = this.scale_ymax = 0; + this.scale_zmin = this.scale_zmax = 0; + + if (this.draw_g) { + this.draw_g.select(".main_layer").selectAll("*").remove(); + this.draw_g.select(".upper_layer").selectAll("*").remove(); + } + } + + TFramePainter.prototype.Cleanup = function() { + + this.CleanDrawings(); + + if (this.draw_g) { + this.draw_g.selectAll("*").remove(); + this.draw_g.on("mousedown", null) + .on("dblclick", null) + .on("wheel", null) + .on("contextmenu", null) + .property('interactive_set', null); + } + + if (this.keys_handler) { + window.removeEventListener('keydown', this.keys_handler, false); + this.keys_handler = null; + } + + this.draw_g = null; + delete this._click_handler; + delete this._dblclick_handler; + + JSROOT.TooltipHandler.prototype.Cleanup.call(this); + } + + TFramePainter.prototype.Redraw = function() { + + var pp = this.pad_painter(); + if (pp) pp.frame_painter_ref = this; + + if (this.mode3d) return; + + // first update all attributes from objects + this.UpdateAttributes(); + + var width = this.pad_width(), + height = this.pad_height(), + lm = Math.round(width * this.fX1NDC), + w = Math.round(width * (this.fX2NDC - this.fX1NDC)), + tm = Math.round(height * (1 - this.fY2NDC)), + h = Math.round(height * (this.fY2NDC - this.fY1NDC)), + rotate = false, fixpos = false; + + if (pp && pp.options) { + if (pp.options.RotateFrame) rotate = true; + if (pp.options.FixFrame) fixpos = true; + } + + // this is svg:g object - container for every other items belonging to frame + this.draw_g = this.svg_layer("primitives_layer").select(".root_frame"); + + var top_rect, main_svg; + + if (this.draw_g.empty()) { + + var layer = this.svg_layer("primitives_layer"); + + this.draw_g = layer.append("svg:g").attr("class", "root_frame"); + + this.draw_g.append("svg:title").text(""); + + top_rect = this.draw_g.append("svg:rect"); + + // append for the moment three layers - for drawing and axis + this.draw_g.append('svg:g').attr('class','grid_layer'); + + main_svg = this.draw_g.append('svg:svg') + .attr('class','main_layer') + .attr("x", 0) + .attr("y", 0) + .attr('overflow', 'hidden'); + + this.draw_g.append('svg:g').attr('class','axis_layer'); + this.draw_g.append('svg:g').attr('class','upper_layer'); + } else { + top_rect = this.draw_g.select("rect"); + main_svg = this.draw_g.select(".main_layer"); + } + + this.axes_drawn = false; + + var trans = "translate(" + lm + "," + tm + ")"; + if (rotate) { + trans += " rotate(-90) " + "translate(" + -h + ",0)"; + var d = w; w = h; h = d; + } + + this._frame_x = lm; + this._frame_y = tm; + this._frame_width = w; + this._frame_height = h; + + this.draw_g.attr("transform", trans); + + top_rect.attr("x", 0) + .attr("y", 0) + .attr("width", w) + .attr("height", h) + .call(this.fillatt.func) + .call(this.lineatt.func); + + main_svg.attr("width", w) + .attr("height", h) + .attr("viewBox", "0 0 " + w + " " + h); + + var tooltip_rect = this.draw_g.select(".interactive_rect"); + + if (JSROOT.BatchMode) return tooltip_rect.remove(); + + this.draw_g.attr("x", lm) + .attr("y", tm) + .attr("width", w) + .attr("height", h); + + if (!rotate && !fixpos) + this.AddDrag({ obj: this, only_resize: true, minwidth: 20, minheight: 20, + redraw: this.SizeChanged.bind(this) }); + + if (tooltip_rect.empty()) + tooltip_rect = + this.draw_g + .append("rect") + .attr("class","interactive_rect") + .style('opacity',0) + .style('fill',"none") + .style("pointer-events","visibleFill") + .property('handlers_set', 0); + + var handlers_set = (pp && pp._fast_drawing) ? 0 : 1; + + if (tooltip_rect.property('handlers_set') != handlers_set) { + var close_handler = handlers_set ? this.ProcessTooltipEvent.bind(this, null) : null, + mouse_handler = handlers_set ? this.ProcessTooltipEvent.bind(this, { handler: true, touch: false }) : null; + + tooltip_rect.property('handlers_set', handlers_set) + .on('mouseenter', mouse_handler) + .on('mousemove', mouse_handler) + .on('mouseleave', close_handler); + + if (JSROOT.touches) { + var touch_handler = handlers_set ? this.ProcessTooltipEvent.bind(this, { handler: true, touch: true }) : null; + + tooltip_rect.on("touchstart", touch_handler) + .on("touchmove", touch_handler) + .on("touchend", close_handler) + .on("touchcancel", close_handler); + } + } + + tooltip_rect.attr("x", 0) + .attr("y", 0) + .attr("width", w) + .attr("height", h); + + var hintsg = this.hints_layer().select(".objects_hints"); + // if tooltips were visible before, try to reconstruct them after short timeout + if (!hintsg.empty() && this.IsTooltipAllowed() && (hintsg.property("hints_pad") == this.pad_name)) + setTimeout(this.ProcessTooltipEvent.bind(this, hintsg.property('last_point')), 10); + } + + TFramePainter.prototype.GetFrameRect = function() { + // returns frame rectangle plus extra info for hint display + + return { + x: this.frame_x(), + y: this.frame_y(), + width: this.frame_width(), + height: this.frame_height(), + transform: this.draw_g ? this.draw_g.attr("transform") : "", + hint_delta_x: 0, + hint_delta_y: 0 + } + } + + TFramePainter.prototype.ProcessFrameClick = function(pnt, dblckick) { + // function called when frame is clicked and object selection can be performed + // such event can be used to select + + var pp = this.pad_painter(); + if (!pp) return; + + pnt.painters = true; // provide painters reference in the hints + pnt.disabled = true; // do not invoke graphics + + // collect tooltips from pad painter - it has list of all drawn objects + var hints = pp.GetTooltips(pnt), exact = null; + for (var k=0; (k<hints.length) && !exact; ++k) + if (hints[k] && hints[k].exact) exact = hints[k]; + //if (exact) console.log('Click exact', pnt, exact.painter.GetTipName()); + // else console.log('Click frame', pnt); + + var res; + + if (exact) { + var handler = dblckick ? this._dblclick_handler : this._click_handler; + if (handler) res = handler(exact.user_info, pnt); + } + + if (!dblckick) + pp.SelectObjectPainter(exact ? exact.painter : this, + { x: pnt.x + (this._frame_x || 0), y: pnt.y + (this._frame_y || 0) }); + + return res; + } + + TFramePainter.prototype.ConfigureUserClickHandler = function(handler) { + this._click_handler = handler && (typeof handler == 'function') ? handler : null; + } + + TFramePainter.prototype.ConfigureUserDblclickHandler = function(handler) { + this._dblclick_handler = handler && (typeof handler == 'function') ? handler : null; + } + + TFramePainter.prototype.Zoom = function(xmin, xmax, ymin, ymax, zmin, zmax) { + // function can be used for zooming into specified range + // if both limits for each axis 0 (like xmin==xmax==0), axis will be unzoomed + + // disable zooming when axis conversion is enabled + if (this.options && this.options.Proj) return false; + + if (xmin==="x") { xmin = xmax; xmax = ymin; ymin = undefined; } else + if (xmin==="y") { ymax = ymin; ymin = xmax; xmin = xmax = undefined; } else + if (xmin==="z") { zmin = xmax; zmax = ymin; xmin = xmax = ymin = undefined; } + + var zoom_x = (xmin !== xmax), zoom_y = (ymin !== ymax), zoom_z = (zmin !== zmax), + unzoom_x = false, unzoom_y = false, unzoom_z = false; + + if (zoom_x) { + var cnt = 0; + if (xmin <= this.xmin) { xmin = this.xmin; cnt++; } + if (xmax >= this.xmax) { xmax = this.xmax; cnt++; } + if (cnt === 2) { zoom_x = false; unzoom_x = true; } + } else { + unzoom_x = (xmin === xmax) && (xmin === 0); + } + + if (zoom_y) { + var cnt = 0; + if (ymin <= this.ymin) { ymin = this.ymin; cnt++; } + if (ymax >= this.ymax) { ymax = this.ymax; cnt++; } + if (cnt === 2) { zoom_y = false; unzoom_y = true; } + } else { + unzoom_y = (ymin === ymax) && (ymin === 0); + } + + if (zoom_z) { + var cnt = 0; + // if (this.logz && this.ymin_nz && this.Dimension()===2) main_zmin = 0.3*this.ymin_nz; + if (zmin <= this.zmin) { zmin = this.zmin; cnt++; } + if (zmax >= this.zmax) { zmax = this.zmax; cnt++; } + if (cnt === 2) { zoom_z = false; unzoom_z = true; } + } else { + unzoom_z = (zmin === zmax) && (zmin === 0); + } + + var changed = false, fp = this; + + // first process zooming (if any) + if (zoom_x || zoom_y || zoom_z) + this.ForEachPainter(function(obj) { + if (zoom_x && obj.CanZoomIn("x", xmin, xmax)) { + fp.zoom_xmin = xmin; + fp.zoom_xmax = xmax; + changed = true; + zoom_x = false; + } + if (zoom_y && obj.CanZoomIn("y", ymin, ymax)) { + fp.zoom_ymin = ymin; + fp.zoom_ymax = ymax; + changed = true; + zoom_y = false; + } + if (zoom_z && obj.CanZoomIn("z", zmin, zmax)) { + fp.zoom_zmin = zmin; + fp.zoom_zmax = zmax; + changed = true; + zoom_z = false; + } + }); + + // and process unzoom, if any + if (unzoom_x || unzoom_y || unzoom_z) { + if (unzoom_x) { + if (this.zoom_xmin !== this.zoom_xmax) changed = true; + this.zoom_xmin = this.zoom_xmax = 0; + } + if (unzoom_y) { + if (this.zoom_ymin !== this.zoom_ymax) changed = true; + this.zoom_ymin = this.zoom_ymax = 0; + } + if (unzoom_z) { + if (this.zoom_zmin !== this.zoom_zmax) changed = true; + this.zoom_zmin = this.zoom_zmax = 0; + } + } + + if (changed) this.RedrawPad(); + + return changed; + } + + TFramePainter.prototype.IsAxisZoomed = function(axis) { + return this['zoom_'+axis+'min'] !== this['zoom_'+axis+'max']; + } + + TFramePainter.prototype.Unzoom = function(dox, doy, doz) { + if (typeof dox === 'undefined') { dox = true; doy = true; doz = true; } else + if (typeof dox === 'string') { doz = dox.indexOf("z")>=0; doy = dox.indexOf("y")>=0; dox = dox.indexOf("x")>=0; } + + var last = this.zoom_changed_interactive; + + if (dox || doy || doz) this.zoom_changed_interactive = 2; + + var changed = this.Zoom(dox ? 0 : undefined, dox ? 0 : undefined, + doy ? 0 : undefined, doy ? 0 : undefined, + doz ? 0 : undefined, doz ? 0 : undefined); + + // if unzooming has no effect, decrease counter + if ((dox || doy || doz) && !changed) + this.zoom_changed_interactive = (!isNaN(last) && (last>0)) ? last - 1 : 0; + + return changed; + + } + + TFramePainter.prototype.clearInteractiveElements = function() { + JSROOT.Painter.closeMenu(); + if (this.zoom_rect) { this.zoom_rect.remove(); this.zoom_rect = null; } + this.zoom_kind = 0; + + // enable tooltip in frame painter + this.SwitchTooltip(true); + } + + TFramePainter.prototype.mouseDoubleClick = function() { + d3.event.preventDefault(); + var m = d3.mouse(this.svg_frame().node()); + this.clearInteractiveElements(); + + var valid_x = (m[0] >= 0) && (m[0] <= this.frame_width()), + valid_y = (m[1] >= 0) && (m[1] <= this.frame_height()); + + if (valid_x && valid_y && this._dblclick_handler) + if (this.ProcessFrameClick({ x: m[0], y: m[1] }, true)) return; + + var kind = "xyz"; + if (!valid_x) kind = this.swap_xy ? "x" : "y"; else + if (!valid_y) kind = this.swap_xy ? "y" : "x"; + if (this.Unzoom(kind)) return; + } + + TFramePainter.prototype.FindAlternativeClickHandler = function(pos) { + var pp = this.pad_painter(); + if (!pp) return false; + + var pnt = { x: pos[0], y: pos[1], painters: true, disabled: true, click_handler: true }; + + var hints = pp.GetTooltips(pnt); + for (var k=0;k<hints.length;++k) + if (hints[k] && (typeof hints[k].click_handler == 'function')) { + hints[k].click_handler(hints[k]); + return true; + } + + return false; + } + + TFramePainter.prototype.startRectSel = function() { + // ignore when touch selection is activated + + if (this.zoom_kind > 100) return; + + // ignore all events from non-left button + if ((d3.event.which || d3.event.button) !== 1) return; + + d3.event.preventDefault(); + + var pos = d3.mouse(this.svg_frame().node()); + + if (this.FindAlternativeClickHandler(pos)) return; + + this.clearInteractiveElements(); + this.zoom_origin = pos; + + var w = this.frame_width(), h = this.frame_height(); + + this.zoom_curr = [ Math.max(0, Math.min(w, this.zoom_origin[0])), + Math.max(0, Math.min(h, this.zoom_origin[1])) ]; + + if ((this.zoom_origin[0] < 0) || (this.zoom_origin[0] > w)) { + this.zoom_kind = 3; // only y + this.zoom_origin[0] = 0; + this.zoom_origin[1] = this.zoom_curr[1]; + this.zoom_curr[0] = w; + this.zoom_curr[1] += 1; + } else if ((this.zoom_origin[1] < 0) || (this.zoom_origin[1] > h)) { + this.zoom_kind = 2; // only x + this.zoom_origin[0] = this.zoom_curr[0]; + this.zoom_origin[1] = 0; + this.zoom_curr[0] += 1; + this.zoom_curr[1] = h; + } else { + this.zoom_kind = 1; // x and y + this.zoom_origin[0] = this.zoom_curr[0]; + this.zoom_origin[1] = this.zoom_curr[1]; + } + + d3.select(window).on("mousemove.zoomRect", this.moveRectSel.bind(this)) + .on("mouseup.zoomRect", this.endRectSel.bind(this), true); + + this.zoom_rect = null; + + // disable tooltips in frame painter + this.SwitchTooltip(false); + + d3.event.stopPropagation(); + } + + TFramePainter.prototype.moveRectSel = function() { + + if ((this.zoom_kind == 0) || (this.zoom_kind > 100)) return; + + d3.event.preventDefault(); + var m = d3.mouse(this.svg_frame().node()); + + m[0] = Math.max(0, Math.min(this.frame_width(), m[0])); + m[1] = Math.max(0, Math.min(this.frame_height(), m[1])); + + switch (this.zoom_kind) { + case 1: this.zoom_curr[0] = m[0]; this.zoom_curr[1] = m[1]; break; + case 2: this.zoom_curr[0] = m[0]; break; + case 3: this.zoom_curr[1] = m[1]; break; + } + + if (this.zoom_rect===null) + this.zoom_rect = this.svg_frame() + .append("rect") + .attr("class", "zoom") + .attr("pointer-events","none"); + + this.zoom_rect.attr("x", Math.min(this.zoom_origin[0], this.zoom_curr[0])) + .attr("y", Math.min(this.zoom_origin[1], this.zoom_curr[1])) + .attr("width", Math.abs(this.zoom_curr[0] - this.zoom_origin[0])) + .attr("height", Math.abs(this.zoom_curr[1] - this.zoom_origin[1])); + } + + TFramePainter.prototype.endRectSel = function() { + if ((this.zoom_kind == 0) || (this.zoom_kind > 100)) return; + + d3.event.preventDefault(); + + d3.select(window).on("mousemove.zoomRect", null) + .on("mouseup.zoomRect", null); + + var m = d3.mouse(this.svg_frame().node()), changed = [true, true]; + m[0] = Math.max(0, Math.min(this.frame_width(), m[0])); + m[1] = Math.max(0, Math.min(this.frame_height(), m[1])); + + switch (this.zoom_kind) { + case 1: this.zoom_curr[0] = m[0]; this.zoom_curr[1] = m[1]; break; + case 2: this.zoom_curr[0] = m[0]; changed[1] = false; break; // only X + case 3: this.zoom_curr[1] = m[1]; changed[0] = false; break; // only Y + } + + var xmin, xmax, ymin, ymax, isany = false, + idx = this.swap_xy ? 1 : 0, idy = 1 - idx; + + if (changed[idx] && (Math.abs(this.zoom_curr[idx] - this.zoom_origin[idx]) > 10)) { + xmin = Math.min(this.RevertX(this.zoom_origin[idx]), this.RevertX(this.zoom_curr[idx])); + xmax = Math.max(this.RevertX(this.zoom_origin[idx]), this.RevertX(this.zoom_curr[idx])); + isany = true; + } + + if (changed[idy] && (Math.abs(this.zoom_curr[idy] - this.zoom_origin[idy]) > 10)) { + ymin = Math.min(this.RevertY(this.zoom_origin[idy]), this.RevertY(this.zoom_curr[idy])); + ymax = Math.max(this.RevertY(this.zoom_origin[idy]), this.RevertY(this.zoom_curr[idy])); + isany = true; + } + + var kind = this.zoom_kind, pnt = (kind===1) ? { x: this.zoom_origin[0], y: this.zoom_origin[1] } : null; + + this.clearInteractiveElements(); + + if (isany) { + this.zoom_changed_interactive = 2; + this.Zoom(xmin, xmax, ymin, ymax); + } else { + switch (kind) { + case 1: + var fp = this.frame_painter(); + if (fp) fp.ProcessFrameClick(pnt); + break; + case 2: + var pp = this.pad_painter(); + if (pp) pp.SelectObjectPainter(this.x_handle); + break; + case 3: + var pp = this.pad_painter(); + if (pp) pp.SelectObjectPainter(this.y_handle); + break; + } + } + + this.zoom_kind = 0; + } + + TFramePainter.prototype.startTouchZoom = function() { + // in case when zooming was started, block any other kind of events + if (this.zoom_kind != 0) { + d3.event.preventDefault(); + d3.event.stopPropagation(); + return; + } + + var arr = d3.touches(this.svg_frame().node()); + this.touch_cnt+=1; + + // normally double-touch will be handled + // touch with single click used for context menu + if (arr.length == 1) { + // this is touch with single element + + var now = new Date(), diff = now.getTime() - this.last_touch.getTime(); + this.last_touch = now; + + if ((diff < 300) && this.zoom_curr + && (Math.abs(this.zoom_curr[0] - arr[0][0]) < 30) + && (Math.abs(this.zoom_curr[1] - arr[0][1]) < 30)) { + + d3.event.preventDefault(); + d3.event.stopPropagation(); + + this.clearInteractiveElements(); + this.Unzoom("xyz"); + + this.last_touch = new Date(0); + + this.svg_frame().on("touchcancel", null) + .on("touchend", null, true); + } else + if (JSROOT.gStyle.ContextMenu) { + this.zoom_curr = arr[0]; + this.svg_frame().on("touchcancel", this.endTouchSel.bind(this)) + .on("touchend", this.endTouchSel.bind(this)); + d3.event.preventDefault(); + d3.event.stopPropagation(); + } + } + + if ((arr.length != 2) || !JSROOT.gStyle.Zooming || !JSROOT.gStyle.ZoomTouch) return; + + d3.event.preventDefault(); + d3.event.stopPropagation(); + + this.clearInteractiveElements(); + + this.svg_frame().on("touchcancel", null) + .on("touchend", null); + + var pnt1 = arr[0], pnt2 = arr[1], w = this.frame_width(), h = this.frame_height(); + + this.zoom_curr = [ Math.min(pnt1[0], pnt2[0]), Math.min(pnt1[1], pnt2[1]) ]; + this.zoom_origin = [ Math.max(pnt1[0], pnt2[0]), Math.max(pnt1[1], pnt2[1]) ]; + + if ((this.zoom_curr[0] < 0) || (this.zoom_curr[0] > w)) { + this.zoom_kind = 103; // only y + this.zoom_curr[0] = 0; + this.zoom_origin[0] = w; + } else if ((this.zoom_origin[1] > h) || (this.zoom_origin[1] < 0)) { + this.zoom_kind = 102; // only x + this.zoom_curr[1] = 0; + this.zoom_origin[1] = h; + } else { + this.zoom_kind = 101; // x and y + } + + this.SwitchTooltip(false); + + this.zoom_rect = this.svg_frame().append("rect") + .attr("class", "zoom") + .attr("id", "zoomRect") + .attr("x", this.zoom_curr[0]) + .attr("y", this.zoom_curr[1]) + .attr("width", this.zoom_origin[0] - this.zoom_curr[0]) + .attr("height", this.zoom_origin[1] - this.zoom_curr[1]); + + d3.select(window).on("touchmove.zoomRect", this.moveTouchSel.bind(this)) + .on("touchcancel.zoomRect", this.endTouchSel.bind(this)) + .on("touchend.zoomRect", this.endTouchSel.bind(this)); + } + + TFramePainter.prototype.moveTouchSel = function() { + if (this.zoom_kind < 100) return; + + d3.event.preventDefault(); + + var arr = d3.touches(this.svg_frame().node()); + + if (arr.length != 2) + return this.clearInteractiveElements(); + + var pnt1 = arr[0], pnt2 = arr[1]; + + if (this.zoom_kind != 103) { + this.zoom_curr[0] = Math.min(pnt1[0], pnt2[0]); + this.zoom_origin[0] = Math.max(pnt1[0], pnt2[0]); + } + if (this.zoom_kind != 102) { + this.zoom_curr[1] = Math.min(pnt1[1], pnt2[1]); + this.zoom_origin[1] = Math.max(pnt1[1], pnt2[1]); + } + + this.zoom_rect.attr("x", this.zoom_curr[0]) + .attr("y", this.zoom_curr[1]) + .attr("width", this.zoom_origin[0] - this.zoom_curr[0]) + .attr("height", this.zoom_origin[1] - this.zoom_curr[1]); + + if ((this.zoom_origin[0] - this.zoom_curr[0] > 10) + || (this.zoom_origin[1] - this.zoom_curr[1] > 10)) + this.SwitchTooltip(false); + + d3.event.stopPropagation(); + } + + TFramePainter.prototype.endTouchSel = function() { + + this.svg_frame().on("touchcancel", null) + .on("touchend", null); + + if (this.zoom_kind === 0) { + // special case - single touch can ends up with context menu + + d3.event.preventDefault(); + + var now = new Date(); + + var diff = now.getTime() - this.last_touch.getTime(); + + if ((diff > 500) && (diff<2000) && !this.frame_painter().IsTooltipShown()) { + this.ShowContextMenu('main', { clientX: this.zoom_curr[0], clientY: this.zoom_curr[1] }); + this.last_touch = new Date(0); + } else { + this.clearInteractiveElements(); + } + } + + if (this.zoom_kind < 100) return; + + d3.event.preventDefault(); + d3.select(window).on("touchmove.zoomRect", null) + .on("touchend.zoomRect", null) + .on("touchcancel.zoomRect", null); + + var xmin, xmax, ymin, ymax, isany = false, + xid = this.swap_xy ? 1 : 0, yid = 1 - xid, + changed = [true, true]; + if (this.zoom_kind === 102) changed[1] = false; + if (this.zoom_kind === 103) changed[0] = false; + + if (changed[xid] && (Math.abs(this.zoom_curr[xid] - this.zoom_origin[xid]) > 10)) { + xmin = Math.min(this.RevertX(this.zoom_origin[xid]), this.RevertX(this.zoom_curr[xid])); + xmax = Math.max(this.RevertX(this.zoom_origin[xid]), this.RevertX(this.zoom_curr[xid])); + isany = true; + } + + if (changed[yid] && (Math.abs(this.zoom_curr[yid] - this.zoom_origin[yid]) > 10)) { + ymin = Math.min(this.RevertY(this.zoom_origin[yid]), this.RevertY(this.zoom_curr[yid])); + ymax = Math.max(this.RevertY(this.zoom_origin[yid]), this.RevertY(this.zoom_curr[yid])); + isany = true; + } + + this.clearInteractiveElements(); + this.last_touch = new Date(0); + + if (isany) { + this.zoom_changed_interactive = 2; + this.Zoom(xmin, xmax, ymin, ymax); + } + + d3.event.stopPropagation(); + } + + TFramePainter.prototype.ShowContextMenu = function(kind, evnt, obj) { + // ignore context menu when touches zooming is ongoing + if (('zoom_kind' in this) && (this.zoom_kind > 100)) return; + + // this is for debug purposes only, when context menu is where, close is and show normal menu + //if (!evnt && !kind && document.getElementById('root_ctx_menu')) { + // var elem = document.getElementById('root_ctx_menu'); + // elem.parentNode.removeChild(elem); + // return; + //} + + var menu_painter = this, frame_corner = false, fp = this; // object used to show context menu + + if (!evnt) { + d3.event.preventDefault(); + d3.event.stopPropagation(); // disable main context menu + evnt = d3.event; + + if (kind === undefined) { + var ms = d3.mouse(this.svg_frame().node()), + tch = d3.touches(this.svg_frame().node()), + pp = this.pad_painter(), + pnt = null, sel = null; + + if (tch.length === 1) pnt = { x: tch[0][0], y: tch[0][1], touch: true }; else + if (ms.length === 2) pnt = { x: ms[0], y: ms[1], touch: false }; + + if ((pnt !== null) && (pp !== null)) { + pnt.painters = true; // assign painter for every tooltip + var hints = pp.GetTooltips(pnt), bestdist = 1000; + for (var n=0;n<hints.length;++n) + if (hints[n] && hints[n].menu) { + var dist = ('menu_dist' in hints[n]) ? hints[n].menu_dist : 7; + if (dist < bestdist) { sel = hints[n].painter; bestdist = dist; } + } + } + + if (sel!==null) menu_painter = sel; + + if (pnt!==null) frame_corner = (pnt.x>0) && (pnt.x<20) && (pnt.y>0) && (pnt.y<20); + + this.SetLastEventPos(pnt); + } + } + + // one need to copy event, while after call back event may be changed + menu_painter.ctx_menu_evnt = evnt; + + JSROOT.Painter.createMenu(menu_painter, function(menu) { + var domenu = menu.painter.FillContextMenu(menu, kind, obj); + + // fill frame menu by default - or append frame elements when activated in the frame corner + if (fp && (!domenu || (frame_corner && (kind!=="frame") && (fp!=menu.painter)))) + domenu = fp.FillContextMenu(menu); + + if (domenu) + menu.painter.FillObjectExecMenu(menu, kind, function() { + // suppress any running zooming + menu.painter.SwitchTooltip(false); + menu.show(menu.painter.ctx_menu_evnt, menu.painter.SwitchTooltip.bind(menu.painter, true) ); + }); + + }); // end menu creation + } + + TFramePainter.prototype.FillContextMenu = function(menu, kind, obj) { + + // when fill and show context menu, remove all zooming + this.clearInteractiveElements(); + + if ((kind=="x") || (kind=="y")) { + var faxis = null; + //this.histo.fXaxis; + //if (kind=="y") faxis = this.histo.fYaxis; else + //if (kind=="z") faxis = obj ? obj : this.histo.fZaxis; + menu.add("header: " + kind.toUpperCase() + " axis"); + menu.add("Unzoom", this.Unzoom.bind(this, kind)); + + if (this[kind+"_kind"] == "normal") + menu.addchk(this["log"+kind], "SetLog"+kind, this.ToggleLog.bind(this, kind) ); + + // if ((kind === "z") && this.options.Zscale) + // if (this.FillPaletteMenu) this.FillPaletteMenu(menu); + + if (faxis) { + menu.addchk(faxis.TestBit(JSROOT.EAxisBits.kMoreLogLabels), "More log", + function() { faxis.InvertBit(JSROOT.EAxisBits.kMoreLogLabels); this.RedrawPad(); }); + menu.addchk(faxis.TestBit(JSROOT.EAxisBits.kNoExponent), "No exponent", + function() { faxis.InvertBit(JSROOT.EAxisBits.kNoExponent); this.RedrawPad(); }); + menu.add("sub:Labels"); + menu.addchk(faxis.TestBit(JSROOT.EAxisBits.kCenterLabels), "Center", + function() { faxis.InvertBit(JSROOT.EAxisBits.kCenterLabels); this.RedrawPad(); }); + menu.addchk(faxis.TestBit(JSROOT.EAxisBits.kLabelsVert), "Rotate", + function() { faxis.InvertBit(JSROOT.EAxisBits.kLabelsVert); this.RedrawPad(); }); + this.AddColorMenuEntry(menu, "Color", faxis.fLabelColor, + function(arg) { faxis.fLabelColor = parseInt(arg); this.RedrawPad(); }); + this.AddSizeMenuEntry(menu,"Offset", 0, 0.1, 0.01, faxis.fLabelOffset, + function(arg) { faxis.fLabelOffset = parseFloat(arg); this.RedrawPad(); } ); + this.AddSizeMenuEntry(menu,"Size", 0.02, 0.11, 0.01, faxis.fLabelSize, + function(arg) { faxis.fLabelSize = parseFloat(arg); this.RedrawPad(); } ); + menu.add("endsub:"); + menu.add("sub:Title"); + menu.add("SetTitle", function() { + var t = prompt("Enter axis title", faxis.fTitle); + if (t!==null) { faxis.fTitle = t; this.RedrawPad(); } + }); + menu.addchk(faxis.TestBit(JSROOT.EAxisBits.kCenterTitle), "Center", + function() { faxis.InvertBit(JSROOT.EAxisBits.kCenterTitle); this.RedrawPad(); }); + menu.addchk(faxis.TestBit(JSROOT.EAxisBits.kRotateTitle), "Rotate", + function() { faxis.InvertBit(JSROOT.EAxisBits.kRotateTitle); this.RedrawPad(); }); + this.AddColorMenuEntry(menu, "Color", faxis.fTitleColor, + function(arg) { faxis.fTitleColor = parseInt(arg); this.RedrawPad(); }); + this.AddSizeMenuEntry(menu,"Offset", 0, 3, 0.2, faxis.fTitleOffset, + function(arg) { faxis.fTitleOffset = parseFloat(arg); this.RedrawPad(); } ); + this.AddSizeMenuEntry(menu,"Size", 0.02, 0.11, 0.01, faxis.fTitleSize, + function(arg) { faxis.fTitleSize = parseFloat(arg); this.RedrawPad(); } ); + menu.add("endsub:"); + menu.add("sub:Ticks"); + this.AddColorMenuEntry(menu, "Color", faxis.fAxisColor, + function(arg) { faxis.fAxisColor = parseInt(arg); this.RedrawPad(); }); + this.AddSizeMenuEntry(menu, "Size", -0.05, 0.055, 0.01, faxis.fTickLength, + function(arg) { faxis.fTickLength = parseFloat(arg); this.RedrawPad(); } ); + menu.add("endsub:"); + } + return true; + } + + var alone = menu.size()==0; + + if (alone) + menu.add("header:Frame"); + else + menu.add("separator"); + + if (this.zoom_xmin !== this.zoom_xmax) + menu.add("Unzoom X", this.Unzoom.bind(this,"x")); + if (this.zoom_ymin !== this.zoom_ymax) + menu.add("Unzoom Y", this.Unzoom.bind(this,"y")); + if (this.zoom_zmin !== this.zoom_zmax) + menu.add("Unzoom Z", this.Unzoom.bind(this,"z")); + menu.add("Unzoom all", this.Unzoom.bind(this,"xyz")); + + menu.addchk(this.logx, "SetLogx", this.ToggleLog.bind(this,"x")); + menu.addchk(this.logy, "SetLogy", this.ToggleLog.bind(this,"y")); + // if (this.Dimension() == 2) + // menu.addchk(pad.fLogz, "SetLogz", this.ToggleLog.bind(main,"z")); + menu.add("separator"); + + + menu.addchk(this.IsTooltipAllowed(), "Show tooltips", function() { + this.SetTooltipAllowed("toggle"); + }); + this.FillAttContextMenu(menu,alone ? "" : "Frame "); + menu.add("separator"); + menu.add("Save as frame.png", function() { this.pad_painter().SaveAs("png", 'frame', 'frame.png'); }); + menu.add("Save as frame.svg", function() { this.pad_painter().SaveAs("svg", 'frame', 'frame.svg'); }); + + + return true; + } + + TFramePainter.prototype.ShowAxisStatus = function(axis_name) { + // method called normally when mouse enter main object element + + var status_func = this.GetShowStatusFunc(); + + if (!status_func) return; + + var taxis = null; + + var hint_name = axis_name, hint_title = "TAxis"; + + if (taxis) { hint_name = taxis.fName; hint_title = taxis.fTitle || "histogram TAxis object"; } + + var m = d3.mouse(this.svg_frame().node()); + + var id = (axis_name=="x") ? 0 : 1; + if (this.swap_xy) id = 1-id; + + var axis_value = (axis_name=="x") ? this.RevertX(m[id]) : this.RevertY(m[id]); + + status_func(hint_name, hint_title, axis_name + " : " + this.AxisAsText(axis_name, axis_value), + m[0].toFixed(0)+","+ m[1].toFixed(0)); + } + + TFramePainter.prototype.AddInteractive = function() { + // only first painter in list allowed to add interactive functionality to the frame + + if (JSROOT.BatchMode || (!JSROOT.gStyle.Zooming && !JSROOT.gStyle.ContextMenu)) return; + + var pp = this.pad_painter(); + if (pp && pp._fast_drawing) return; + + var svg = this.svg_frame(); + + if (svg.empty()) return; + + var svg_x = svg.selectAll(".xaxis_container"), + svg_y = svg.selectAll(".yaxis_container"); + + if (!svg.property('interactive_set')) { + this.AddKeysHandler(); + + this.last_touch = new Date(0); + this.zoom_kind = 0; // 0 - none, 1 - XY, 2 - only X, 3 - only Y, (+100 for touches) + this.zoom_rect = null; + this.zoom_origin = null; // original point where zooming started + this.zoom_curr = null; // current point for zooming + this.touch_cnt = 0; + } + + if (JSROOT.gStyle.Zooming && (!this.options || !this.options.Proj)) { + if (JSROOT.gStyle.ZoomMouse) { + svg.on("mousedown", this.startRectSel.bind(this)); + svg.on("dblclick", this.mouseDoubleClick.bind(this)); + } + if (JSROOT.gStyle.ZoomWheel) { + svg.on("wheel", this.mouseWheel.bind(this)); + } + } + + if (JSROOT.touches && ((JSROOT.gStyle.Zooming && JSROOT.gStyle.ZoomTouch) || JSROOT.gStyle.ContextMenu)) + svg.on("touchstart", this.startTouchZoom.bind(this)); + + if (JSROOT.gStyle.ContextMenu) { + if (JSROOT.touches) { + svg_x.on("touchstart", this.startTouchMenu.bind(this,"x")); + svg_y.on("touchstart", this.startTouchMenu.bind(this,"y")); + } + svg.on("contextmenu", this.ShowContextMenu.bind(this)); + svg_x.on("contextmenu", this.ShowContextMenu.bind(this,"x")); + svg_y.on("contextmenu", this.ShowContextMenu.bind(this,"y")); + } + + svg_x.on("mousemove", this.ShowAxisStatus.bind(this,"x")); + svg_y.on("mousemove", this.ShowAxisStatus.bind(this,"y")); + + svg.property('interactive_set', true); + } + + TFramePainter.prototype.mouseWheel = function() { + d3.event.stopPropagation(); + + d3.event.preventDefault(); + this.clearInteractiveElements(); + + var itemx = { name: "x", ignore: false }, + itemy = { name: "y", ignore: !this.AllowDefaultYZooming() }, + cur = d3.mouse(this.svg_frame().node()), + w = this.frame_width(), h = this.frame_height(); + + this.AnalyzeMouseWheelEvent(d3.event, this.swap_xy ? itemy : itemx, cur[0] / w, (cur[1] >=0) && (cur[1] <= h)); + + this.AnalyzeMouseWheelEvent(d3.event, this.swap_xy ? itemx : itemy, 1 - cur[1] / h, (cur[0] >= 0) && (cur[0] <= w)); + + this.Zoom(itemx.min, itemx.max, itemy.min, itemy.max); + + if (itemx.changed || itemy.changed) this.zoom_changed_interactive = 2; + } + + TFramePainter.prototype.AllowDefaultYZooming = function() { + // return true if default Y zooming should be enabled + // it is typically for 2-Dim histograms or + // when histogram not draw, defined by other painters + + var pad_painter = this.pad_painter(); + if (pad_painter && pad_painter.painters) + for (var k = 0; k < pad_painter.painters.length; ++k) { + var subpainter = pad_painter.painters[k]; + if (subpainter && (subpainter.wheel_zoomy!==undefined)) + return subpainter.wheel_zoomy; + } + + return false; + } + + + TFramePainter.prototype.AnalyzeMouseWheelEvent = function(event, item, dmin, ignore) { + + item.min = item.max = undefined; + item.changed = false; + if (ignore && item.ignore) return; + + var delta = 0, delta_left = 1, delta_right = 1; + + if ('dleft' in item) { delta_left = item.dleft; delta = 1; } + if ('dright' in item) { delta_right = item.dright; delta = 1; } + + if ('delta' in item) { + delta = item.delta; + } else if (event && event.wheelDelta !== undefined ) { + // WebKit / Opera / Explorer 9 + delta = -event.wheelDelta; + } else if (event && event.deltaY !== undefined ) { + // Firefox + delta = event.deltaY; + } else if (event && event.detail !== undefined) { + delta = event.detail; + } + + if (delta===0) return; + delta = (delta<0) ? -0.2 : 0.2; + + delta_left *= delta + delta_right *= delta; + + var lmin = item.min = this["scale_"+item.name+"min"], + lmax = item.max = this["scale_"+item.name+"max"], + gmin = this[item.name+"min"], + gmax = this[item.name+"max"]; + + if ((item.min === item.max) && (delta<0)) { + item.min = gmin; + item.max = gmax; + } + + if (item.min >= item.max) return; + + if ((dmin>0) && (dmin<1)) { + if (this['log'+item.name]) { + var factor = (item.min>0) ? JSROOT.log10(item.max/item.min) : 2; + if (factor>10) factor = 10; else if (factor<0.01) factor = 0.01; + item.min = item.min / Math.pow(10, factor*delta_left*dmin); + item.max = item.max * Math.pow(10, factor*delta_right*(1-dmin)); + } else { + var rx_left = (item.max - item.min), rx_right = rx_left; + if (delta_left>0) rx_left = 1.001 * rx_left / (1-delta_left); + item.min += -delta_left*dmin*rx_left; + + if (delta_right>0) rx_right = 1.001 * rx_right / (1-delta_right); + + item.max -= -delta_right*(1-dmin)*rx_right; + } + if (item.min >= item.max) + item.min = item.max = undefined; + else + if (delta_left !== delta_right) { + // extra check case when moving left or right + if (((item.min < gmin) && (lmin===gmin)) || + ((item.max > gmax) && (lmax==gmax))) + item.min = item.max = undefined; + } + + } else { + item.min = item.max = undefined; + } + + item.changed = ((item.min !== undefined) && (item.max !== undefined)); + } + + TFramePainter.prototype.AddKeysHandler = function() { + if (this.keys_handler || JSROOT.BatchMode || (typeof window == 'undefined')) return; + + this.keys_handler = this.ProcessKeyPress.bind(this); + + window.addEventListener('keydown', this.keys_handler, false); + } + + TFramePainter.prototype.ProcessKeyPress = function(evnt) { + + var main = this.select_main(); + if (main.empty()) return; + + var key = ""; + switch (evnt.keyCode) { + case 33: key = "PageUp"; break; + case 34: key = "PageDown"; break; + case 37: key = "ArrowLeft"; break; + case 38: key = "ArrowUp"; break; + case 39: key = "ArrowRight"; break; + case 40: key = "ArrowDown"; break; + case 42: key = "PrintScreen"; break; + case 106: key = "*"; break; + default: return false; + } + + if (evnt.shiftKey) key = "Shift " + key; + if (evnt.altKey) key = "Alt " + key; + if (evnt.ctrlKey) key = "Ctrl " + key; + + var zoom = { name: "x", dleft: 0, dright: 0 }; + + switch (key) { + case "ArrowLeft": zoom.dleft = -1; zoom.dright = 1; break; + case "ArrowRight": zoom.dleft = 1; zoom.dright = -1; break; + case "Ctrl ArrowLeft": zoom.dleft = zoom.dright = -1; break; + case "Ctrl ArrowRight": zoom.dleft = zoom.dright = 1; break; + case "ArrowUp": zoom.name = "y"; zoom.dleft = 1; zoom.dright = -1; break; + case "ArrowDown": zoom.name = "y"; zoom.dleft = -1; zoom.dright = 1; break; + case "Ctrl ArrowUp": zoom.name = "y"; zoom.dleft = zoom.dright = 1; break; + case "Ctrl ArrowDown": zoom.name = "y"; zoom.dleft = zoom.dright = -1; break; + } + + if (zoom.dleft || zoom.dright) { + if (!JSROOT.gStyle.Zooming) return false; + // in 3dmode with orbit control ignore simple arrows + if (this.mode3d && (key.indexOf("Ctrl")!==0)) return false; + this.AnalyzeMouseWheelEvent(null, zoom, 0.5); + this.Zoom(zoom.name, zoom.min, zoom.max); + if (zoom.changed) this.zoom_changed_interactive = 2; + evnt.stopPropagation(); + evnt.preventDefault(); + } else { + var pp = this.pad_painter(), + func = pp ? pp.FindButton(key) : ""; + if (func) { + pp.PadButtonClick(func); + evnt.stopPropagation(); + evnt.preventDefault(); + } + } + + return true; // just process any key press + } + + TFramePainter.prototype.CreateXY = function() { + // here we create x,y objects which maps our physical coordinates into pixels + // while only first painter really need such object, all others just reuse it + // following functions are introduced + // this.GetBin[X/Y] return bin coordinate + // this.Convert[X/Y] converts root value in JS date when date scale is used + // this.[x,y] these are d3.scale objects + // this.gr[x,y] converts root scale into graphical value + // this.Revert[X/Y] converts graphical coordinates to root scale value + + this.swap_xy = false; + this.reverse_x = false; + this.reverse_y = false; + + // if (this.options.BarStyle>=20) this.swap_xy = true; + this.logx = this.logy = false; + + var w = this.frame_width(), h = this.frame_height(); + + this.scale_xmin = this.xmin; + this.scale_xmax = this.xmax; + + this.scale_ymin = this.ymin; + this.scale_ymax = this.ymax; + + // if (opts.extra_y_space) { + // var log_scale = this.swap_xy ? pad.fLogx : pad.fLogy; + // if (log_scale && (this.scale_ymax > 0)) + // this.scale_ymax = Math.exp(Math.log(this.scale_ymax)*1.1); + // else + // this.scale_ymax += (this.scale_ymax - this.scale_ymin) * 0.1; + // } + + //if (typeof this.RecalculateRange == "function") + // this.RecalculateRange(); + + if (false /*this.histo.fXaxis.fTimeDisplay*/) { + this.x_kind = 'time'; + this.timeoffsetx = JSROOT.Painter.getTimeOffset(this.histo.fXaxis); + this.ConvertX = function(x) { return new Date(this.timeoffsetx + x*1000); }; + this.RevertX = function(grx) { return (this.x.invert(grx) - this.timeoffsetx) / 1000; }; + } else { + this.x_kind = 'normal'; // (this.histo.fXaxis.fLabels==null) ? 'normal' : 'labels'; + this.ConvertX = function(x) { return x; }; + this.RevertX = function(grx) { return this.x.invert(grx); }; + } + + if (this.zoom_xmin != this.zoom_xmax) { + this.scale_xmin = this.zoom_xmin; + this.scale_xmax = this.zoom_xmax; + } + + if (this.x_kind == 'time') { + this.x = d3.scaleTime(); + } else if (this.logx) { + if (this.scale_xmax <= 0) this.scale_xmax = 1; + if ((this.scale_xmin <= 0) || (this.scale_xmin >= this.scale_xmax)) + this.scale_xmin = this.scale_xmax * 0.0001; + + this.x = d3.scaleLog(); + } else { + this.x = d3.scaleLinear(); + } + + var gr_range_x = this.reverse_x ? [ w, 0 ] : [ 0, w ], + gr_range_y = this.reverse_y ? [ 0, h ] : [ h, 0 ]; + + this.x.domain([this.ConvertX(this.scale_xmin), this.ConvertX(this.scale_xmax)]) + .range(this.swap_xy ? gr_range_y : gr_range_x); + + if (this.x_kind == 'time') { + // we emulate scale functionality + this.grx = function(val) { return this.x(this.ConvertX(val)); } + } else if (this.logx) { + this.grx = function(val) { return (val < this.scale_xmin) ? (this.swap_xy ? this.x.range()[0]+5 : -5) : this.x(val); } + } else { + this.grx = this.x; + } + + if (this.zoom_ymin != this.zoom_ymax) { + this.scale_ymin = this.zoom_ymin; + this.scale_ymax = this.zoom_ymax; + } + + if (false /*this.histo.fYaxis.fTimeDisplay*/) { + this.y_kind = 'time'; + this.timeoffsety = JSROOT.Painter.getTimeOffset(this.histo.fYaxis); + this.ConvertY = function(y) { return new Date(this.timeoffsety + y*1000); }; + this.RevertY = function(gry) { return (this.y.invert(gry) - this.timeoffsety) / 1000; }; + } else { + this.y_kind = 'normal'; // !this.histo.fYaxis.fLabels ? 'normal' : 'labels'; + this.ConvertY = function(y) { return y; }; + this.RevertY = function(gry) { return this.y.invert(gry); }; + } + + if (this.logy) { + if (this.scale_ymax <= 0) this.scale_ymax = 1; + if ((this.scale_ymin <= 0) || (this.scale_ymin >= this.scale_ymax)) + this.scale_ymin = 3e-4 * this.scale_ymax; + + this.y = d3.scaleLog(); + } else if (this.y_kind == 'time') { + this.y = d3.scaleTime(); + } else { + this.y = d3.scaleLinear() + } + + this.y.domain([ this.ConvertY(this.scale_ymin), this.ConvertY(this.scale_ymax) ]) + .range(this.swap_xy ? gr_range_x : gr_range_y); + + if (this.y_kind=='time') { + // we emulate scale functionality + this.gry = function(val) { return this.y(this.ConvertY(val)); } + } else if (this.logy) { + // make protection for log + this.gry = function(val) { return (val < this.scale_ymin) ? (this.swap_xy ? -5 : this.y.range()[0]+5) : this.y(val); } + } else { + this.gry = this.y; + } + + // this.SetRootPadRange(); + } + + /** Set selected range back to TPad object */ + TFramePainter.prototype.SetRootPadRange = function(pad, is3d) { + // TODO: change of pad range and send back to root application +/* + if (!pad || this.options.Same) return; + + if (is3d) { + // this is fake values, algorithm should be copied from TView3D class of ROOT + pad.fLogx = pad.fLogy = 0; + pad.fUxmin = pad.fUymin = -0.9; + pad.fUxmax = pad.fUymax = 0.9; + } else { + pad.fLogx = (this.swap_xy ? this.logy : this.logx) ? 1 : 0; + pad.fUxmin = this.scale_xmin; + pad.fUxmax = this.scale_xmax; + pad.fLogy = (this.swap_xy ? this.logx : this.logy) ? 1 : 0; + pad.fUymin = this.scale_ymin; + pad.fUymax = this.scale_ymax; + } + + if (pad.fLogx) { + pad.fUxmin = JSROOT.log10(pad.fUxmin); + pad.fUxmax = JSROOT.log10(pad.fUxmax); + } + if (pad.fLogy) { + pad.fUymin = JSROOT.log10(pad.fUymin); + pad.fUymax = JSROOT.log10(pad.fUymax); + } + + var rx = pad.fUxmax - pad.fUxmin, + mx = 1 - pad.fLeftMargin - pad.fRightMargin, + ry = pad.fUymax - pad.fUymin, + my = 1 - pad.fBottomMargin - pad.fTopMargin; + + if (mx <= 0) mx = 0.01; // to prevent overflow + if (my <= 0) my = 0.01; + + pad.fX1 = pad.fUxmin - rx/mx*pad.fLeftMargin; + pad.fX2 = pad.fUxmax + rx/mx*pad.fRightMargin; + pad.fY1 = pad.fUymin - ry/my*pad.fBottomMargin; + pad.fY2 = pad.fUymax + ry/my*pad.fTopMargin; + */ + } + + TFramePainter.prototype.ToggleLog = function(axis) { + var painter = this.main_painter() || this, + pad = this.root_pad(); + var curr = pad["fLog" + axis]; + // do not allow log scale for labels + if (!curr) { + var kind = this[axis+"_kind"]; + if (this.swap_xy && axis==="x") kind = this["y_kind"]; else + if (this.swap_xy && axis==="y") kind = this["x_kind"]; + if (kind === "labels") return; + } + + var pp = this.pad_painter(), canp = this.canv_painter(); + if (pp && pp.snapid && canp && canp._websocket) { + canp.SendWebsocket("OBJEXEC:" + pp.snapid + ":SetLog" + axis + (curr ? "(0)" : "(1)")); + } else { + pad["fLog" + axis] = curr ? 0 : 1; + painter.RedrawPad(); + } + } + + function drawFrame(divid, obj, opt) { + var p = new TFramePainter(obj); + if (opt == "3d") p.mode3d = true; + p.SetDivId(divid, 2); + p.Redraw(); + return p.DrawingReady(); + } + + // =========================================================================== + + function TPadPainter(pad, iscan) { + JSROOT.TObjectPainter.call(this, pad); + this.pad = pad; + this.iscan = iscan; // indicate if working with canvas + this.this_pad_name = ""; + if (!this.iscan && (pad !== null)) { + if (pad.fObjectID) + this.this_pad_name = "pad" + pad.fObjectID; // use objectid as padname + else + this.this_pad_name = "ppp" + JSROOT.id_counter++; // artificical name + } + this.painters = []; // complete list of all painters in the pad + this.has_canvas = true; + } + + TPadPainter.prototype = Object.create(JSROOT.TObjectPainter.prototype); + + TPadPainter.prototype.Cleanup = function() { + // cleanup only pad itself, all child elements will be collected and cleanup separately + + for (var k=0;k<this.painters.length;++k) + this.painters[k].Cleanup(); + + var svg_p = this.svg_pad(this.this_pad_name); + if (!svg_p.empty()) { + svg_p.property('pad_painter', null); + svg_p.property('mainpainter', null); + if (!this.iscan) svg_p.remove(); + } + + delete this.frame_painter_ref; + delete this.pads_cache; + this.painters = []; + this.pad = null; + this.draw_object = null; + this.pad_frame = null; + this.this_pad_name = ""; + this.has_canvas = false; + + JSROOT.Painter.SelectActivePad({ pp: this, active: false }); + + JSROOT.TObjectPainter.prototype.Cleanup.call(this); + } + + /** @summary Cleanup primitives from pad - selector lets define which painters to remove + * @private + */ + + TPadPainter.prototype.CleanPrimitives = function(selector) { + if (!selector || (typeof selector !== 'function')) return; + + for (var k = this.painters.length-1; k >= 0; --k) + if (selector(this.painters[k])) { + this.painters[k].Cleanup(); + this.painters.splice(k, 1); + } + } + + /// call function for each painter + /// kind == "all" for all objects (default) + /// kind == "pads" only pads and subpads + /// kind == "objects" only for object in current pad + TPadPainter.prototype.ForEachPainterInPad = function(userfunc, kind) { + if (!kind) kind = "all"; + if (kind!="objects") userfunc(this); + for (var k = 0; k < this.painters.length; ++k) { + var sub = this.painters[k]; + if (typeof sub.ForEachPainterInPad === 'function') { + if (kind!="objects") sub.ForEachPainterInPad(userfunc, kind); + } else if (kind != "pads") userfunc(sub); + } + } + + TPadPainter.prototype.ButtonSize = function(fact) { + return Math.round((!fact ? 1 : fact) * (this.iscan || !this.has_canvas ? 16 : 12)); + } + + TPadPainter.prototype.RegisterForPadEvents = function(receiver) { + this.pad_events_receiver = receiver; + } + + TPadPainter.prototype.SelectObjectPainter = function(_painter, pos) { + // dummy function, redefined in the TCanvasPainter + + var istoppad = (this.iscan || !this.has_canvas), + canp = istoppad ? this : this.canv_painter(), + pp = _painter instanceof TPadPainter ? _painter : _painter.pad_painter(); + + if (pos && !istoppad) + this.CalcAbsolutePosition(this.svg_pad(this.this_pad_name), pos); + + JSROOT.Painter.SelectActivePad({ pp: pp, active: true }); + + if (typeof canp.SelectActivePad == "function") + canp.SelectActivePad(pp, _painter, pos); + + if (canp.pad_events_receiver) + canp.pad_events_receiver({ what: "select", padpainter: pp, painter: _painter, position: pos }); + } + + /** @brief Called by framework when pad is supposed to be active and get focus + * @private */ + TPadPainter.prototype.SetActive = function(on) { + var fp = this.frame_painter(); + if (fp && (typeof fp.SetActive == 'function')) fp.SetActive(on); + } + + TPadPainter.prototype.CreateCanvasSvg = function(check_resize, new_size) { + + var factor = null, svg = null, lmt = 5, rect = null, btns; + + if (check_resize > 0) { + + if (this._fixed_size) return (check_resize > 1); // flag used to force re-drawing of all subpads + + svg = this.svg_canvas(); + + if (svg.empty()) return false; + + factor = svg.property('height_factor'); + + rect = this.check_main_resize(check_resize, null, factor); + + if (!rect.changed) return false; + + btns = this.svg_layer("btns_layer"); + + } else { + + var render_to = this.select_main(); + + if (render_to.style('position')=='static') + render_to.style('position','relative'); + + svg = render_to.append("svg") + .attr("class", "jsroot root_canvas") + .property('pad_painter', this) // this is custom property + .property('mainpainter', null) // this is custom property + .property('current_pad', "") // this is custom property + .property('redraw_by_resize', false); // could be enabled to force redraw by each resize + + svg.append("svg:title").text("ROOT canvas"); + var frect = svg.append("svg:rect").attr("class","canvas_fillrect") + .attr("x",0).attr("y",0); + if (!JSROOT.BatchMode) + frect.style("pointer-events", "visibleFill") + .on("dblclick", this.EnlargePad.bind(this)) + .on("click", this.SelectObjectPainter.bind(this, this)) + .on("mouseenter", this.ShowObjectStatus.bind(this)); + + svg.append("svg:g").attr("class","primitives_layer"); + svg.append("svg:g").attr("class","info_layer"); + btns = svg.append("svg:g").attr("class","btns_layer") + .property('leftside', JSROOT.gStyle.ToolBarSide == 'left') + .property('vertical', JSROOT.gStyle.ToolBarVert); + + if (JSROOT.gStyle.ContextMenu) + svg.select(".canvas_fillrect").on("contextmenu", this.ShowContextMenu.bind(this)); + + factor = 0.66; + if (this.pad && this.pad.fCw && this.pad.fCh && (this.pad.fCw > 0)) { + factor = this.pad.fCh / this.pad.fCw; + if ((factor < 0.1) || (factor > 10)) factor = 0.66; + } + + if (this._fixed_size) { + render_to.style("overflow","auto"); + rect = { width: this.pad.fCw, height: this.pad.fCh }; + } else { + rect = this.check_main_resize(2, new_size, factor); + } + } + + // this.createAttFill({ attr: this.pad }); + + if ((rect.width<=lmt) || (rect.height<=lmt)) { + svg.style("display", "none"); + console.warn("Hide canvas while geometry too small w=",rect.width," h=",rect.height); + rect.width = 200; rect.height = 100; // just to complete drawing + } else { + svg.style("display", null); + } + + if (this._fixed_size) { + svg.attr("x", 0) + .attr("y", 0) + .attr("width", rect.width) + .attr("height", rect.height) + .style("position", "absolute"); + } else { + svg.attr("x", 0) + .attr("y", 0) + .style("width", "100%") + .style("height", "100%") + .style("position", "absolute") + .style("left", 0) + .style("top", 0) + .style("right", 0) + .style("bottom", 0); + } + + // console.log('CANVAS SVG width = ' + rect.width + " height = " + rect.height); + + svg.attr("viewBox", "0 0 " + rect.width + " " + rect.height) + .attr("preserveAspectRatio", "none") // we do not preserve relative ratio + .property('height_factor', factor) + .property('draw_x', 0) + .property('draw_y', 0) + .property('draw_width', rect.width) + .property('draw_height', rect.height); + + //svg.select(".canvas_fillrect") + // .attr("width", rect.width) + // .attr("height", rect.height) + // .call(this.fillatt.func); + + this._fast_drawing = JSROOT.gStyle.SmallPad && ((rect.width < JSROOT.gStyle.SmallPad.width) || (rect.height < JSROOT.gStyle.SmallPad.height)); + + this.AlignBtns(btns, rect.width, rect.height, svg); + + return true; + } + + TPadPainter.prototype.EnlargePad = function() { + + if (d3.event) { + d3.event.preventDefault(); + d3.event.stopPropagation(); + } + + var svg_can = this.svg_canvas(), + pad_enlarged = svg_can.property("pad_enlarged"); + + if (this.iscan || !this.has_canvas || (!pad_enlarged && !this.HasObjectsToDraw() && !this.painters)) { + if (this._fixed_size) return; // canvas cannot be enlarged in such mode + if (!this.enlarge_main('toggle')) return; + if (this.enlarge_main('state')=='off') svg_can.property("pad_enlarged", null); + } else if (!pad_enlarged) { + this.enlarge_main(true, true); + svg_can.property("pad_enlarged", this.pad); + } else if (pad_enlarged === this.pad) { + this.enlarge_main(false); + svg_can.property("pad_enlarged", null); + } else { + console.error('missmatch with pad double click events'); + } + + var was_fast = this._fast_drawing; + + this.CheckResize({ force: true }); + + if (this._fast_drawing != was_fast) + this.ShowButtons(); + } + + TPadPainter.prototype.CreatePadSvg = function(only_resize) { + // returns true when pad is displayed and all its items should be redrawn + + if (!this.has_canvas) { + this.CreateCanvasSvg(only_resize ? 2 : 0); + return true; + } + + var svg_parent = this.svg_pad(), + svg_can = this.svg_canvas(), + width = svg_parent.property("draw_width"), + height = svg_parent.property("draw_height"), + pad_enlarged = svg_can.property("pad_enlarged"), + pad_visible = !pad_enlarged || (pad_enlarged === this.pad), + w = width, h = height, x = 0, y = 0, + svg_pad = null, svg_rect = null, btns = null; + + if (this.pad && this.pad.fDrawOpts && this.pad.fSize) { + w = Math.round(width * this.pad.fSize.fHoriz.fNormal.fVal); + h = Math.round(height * this.pad.fSize.fVert.fNormal.fVal); + x = Math.round(width * this.pad.fDrawOpts.fPos.fAttr.fHoriz.fNormal.fVal); + y = Math.round(height * this.pad.fDrawOpts.fPos.fAttr.fVert.fNormal.fVal); + } + + if (pad_enlarged === this.pad) { w = width; h = height; x = y = 0; } + + if (only_resize) { + svg_pad = this.svg_pad(this.this_pad_name); + svg_rect = svg_pad.select(".root_pad_border"); + btns = this.svg_layer("btns_layer", this.this_pad_name); + } else { + svg_pad = svg_parent.select(".primitives_layer") + .append("svg:svg") // here was g before, svg used to blend all drawin outside + .classed("__root_pad_" + this.this_pad_name, true) + .attr("pad", this.this_pad_name) // set extra attribute to mark pad name + .property('pad_painter', this) // this is custom property + .property('mainpainter', null); // this is custom property + svg_rect = svg_pad.append("svg:rect").attr("class", "root_pad_border"); + + svg_pad.append("svg:g").attr("class","primitives_layer"); + btns = svg_pad.append("svg:g").attr("class","btns_layer") + .property('leftside', JSROOT.gStyle.ToolBarSide != 'left') + .property('vertical', JSROOT.gStyle.ToolBarVert); + + if (JSROOT.gStyle.ContextMenu) + svg_rect.on("contextmenu", this.ShowContextMenu.bind(this)); + + if (!JSROOT.BatchMode) + svg_rect.attr("pointer-events", "visibleFill") // get events also for not visible rect + .on("dblclick", this.EnlargePad.bind(this)) + .on("click", this.SelectObjectPainter.bind(this, this)) + .on("mouseenter", this.ShowObjectStatus.bind(this)); + } + + this.createAttFill({ attr: this.pad }); + + this.createAttLine({ attr: this.pad, color0: this.pad.fBorderMode == 0 ? 'none' : '' }); + + svg_pad + //.attr("transform", "translate(" + x + "," + y + ")") // is not handled for SVG + .attr("display", pad_visible ? null : "none") + .attr("viewBox", "0 0 " + w + " " + h) // due to svg + .attr("preserveAspectRatio", "none") // due to svg, we do not preserve relative ratio + .attr("x", x) // due to svg + .attr("y", y) // due to svg + .attr("width", w) // due to svg + .attr("height", h) // due to svg + .property('draw_x', x) // this is to make similar with canvas + .property('draw_y', y) + .property('draw_width', w) + .property('draw_height', h); + + svg_rect.attr("x", 0) + .attr("y", 0) + .attr("width", w) + .attr("height", h) + .call(this.fillatt.func) + .call(this.lineatt.func); + + this._fast_drawing = JSROOT.gStyle.SmallPad && ((w < JSROOT.gStyle.SmallPad.width) || (h < JSROOT.gStyle.SmallPad.height)); + + if (svg_pad.property('can3d') === 1) + // special case of 3D canvas overlay + this.select_main() + .select(".draw3d_" + this.this_pad_name) + .style('display', pad_visible ? '' : 'none'); + + this.AlignBtns(btns, w, h); + + return pad_visible; + } + + TPadPainter.prototype.RemovePrimitive = function(obj) { + if (!this.pad || !this.pad.fPrimitives) return; + var indx = this.pad.fPrimitives.arr.indexOf(obj); + if (indx>=0) this.pad.fPrimitives.RemoveAt(indx); + } + + TPadPainter.prototype.FindPrimitive = function(exact_obj, classname, name) { + if (!this.pad || !this.pad.fPrimitives) return null; + + for (var i=0; i < this.pad.fPrimitives.arr.length; i++) { + var obj = this.pad.fPrimitives.arr[i]; + + if ((exact_obj!==null) && (obj !== exact_obj)) continue; + + if ((classname !== undefined) && (classname !== null)) + if (obj._typename !== classname) continue; + + if ((name !== undefined) && (name !== null)) + if (obj.fName !== name) continue; + + return obj; + } + + return null; + } + + TPadPainter.prototype.HasObjectsToDraw = function() { + // return true if any objects beside sub-pads exists in the pad + + var arr = this.pad ? this.pad.fPrimitives : null; + + if (arr) + for (var n=0;n<arr.length;++n) + if (arr[n] && arr[n]._typename != "ROOT::Experimental::RPadDisplayItem") return true; + + return false; + } + + TPadPainter.prototype.DrawPrimitives = function(indx, callback, ppainter) { + + if (indx===0) { + // flag used to prevent immediate pad redraw during normal drawing sequence + this._doing_pad_draw = true; + + if (this.iscan) + this._start_tm = this._lasttm_tm = new Date().getTime(); + + // set number of primitves + this._num_primitives = this.pad && this.pad.fPrimitives ? this.pad.fPrimitives.length : 0; + } + + while (true) { + if (ppainter && (typeof ppainter=='object')) ppainter._primitive = true; // mark painter as belonging to primitives + + if (!this.pad || (indx >= this.pad.fPrimitives.length)) { + delete this._doing_pad_draw; + delete this._current_primitive_indx; + + if (this._start_tm) { + var spenttm = new Date().getTime() - this._start_tm; + if (spenttm > 3000) console.log("Canvas drawing took " + (spenttm*1e-3).toFixed(2) + "s"); + delete this._start_tm; + delete this._lasttm_tm; + } + + return JSROOT.CallBack(callback); + } + + // handle use to invoke callback only when necessary + var handle = { func: this.DrawPrimitives.bind(this, indx+1, callback) }; + + // set current index + this._current_primitive_indx = indx; + + ppainter = JSROOT.draw(this.divid, this.pad.fPrimitives[indx], "", handle); + + indx++; + + if (!handle.completed) return; + + if (!JSROOT.BatchMode && this.iscan) { + var curtm = new Date().getTime(); + if (curtm > this._lasttm_tm + 500) { + this._lasttm_tm = curtm; + ppainter._primitive = true; // mark primitive ourself + return requestAnimationFrame(handle.func); + } + } + } + } + + TPadPainter.prototype.GetTooltips = function(pnt) { + var painters = [], hints = []; + + // first count - how many processors are there + if (this.painters !== null) + this.painters.forEach(function(obj) { + if ('ProcessTooltip' in obj) painters.push(obj); + }); + + if (pnt) pnt.nproc = painters.length; + + painters.forEach(function(obj) { + var hint = obj.ProcessTooltip(pnt); + if (!hint) hint = { user_info: null }; + hints.push(hint); + if (hint && pnt && pnt.painters) hint.painter = obj; + }); + + return hints; + } + + TPadPainter.prototype.FillContextMenu = function(menu) { + + if (this.pad) + menu.add("header: " + this.pad._typename + "::" + this.pad.fName); + else + menu.add("header: Canvas"); + + menu.addchk(this.IsTooltipAllowed(), "Show tooltips", this.SetTooltipAllowed.bind(this, "toggle")); + + if (!this._websocket) { + + function ToggleGridField(arg) { + this.pad[arg] = this.pad[arg] ? 0 : 1; + var main = this.svg_pad(this.this_pad_name).property('mainpainter'); + if (main && (typeof main.DrawGrids == 'function')) main.DrawGrids(); + } + + function SetTickField(arg) { + this.pad[arg.substr(1)] = parseInt(arg[0]); + + var main = this.svg_pad(this.this_pad_name).property('mainpainter'); + if (main && (typeof main.DrawAxes == 'function')) main.DrawAxes(); + } + + menu.addchk(this.pad.fGridx, 'Grid x', 'fGridx', ToggleGridField); + menu.addchk(this.pad.fGridy, 'Grid y', 'fGridy', ToggleGridField); + menu.add("sub:Ticks x"); + menu.addchk(this.pad.fTickx == 0, "normal", "0fTickx", SetTickField); + menu.addchk(this.pad.fTickx == 1, "ticks on both sides", "1fTickx", SetTickField); + menu.addchk(this.pad.fTickx == 2, "labels up", "2fTickx", SetTickField); + menu.add("endsub:"); + menu.add("sub:Ticks y"); + menu.addchk(this.pad.fTicky == 0, "normal", "0fTicky", SetTickField); + menu.addchk(this.pad.fTicky == 1, "ticks on both side", "1fTicky", SetTickField); + menu.addchk(this.pad.fTicky == 2, "labels right", "2fTicky", SetTickField); + menu.add("endsub:"); + + //menu.addchk(this.pad.fTickx, 'Tick x', 'fTickx', ToggleField); + //menu.addchk(this.pad.fTicky, 'Tick y', 'fTicky', ToggleField); + + this.FillAttContextMenu(menu); + } + + menu.add("separator"); + + if (this.ToggleEventStatus) + menu.addchk(this.HasEventStatus(), "Event status", this.ToggleEventStatus.bind(this)); + + if (this.enlarge_main() || (this.has_canvas && this.HasObjectsToDraw())) + menu.addchk((this.enlarge_main('state')=='on'), "Enlarge " + (this.iscan ? "canvas" : "pad"), this.EnlargePad.bind(this)); + + var fname = this.this_pad_name; + if (fname.length===0) fname = this.iscan ? "canvas" : "pad"; + menu.add("Save as "+fname+".png", fname+".png", this.SaveAs.bind(this, "png", false)); + menu.add("Save as "+fname+".svg", fname+".svg", this.SaveAs.bind(this, "svg", false)); + + return true; + } + + TPadPainter.prototype.ShowContextMenu = function(evnt) { + if (!evnt) { + // for debug purposes keep original context menu for small region in top-left corner + var pos = d3.mouse(this.svg_pad(this.this_pad_name).node()); + + if (pos && (pos.length==2) && (pos[0]>0) && (pos[0]<10) && (pos[1]>0) && pos[1]<10) return; + + d3.event.stopPropagation(); // disable main context menu + d3.event.preventDefault(); // disable browser context menu + + // one need to copy event, while after call back event may be changed + evnt = d3.event; + + var fp = this.frame_painter(); + if (fp) fp.SetLastEventPos(); + } + + JSROOT.Painter.createMenu(this, function(menu) { + + menu.painter.FillContextMenu(menu); + + menu.painter.FillObjectExecMenu(menu, "", function() { menu.show(evnt); }); + }); // end menu creation + } + + TPadPainter.prototype.Redraw = function(resize) { + + // prevent redrawing + if (this._doing_pad_draw) return console.log('Prevent redrawing', this.pad.fName); + + var showsubitems = true; + + if (this.iscan) { + this.CreateCanvasSvg(2); + } else { + showsubitems = this.CreatePadSvg(true); + } + + // even sub-pad is not visible, we should redraw sub-sub-pads to hide them as well + for (var i = 0; i < this.painters.length; ++i) { + var sub = this.painters[i]; + if (showsubitems || sub.this_pad_name) sub.Redraw(resize); + } + } + + TPadPainter.prototype.NumDrawnSubpads = function() { + if (this.painters === undefined) return 0; + + var num = 0; + + for (var i = 0; i < this.painters.length; ++i) { + var obj = this.painters[i].GetObject(); + if (obj && (obj._typename === "TPad")) num++; + } + + return num; + } + + TPadPainter.prototype.RedrawByResize = function() { + if (this.access_3d_kind() === 1) return true; + + for (var i = 0; i < this.painters.length; ++i) + if (typeof this.painters[i].RedrawByResize === 'function') + if (this.painters[i].RedrawByResize()) return true; + + return false; + } + + TPadPainter.prototype.CheckCanvasResize = function(size, force) { + + if (!this.iscan && this.has_canvas) return false; + + if ((size === true) || (size === false)) { force = size; size = null; } + + if (size && (typeof size === 'object') && size.force) force = true; + + if (!force) force = this.RedrawByResize(); + + var changed = this.CreateCanvasSvg(force ? 2 : 1, size); + + // if canvas changed, redraw all its subitems. + // If redrawing was forced for canvas, same applied for sub-elements + if (changed) + for (var i = 0; i < this.painters.length; ++i) + this.painters[i].Redraw(force ? false : true); + + return changed; + } + + TPadPainter.prototype.UpdateObject = function(obj) { + if (!obj) return false; + + this.pad.fCw = obj.fCw; + this.pad.fCh = obj.fCh; + this.pad.fTitle = obj.fTitle; + + return true; + } + + TPadPainter.prototype.DrawNextSnap = function(lst, indx, call_back, objpainter) { + // function called when drawing next snapshot from the list + // it is also used as callback for drawing of previous snap + + if (indx===-1) { + // flag used to prevent immediate pad redraw during first draw + this._doing_pad_draw = true; + this._snaps_map = {}; // to control how much snaps are drawn + this._num_primitives = lst ? lst.length : 0; + } + + // workaround to insert v6 frame in list of primitives + if (objpainter === "workaround") { --indx; objpainter = null; } + + while (true) { + + if (objpainter && lst && lst[indx] && objpainter.snapid === undefined) { + // keep snap id in painter, will be used for the + if (this.painters.indexOf(objpainter)<0) this.painters.push(objpainter); + objpainter.snapid = lst[indx].fObjectID; + } + + objpainter = null; + + ++indx; // change to the next snap + + if (!lst || indx >= lst.length) { + delete this._doing_pad_draw; + delete this._snaps_map; + delete this._current_primitive_indx; + return JSROOT.CallBack(call_back, this); + } + + var snap = lst[indx], + snapid = snap.fObjectID, + cnt = this._snaps_map[snapid]; + + if (cnt) cnt++; else cnt=1; + this._snaps_map[snapid] = cnt; // check how many objects with same snapid drawn, use them again + + this._current_primitive_indx = indx; + + // first appropriate painter for the object + // if same object drawn twice, two painters will exists + for (var k=0; k<this.painters.length; ++k) { + if (this.painters[k].snapid === snapid) + if (--cnt === 0) { objpainter = this.painters[k]; break; } + } + + // function which should be called when drawing of next item finished + var draw_callback = this.DrawNextSnap.bind(this, lst, indx, call_back); + + if (objpainter) { + + if (snap._typename == "ROOT::Experimental::RPadDisplayItem") // subpad + return objpainter.RedrawPadSnap(snap, draw_callback); + + if (objpainter.UpdateObject(snap.fObject, snap.fOption || "")) objpainter.Redraw(); + + continue; // call next + } + + if (snap._typename == "ROOT::Experimental::RPadDisplayItem") { // subpad + + var subpad = snap; // not subpad, but just attributes + + var padpainter = new TPadPainter(subpad, false); + padpainter.DecodeOptions(""); + padpainter.SetDivId(this.divid); // pad painter will be registered in the canvas painters list + padpainter.snapid = snap.fObjectID; + + padpainter.CreatePadSvg(); + + if (snap.fPrimitives && snap.fPrimitives.length > 0) { + padpainter.AddButton(JSROOT.ToolbarIcons.camera, "Create PNG", "PadSnapShot"); + padpainter.AddButton(JSROOT.ToolbarIcons.circle, "Enlarge pad", "EnlargePad"); + + if (JSROOT.gStyle.ContextMenu) + padpainter.AddButton(JSROOT.ToolbarIcons.question, "Access context menus", "PadContextMenus"); + } + + // we select current pad, where all drawing is performed + var prev_name = padpainter.CurrentPadName(padpainter.this_pad_name); + padpainter.DrawNextSnap(snap.fPrimitives, -1, function() { + padpainter.CurrentPadName(prev_name); + draw_callback(padpainter); + }); + return; + } + + var handle = { func: draw_callback }; + + if (snap._typename === "ROOT::Experimental::RObjectDisplayItem") + if (!this.frame_painter()) + return JSROOT.draw(this.divid, { _typename: "TFrame", $dummy: true }, "", function() { + handle.func("workaround"); // call function with "workaround" as argument + }); + + // here the case of normal drawing, can be improved + objpainter = JSROOT.draw(this.divid, snap.fObject, snap.fOption || "", handle); + + if (!handle.completed) return; // if callback will be invoked, break while loop + } + } + + TPadPainter.prototype.FindSnap = function(snapid) { + + if (this.snapid === snapid) return this; + + if (!this.painters) return null; + + for (var k=0;k<this.painters.length;++k) { + var sub = this.painters[k]; + + if (typeof sub.FindSnap === 'function') sub = sub.FindSnap(snapid); + else if (sub.snapid !== snapid) sub = null; + + if (sub) return sub; + } + + return null; + } + + TPadPainter.prototype.AddOnlineButtons = function() { + this.AddButton(JSROOT.ToolbarIcons.camera, "Create PNG", "CanvasSnapShot", "Ctrl PrintScreen"); + if (JSROOT.gStyle.ContextMenu) + this.AddButton(JSROOT.ToolbarIcons.question, "Access context menus", "PadContextMenus"); + + if (this.enlarge_main('verify')) + this.AddButton(JSROOT.ToolbarIcons.circle, "Enlarge canvas", "EnlargePad"); + } + + TPadPainter.prototype.RedrawPadSnap = function(snap, call_back) { + // for the pad/canvas display item contains list of primitives plus pad attributes + + if (!snap || !snap.fPrimitives) return; + + // for the moment only window size attributes are provided + var padattr = { fCw: snap.fWinSize[0].fVal, fCh: snap.fWinSize[1].fVal, fTitle: snap.fTitle }; + + // if canvas size not specified in batch mode, temporary use 900x700 size + if (this.batch_mode && this.iscan && (!padattr.fCw || !padattr.fCh)) { padattr.fCw = 900; padattr.fCh = 700; } + + if (this.iscan && snap.fTitle && document) + document.title = snap.fTitle; + + if (this.iscan && snap.fTitle && document) + document.title = snap.fTitle; + + if (this.snapid === undefined) { + // first time getting snap, create all gui elements first + + this.snapid = snap.fObjectID; + + this.draw_object = padattr; + this.pad = padattr; + this.pad_frame = snap.fFrame; + + if (this.batch_mode && this.iscan) + this._fixed_size = true; + + this.CreateCanvasSvg(0); + this.SetDivId(this.divid); // now add to painters list + this.AddOnlineButtons(); + + this.DrawNextSnap(snap.fPrimitives, -1, call_back); + + return; + } + + // update only pad/canvas attributes + this.UpdateObject(padattr); + + // apply all changes in the object (pad or canvas) + if (this.iscan) { + this.CreateCanvasSvg(2); + } else { + this.CreatePadSvg(true); + } + + var isanyfound = false, isanyremove = false; + + // find and remove painters which no longer exists in the list + for (var k=0;k<this.painters.length;++k) { + var sub = this.painters[k]; + if (sub.snapid===undefined) continue; // look only for painters with snapid + + for (var i=0;i<snap.fPrimitives.length;++i) + if (snap.fPrimitives[i].fObjectID === sub.snapid) { sub = null; isanyfound = true; break; } + + if (sub) { + // remove painter which does not found in the list of snaps + this.painters.splice(k--,1); + sub.Cleanup(); // cleanup such painter + isanyremove = true; + } + } + + if (isanyremove) { + delete this.pads_cache; + } + + if (!isanyfound) { + var svg_p = this.svg_pad(this.this_pad_name), + fp = this.frame_painter(); + if (svg_p && !svg_p.empty()) + svg_p.property('mainpainter', null); + for (var k=0;k<this.painters.length;++k) + if (fp !== this.painters[k]) + this.painters[k].Cleanup(); + this.painters = []; + if (fp) { + this.painters.push(fp); + fp.CleanDrawings(); + } + this.RemoveButtons(); + this.AddOnlineButtons(); + } + + var padpainter = this, + prev_name = padpainter.CurrentPadName(padpainter.this_pad_name); + + padpainter.DrawNextSnap(snap.fPrimitives, -1, function() { + padpainter.CurrentPadName(prev_name); + call_back(padpainter); + }); + } + + TPadPainter.prototype.CreateImage = function(format, call_back) { + if (format=="pdf") { + // use https://github.com/MrRio/jsPDF in the future here + JSROOT.CallBack(call_back, btoa("dummy PDF file")); + } else if ((format=="png") || (format=="jpeg") || (format=="svg")) { + this.ProduceImage(true, format, function(res) { + if ((format=="svg") || !res) + return JSROOT.CallBack(call_back, res); + var separ = res.indexOf("base64,"); + JSROOT.CallBack(call_back, (separ>0) ? res.substr(separ+7) : ""); + }); + } else { + JSROOT.CallBack(call_back, ""); + } + } + + TPadPainter.prototype.ItemContextMenu = function(name) { + var rrr = this.svg_pad(this.this_pad_name).node().getBoundingClientRect(); + var evnt = { clientX: rrr.left+10, clientY: rrr.top + 10 }; + + // use timeout to avoid conflict with mouse click and automatic menu close + if (name=="pad") + return setTimeout(this.ShowContextMenu.bind(this, evnt), 50); + + var selp = null, selkind; + + switch(name) { + case "xaxis": + case "yaxis": + case "zaxis": + selp = this.main_painter(); + selkind = name[0]; + break; + case "frame": + selp = this.frame_painter(); + break; + default: { + var indx = parseInt(name); + if (!isNaN(indx)) selp = this.painters[indx]; + } + } + + if (!selp || (typeof selp.FillContextMenu !== 'function')) return; + + JSROOT.Painter.createMenu(selp, function(menu) { + if (selp.FillContextMenu(menu,selkind)) + setTimeout(menu.show.bind(menu, evnt), 50); + }); + } + + TPadPainter.prototype.SaveAs = function(kind, full_canvas, filename) { + if (!filename) { + filename = this.this_pad_name; + if (filename.length === 0) filename = this.iscan ? "canvas" : "pad"; + filename += "." + kind; + } + this.ProduceImage(full_canvas, kind, function(imgdata) { + var a = document.createElement('a'); + a.download = filename; + a.href = (kind != "svg") ? imgdata : "data:image/svg+xml;charset=utf-8,"+encodeURIComponent(imgdata); + document.body.appendChild(a); + a.addEventListener("click", function(e) { + a.parentNode.removeChild(a); + }); + a.click(); + }); + } + + TPadPainter.prototype.ProduceImage = function(full_canvas, file_format, call_back) { + + var use_frame = (full_canvas === "frame"); + + var elem = use_frame ? this.svg_frame() : (full_canvas ? this.svg_canvas() : this.svg_pad(this.this_pad_name)); + + if (elem.empty()) return JSROOT.CallBack(call_back); + + var painter = (full_canvas && !use_frame) ? this.canv_painter() : this; + + var items = []; // keep list of replaced elements, which should be moved back at the end + +// document.body.style.cursor = 'wait'; + + if (!use_frame) // do not make transformations for the frame + painter.ForEachPainterInPad(function(pp) { + + // console.log('Check painter pp', pp.this_pad_name); + + var item = { prnt: pp.svg_pad(pp.this_pad_name) }; + items.push(item); + + // remove buttons from each subpad + var btns = pp.svg_layer("btns_layer", pp.this_pad_name); + item.btns_node = btns.node(); + if (item.btns_node) { + item.btns_prnt = item.btns_node.parentNode; + item.btns_next = item.btns_node.nextSibling; + btns.remove(); + } + + var main = pp.frame_painter_ref; + if (!main || (typeof main.Render3D !== 'function')) return; + + var can3d = main.access_3d_kind(); + + if ((can3d !== 1) && (can3d !== 2)) return; + + var sz2 = main.size_for_3d(2); // get size of DOM element as it will be embed + + var sz = (can3d == 2) ? sz : main.size_for_3d(1); + + // console.log('Render 3D', sz2); + + var canvas = main.renderer.domElement; + main.Render3D(0); // WebGL clears buffers, therefore we should render scene and convert immediately + var dataUrl = canvas.toDataURL("image/png"); + + // console.log('canvas width height', canvas.width, canvas.height); + + // console.log('produced png image len = ', dataUrl.length, 'begin', dataUrl.substr(0,100)); + + // remove 3D drawings + + if (can3d == 2) { + item.foreign = item.prnt.select("." + sz2.clname); + item.foreign.remove(); + } + + var svg_frame = main.svg_frame(); + item.frame_node = svg_frame.node(); + if (item.frame_node) { + item.frame_next = item.frame_node.nextSibling; + svg_frame.remove(); + } + + //var origin = main.apply_3d_size(sz3d, true); + //origin.remove(); + + // add svg image + item.img = item.prnt.insert("image",".primitives_layer") // create image object + .attr("x", sz2.x) + .attr("y", sz2.y) + .attr("width", canvas.width) + .attr("height", canvas.height) + .attr("href", dataUrl); + + }, "pads"); + + function reEncode(data) { + data = encodeURIComponent(data); + data = data.replace(/%([0-9A-F]{2})/g, function(match, p1) { + var c = String.fromCharCode('0x'+p1); + return c === '%' ? '%25' : c; + }); + return decodeURIComponent(data); + } + + function reconstruct(res) { + for (var k=0;k<items.length;++k) { + var item = items[k]; + + if (item.img) + item.img.remove(); // delete embed image + + var prim = item.prnt.select(".primitives_layer"); + + if (item.foreign) // reinsert foreign object + item.prnt.node().insertBefore(item.foreign.node(), prim.node()); + + if (item.frame_node) // reinsert frame as first in list of primitives + prim.node().insertBefore(item.frame_node, item.frame_next); + + if (item.btns_node) // reinsert buttons + item.btns_prnt.insertBefore(item.btns_node, item.btns_next); + } + + JSROOT.CallBack(call_back, res); + } + + var width = elem.property('draw_width'), height = elem.property('draw_height'); + if (use_frame) { width = this.frame_width(); height = this.frame_height(); } + + var svg = '<svg width="' + width + '" height="' + height + '" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">' + + elem.node().innerHTML + + '</svg>'; + + if (file_format == "svg") + return reconstruct(svg); // return SVG file as is + + var doctype = '<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">'; + + var image = new Image(); + image.onload = function() { + // if (options.result==="image") return JSROOT.CallBack(call_back, image); + + // console.log('GOT IMAGE', image.width, image.height); + + var canvas = document.createElement('canvas'); + canvas.width = image.width; + canvas.height = image.height; + var context = canvas.getContext('2d'); + context.drawImage(image, 0, 0); + + reconstruct(canvas.toDataURL('image/' + file_format)); + } + + image.onerror = function(arg) { + console.log('IMAGE ERROR', arg); + reconstruct(null); + } + + image.src = 'data:image/svg+xml;base64,' + window.btoa(reEncode(doctype + svg)); + } + + + TPadPainter.prototype.PadButtonClick = function(funcname) { + + if (funcname == "CanvasSnapShot") return this.SaveAs("png", true); + + if (funcname == "EnlargePad") return this.EnlargePad(); + + if (funcname == "PadSnapShot") return this.SaveAs("png", false); + + if (funcname == "PadContextMenus") { + + d3.event.preventDefault(); + d3.event.stopPropagation(); + + if (JSROOT.Painter.closeMenu()) return; + + var pthis = this, evnt = d3.event; + + JSROOT.Painter.createMenu(pthis, function(menu) { + menu.add("header:Menus"); + + if (pthis.iscan) + menu.add("Canvas", "pad", pthis.ItemContextMenu); + else + menu.add("Pad", "pad", pthis.ItemContextMenu); + + if (pthis.frame_painter()) + menu.add("Frame", "frame", pthis.ItemContextMenu); + + var main = pthis.main_painter(); + + if (main) { + menu.add("X axis", "xaxis", pthis.ItemContextMenu); + menu.add("Y axis", "yaxis", pthis.ItemContextMenu); + if ((typeof main.Dimension === 'function') && (main.Dimension() > 1)) + menu.add("Z axis", "zaxis", pthis.ItemContextMenu); + } + + if (pthis.painters && (pthis.painters.length>0)) { + menu.add("separator"); + var shown = []; + for (var n=0;n<pthis.painters.length;++n) { + var pp = pthis.painters[n]; + var obj = pp ? pp.GetObject() : null; + if (!obj || (shown.indexOf(obj)>=0)) continue; + + var name = ('_typename' in obj) ? (obj._typename + "::") : ""; + if ('fName' in obj) name += obj.fName; + if (name.length==0) name = "item" + n; + menu.add(name, n, pthis.ItemContextMenu); + } + } + + menu.show(evnt); + }); + + return; + } + + // click automatically goes to all sub-pads + // if any painter indicates that processing completed, it returns true + var done = false; + + for (var i = 0; i < this.painters.length; ++i) { + var pp = this.painters[i]; + + if (typeof pp.PadButtonClick == 'function') + pp.PadButtonClick(funcname); + + if (!done && (typeof pp.ButtonClick == 'function')) + done = pp.ButtonClick(funcname); + } + } + + TPadPainter.prototype.FindButton = function(keyname) { + var group = this.svg_layer("btns_layer", this.this_pad_name), found_func = ""; + if (!group.empty()) + group.selectAll("svg").each(function() { + if (d3.select(this).attr("key") === keyname) + found_func = d3.select(this).attr("name"); + }); + return found_func; + } + + TPadPainter.prototype.toggleButtonsVisibility = function(action) { + var group = this.svg_layer("btns_layer", this.this_pad_name), + btn = group.select("[name='Toggle']"); + + if (btn.empty()) return; + + var state = btn.property('buttons_state'); + + if (btn.property('timout_handler')) { + if (action!=='timeout') clearTimeout(btn.property('timout_handler')); + btn.property('timout_handler', null); + } + + var is_visible = false; + switch(action) { + case 'enable': is_visible = true; break; + case 'enterbtn': return; // do nothing, just cleanup timeout + case 'timeout': is_visible = false; break; + case 'toggle': + state = !state; + btn.property('buttons_state', state); + is_visible = state; + break; + case 'disable': + case 'leavebtn': + if (!state) btn.property('timout_handler', setTimeout(this.toggleButtonsVisibility.bind(this,'timeout'), 500)); + return; + } + + group.selectAll('svg').each(function() { + if (this===btn.node()) return; + d3.select(this).style('display', is_visible ? "" : "none"); + }); + } + + TPadPainter.prototype.RemoveButtons = function() { + var group = this.svg_layer("btns_layer", this.this_pad_name); + if (!group.empty()) { + group.selectAll("*").remove(); + group.property("nextx", null); + } + } + + TPadPainter.prototype.RemoveButtons = function() { + var group = this.svg_layer("btns_layer", this.this_pad_name); + if (!group.empty()) { + group.selectAll("*").remove(); + group.property("nextx", null); + } + } + + TPadPainter.prototype.AddButton = function(_btn, _tooltip, _funcname, _keyname) { + if (!JSROOT.gStyle.ToolBar) return; + + if (!this._buttons) this._buttons = []; + // check if there are duplications + + for (var k=0;k<this._buttons.length;++k) + if (this._buttons[k].funcname == _funcname) return; + + this._buttons.push({ btn: _btn, tooltip: _tooltip, funcname: _funcname, keyname: _keyname }); + + var iscan = this.iscan || !this.has_canvas; + if (!iscan && (_funcname.indexOf("Pad")!=0) && (_funcname !== "EnlargePad")) { + var cp = this.canv_painter(); + if (cp && (cp!==this)) cp.AddButton(_btn, _tooltip, _funcname); + } + } + + TPadPainter.prototype.ShowButtons = function() { + + if (!this._buttons) return; + + var group = this.svg_layer("btns_layer", this.this_pad_name); + if (group.empty()) return; + + // clean all previous buttons + group.selectAll("*").remove(); + + var iscan = this.iscan || !this.has_canvas, ctrl, + x = group.property('leftside') ? this.ButtonSize(1.25) : 0, y = 0; + + if (this._fast_drawing) { + ctrl = JSROOT.ToolbarIcons.CreateSVG(group, JSROOT.ToolbarIcons.circle, this.ButtonSize(), "EnlargePad"); + ctrl.attr("name", "Enlarge").attr("x", 0).attr("y", 0) + // .property("buttons_state", (JSROOT.gStyle.ToolBar!=='popup')) + .on("click", this.PadButtonClick.bind(this, "EnlargePad")); + } else { + ctrl = JSROOT.ToolbarIcons.CreateSVG(group, JSROOT.ToolbarIcons.rect, this.ButtonSize(), "Toggle tool buttons"); + + ctrl.attr("name", "Toggle").attr("x", 0).attr("y", 0) + .property("buttons_state", (JSROOT.gStyle.ToolBar!=='popup')) + .on("click", this.toggleButtonsVisibility.bind(this, 'toggle')) + .on("mouseenter", this.toggleButtonsVisibility.bind(this, 'enable')) + .on("mouseleave", this.toggleButtonsVisibility.bind(this, 'disable')); + + for (var k=0;k<this._buttons.length;++k) { + var item = this._buttons[k]; + + var svg = JSROOT.ToolbarIcons.CreateSVG(group, item.btn, this.ButtonSize(), + item.tooltip + (iscan ? "" : (" on pad " + this.this_pad_name)) + (item.keyname ? " (keyshortcut " + item.keyname + ")" : "")); + + if (group.property('vertical')) + svg.attr("x", y).attr("y", x); + else + svg.attr("x", x).attr("y", y); + + svg.attr("name", item.funcname) + .style('display', (ctrl.property("buttons_state") ? '' : 'none')) + .on("mouseenter", this.toggleButtonsVisibility.bind(this, 'enterbtn')) + .on("mouseleave", this.toggleButtonsVisibility.bind(this, 'leavebtn')); + + if (item.keyname) svg.attr("key", item.keyname); + + svg.on("click", this.PadButtonClick.bind(this, item.funcname)); + + x += this.ButtonSize(1.25); + } + } + + group.property("nextx", x); + + this.AlignBtns(group, this.pad_width(this.this_pad_name), this.pad_height(this.this_pad_name)); + + if (group.property('vertical')) ctrl.attr("y", x); + else if (!group.property('leftside')) ctrl.attr("x", x); + } + + TPadPainter.prototype.AlignBtns = function(btns, width, height, svg) { + var sz0 = this.ButtonSize(1.25), nextx = (btns.property('nextx') || 0) + sz0, btns_x, btns_y; + if (btns.property('vertical')) { + btns_x = btns.property('leftside') ? 2 : (width - sz0); + btns_y = height - nextx; + } else { + btns_x = btns.property('leftside') ? 2 : (width - nextx); + btns_y = height - sz0; + } + + btns.attr("transform","translate("+btns_x+","+btns_y+")"); + } + +// TPadPainter.prototype.DrawingReady = function(res_painter) { +// var main = this.main_painter(); +// if (main && main.mode3d && typeof main.Render3D == 'function') main.Render3D(-2222); +// TBasePainter.prototype.DrawingReady.call(this, res_painter); +// } + + TPadPainter.prototype.DecodeOptions = function(opt) { + var pad = this.GetObject(); + if (!pad) return; + + var d = new JSROOT.DrawOptions(opt); + + if (d.check('WEBSOCKET')) this.OpenWebsocket(); + if (!this.options) this.options = {}; + + JSROOT.extend(this.options, { GlobalColors: true, LocalColors: false, IgnorePalette: false, RotateFrame: false, FixFrame: false }); + + if (d.check('NOCOLORS') || d.check('NOCOL')) this.options.GlobalColors = this.options.LocalColors = false; + if (d.check('LCOLORS') || d.check('LCOL')) { this.options.GlobalColors = false; this.options.LocalColors = true; } + if (d.check('NOPALETTE') || d.check('NOPAL')) this.options.IgnorePalette = true; + if (d.check('ROTATE')) this.options.RotateFrame = true; + if (d.check('FIXFRAME')) this.options.FixFrame = true; + + if (d.check('WHITE')) pad.fFillColor = 0; + if (d.check('LOGX')) pad.fLogx = 1; + if (d.check('LOGY')) pad.fLogy = 1; + if (d.check('LOGZ')) pad.fLogz = 1; + if (d.check('LOG')) pad.fLogx = pad.fLogy = pad.fLogz = 1; + if (d.check('GRIDX')) pad.fGridx = 1; + if (d.check('GRIDY')) pad.fGridy = 1; + if (d.check('GRID')) pad.fGridx = pad.fGridy = 1; + if (d.check('TICKX')) pad.fTickx = 1; + if (d.check('TICKY')) pad.fTicky = 1; + if (d.check('TICK')) pad.fTickx = pad.fTicky = 1; + } + + function drawPad(divid, pad, opt) { + var painter = new TPadPainter(pad, false); + painter.DecodeOptions(opt); + + painter.SetDivId(divid); // pad painter will be registered in the canvas painters list + + if (painter.svg_canvas().empty()) { + painter.has_canvas = false; + painter.this_pad_name = ""; + } + + painter.CreatePadSvg(); + + if (painter.MatchObjectType("TPad") && (!painter.has_canvas || painter.HasObjectsToDraw())) { + painter.AddButton(JSROOT.ToolbarIcons.camera, "Create PNG", "PadSnapShot"); + + if ((painter.has_canvas && painter.HasObjectsToDraw()) || painter.enlarge_main('verify')) + painter.AddButton(JSROOT.ToolbarIcons.circle, "Enlarge pad", "EnlargePad"); + + if (JSROOT.gStyle.ContextMenu) + painter.AddButton(JSROOT.ToolbarIcons.question, "Access context menus", "PadContextMenus"); + } + + // we select current pad, where all drawing is performed + var prev_name = painter.has_canvas ? painter.CurrentPadName(painter.this_pad_name) : undefined; + + JSROOT.Painter.SelectActivePad({ pp: painter, active: false }); + + // flag used to prevent immediate pad redraw during first draw + painter.DrawPrimitives(0, function() { + painter.ShowButtons(); + // we restore previous pad name + painter.CurrentPadName(prev_name); + painter.DrawingReady(); + }); + + return painter; + } + + // ========================================================================================== + + function TCanvasPainter(canvas) { + // used for online canvas painter + TPadPainter.call(this, canvas, true); + this._websocket = null; + this.tooltip_allowed = (JSROOT.gStyle.Tooltip > 0); + } + + TCanvasPainter.prototype = Object.create(TPadPainter.prototype); + + TCanvasPainter.prototype.ChangeLayout = function(layout_kind, call_back) { + var current = this.get_layout_kind(); + if (current == layout_kind) return JSROOT.CallBack(call_back, true); + + var origin = this.select_main('origin'), + sidebar = origin.select('.side_panel'), + main = this.select_main(), lst = []; + + while (main.node().firstChild) + lst.push(main.node().removeChild(main.node().firstChild)); + + if (!sidebar.empty()) JSROOT.cleanup(sidebar.node()); + + this.set_layout_kind("simple"); // restore defaults + origin.html(""); // cleanup origin + + if (layout_kind == 'simple') { + main = origin; + for (var k=0;k<lst.length;++k) + main.node().appendChild(lst[k]); + this.set_layout_kind(layout_kind); + // JSROOT.resize(main.node()); + return JSROOT.CallBack(call_back, true); + } + + var pthis = this; + + JSROOT.AssertPrerequisites("jq2d", function() { + + var grid = new JSROOT.GridDisplay(origin.node(), layout_kind); + + if (layout_kind.indexOf("vert")==0) { + main = d3.select(grid.GetFrame(0)); + sidebar = d3.select(grid.GetFrame(1)); + } else { + main = d3.select(grid.GetFrame(1)); + sidebar = d3.select(grid.GetFrame(0)); + } + + main.classed("central_panel", true).style('position','relative'); + sidebar.classed("side_panel", true).style('position','relative'); + + // now append all childs to the new main + for (var k=0;k<lst.length;++k) + main.node().appendChild(lst[k]); + + pthis.set_layout_kind(layout_kind, ".central_panel"); + + JSROOT.CallBack(call_back, true); + }); + } + + TCanvasPainter.prototype.ToggleProjection = function(kind, call_back) { + delete this.proj_painter; + + if (kind) this.proj_painter = 1; // just indicator that drawing can be preformed + + if (this.use_openui && this.ShowUI5ProjectionArea) + return this.ShowUI5ProjectionArea(kind, call_back); + + var layout = 'simple'; + + if (kind == "X") layout = 'vert2_31'; else + if (kind == "Y") layout = 'horiz2_13'; + + this.ChangeLayout(layout, call_back); + } + + TCanvasPainter.prototype.DrawProjection = function(kind,hist) { + if (!this.proj_painter) return; // ignore drawing if projection not configured + + if (this.proj_painter === 1) { + + var canv = JSROOT.Create("TCanvas"), pthis = this, pad = this.root_pad(), main = this.main_painter(), drawopt; + + if (kind == "X") { + canv.fLeftMargin = pad.fLeftMargin; + canv.fRightMargin = pad.fRightMargin; + canv.fLogx = main.logx ? 1 : 0; + canv.fUxmin = main.logx ? JSROOT.log10(main.scale_xmin) : main.scale_xmin; + canv.fUxmax = main.logx ? JSROOT.log10(main.scale_xmax) : main.scale_xmax; + drawopt = "fixframe"; + } else { + canv.fBottomMargin = pad.fBottomMargin; + canv.fTopMargin = pad.fTopMargin; + canv.fLogx = main.logy ? 1 : 0; + canv.fUxmin = main.logy ? JSROOT.log10(main.scale_ymin) : main.scale_ymin; + canv.fUxmax = main.logy ? JSROOT.log10(main.scale_ymax) : main.scale_ymax; + drawopt = "rotate"; + } + + canv.fPrimitives.Add(hist, "hist"); + + if (this.use_openui && this.DrawInUI5ProjectionArea ) { + // copy frame attributes + this.DrawInUI5ProjectionArea(canv, drawopt, function(painter) { pthis.proj_painter = painter; }) + } else { + this.DrawInSidePanel(canv, drawopt, function(painter) { pthis.proj_painter = painter; }) + } + } else { + var hp = this.proj_painter.main_painter(); + if (hp) hp.UpdateObject(hist, "hist"); + this.proj_painter.RedrawPad(); + } + } + + TCanvasPainter.prototype.DrawInSidePanel = function(canv, opt, call_back) { + var side = this.select_main('origin').select(".side_panel"); + if (side.empty()) return JSROOT.CallBack(call_back, null); + JSROOT.draw(side.node(), canv, opt, call_back); + } + + TCanvasPainter.prototype.ShowMessage = function(msg) { + JSROOT.progress(msg, 7000); + } + + /// function called when canvas menu item Save is called + TCanvasPainter.prototype.SaveCanvasAsFile = function(fname) { + var pthis = this, pnt = fname.indexOf("."); + this.CreateImage(fname.substr(pnt+1), function(res) { + pthis.SendWebsocket("SAVE:" + fname + ":" + res); + }) + } + + TCanvasPainter.prototype.SendSaveCommand = function(fname) { + this.SendWebsocket("PRODUCE:" + fname); + } + + TCanvasPainter.prototype.SendWebsocket = function(msg, chid) { + if (this._websocket) + this._websocket.Send(msg, chid); + } + + TCanvasPainter.prototype.CloseWebsocket = function(force) { + if (this._websocket) { + this._websocket.Close(force); + this._websocket.Cleanup(); + delete this._websocket; + } + } + + TCanvasPainter.prototype.OpenWebsocket = function(socket_kind) { + // create websocket for current object (canvas) + // via websocket one recieved many extra information + + this.CloseWebsocket(); + + this._websocket = new JSROOT.WebWindowHandle(socket_kind); + this._websocket.SetReceiver(this); + this._websocket.Connect(); + } + + TCanvasPainter.prototype.UseWebsocket = function(handle) { + this.CloseWebsocket(); + + this._websocket = handle; + console.log('Use websocket', this._websocket.key); + this._websocket.SetReceiver(this); + this._websocket.Connect(); + } + + TCanvasPainter.prototype.WindowBeforeUnloadHanlder = function() { + // when window closed, close socket + this.CloseWebsocket(true); + } + + TCanvasPainter.prototype.OnWebsocketOpened = function(handle) { + // indicate that we are ready to recieve any following commands + } + + TCanvasPainter.prototype.OnWebsocketClosed = function(handle) { + JSROOT.CloseCurrentWindow(); + } + + TCanvasPainter.prototype.OnWebsocketMsg = function(handle, msg) { + console.log("GET MSG " + msg.substr(0,30)); + + if (msg == "CLOSE") { + this.OnWebsocketClosed(); + this.CloseWebsocket(true); + } else if (msg.substr(0,5)=='SNAP:') { + msg = msg.substr(5); + var p1 = msg.indexOf(":"), + snapid = msg.substr(0,p1), + snap = JSROOT.parse(msg.substr(p1+1)); + this.RedrawPadSnap(snap, function() { + handle.Send("SNAPDONE:" + snapid); // send ready message back when drawing completed + }); + } else if (msg.substr(0,4)=='JSON') { + var obj = JSROOT.parse(msg.substr(4)); + // console.log("get JSON ", msg.length-4, obj._typename); + this.RedrawObject(obj); + + } else if (msg.substr(0,5)=='MENU:') { + // this is menu with exact identifier for object + msg = msg.substr(5); + var p1 = msg.indexOf(":"), + menuid = msg.substr(0,p1), + lst = JSROOT.parse(msg.substr(p1+1)); + // console.log("get MENUS ", typeof lst, 'nitems', lst.length, msg.length-4); + if (typeof this._getmenu_callback == 'function') + this._getmenu_callback(lst, menuid); + } else if (msg.substr(0,4)=='CMD:') { + msg = msg.substr(4); + var p1 = msg.indexOf(":"), + cmdid = msg.substr(0,p1), + cmd = msg.substr(p1+1), + reply = "REPLY:" + cmdid + ":"; + if ((cmd == "SVG") || (cmd == "PNG") || (cmd == "JPEG")) { + this.CreateImage(cmd.toLowerCase(), function(res) { + handle.Send(reply + res); + }); + } else if (cmd.indexOf("ADDPANEL:") == 0) { + var relative_path = cmd.substr(9); + console.log('request panel = ' + relative_path); + if (!this.ActivatePanel) { + handle.Send(reply + "false"); + } else { + + var conn = new JSROOT.WebWindowHandle(handle.kind); + + // set interim receiver until first message arrives + conn.SetReceiver({ + cpainter: this, + + OnWebsocketOpened: function(hhh) { + console.log('Panel socket connected'); + }, + + OnWebsocketMsg: function(panel_handle, msg) { + + var panel_name = (msg.indexOf("SHOWPANEL:")==0) ? msg.substr(10) : ""; + console.log('Panel get message ' + msg + " show " + panel_name); + + this.cpainter.ActivatePanel(panel_name, panel_handle, function(res) { + handle.Send(reply + (res ? "true" : "false")); + }); + }, + + OnWebsocketClosed: function(hhh) { + // if connection failed, + handle.Send(reply + "false"); + }, + + OnWebsocketError: function(hhh) { + // if connection failed, + handle.Send(reply + "false"); + } + + }); + + var addr = handle.href; + if (relative_path.indexOf("../")==0) { + var ddd = addr.lastIndexOf("/",addr.length-2); + addr = addr.substr(0,ddd) + relative_path.substr(2); + } else { + addr += relative_path; + } + // only when connection established, panel will be activated + conn.Connect(addr); + } + } else { + console.log('Unrecognized command ' + cmd); + handle.Send(reply); + } + } else if ((msg.substr(0,7)=='DXPROJ:') || (msg.substr(0,7)=='DYPROJ:')) { + var kind = msg[1], + hist = JSROOT.parse(msg.substr(7)); + this.DrawProjection(kind, hist); + } else if (msg.substr(0,5)=='SHOW:') { + var that = msg.substr(5), + on = that[that.length-1] == '1'; + this.ShowSection(that.substr(0,that.length-2), on); + } else { + console.log("unrecognized msg len:" + msg.length + " msg:" + msg.substr(0,20)); + } + } + + TCanvasPainter.prototype.ShowSection = function(that, on) { + switch(that) { + case "Menu": break; + case "StatusBar": break; + case "Editor": break; + case "ToolBar": break; + case "ToolTips": this.SetTooltipAllowed(on); break; + } + } + + JSROOT.TCanvasStatusBits = { + kShowEventStatus : JSROOT.BIT(15), + kAutoExec : JSROOT.BIT(16), + kMenuBar : JSROOT.BIT(17), + kShowToolBar : JSROOT.BIT(18), + kShowEditor : JSROOT.BIT(19), + kMoveOpaque : JSROOT.BIT(20), + kResizeOpaque : JSROOT.BIT(21), + kIsGrayscale : JSROOT.BIT(22), + kShowToolTips : JSROOT.BIT(23) + }; + + TCanvasPainter.prototype.CompeteCanvasSnapDrawing = function() { + if (!this.pad) return; + + if (document) document.title = this.pad.fTitle; + + if (this._all_sections_showed) return; + this._all_sections_showed = true; + this.ShowSection("Menu", this.pad.TestBit(JSROOT.TCanvasStatusBits.kMenuBar)); + this.ShowSection("StatusBar", this.pad.TestBit(JSROOT.TCanvasStatusBits.kShowEventStatus)); + this.ShowSection("ToolBar", this.pad.TestBit(JSROOT.TCanvasStatusBits.kShowToolBar)); + this.ShowSection("Editor", this.pad.TestBit(JSROOT.TCanvasStatusBits.kShowEditor)); + this.ShowSection("ToolTips", this.pad.TestBit(JSROOT.TCanvasStatusBits.kShowToolTips)); + } + + TCanvasPainter.prototype.HasEventStatus = function() { + return this.has_event_status; + } + + +//////////////////////////////////////////////////////////////////////////////// +/// Return the color in a string ready for SVG from the value found in `RGBa` +/// If `fKind` == 0 the color `RGBa` contains the Red Green Blue and alpha values. +/// Otherwise the `fRedOrPalettePos` member of RGBa contains the color index in +/// the current palette + + TCanvasPainter.prototype.GetNewColor = function(attr, direct) { + if (!attr) return; + + var tcol = direct ? attr : attr.fAttr; // this is TColor instance + if (!tcol.fKind) + return "rgb(" + Math.round(tcol.fRedOrPalettePos*255) + "," + + Math.round(tcol.fGreen*255) + "," + + Math.round(tcol.fBlue*255) + ")"; + return col; + } + + function drawCanvas(divid, can, opt) { + var nocanvas = !can; + if (nocanvas) { + console.log("No canvas specified"); + return null; + can = JSROOT.Create("ROOT::Experimental::TCanvas"); + } + + var painter = new TCanvasPainter(can); + painter.normal_canvas = !nocanvas; + + painter.SetDivId(divid, -1); // just assign id + painter.CreateCanvasSvg(0); + painter.SetDivId(divid); // now add to painters list + + painter.AddButton(JSROOT.ToolbarIcons.camera, "Create PNG", "CanvasSnapShot", "Ctrl PrintScreen"); + if (JSROOT.gStyle.ContextMenu) + painter.AddButton(JSROOT.ToolbarIcons.question, "Access context menus", "PadContextMenus"); + + if (painter.enlarge_main('verify')) + painter.AddButton(JSROOT.ToolbarIcons.circle, "Enlarge canvas", "EnlargePad"); + + JSROOT.Painter.SelectActivePad({ pp: painter, active: false }); + + painter.DrawPrimitives(0, function() { + painter.ShowButtons(); + painter.DrawingReady(); + }); + + return painter; + } + + // JSROOT.addDrawFunc({ name: "ROOT::Experimental::RPadDisplayItem", icon: "img_canvas", func: drawPad, opt: "" }); + + JSROOT.addDrawFunc({ name: "ROOT::Experimental::RHistDrawable<1>", icon: "img_histo1d", prereq: "v7hist", func: "JSROOT.v7.drawHist1", opt: "" }); + JSROOT.addDrawFunc({ name: "ROOT::Experimental::RHistDrawable<2>", icon: "img_histo2d", prereq: "v7hist", func: "JSROOT.v7.drawHist2", opt: "" }); + JSROOT.addDrawFunc({ name: "ROOT::Experimental::RText", icon: "img_text", prereq: "v7more", func: "JSROOT.v7.drawText", opt: "", direct: true }); + JSROOT.addDrawFunc({ name: "ROOT::Experimental::RLine", icon: "img_graph", prereq: "v7more", func: "JSROOT.v7.drawLine", opt: "", direct: true }); + JSROOT.addDrawFunc({ name: "ROOT::Experimental::RBox", icon: "img_graph", prereq: "v7more", func: "JSROOT.v7.drawBox", opt: "", direct: true }); + JSROOT.addDrawFunc({ name: "ROOT::Experimental::RMarker", icon: "img_graph", prereq: "v7more", func: "JSROOT.v7.drawMarker", opt: "", direct: true }); + + JSROOT.v7.TAxisPainter = TAxisPainter; + JSROOT.v7.TFramePainter = TFramePainter; + JSROOT.v7.TPadPainter = TPadPainter; + JSROOT.v7.TCanvasPainter = TCanvasPainter; + JSROOT.v7.drawFrame = drawFrame; + JSROOT.v7.drawPad = drawPad; + JSROOT.v7.drawCanvas = drawCanvas; + + return JSROOT; + +})); \ No newline at end of file diff --git a/js/scripts/JSRootPainter.v7hist.js b/js/scripts/JSRootPainter.v7hist.js new file mode 100644 index 00000000000..1a8f1126617 --- /dev/null +++ b/js/scripts/JSRootPainter.v7hist.js @@ -0,0 +1,3622 @@ +/// @file JSRootPainter.v7hist.js +/// JavaScript ROOT v7 graphics for histogram classes + +(function( factory ) { + if ( typeof define === "function" && define.amd ) { + define( ['JSRootPainter', 'd3'], factory ); + } else + if (typeof exports === 'object' && typeof module !== 'undefined') { + factory(require("./JSRootCore.js"), require("./d3.min.js")); + } else { + + if (typeof d3 != 'object') + throw new Error('This extension requires d3.js', 'JSRootPainter.v7hist.js'); + + if (typeof JSROOT == 'undefined') + throw new Error('JSROOT is not defined', 'JSRootPainter.v7hist.js'); + + if (typeof JSROOT.Painter != 'object') + throw new Error('JSROOT.Painter not defined', 'JSRootPainter.v7hist.js'); + + factory(JSROOT, d3); + } +} (function(JSROOT, d3) { + + "use strict"; + + JSROOT.sources.push("v7hist"); + + + // ============================================================= + + function THistPainter(histo) { + JSROOT.TObjectPainter.call(this, histo); + this.draw_content = true; + this.nbinsx = 0; + this.nbinsy = 0; + this.accept_drops = true; // indicate that one can drop other objects like doing Draw("same") + this.mode3d = false; + this.zoom_changed_interactive = 0; + // this.DecomposeTitle(); + } + + THistPainter.prototype = Object.create(JSROOT.TObjectPainter.prototype); + + // function ensure that frame is drawn on the canvas + THistPainter.prototype.PrepareFrame = function(divid) { + this.SetDivId(divid, -1); + + if (!this.frame_painter()) { + var pad = this.root_pad(), + fr = pad ? pad.fFrame : null; + JSROOT.v7.drawFrame(divid, fr); + } + + this.SetDivId(divid, 1); + } + + THistPainter.prototype.GetHImpl = function(obj) { + if (obj && obj.fHistImpl) + return obj.fHistImpl.fIsWeak ? obj.fHistImpl.fWeakForIO : obj.fHistImpl.fUnique; + return null; + } + + THistPainter.prototype.GetHisto = function() { + var obj = this.GetObject(), histo = this.GetHImpl(obj); + + if (histo && !histo.getBinContent) { + if (histo.fAxes._1) { + histo.getBin = function(x, y) { return (x + this.fAxes._0.fNBins * y); } + histo.getBinContent = function(x, y) { return this.fStatistics.fBinContent[this.getBin(x, y)]; } + histo.getBinError = function(x,y) { + var bin = this.getBin(x,y); + if (this.fStatistics.fSumWeightsSquared) + return Math.sqrt(this.fStatistics.fSumWeightsSquared[bin]); + return Math.sqrt(Math.abs(this.fStatistics.fBinContent[bin])); + } + } else { + + histo.getBinContent = function(bin) { + return this.fStatistics.fBinContent[bin]; + } + histo.getBinError = function(bin) { + if (this.fStatistics.fSumWeightsSquared) + return Math.sqrt(this.fStatistics.fSumWeightsSquared[bin]); + return Math.sqrt(Math.abs(this.getBinContent(bin))); + } + } + } + + return histo; + } + + THistPainter.prototype.IsTProfile = function() { + return false; + } + + THistPainter.prototype.IsTH1K = function() { + return false; + } + + THistPainter.prototype.IsTH2Poly = function() { + return false; + } + + THistPainter.prototype.DecodeOptions = function(opt) { + if (!this.options) this.options = { Hist : 1 }; + } + + THistPainter.prototype.Clear3DScene = function() { + var fp = this.frame_painter(); + if (fp && typeof fp.Create3DScene === 'function') + fp.Create3DScene(-1); + this.mode3d = false; + } + + THistPainter.prototype.Cleanup = function() { + + // clear all 3D buffers + this.Clear3DScene(); + + delete this.fPalette; + delete this.fContour; + delete this.options; + + JSROOT.TObjectPainter.prototype.Cleanup.call(this); + } + + THistPainter.prototype.Dimension = function() { + return 1; + } + + THistPainter.prototype.ScanContent = function(when_axis_changed) { + // function will be called once new histogram or + // new histogram content is assigned + // one should find min,max,nbins, maxcontent values + // if when_axis_changed === true specified, content will be scanned after axis zoom changed + + alert("HistPainter.prototype.ScanContent not implemented"); + } + + THistPainter.prototype.DrawAxes = function() { + // return true when axes was drawn + var main = this.frame_painter(); + if (!main) return false; + + if (this.is_main_painter() && this.draw_content) { + main.CleanupAxes(); + main.xmin = main.xmax = 0; + main.ymin = main.ymax = 0; + main.zmin = main.zmax = 0; + main.SetAxesRanges(this.xmin, this.xmax, this.ymin, this.ymax); + } + + return main.DrawAxes(true); + } + + THistPainter.prototype.CheckHistDrawAttributes = function() { + +/* if (this.options._pfc || this.options._plc || this.options._pmc) { + if (!this.pallette && JSROOT.Painter.GetColorPalette) + this.palette = JSROOT.Painter.GetColorPalette(); + + var pp = this.pad_painter(); + if (this.palette && pp) { + var icolor = pp.GetAutoColor(this); + + if (this.options._pfc) { this.histo.fFillColor = icolor; delete this.fillatt; } + if (this.options._plc) { this.histo.fLineColor = icolor; delete this.lineatt; } + if (this.options._pmc) { this.histo.fMarkerColor = icolor; delete this.markeratt; } + } + + this.options._pfc = this.options._plc = this.options._pmc = false; + } +*/ + + var opts = this.GetObject().fOpts, + pp = this.canv_painter(); + + this.createAttFill( { pattern: 0, color: 0 }); + + var lcol = pp.GetNewColor(opts.fLineColor); + + this.createAttLine({ color: lcol || 'black' }); + } + + THistPainter.prototype.UpdateObject = function(obj, opt) { + + var origin = this.GetObject(); + + if (obj !== origin) { + + if (!this.MatchObjectType(obj)) return false; + + var horigin = this.GetHImpl(origin), + hobj = this.GetHImpl(obj); + + if (!horigin || !hobj) return false; + + // make it easy - copy statistics without axes + horigin.fStatistics = hobj.fStatistics; + + // special tratement for webcanvas - also name can be changed + // if (this.snapid !== undefined) + // histo.fName = obj.fName; + + // histo.fTitle = obj.fTitle; + } + + this.ScanContent(); + + this.histogram_updated = true; // indicate that object updated + + return true; + } + + THistPainter.prototype.GetAxis = function(name) { + var histo = this.GetHisto(); + if (!histo || !histo.fAxes) return null; + + var axis = histo.fAxes._0; + + switch(name) { + case "x": axis = histo.fAxes._0; break; + case "y": axis = histo.fAxes._1; break; + case "z": axis = histo.fAxes._2; break; + } + if (!axis || axis.GetBinCoord) return axis; + + if (axis._typename == "ROOT::Experimental::RAxisEquidistant") { + axis.min = axis.fLow; + axis.max = axis.fLow + (axis.fNBins-2)/axis.fInvBinWidth; + + axis.GetBinCoord = function(bin) { return this.fLow + bin/this.fInvBinWidth; }; + axis.FindBin = function(x,add) { return Math.floor((x - this.fLow)*this.fInvBinWidth + add); }; + + } else { + axis.min = axis.fBinBorders[0]; + axis.max = axis.fBinBorders[axis.fNBins - 2]; + axis.GetBinCoord = function(bin) { + var indx = Math.round(bin); + if (indx <= 0) return this.fBinBorders[0]; + if (indx > this.fNBins - 2) return this.fBinBorders[this.fNBins - 2]; + if (indx==bin) return this.fBinBorders[indx]; + var indx2 = (bin < indx) ? indx - 1 : indx + 1; + return this.fBinBorders[indx] * Math.abs(bin-indx2) + this.fBinBorders[indx2] * Math.abs(bin-indx); + }; + axis.FindBin = function(x,add) { + for (var k = 1; k < this.fBinBorders.length; ++k) + if (x < this.fBinBorders[k]) return Math.floor(k-1+add); + return this.fNBins - 2; + }; + } + + return axis; + } + + THistPainter.prototype.CreateAxisFuncs = function(with_y_axis, with_z_axis) { + // here functions are defined to convert index to axis value and back + // introduced to support non-equidistant bins + + var histo = this.GetHisto(); + if (!histo) return; + + var axis = this.GetAxis("x"); + this.xmin = axis.min; + this.xmax = axis.max; + + if (!with_y_axis || !this.nbinsy) return; + + axis = this.GetAxis("y"); + this.ymin = axis.min; + this.ymax = axis.max; + if (!with_z_axis || !this.nbinsz) return; + + axis = this.GetAxis("z"); + this.zmin = axis.min; + this.zmax = axis.max; + } + + THistPainter.prototype.AddInteractive = function() { + // only first painter in list allowed to add interactive functionality to the frame + + if (this.is_main_painter()) { + var fp = this.frame_painter(); + if (fp) fp.AddInteractive(); + } + } + + + THistPainter.prototype.DrawBins = function() { + alert("HistPainter.DrawBins not implemented"); + } + + THistPainter.prototype.ToggleTitle = function(arg) { + return false; + } + + THistPainter.prototype.DecomposeTitle = function() { + } + + THistPainter.prototype.DrawTitle = function() { + } + + THistPainter.prototype.UpdateStatWebCanvas = function() { + } + + THistPainter.prototype.ToggleStat = function(arg) { + } + + THistPainter.prototype.GetSelectIndex = function(axis, size, add) { + // be aware - here indexes starts from 0 + var indx = 0, + main = this.frame_painter(), + taxis = this.GetAxis(axis), + nbins = this['nbins'+axis] || 0, + min = main ? main['zoom_' + axis + 'min'] : 0, + max = main ? main['zoom_' + axis + 'max'] : 0; + + if ((min !== max) && taxis) { + if (size == "left") + indx = taxis.FindBin(min, add || 0); + else + indx = taxis.FindBin(max, (add || 0) + 0.5); + if (indx<0) indx = 0; else if (indx>nbins) indx = nbins; + } else { + indx = (size == "left") ? 0 : nbins; + } + + return indx; + } + + THistPainter.prototype.FindStat = function() { + return null; + } + + THistPainter.prototype.IgnoreStatsFill = function() { + return true; + } + + THistPainter.prototype.CreateStat = function(force) { + return null; + } + + THistPainter.prototype.ButtonClick = function(funcname) { + // TODO: move to frame painter + switch(funcname) { + case "ToggleZoom": + if ((this.zoom_xmin !== this.zoom_xmax) || (this.zoom_ymin !== this.zoom_ymax) || (this.zoom_zmin !== this.zoom_zmax)) { + this.Unzoom(); + return true; + } + if (this.draw_content && (typeof this.AutoZoom === 'function')) { + this.AutoZoom(); + return true; + } + break; + case "ToggleLogX": this.frame_painter().ToggleLog("x"); break; + case "ToggleLogY": this.frame_painter().ToggleLog("y"); break; + case "ToggleLogZ": this.frame_painter().ToggleLog("z"); break; + case "ToggleStatBox": this.ToggleStat(); return true; break; + } + return false; + } + + THistPainter.prototype.FillToolbar = function(not_shown) { + var pp = this.pad_painter(); + if (!pp) return; + + pp.AddButton(JSROOT.ToolbarIcons.auto_zoom, 'Toggle between unzoom and autozoom-in', 'ToggleZoom', "Ctrl *"); + pp.AddButton(JSROOT.ToolbarIcons.arrow_right, "Toggle log x", "ToggleLogX", "PageDown"); + pp.AddButton(JSROOT.ToolbarIcons.arrow_up, "Toggle log y", "ToggleLogY", "PageUp"); + if (this.Dimension() > 1) + pp.AddButton(JSROOT.ToolbarIcons.arrow_diag, "Toggle log z", "ToggleLogZ"); + if (this.draw_content) + pp.AddButton(JSROOT.ToolbarIcons.statbox, 'Toggle stat box', "ToggleStatBox"); + if (!not_shown) pp.ShowButtons(); + } + + THistPainter.prototype.Get3DToolTip = function(indx) { + var histo = this.GetHisto(), + tip = { bin: indx, name: histo.fName || "histo", title: histo.fTitle }; + switch (this.Dimension()) { + case 1: + tip.ix = indx; tip.iy = 1; + tip.value = histo.getBinContent(tip.ix); + tip.error = histo.getBinError(indx); + tip.lines = this.GetBinTips(indx-1); + break; + case 2: + tip.ix = indx % (this.nbinsx + 2); + tip.iy = (indx - tip.ix) / (this.nbinsx + 2); + tip.value = histo.getBinContent(tip.ix, tip.iy); + tip.error = histo.getBinError(indx); + tip.lines = this.GetBinTips(tip.ix-1, tip.iy-1); + break; + case 3: + tip.ix = indx % (this.nbinsx+2); + tip.iy = ((indx - tip.ix) / (this.nbinsx+2)) % (this.nbinsy+2); + tip.iz = (indx - tip.ix - tip.iy * (this.nbinsx+2)) / (this.nbinsx+2) / (this.nbinsy+2); + tip.value = this.GetObject().getBinContent(tip.ix, tip.iy, tip.iz); + tip.error = histo.getBinError(indx); + tip.lines = this.GetBinTips(tip.ix-1, tip.iy-1, tip.iz-1); + break; + } + + return tip; + } + + THistPainter.prototype.CreateContour = function(nlevels, zmin, zmax, zminpositive) { + + if (nlevels<1) nlevels = JSROOT.gStyle.fNumberContours; + this.fContour = []; + this.colzmin = zmin; + this.colzmax = zmax; + + if (this.root_pad().fLogz) { + if (this.colzmax <= 0) this.colzmax = 1.; + if (this.colzmin <= 0) + if ((zminpositive===undefined) || (zminpositive <= 0)) + this.colzmin = 0.0001*this.colzmax; + else + this.colzmin = ((zminpositive < 3) || (zminpositive>100)) ? 0.3*zminpositive : 1; + if (this.colzmin >= this.colzmax) this.colzmin = 0.0001*this.colzmax; + + var logmin = Math.log(this.colzmin)/Math.log(10), + logmax = Math.log(this.colzmax)/Math.log(10), + dz = (logmax-logmin)/nlevels; + this.fContour.push(this.colzmin); + for (var level=1; level<nlevels; level++) + this.fContour.push(Math.exp((logmin + dz*level)*Math.log(10))); + this.fContour.push(this.colzmax); + this.fCustomContour = true; + } else { + if ((this.colzmin === this.colzmax) && (this.colzmin !== 0)) { + this.colzmax += 0.01*Math.abs(this.colzmax); + this.colzmin -= 0.01*Math.abs(this.colzmin); + } + var dz = (this.colzmax-this.colzmin)/nlevels; + for (var level=0; level<=nlevels; level++) + this.fContour.push(this.colzmin + dz*level); + } + + var main = this.frame_painter(); + + if (this.Dimension() < 3) { + main.zmin = this.zmin = this.colzmin; + main.zmax = this.zmax = this.colzmax; + } + + main.fContour = this.fContour; + main.fCustomContour = this.fCustomContour; + main.colzmin = this.colzmin; + main.colzmax = this.colzmax; + + return this.fContour; + } + + THistPainter.prototype.GetContour = function() { + if (this.fContour) return this.fContour; + + var main = this.frame_painter(); + if (main && main.fContour) { + this.fContour = main.fContour; + this.fCustomContour = main.fCustomContour; + this.colzmin = main.colzmin; + this.colzmax = main.colzmax; + return this.fContour; + } + + // if not initialized, first create contour array + // difference from ROOT - fContour includes also last element with maxbin, which makes easier to build logz + var histo = this.GetHisto(), nlevels = JSROOT.gStyle.fNumberContours, + zmin = this.minbin, zmax = this.maxbin, zminpos = this.minposbin; + if (zmin === zmax) { zmin = this.gminbin; zmax = this.gmaxbin; zminpos = this.gminposbin } + //if (histo.fContour) nlevels = histo.fContour.length; + //if ((this.options.minimum !== -1111) && (this.options.maximum != -1111)) { + // zmin = this.options.minimum; + // zmax = this.options.maximum; + //} + if (main.zoom_zmin != main.zoom_zmax) { + zmin = main.zoom_zmin; + zmax = main.zoom_zmax; + } + + //if (histo.fContour && (histo.fContour.length>1) && histo.TestBit(JSROOT.TH1StatusBits.kUserContour)) { + // this.fContour = JSROOT.clone(histo.fContour); + // this.fCustomContour = true; + // this.colzmin = zmin; + // this.colzmax = zmax; + // if (zmax > this.fContour[this.fContour.length-1]) this.fContour.push(zmax); + // if (this.Dimension()<3) { + // this.zmin = this.colzmin; + // this.zmax = this.colzmax; + // } + // return this.fContour; + //} + + this.fCustomContour = false; + + return this.CreateContour(nlevels, zmin, zmax, zminpos); + } + + THistPainter.prototype.FillContextMenu = function(menu) { + + var histo = this.GetHisto(); + + menu.add("header:v7histo::anyname"); + + if (this.draw_content) { + menu.addchk(this.ToggleStat('only-check'), "Show statbox", function() { this.ToggleStat(); }); + + if (typeof this.FillHistContextMenu == 'function') + this.FillHistContextMenu(menu); + } + + if (this.options.Mode3D) { + // menu for 3D drawings + + if (menu.size() > 0) + menu.add("separator"); + + var main = this.main_painter() || this, + fp = this.frame_painter(), + axis_painter = fp; + + menu.addchk(main.IsTooltipAllowed(), 'Show tooltips', function() { + main.SetTooltipAllowed("toggle"); + }); + + menu.addchk(axis_painter.enable_highlight, 'Highlight bins', function() { + axis_painter.enable_highlight = !axis_painter.enable_highlight; + if (!axis_painter.enable_highlight && main.BinHighlight3D && main.mode3d) main.BinHighlight3D(null); + }); + + if (fp && fp.Render3D) { + menu.addchk(main.options.FrontBox, 'Front box', function() { + main.options.FrontBox = !main.options.FrontBox; + fp.Render3D(); + }); + menu.addchk(main.options.BackBox, 'Back box', function() { + main.options.BackBox = !main.options.BackBox; + fp.Render3D(); + }); + } + + if (this.draw_content) { + menu.addchk(!this.options.Zero, 'Suppress zeros', function() { + this.options.Zero = !this.options.Zero; + this.RedrawPad(); + }); + + if ((this.options.Lego==12) || (this.options.Lego==14)) { + menu.addchk(this.options.Zscale, "Z scale", function() { + this.ToggleColz(); + }); + if (this.FillPaletteMenu) this.FillPaletteMenu(menu); + } + } + + if (main.control && typeof main.control.reset === 'function') + menu.add('Reset camera', function() { + main.control.reset(); + }); + } + + this.FillAttContextMenu(menu); + + if (this.histogram_updated && this.zoom_changed_interactive) + menu.add('Let update zoom', function() { + this.zoom_changed_interactive = 0; + }); + + return true; + } + + + /// return index from contours array, which corresponds to the content value **zc** + THistPainter.prototype.getContourIndex = function(zc) { + + var cntr = this.GetContour(); + + if (this.fCustomContour) { + var l = 0, r = cntr.length-1, mid; + if (zc < cntr[0]) return -1; + if (zc >= cntr[r]) return r; + while (l < r-1) { + mid = Math.round((l+r)/2); + if (cntr[mid] > zc) r = mid; else l = mid; + } + return l; + } + + // bins less than zmin not drawn + if (zc < this.colzmin) return this.options.Zero ? -1 : 0; + + // if bin content exactly zmin, draw it when col0 specified or when content is positive + if (zc===this.colzmin) return ((this.colzmin != 0) || !this.options.Zero || this.IsTH2Poly()) ? 0 : -1; + + return Math.floor(0.01+(zc-this.colzmin)*(cntr.length-1)/(this.colzmax-this.colzmin)); + } + + /// return color from the palette, which corresponds given controur value + /// optionally one can return color index of the palette + THistPainter.prototype.getContourColor = function(zc, asindx) { + var zindx = this.getContourIndex(zc); + if (zindx < 0) return null; + + var cntr = this.GetContour(), + palette = this.GetPalette(), + indx = palette.calcColorIndex(zindx, cntr.length); + + return asindx ? indx : palette.getColor(indx); + } + + THistPainter.prototype.GetPalette = function(force) { + if (!this.fPalette || force) + this.fPalette = this.get_palette(true, this.options.Palette); + return this.fPalette; + } + + THistPainter.prototype.FillPaletteMenu = function(menu) { + + var curr = this.options.Palette, hpainter = this; + if ((curr===null) || (curr===0)) curr = JSROOT.gStyle.Palette; + + function change(arg) { + hpainter.options.Palette = parseInt(arg); + hpainter.GetPalette(true); + hpainter.Redraw(); // redraw histogram + }; + + function add(id, name, more) { + menu.addchk((id===curr) || more, '<nobr>' + name + '</nobr>', id, change); + }; + + menu.add("sub:Palette"); + + add(50, "ROOT 5", (curr>=10) && (curr<51)); + add(51, "Deep Sea"); + add(52, "Grayscale", (curr>0) && (curr<10)); + add(53, "Dark body radiator"); + add(54, "Two-color hue"); + add(55, "Rainbow"); + add(56, "Inverted dark body radiator"); + add(57, "Bird", (curr>112)); + add(58, "Cubehelix"); + add(59, "Green Red Violet"); + add(60, "Blue Red Yellow"); + add(61, "Ocean"); + add(62, "Color Printable On Grey"); + add(63, "Alpine"); + add(64, "Aquamarine"); + add(65, "Army"); + add(66, "Atlantic"); + + menu.add("endsub:"); + } + + THistPainter.prototype.DrawColorPalette = function(enabled, postpone_draw, can_move) { + // only when create new palette, one could change frame size + + return null; + } + + THistPainter.prototype.ToggleColz = function() { + var can_toggle = this.options.Mode3D ? (this.options.Lego === 12 || this.options.Lego === 14 || this.options.Surf === 11 || this.options.Surf === 12) : + this.options.Color || this.options.Contour; + + if (can_toggle) { + this.options.Zscale = !this.options.Zscale; + this.DrawColorPalette(this.options.Zscale, false, true); + } + } + + THistPainter.prototype.ToggleMode3D = function() { + this.options.Mode3D = !this.options.Mode3D; + + if (this.options.Mode3D) { + if (!this.options.Surf && !this.options.Lego && !this.options.Error) { + if ((this.nbinsx>=50) || (this.nbinsy>=50)) + this.options.Lego = this.options.Color ? 14 : 13; + else + this.options.Lego = this.options.Color ? 12 : 1; + + this.options.Zero = false; // do not show zeros by default + } + } + + this.CopyOptionsToOthers(); + this.InteractiveRedraw("pad","drawopt"); + } + + THistPainter.prototype.PrepareColorDraw = function(args) { + + if (!args) args = { rounding: true, extra: 0, middle: 0 }; + + if (args.extra === undefined) args.extra = 0; + if (args.middle === undefined) args.middle = 0; + + var histo = this.GetHisto(), xaxis = this.GetAxis("x"), yaxis = this.GetAxis("y"), + pmain = this.frame_painter(), + hdim = this.Dimension(), + i, j, x, y, binz, binarea, + res = { + i1: this.GetSelectIndex("x", "left", 0 - args.extra), + i2: this.GetSelectIndex("x", "right", 1 + args.extra), + j1: (hdim===1) ? 0 : this.GetSelectIndex("y", "left", 0 - args.extra), + j2: (hdim===1) ? 1 : this.GetSelectIndex("y", "right", 1 + args.extra), + min: 0, max: 0, sumz: 0, xbar1: 0, xbar2: 1, ybar1: 0, ybar2: 1 + }; + res.grx = new Float32Array(res.i2+1); + res.gry = new Float32Array(res.j2+1); + + if (args.original) { + res.original = true; + res.origx = new Float32Array(res.i2+1); + res.origy = new Float32Array(res.j2+1); + } + + if (args.pixel_density) args.rounding = true; + + // calculate graphical coordinates in advance + for (i = res.i1; i <= res.i2; ++i) { + x = xaxis.GetBinCoord(i + args.middle); + if (pmain.logx && (x <= 0)) { res.i1 = i+1; continue; } + if (res.origx) res.origx[i] = x; + res.grx[i] = pmain.grx(x); + if (args.rounding) res.grx[i] = Math.round(res.grx[i]); + + if (args.use3d) { + if (res.grx[i] < -pmain.size_xy3d) { res.i1 = i; res.grx[i] = -pmain.size_xy3d; } + if (res.grx[i] > pmain.size_xy3d) { res.i2 = i; res.grx[i] = pmain.size_xy3d; } + } + } + + if (hdim===1) { + res.gry[0] = pmain.gry(0); + res.gry[1] = pmain.gry(1); + } else + for (j = res.j1; j <= res.j2; ++j) { + y = yaxis.GetBinCoord(j + args.middle); + if (pmain.logy && (y <= 0)) { res.j1 = j+1; continue; } + if (res.origy) res.origy[j] = y; + res.gry[j] = pmain.gry(y); + if (args.rounding) res.gry[j] = Math.round(res.gry[j]); + + if (args.use3d) { + if (res.gry[j] < -pmain.size_xy3d) { res.j1 = j; res.gry[j] = -pmain.size_xy3d; } + if (res.gry[j] > pmain.size_xy3d) { res.j2 = j; res.gry[j] = pmain.size_xy3d; } + } + } + + // find min/max values in selected range + + binz = histo.getBinContent(res.i1 + 1, res.j1 + 1); + this.maxbin = this.minbin = this.minposbin = null; + + for (i = res.i1; i < res.i2; ++i) { + for (j = res.j1; j < res.j2; ++j) { + binz = histo.getBinContent(i + 1, j + 1); + res.sumz += binz; + if (args.pixel_density) { + binarea = (res.grx[i+1]-res.grx[i])*(res.gry[j]-res.gry[j+1]); + if (binarea <= 0) continue; + res.max = Math.max(res.max, binz); + if ((binz>0) && ((binz<res.min) || (res.min===0))) res.min = binz; + binz = binz/binarea; + } + if (this.maxbin===null) { + this.maxbin = this.minbin = binz; + } else { + this.maxbin = Math.max(this.maxbin, binz); + this.minbin = Math.min(this.minbin, binz); + } + if (binz > 0) + if ((this.minposbin===null) || (binz<this.minposbin)) this.minposbin = binz; + } + } + + // force recalculation of z levels + this.fContour = null; + this.fCustomContour = false; + + return res; + } + + // ======= TH1 painter================================================ + + function TH1Painter(histo) { + THistPainter.call(this, histo); + this.wheel_zoomy = false; + } + + TH1Painter.prototype = Object.create(THistPainter.prototype); + + TH1Painter.prototype.ConvertTH1K = function() { + var histo = this.GetObject(); + + if (histo.fReady) return; + + var arr = histo.fArray; // array of values + histo.fNcells = histo.fXaxis.fNbins + 2; + histo.fArray = new Float64Array(histo.fNcells); + for (var n=0;n<histo.fNcells;++n) histo.fArray[n] = 0; + for (var n=0;n<histo.fNIn;++n) histo.Fill(arr[n]); + histo.fReady = true; + } + + TH1Painter.prototype.ScanContent = function(when_axis_changed) { + // if when_axis_changed === true specified, content will be scanned after axis zoom changed + + var histo = this.GetHisto(); + if (!histo) return; + + if (!this.nbinsx && when_axis_changed) when_axis_changed = false; + + if (!when_axis_changed) { + this.nbinsx = this.GetAxis("x").fNBins - 2; + this.nbinsy = 0; + this.CreateAxisFuncs(false); + } + + var left = this.GetSelectIndex("x", "left"), + right = this.GetSelectIndex("x", "right"); + + if (when_axis_changed) { + if ((left === this.scan_xleft) && (right === this.scan_xright)) return; + } + + this.scan_xleft = left; + this.scan_xright = right; + + var hmin = 0, hmin_nz = 0, hmax = 0, hsum = 0, first = true, value, err; + + for (var i = 0; i < this.nbinsx; ++i) { + value = histo.getBinContent(i+1); + hsum += value; + + if ((i<left) || (i>=right)) continue; + + if (value > 0) + if ((hmin_nz == 0) || (value<hmin_nz)) hmin_nz = value; + if (first) { + hmin = hmax = value; + first = false;; + } + + err = 0; + + hmin = Math.min(hmin, value - err); + hmax = Math.max(hmax, value + err); + } + + // account overflow/underflow bins + hsum += histo.getBinContent(0) + histo.getBinContent(this.nbinsx + 1); + + this.stat_entries = hsum; + + this.hmin = hmin; + this.hmax = hmax; + + this.ymin_nz = hmin_nz; // value can be used to show optimal log scale + + if ((this.nbinsx == 0) || ((Math.abs(hmin) < 1e-300 && Math.abs(hmax) < 1e-300))) { + this.draw_content = false; + } else { + this.draw_content = true; + } + + if (this.draw_content) { + if (hmin >= hmax) { + if (hmin == 0) { this.ymin = 0; this.ymax = 1; } + else if (hmin < 0) { this.ymin = 2 * hmin; this.ymax = 0; } + else { this.ymin = 0; this.ymax = hmin * 2; } + } else { + var dy = (hmax - hmin) * 0.05; + this.ymin = hmin - dy; + if ((this.ymin < 0) && (hmin >= 0)) this.ymin = 0; + this.ymax = hmax + dy; + } + } + } + + TH1Painter.prototype.CountStat = function(cond) { + var profile = this.IsTProfile(), + histo = this.GetHisto(), xaxis = this.GetAxis("x"), + left = this.GetSelectIndex("x", "left"), + right = this.GetSelectIndex("x", "right"), + stat_sumw = 0, stat_sumwx = 0, stat_sumwx2 = 0, stat_sumwy = 0, stat_sumwy2 = 0, + i, xx = 0, w = 0, xmax = null, wmax = null, + fp = this.frame_painter(), + res = { name: "histo", meanx: 0, meany: 0, rmsx: 0, rmsy: 0, integral: 0, entries: this.stat_entries, xmax:0, wmax:0 }; + + for (i = left; i < right; ++i) { + xx = xaxis.GetBinCoord(i+0.5); + + if (cond && !cond(xx)) continue; + + if (profile) { + w = histo.fBinEntries[i + 1]; + stat_sumwy += histo.fArray[i + 1]; + stat_sumwy2 += histo.fSumw2[i + 1]; + } else { + w = histo.getBinContent(i + 1); + } + + if ((xmax===null) || (w>wmax)) { xmax = xx; wmax = w; } + + stat_sumw += w; + stat_sumwx += w * xx; + stat_sumwx2 += w * xx * xx; + } + + // when no range selection done, use original statistic from histogram + if (!fp.IsAxisZoomed("x") && histo.fTsumw) { + stat_sumw = histo.fTsumw; + stat_sumwx = histo.fTsumwx; + stat_sumwx2 = histo.fTsumwx2; + } + + res.integral = stat_sumw; + + if (stat_sumw > 0) { + res.meanx = stat_sumwx / stat_sumw; + res.meany = stat_sumwy / stat_sumw; + res.rmsx = Math.sqrt(Math.abs(stat_sumwx2 / stat_sumw - res.meanx * res.meanx)); + res.rmsy = Math.sqrt(Math.abs(stat_sumwy2 / stat_sumw - res.meany * res.meany)); + } + + if (xmax!==null) { + res.xmax = xmax; + res.wmax = wmax; + } + + return res; + } + + TH1Painter.prototype.FillStatistic = function(stat, dostat, dofit) { + + // no need to refill statistic if histogram is dummy + if (this.IgnoreStatsFill()) return false; + + var data = this.CountStat(), + print_name = dostat % 10, + print_entries = Math.floor(dostat / 10) % 10, + print_mean = Math.floor(dostat / 100) % 10, + print_rms = Math.floor(dostat / 1000) % 10, + print_under = Math.floor(dostat / 10000) % 10, + print_over = Math.floor(dostat / 100000) % 10, + print_integral = Math.floor(dostat / 1000000) % 10, + print_skew = Math.floor(dostat / 10000000) % 10, + print_kurt = Math.floor(dostat / 100000000) % 10; + + // make empty at the beginning + stat.ClearPave(); + + if (print_name > 0) + stat.AddText(data.name); + + if (this.IsTProfile()) { + + if (print_entries > 0) + stat.AddText("Entries = " + stat.Format(data.entries,"entries")); + + if (print_mean > 0) { + stat.AddText("Mean = " + stat.Format(data.meanx)); + stat.AddText("Mean y = " + stat.Format(data.meany)); + } + + if (print_rms > 0) { + stat.AddText("Std Dev = " + stat.Format(data.rmsx)); + stat.AddText("Std Dev y = " + stat.Format(data.rmsy)); + } + + } else { + + if (print_entries > 0) + stat.AddText("Entries = " + stat.Format(data.entries,"entries")); + + if (print_mean > 0) + stat.AddText("Mean = " + stat.Format(data.meanx)); + + if (print_rms > 0) + stat.AddText("Std Dev = " + stat.Format(data.rmsx)); + + if (print_under > 0) + stat.AddText("Underflow = " + stat.Format(histo.getBinContent(0), "entries")); + + if (print_over > 0) + stat.AddText("Overflow = " + stat.Format(histo.getBinContent(this.nbinsx+1), "entries")); + + if (print_integral > 0) + stat.AddText("Integral = " + stat.Format(data.integral,"entries")); + + if (print_skew > 0) + stat.AddText("Skew = <not avail>"); + + if (print_kurt > 0) + stat.AddText("Kurt = <not avail>"); + } + + // if (dofit) stat.FillFunctionStat(this.FindFunction('TF1'), dofit); + + return true; + } + + TH1Painter.prototype.DrawBars = function(width, height) { + + this.CreateG(true); + + var left = this.GetSelectIndex("x", "left", -1), + right = this.GetSelectIndex("x", "right", 1), + pmain = this.frame_painter(), + pthis = this, + histo = this.GetHisto(), xaxis = this.GetAxis("x"), + i, x1, x2, grx1, grx2, y, gry1, gry2, w, + bars = "", barsl = "", barsr = "", + side = (this.options.BarStyle > 10) ? this.options.BarStyle % 10 : 0; + + if (side>4) side = 4; + gry2 = pmain.swap_xy ? 0 : height; + if ((this.options.BaseLine !== false) && !isNaN(this.options.BaseLine)) + if (this.options.BaseLine >= pmain.scale_ymin) + gry2 = Math.round(pmain.gry(this.options.BaseLine)); + + for (i = left; i < right; ++i) { + x1 = xaxis.GetBinCoord(i); + x2 = xaxis.GetBinCoord(i+1); + + if (pmain.logx && (x2 <= 0)) continue; + + grx1 = Math.round(pmain.grx(x1)); + grx2 = Math.round(pmain.grx(x2)); + + y = histo.getBinContent(i+1); + if (pmain.logy && (y < pmain.scale_ymin)) continue; + gry1 = Math.round(pmain.gry(y)); + + w = grx2 - grx1; + grx1 += Math.round(this.options.fBarOffset/1000*w); + w = Math.round(this.options.fBarWidth/1000*w); + + if (pmain.swap_xy) + bars += "M"+gry2+","+grx1 + "h"+(gry1-gry2) + "v"+w + "h"+(gry2-gry1) + "z"; + else + bars += "M"+grx1+","+gry1 + "h"+w + "v"+(gry2-gry1) + "h"+(-w)+ "z"; + + if (side > 0) { + grx2 = grx1 + w; + w = Math.round(w * side / 10); + if (pmain.swap_xy) { + barsl += "M"+gry2+","+grx1 + "h"+(gry1-gry2) + "v" + w + "h"+(gry2-gry1) + "z"; + barsr += "M"+gry2+","+grx2 + "h"+(gry1-gry2) + "v" + (-w) + "h"+(gry2-gry1) + "z"; + } else { + barsl += "M"+grx1+","+gry1 + "h"+w + "v"+(gry2-gry1) + "h"+(-w)+ "z"; + barsr += "M"+grx2+","+gry1 + "h"+(-w) + "v"+(gry2-gry1) + "h"+w + "z"; + } + } + } + + if (this.fillatt.empty()) this.fillatt.SetSolidColor("blue"); + + if (bars.length > 0) + this.draw_g.append("svg:path") + .attr("d", bars) + .call(this.fillatt.func); + + if (barsl.length > 0) + this.draw_g.append("svg:path") + .attr("d", barsl) + .call(this.fillatt.func) + .style("fill", d3.rgb(this.fillatt.color).brighter(0.5).toString()); + + if (barsr.length > 0) + this.draw_g.append("svg:path") + .attr("d", barsr) + .call(this.fillatt.func) + .style("fill", d3.rgb(this.fillatt.color).darker(0.5).toString()); + } + + TH1Painter.prototype.DrawFilledErrors = function(width, height) { + this.CreateG(true); + + var left = this.GetSelectIndex("x", "left", -1), + right = this.GetSelectIndex("x", "right", 1), + pmain = this.frame_painter(), + histo = this.GetHisto(), xaxis = this.GetAxis("x"), + i, x, grx, y, yerr, gry1, gry2, + bins1 = [], bins2 = []; + + for (i = left; i < right; ++i) { + x = xaxis.GetBinCoord(i+0.5); + if (pmain.logx && (x <= 0)) continue; + grx = Math.round(pmain.grx(x)); + + y = histo.getBinContent(i+1); + yerr = histo.getBinError(i+1); + if (pmain.logy && (y-yerr < pmain.scale_ymin)) continue; + + gry1 = Math.round(pmain.gry(y + yerr)); + gry2 = Math.round(pmain.gry(y - yerr)); + + bins1.push({grx:grx, gry: gry1}); + bins2.unshift({grx:grx, gry: gry2}); + } + + var kind = (this.options.ErrorKind === 4) ? "bezier" : "line", + path1 = JSROOT.Painter.BuildSvgPath(kind, bins1), + path2 = JSROOT.Painter.BuildSvgPath("L"+kind, bins2); + + if (this.fillatt.empty()) this.fillatt.setSolidColor("blue"); + + this.draw_g.append("svg:path") + .attr("d", path1.path + path2.path + "Z") + .style("stroke", "none") + .call(this.fillatt.func); + } + + TH1Painter.prototype.DrawBins = function() { + // new method, create svg:path expression ourself directly from histogram + // all points will be used, compress expression when too large + + var width = this.frame_width(), height = this.frame_height(), options = this.options; + + if (!this.draw_content || (width<=0) || (height<=0)) + return this.RemoveDrawG(); + + this.CheckHistDrawAttributes(); + + if (options.Bar) + return this.DrawBars(width, height); + + if ((options.ErrorKind === 3) || (options.ErrorKind === 4)) + return this.DrawFilledErrors(width, height); + + this.CreateG(true); + + var left = this.GetSelectIndex("x", "left", -1), + right = this.GetSelectIndex("x", "right", 2), + pmain = this.frame_painter(), + pthis = this, histo = this.GetHisto(), xaxis = this.GetAxis("x"), + res = "", lastbin = false, + startx, currx, curry, x, grx, y, gry, curry_min, curry_max, prevy, prevx, i, bestimin, bestimax, + exclude_zero = !options.Zero, + show_errors = options.Error, + show_markers = options.Mark, + show_line = options.Line, + show_text = options.Text, + text_profile = show_text && (this.options.TextKind == "E") && this.IsTProfile() && histo.fBinEntries, + path_fill = null, path_err = null, path_marker = null, path_line = null, + endx = "", endy = "", dend = 0, my, yerr1, yerr2, bincont, binerr, mx1, mx2, midx, + mpath = "", text_col, text_angle, text_size; + + //if (show_errors && !show_markers && (histo.fMarkerStyle > 1)) + // show_markers = true; + + if (options.ErrorKind === 2) { + if (this.fillatt.empty()) show_markers = true; + else path_fill = ""; + } else + if (options.Error) path_err = ""; + + if (show_line) path_line = ""; + + if (show_markers) { + // draw markers also when e2 option was specified + this.createAttMarker({ attr: histo, style: this.options.MarkStyle }); + if (this.markeratt.size > 0) { + // simply use relative move from point, can optimize in the future + path_marker = ""; + this.markeratt.reset_pos(); + } else { + show_markers = false; + } + } + + if (show_text) { + text_col = this.get_color(histo.fMarkerColor); + text_angle = -1*options.TextAngle; + text_size = 20; + + if ((options.fMarkerSize!==1) && text_angle) + text_size = 0.02 * height * options.fMarkerSize; + + if (!text_angle && !options.TextKind) { + var space = width / (right - left + 1); + if (space < 3 * text_size) { + text_angle = 270; + text_size = Math.round(space*0.7); + } + } + + this.StartTextDrawing(42, text_size, this.draw_g, text_size); + } + + // if there are too many points, exclude many vertical drawings at the same X position + // instead define min and max value and made min-max drawing + var use_minmax = ((right-left) > 3*width); + + if (options.ErrorKind === 1) { + var lw = this.lineatt.width + JSROOT.gStyle.fEndErrorSize; + endx = "m0," + lw + "v-" + 2*lw + "m0," + lw; + endy = "m" + lw + ",0h-" + 2*lw + "m" + lw + ",0"; + dend = Math.floor((this.lineatt.width-1)/2); + } + + var draw_markers = show_errors || show_markers; + + if (draw_markers || show_text || show_line) use_minmax = true; + + function draw_bin(besti) { + bincont = histo.getBinContent(besti+1); + if (!exclude_zero || (bincont!==0)) { + mx1 = Math.round(pmain.grx(xaxis.GetBinLowEdge(besti+1))); + mx2 = Math.round(pmain.grx(xaxis.GetBinLowEdge(besti+2))); + midx = Math.round((mx1+mx2)/2); + my = Math.round(pmain.gry(bincont)); + yerr1 = yerr2 = 20; + if (show_errors) { + binerr = histo.getBinError(besti+1); + yerr1 = Math.round(my - pmain.gry(bincont + binerr)); // up + yerr2 = Math.round(pmain.gry(bincont - binerr) - my); // down + } + + if (show_text) { + var cont = text_profile ? histo.fBinEntries[besti+1] : bincont; + + if (cont!==0) { + var lbl = (cont === Math.round(cont)) ? cont.toString() : JSROOT.FFormat(cont, JSROOT.gStyle.fPaintTextFormat); + + if (text_angle) + pthis.DrawText({ align: 12, x: midx, y: Math.round(my - 2 - text_size/5), width: 0, height: 0, rotate: text_angle, text: lbl, color: text_col, latex: 0 }); + else + pthis.DrawText({ align: 22, x: Math.round(mx1 + (mx2-mx1)*0.1), y: Math.round(my-2-text_size), width: Math.round((mx2-mx1)*0.8), height: text_size, text: lbl, color: text_col, latex: 0 }); + } + } + + if (show_line && (path_line !== null)) + path_line += ((path_line.length===0) ? "M" : "L") + midx + "," + my; + + if (draw_markers) { + if ((my >= -yerr1) && (my <= height + yerr2)) { + if (path_fill !== null) + path_fill += "M" + mx1 +","+(my-yerr1) + + "h" + (mx2-mx1) + "v" + (yerr1+yerr2+1) + "h-" + (mx2-mx1) + "z"; + if (path_marker !== null) + path_marker += pthis.markeratt.create(midx, my); + if (path_err !== null) { + if (pthis.options.errorX > 0) { + var mmx1 = Math.round(midx - (mx2-mx1)*pthis.options.errorX), + mmx2 = Math.round(midx + (mx2-mx1)*pthis.options.errorX); + path_err += "M" + (mmx1+dend) +","+ my + endx + "h" + (mmx2-mmx1-2*dend) + endx; + } + path_err += "M" + midx +"," + (my-yerr1+dend) + endy + "v" + (yerr1+yerr2-2*dend) + endy; + } + } + } + } + } + + for (i = left; i <= right; ++i) { + + x = xaxis.GetBinCoord(i); + + if (pmain.logx && (x <= 0)) continue; + + grx = Math.round(pmain.grx(x)); + + lastbin = (i === right); + + if (lastbin && (left<right)) { + gry = curry; + } else { + y = histo.getBinContent(i+1); + gry = Math.round(pmain.gry(y)); + } + + if (res.length === 0) { + bestimin = bestimax = i; + prevx = startx = currx = grx; + prevy = curry_min = curry_max = curry = gry; + res = "M"+currx+","+curry; + } else + if (use_minmax) { + if ((grx === currx) && !lastbin) { + if (gry < curry_min) bestimax = i; else + if (gry > curry_max) bestimin = i; + curry_min = Math.min(curry_min, gry); + curry_max = Math.max(curry_max, gry); + curry = gry; + } else { + + if (draw_markers || show_text || show_line) { + if (bestimin === bestimax) { draw_bin(bestimin); } else + if (bestimin < bestimax) { draw_bin(bestimin); draw_bin(bestimax); } else { + draw_bin(bestimax); draw_bin(bestimin); + } + } + + // when several points as same X differs, need complete logic + if (!draw_markers && ((curry_min !== curry_max) || (prevy !== curry_min))) { + + if (prevx !== currx) + res += "h"+(currx-prevx); + + if (curry === curry_min) { + if (curry_max !== prevy) + res += "v" + (curry_max - prevy); + if (curry_min !== curry_max) + res += "v" + (curry_min - curry_max); + } else { + if (curry_min !== prevy) + res += "v" + (curry_min - prevy); + if (curry_max !== curry_min) + res += "v" + (curry_max - curry_min); + if (curry !== curry_max) + res += "v" + (curry - curry_max); + } + + prevx = currx; + prevy = curry; + } + + if (lastbin && (prevx !== grx)) + res += "h"+(grx-prevx); + + bestimin = bestimax = i; + curry_min = curry_max = curry = gry; + currx = grx; + } + } else + if ((gry !== curry) || lastbin) { + if (grx !== currx) res += "h"+(grx-currx); + if (gry !== curry) res += "v"+(gry-curry); + curry = gry; + currx = grx; + } + } + + var close_path = ""; + if (!this.fillatt.empty()) { + var h0 = height + 3, gry0 = Math.round(pmain.gry(0)); + if (gry0 <= 0) h0 = -3; else if (gry0 < height) h0 = gry0; + close_path = "L"+currx+","+h0 + "L"+startx+","+h0 + "Z"; + if (res.length>0) res += close_path; + } + + if (draw_markers || show_line) { + if ((path_fill !== null) && (path_fill.length > 0)) + this.draw_g.append("svg:path") + .attr("d", path_fill) + .call(this.fillatt.func); + + if ((path_err !== null) && (path_err.length > 0)) + this.draw_g.append("svg:path") + .attr("d", path_err) + .call(this.lineatt.func); + + if ((path_line !== null) && (path_line.length > 0)) { + if (!this.fillatt.empty()) + this.draw_g.append("svg:path") + .attr("d", options.Fill ? (path_line + close_path) : res) + .attr("stroke", "none") + .call(this.fillatt.func); + + this.draw_g.append("svg:path") + .attr("d", path_line) + .attr("fill", "none") + .call(this.lineatt.func); + } + + if ((path_marker !== null) && (path_marker.length > 0)) + this.draw_g.append("svg:path") + .attr("d", path_marker) + .call(this.markeratt.func); + + } else + if (res && options.Hist) { + this.draw_g.append("svg:path") + .attr("d", res) + .style("stroke-linejoin","miter") + .call(this.lineatt.func) + .call(this.fillatt.func); + } + + if (show_text) + this.FinishTextDrawing(this.draw_g); + + } + + TH1Painter.prototype.GetBinTips = function(bin) { + var tips = [], + name = this.GetTipName(), + pmain = this.frame_painter(), + histo = this.GetHisto(), xaxis = this.GetAxis("x"), + x1 = xaxis.GetBinCoord(bin), + x2 = xaxis.GetBinCoord(bin+1), + cont = histo.getBinContent(bin+1), + xlbl = "", xnormal = false; + + if (name.length>0) tips.push(name); + + if (pmain.x_kind === 'labels') xlbl = pmain.AxisAsText("x", x1); else + if (pmain.x_kind === 'time') xlbl = pmain.AxisAsText("x", (x1+x2)/2); else + { xnormal = true; xlbl = "[" + pmain.AxisAsText("x", x1) + ", " + pmain.AxisAsText("x", x2) + ")"; } + + if (this.options.Error || this.options.Mark) { + tips.push("x = " + xlbl); + tips.push("y = " + pmain.AxisAsText("y", cont)); + if (this.options.Error) { + if (xnormal) tips.push("error x = " + ((x2 - x1) / 2).toPrecision(4)); + tips.push("error y = " + histo.getBinError(bin + 1).toPrecision(4)); + } + } else { + tips.push("bin = " + (bin+1)); + tips.push("x = " + xlbl); + if (histo['$baseh']) cont -= histo['$baseh'].getBinContent(bin+1); + if (cont === Math.round(cont)) + tips.push("entries = " + cont); + else + tips.push("entries = " + JSROOT.FFormat(cont, JSROOT.gStyle.fStatFormat)); + } + + return tips; + } + + TH1Painter.prototype.ProcessTooltip = function(pnt) { + if ((pnt === null) || !this.draw_content || this.options.Mode3D) { + if (this.draw_g !== null) + this.draw_g.select(".tooltip_bin").remove(); + return null; + } + + var width = this.frame_width(), + height = this.frame_height(), + pmain = this.frame_painter(), + painter = this, + histo = this.GetHisto(), xaxis = this.GetAxis("x"), + findbin = null, show_rect = true, + grx1, midx, grx2, gry1, midy, gry2, gapx = 2, + left = this.GetSelectIndex("x", "left", -1), + right = this.GetSelectIndex("x", "right", 2), + l = left, r = right; + + function GetBinGrX(i) { + var xx = xaxis.GetBinCoord(i); + return (pmain.logx && (xx<=0)) ? null : pmain.grx(xx); + } + + function GetBinGrY(i) { + var yy = histo.getBinContent(i + 1); + if (pmain.logy && (yy < pmain.scale_ymin)) + return pmain.swap_xy ? -1000 : 10*height; + return Math.round(pmain.gry(yy)); + } + + var pnt_x = pmain.swap_xy ? pnt.y : pnt.x, + pnt_y = pmain.swap_xy ? pnt.x : pnt.y; + + while (l < r-1) { + var m = Math.round((l+r)*0.5), + xx = GetBinGrX(m); + if ((xx === null) || (xx < pnt_x - 0.5)) { + if (pmain.swap_xy) r = m; else l = m; + } else if (xx > pnt_x + 0.5) { + if (pmain.swap_xy) l = m; else r = m; + } else { l++; r--; } + } + + findbin = r = l; + grx1 = GetBinGrX(findbin); + + if (pmain.swap_xy) { + while ((l>left) && (GetBinGrX(l-1) < grx1 + 2)) --l; + while ((r<right) && (GetBinGrX(r+1) > grx1 - 2)) ++r; + } else { + while ((l>left) && (GetBinGrX(l-1) > grx1 - 2)) --l; + while ((r<right) && (GetBinGrX(r+1) < grx1 + 2)) ++r; + } + + if (l < r) { + // many points can be assigned with the same cursor position + // first try point around mouse y + var best = height; + for (var m=l;m<=r;m++) { + var dist = Math.abs(GetBinGrY(m) - pnt_y); + if (dist < best) { best = dist; findbin = m; } + } + + // if best distance still too far from mouse position, just take from between + if (best > height/10) + findbin = Math.round(l + (r-l) / height * pnt_y); + + grx1 = GetBinGrX(findbin); + } + + grx1 = Math.round(grx1); + grx2 = Math.round(GetBinGrX(findbin+1)); + + if (this.options.Bar) { + var w = grx2 - grx1; + grx1 += Math.round(this.options.fBarOffset/1000*w); + grx2 = grx1 + Math.round(this.options.fBarWidth/1000*w); + } + + if (grx1 > grx2) { var d = grx1; grx1 = grx2; grx2 = d; } + + midx = Math.round((grx1+grx2)/2); + + midy = gry1 = gry2 = GetBinGrY(findbin); + + if (this.options.Bar) { + show_rect = true; + + gapx = 0; + + gry1 = Math.round(pmain.gry(((this.options.BaseLine!==false) && (this.options.BaseLine > pmain.scale_ymin)) ? this.options.BaseLine : pmain.scale_ymin)); + + if (gry1 > gry2) { var d = gry1; gry1 = gry2; gry2 = d; } + + if (!pnt.touch && (pnt.nproc === 1)) + if ((pnt_y<gry1) || (pnt_y>gry2)) findbin = null; + + } else if (this.options.Error || this.options.Mark || this.options.Line) { + + show_rect = true; + + var msize = 3; + if (this.markeratt) msize = Math.max(msize, this.markeratt.GetFullSize()); + + if (this.options.Error) { + var cont = histo.getBinContent(findbin+1), + binerr = histo.getBinError(findbin+1); + + gry1 = Math.round(pmain.gry(cont + binerr)); // up + gry2 = Math.round(pmain.gry(cont - binerr)); // down + + if ((cont==0) && this.IsTProfile()) findbin = null; + + var dx = (grx2-grx1)*this.options.errorX; + grx1 = Math.round(midx - dx); + grx2 = Math.round(midx + dx); + } + + // show at least 6 pixels as tooltip rect + if (grx2 - grx1 < 2*msize) { grx1 = midx-msize; grx2 = midx+msize; } + + gry1 = Math.min(gry1, midy - msize); + gry2 = Math.max(gry2, midy + msize); + + if (!pnt.touch && (pnt.nproc === 1)) + if ((pnt_y<gry1) || (pnt_y>gry2)) findbin = null; + + } else { + + // if histogram alone, use old-style with rects + // if there are too many points at pixel, use circle + show_rect = (pnt.nproc === 1) && (right-left < width); + + if (show_rect) { + gry2 = height; + + if (!this.fillatt.empty()) { + gry2 = Math.round(pmain.gry(0)); + if (gry2 < 0) gry2 = 0; else if (gry2 > height) gry2 = height; + if (gry2 < gry1) { var d = gry1; gry1 = gry2; gry2 = d; } + } + + // for mouse events pointer should be between y1 and y2 + if (((pnt.y < gry1) || (pnt.y > gry2)) && !pnt.touch) findbin = null; + } + } + + if (findbin!==null) { + // if bin on boundary found, check that x position is ok + if ((findbin === left) && (grx1 > pnt_x + gapx)) findbin = null; else + if ((findbin === right-1) && (grx2 < pnt_x - gapx)) findbin = null; else + // if bars option used check that bar is not match + if ((pnt_x < grx1 - gapx) || (pnt_x > grx2 + gapx)) findbin = null; else + // exclude empty bin if empty bins suppressed + if (!this.options.Zero && (histo.getBinContent(findbin+1)===0)) findbin = null; + } + + var ttrect = this.draw_g.select(".tooltip_bin"); + + if ((findbin === null) || ((gry2 <= 0) || (gry1 >= height))) { + ttrect.remove(); + return null; + } + + var res = { name: "histo", title: histo.fTitle, + x: midx, y: midy, exact: true, + color1: this.lineatt ? this.lineatt.color : 'green', + color2: this.fillatt ? this.fillatt.fillcoloralt('blue') : 'blue', + lines: this.GetBinTips(findbin) }; + + if (pnt.disabled) { + // case when tooltip should not highlight bin + + ttrect.remove(); + res.changed = true; + } else if (show_rect) { + + if (ttrect.empty()) + ttrect = this.draw_g.append("svg:rect") + .attr("class","tooltip_bin h1bin") + .style("pointer-events","none"); + + res.changed = ttrect.property("current_bin") !== findbin; + + if (res.changed) + ttrect.attr("x", pmain.swap_xy ? gry1 : grx1) + .attr("width", pmain.swap_xy ? gry2-gry1 : grx2-grx1) + .attr("y", pmain.swap_xy ? grx1 : gry1) + .attr("height", pmain.swap_xy ? grx2-grx1 : gry2-gry1) + .style("opacity", "0.3") + .property("current_bin", findbin); + + res.exact = (Math.abs(midy - pnt_y) <= 5) || ((pnt_y>=gry1) && (pnt_y<=gry2)); + + res.menu = true; // one could show context menu + // distance to middle point, use to decide which menu to activate + res.menu_dist = Math.sqrt((midx-pnt_x)*(midx-pnt_x) + (midy-pnt_y)*(midy-pnt_y)); + + } else { + var radius = this.lineatt.width + 3; + + if (ttrect.empty()) + ttrect = this.draw_g.append("svg:circle") + .attr("class","tooltip_bin") + .style("pointer-events","none") + .attr("r", radius) + .call(this.lineatt.func) + .call(this.fillatt.func); + + res.exact = (Math.abs(midx - pnt.x) <= radius) && (Math.abs(midy - pnt.y) <= radius); + + res.menu = res.exact; // show menu only when mouse pointer exactly over the histogram + res.menu_dist = Math.sqrt((midx-pnt.x)*(midx-pnt.x) + (midy-pnt.y)*(midy-pnt.y)); + + res.changed = ttrect.property("current_bin") !== findbin; + + if (res.changed) + ttrect.attr("cx", midx) + .attr("cy", midy) + .property("current_bin", findbin); + } + + if (res.changed) + res.user_info = { obj: histo, name: "histo", + bin: findbin, cont: histo.getBinContent(findbin+1), + grx: midx, gry: midy }; + + return res; + } + + + TH1Painter.prototype.FillHistContextMenu = function(menu) { + + menu.add("Auto zoom-in", this.AutoZoom); + + var sett = JSROOT.getDrawSettings("ROOT." + this.GetObject()._typename, 'nosame'); + + menu.addDrawMenu("Draw with", sett.opts, function(arg) { + if (arg==='inspect') + return JSROOT.draw(this.divid, this.GetObject(), arg); + + this.DecodeOptions(arg); // obsolete, should be implemented differently + + if (this.options.need_fillcol && this.fillatt && this.fillatt.empty()) + this.fillatt.Change(5,1001); + + // redraw all objects + this.InteractiveRedraw("pad", "drawopt"); + }); + } + + TH1Painter.prototype.AutoZoom = function() { + var left = this.GetSelectIndex("x", "left", -1), + right = this.GetSelectIndex("x", "right", 1), + dist = right - left, histo = this.GetHisto(), xaxis = this.GetAxis("x"); + + if (dist == 0) return; + + // first find minimum + var min = histo.getBinContent(left + 1); + for (var indx = left; indx < right; ++indx) + min = Math.min(min, histo.getBinContent(indx+1)); + if (min > 0) return; // if all points positive, no chance for autoscale + + while ((left < right) && (histo.getBinContent(left+1) <= min)) ++left; + while ((left < right) && (histo.getBinContent(right) <= min)) --right; + + // if singular bin + if ((left === right-1) && (left > 2) && (right < this.nbinsx-2)) { + --left; ++right; + } + + if ((right - left < dist) && (left < right)) + this.frame_painter().Zoom(xaxis.GetBinCoord(left), xaxis.GetBinCoord(right)); + } + + TH1Painter.prototype.CanZoomIn = function(axis,min,max) { + var xaxis = this.GetAxis("x"); + + if ((axis=="x") && (xaxis.FindBin(max,0.5) - xaxis.FindBin(min,0) > 1)) return true; + + if ((axis=="y") && (Math.abs(max-min) > Math.abs(this.ymax-this.ymin)*1e-6)) return true; + + // check if it makes sense to zoom inside specified axis range + return false; + } + + TH1Painter.prototype.CallDrawFunc = function(callback, resize) { + + var main = this.frame_painter(); + + if (main && (main.mode3d !== this.options.Mode3D)) { + // that to do with that case + this.options.Mode3D = main.mode3d; + } + + var funcname = this.options.Mode3D ? "Draw3D" : "Draw2D"; + + this[funcname](callback, resize); + } + + TH1Painter.prototype.Draw2D = function(call_back) { + + this.Clear3DScene(); + this.mode3d = false; + + // this.ScanContent(true); + + if (typeof this.DrawColorPalette === 'function') + this.DrawColorPalette(false); + + if (this.DrawAxes()) + this.DrawBins(); + else + console.log('FAIL DARWING AXES'); + + // this.DrawTitle(); + // this.UpdateStatWebCanvas(); + this.AddInteractive(); + JSROOT.CallBack(call_back); + } + + TH1Painter.prototype.Draw3D = function(call_back, resize) { + this.mode3d = true; + JSROOT.AssertPrerequisites('hist3d', function() { + this.Draw3D(call_back, resize); + }.bind(this)); + } + + TH1Painter.prototype.Redraw = function(resize) { + this.CallDrawFunc(null, resize); + } + + function drawHist1(divid, histo, opt) { + // create painter and add it to canvas + var painter = new TH1Painter(histo); + + painter.PrepareFrame(divid); + + painter.options = { Hist: true, Bar: false, Error: false, ErrorKind: -1, errorX: 0, Zero: false, Mark: false, + Line: false, Fill: false, Lego: 0, Surf: 0, + Text: false, TextAngle: 0, TextKind: "", AutoColor: 0, + fBarOffset: 0, fBarWidth: 1000, fMarkerSize: 1, BaseLine: false, Mode3D: false }; + + // here we deciding how histogram will look like and how will be shown + // painter.DecodeOptions(opt); + + painter.ScanContent(); + + // painter.CreateStat(); // only when required + + painter.CallDrawFunc(function() { + // if (!painter.options.Mode3D && painter.options.AutoZoom) painter.AutoZoom(); + // painter.FillToolbar(); + painter.DrawingReady(); + }); + + return painter; + } + + // ==================== painter for TH2 histograms ============================== + + function TH2Painter(histo) { + THistPainter.call(this, histo); + this.fContour = null; // contour levels + this.fCustomContour = false; // are this user-defined levels (can be irregular) + this.fPalette = null; + this.wheel_zoomy = true; + } + + TH2Painter.prototype = Object.create(THistPainter.prototype); + + TH2Painter.prototype.Cleanup = function() { + delete this.fCustomContour; + delete this.tt_handle; + + THistPainter.prototype.Cleanup.call(this); + } + + TH2Painter.prototype.Dimension = function() { + return 2; + } + + TH2Painter.prototype.ToggleProjection = function(kind, width) { + + if (kind=="Projections") kind = ""; + + if ((typeof kind == 'string') && (kind.length>1)) { + width = parseInt(kind.substr(1)); + kind = kind[0]; + } + + if (!width) width = 1; + + if (kind && (this.is_projection==kind)) { + if (this.projection_width === width) { + kind = ""; + } else { + this.projection_width = width; + return; + } + } + + delete this.proj_hist; + + this.is_projection = (this.is_projection === kind) ? "" : kind; + this.projection_width = width; + + var canp = this.canv_painter(); + if (canp) canp.ToggleProjection(this.is_projection, this.RedrawProjection.bind(this)); + } + + TH2Painter.prototype.RedrawProjection = function(ii1, ii2, jj1, jj2) { + // do nothing for the moment + + } + + TH2Painter.prototype.ExecuteMenuCommand = function(method, args) { + if (THistPainter.prototype.ExecuteMenuCommand.call(this,method, args)) return true; + + if ((method.fName == 'SetShowProjectionX') || (method.fName == 'SetShowProjectionY')) { + this.ToggleProjection(method.fName[17], args && parseInt(args) ? parseInt(args) : 1); + return true; + } + + return false; + } + + TH2Painter.prototype.FillHistContextMenu = function(menu) { + // painter automatically bind to menu callbacks + + menu.add("sub:Projections", this.ToggleProjection); + var kind = this.is_projection || ""; + if (kind) kind += this.projection_width; + var kinds = ["X1", "X2", "X3", "X5", "X10", "Y1", "Y2", "Y3", "Y5", "Y10"]; + for (var k=0;k<kinds.length;++k) + menu.addchk(kind==kinds[k], kinds[k], kinds[k], this.ToggleProjection); + menu.add("endsub:"); + + menu.add("Auto zoom-in", this.AutoZoom); + + var sett = JSROOT.getDrawSettings("ROOT." + this.GetObject()._typename, 'nosame'); + + menu.addDrawMenu("Draw with", sett.opts, function(arg) { + if (arg==='inspect') + return JSROOT.draw(this.divid, this.GetObject(), arg); + this.DecodeOptions(arg); + this.InteractiveRedraw("pad", "drawopt"); + }); + + if (this.options.Color) + this.FillPaletteMenu(menu); + } + + TH2Painter.prototype.ButtonClick = function(funcname) { + if (THistPainter.prototype.ButtonClick.call(this, funcname)) return true; + + switch(funcname) { + case "ToggleColor": this.ToggleColor(); break; + case "ToggleColorZ": this.ToggleColz(); break; + case "Toggle3D": this.ToggleMode3D(); break; + default: return false; + } + + // all methods here should not be processed further + return true; + } + + TH2Painter.prototype.FillToolbar = function() { + THistPainter.prototype.FillToolbar.call(this, true); + + var pp = this.pad_painter(); + if (!pp) return; + + if (!this.IsTH2Poly()) + pp.AddButton(JSROOT.ToolbarIcons.th2color, "Toggle color", "ToggleColor"); + pp.AddButton(JSROOT.ToolbarIcons.th2colorz, "Toggle color palette", "ToggleColorZ"); + pp.AddButton(JSROOT.ToolbarIcons.th2draw3d, "Toggle 3D mode", "Toggle3D"); + pp.ShowButtons(); + } + + TH2Painter.prototype.ToggleColor = function() { + + if (this.options.Mode3D) { + this.options.Mode3D = false; + this.options.Color = true; + } else { + this.options.Color = !this.options.Color; + } + + this._can_move_colz = true; // indicate that next redraw can move Z scale + + this.Redraw(); + + // this.DrawColorPalette(this.options.Color && this.options.Zscale); + } + + TH2Painter.prototype.AutoZoom = function() { + if (this.IsTH2Poly()) return; // not implemented + + var i1 = this.GetSelectIndex("x", "left", -1), + i2 = this.GetSelectIndex("x", "right", 1), + j1 = this.GetSelectIndex("y", "left", -1), + j2 = this.GetSelectIndex("y", "right", 1), + i,j, histo = this.GetHisto(), xaxis = this.GetAxis("x"), yaxis = this.GetAxis("y"); + + if ((i1 == i2) || (j1 == j2)) return; + + // first find minimum + var min = histo.getBinContent(i1 + 1, j1 + 1); + for (i = i1; i < i2; ++i) + for (j = j1; j < j2; ++j) + min = Math.min(min, histo.getBinContent(i+1, j+1)); + if (min > 0) return; // if all points positive, no chance for autoscale + + var ileft = i2, iright = i1, jleft = j2, jright = j1; + + for (i = i1; i < i2; ++i) + for (j = j1; j < j2; ++j) + if (histo.getBinContent(i + 1, j + 1) > min) { + if (i < ileft) ileft = i; + if (i >= iright) iright = i + 1; + if (j < jleft) jleft = j; + if (j >= jright) jright = j + 1; + } + + var xmin, xmax, ymin, ymax, isany = false; + + if ((ileft === iright-1) && (ileft > i1+1) && (iright < i2-1)) { ileft--; iright++; } + if ((jleft === jright-1) && (jleft > j1+1) && (jright < j2-1)) { jleft--; jright++; } + + if ((ileft > i1 || iright < i2) && (ileft < iright - 1)) { + xmin = xaxis.GetBinCoord(ileft); + xmax = xaxis.GetBinCoord(iright); + isany = true; + } + + if ((jleft > j1 || jright < j2) && (jleft < jright - 1)) { + ymin = yaxis.GetBinCoord(jleft); + ymax = yaxis.GetBinCoord(jright); + isany = true; + } + + if (isany) this.frame_painter().Zoom(xmin, xmax, ymin, ymax); + } + + TH2Painter.prototype.ScanContent = function(when_axis_changed) { + + // no need to rescan histogram while result does not depend from axis selection + if (when_axis_changed && this.nbinsx && this.nbinsy) return; + + var i, j, histo = this.GetHisto(); + + this.nbinsx = this.GetAxis("x").fNBins - 2; + this.nbinsy = this.GetAxis("y").fNBins - 2; + + // used in CreateXY method + + this.CreateAxisFuncs(true); + + if (this.IsTH2Poly()) { + this.gminposbin = null; + this.gminbin = this.gmaxbin = 0; + + for (var n=0, len=histo.fBins.arr.length; n<len; ++n) { + var bin_content = histo.fBins.arr[n].fContent; + if (n===0) this.gminbin = this.gmaxbin = bin_content; + + if (bin_content < this.gminbin) this.gminbin = bin_content; else + if (bin_content > this.gmaxbin) this.gmaxbin = bin_content; + + if (bin_content > 0) + if ((this.gminposbin===null) || (this.gminposbin > bin_content)) this.gminposbin = bin_content; + } + } else { + // global min/max, used at the moment in 3D drawing + this.gminbin = this.gmaxbin = histo.getBinContent(1, 1); + this.gminposbin = null; + for (i = 0; i < this.nbinsx; ++i) { + for (j = 0; j < this.nbinsy; ++j) { + var bin_content = histo.getBinContent(i+1, j+1); + if (bin_content < this.gminbin) this.gminbin = bin_content; else + if (bin_content > this.gmaxbin) this.gmaxbin = bin_content; + if (bin_content > 0) + if ((this.gminposbin===null) || (this.gminposbin > bin_content)) this.gminposbin = bin_content; + } + } + } + + // this value used for logz scale drawing + if (this.gminposbin === null) this.gminposbin = this.gmaxbin*1e-4; + + if (this.options.Axis > 0) { // Paint histogram axis only + this.draw_content = false; + } else { + this.draw_content = this.gmaxbin > 0; + if (!this.draw_content && this.options.Zero && this.IsTH2Poly()) { + this.draw_content = true; + this.options.Line = 1; + } + } + } + + TH2Painter.prototype.CountStat = function(cond) { + var histo = this.GetObject(), + stat_sum0 = 0, stat_sumx1 = 0, stat_sumy1 = 0, + stat_sumx2 = 0, stat_sumy2 = 0, stat_sumxy = 0, + xside, yside, xx, yy, zz, + fp = this.frame_painter(), + res = { name: "histo", entries: 0, integral: 0, meanx: 0, meany: 0, rmsx: 0, rmsy: 0, matrix: [0,0,0,0,0,0,0,0,0], xmax: 0, ymax:0, wmax: null }; + + if (this.IsTH2Poly()) { + + var len = histo.fBins.arr.length, i, bin, n, gr, ngr, numgraphs, numpoints, + pmain = this.frame_painter(); + + for (i=0;i<len;++i) { + bin = histo.fBins.arr[i]; + + xside = 1; yside = 1; + + if (bin.fXmin > pmain.scale_xmax) xside = 2; else + if (bin.fXmax < pmain.scale_xmin) xside = 0; + if (bin.fYmin > pmain.scale_ymax) yside = 2; else + if (bin.fYmax < pmain.scale_ymin) yside = 0; + + xx = yy = numpoints = 0; + gr = bin.fPoly; numgraphs = 1; + if (gr._typename === 'TMultiGraph') { numgraphs = bin.fPoly.fGraphs.arr.length; gr = null; } + + for (ngr=0;ngr<numgraphs;++ngr) { + if (!gr || (ngr>0)) gr = bin.fPoly.fGraphs.arr[ngr]; + + for (n=0;n<gr.fNpoints;++n) { + ++numpoints; + xx += gr.fX[n]; + yy += gr.fY[n]; + } + } + + if (numpoints > 1) { + xx = xx / numpoints; + yy = yy / numpoints; + } + + zz = bin.fContent; + + res.entries += zz; + + res.matrix[yside * 3 + xside] += zz; + + if ((xside != 1) || (yside != 1)) continue; + + if ((cond!=null) && !cond(xx,yy)) continue; + + if ((res.wmax==null) || (zz>res.wmax)) { res.wmax = zz; res.xmax = xx; res.ymax = yy; } + + stat_sum0 += zz; + stat_sumx1 += xx * zz; + stat_sumy1 += yy * zz; + stat_sumx2 += xx * xx * zz; + stat_sumy2 += yy * yy * zz; + stat_sumxy += xx * yy * zz; + } + } else { + var xleft = this.GetSelectIndex("x", "left"), + xright = this.GetSelectIndex("x", "right"), + yleft = this.GetSelectIndex("y", "left"), + yright = this.GetSelectIndex("y", "right"), + xi, yi, xaxis = this.GetAxis("x"), yaxis = this.GetAxis("y"); + + for (xi = 0; xi <= this.nbinsx + 1; ++xi) { + xside = (xi <= xleft) ? 0 : (xi > xright ? 2 : 1); + xx = xaxis.GetBinCoord(xi - 0.5); + + for (yi = 0; yi <= this.nbinsy + 1; ++yi) { + yside = (yi <= yleft) ? 0 : (yi > yright ? 2 : 1); + yy = yaxis.GetBinCoord(yi - 0.5); + + zz = histo.getBinContent(xi, yi); + + res.entries += zz; + + res.matrix[yside * 3 + xside] += zz; + + if ((xside != 1) || (yside != 1)) continue; + + if ((cond!=null) && !cond(xx,yy)) continue; + + if ((res.wmax==null) || (zz>res.wmax)) { res.wmax = zz; res.xmax = xx; res.ymax = yy; } + + stat_sum0 += zz; + stat_sumx1 += xx * zz; + stat_sumy1 += yy * zz; + stat_sumx2 += xx * xx * zz; + stat_sumy2 += yy * yy * zz; + stat_sumxy += xx * yy * zz; + } + } + } + + if (!fp.IsAxisZoomed("x") && !fp.IsAxisZoomed("y") && (histo.fTsumw > 0)) { + stat_sum0 = histo.fTsumw; + stat_sumx1 = histo.fTsumwx; + stat_sumx2 = histo.fTsumwx2; + stat_sumy1 = histo.fTsumwy; + stat_sumy2 = histo.fTsumwy2; + stat_sumxy = histo.fTsumwxy; + } + + if (stat_sum0 > 0) { + res.meanx = stat_sumx1 / stat_sum0; + res.meany = stat_sumy1 / stat_sum0; + res.rmsx = Math.sqrt(Math.abs(stat_sumx2 / stat_sum0 - res.meanx * res.meanx)); + res.rmsy = Math.sqrt(Math.abs(stat_sumy2 / stat_sum0 - res.meany * res.meany)); + } + + if (res.wmax===null) res.wmax = 0; + res.integral = stat_sum0; + + if (histo.fEntries > 1) res.entries = histo.fEntries; + + return res; + } + + TH2Painter.prototype.FillStatistic = function(stat, dostat, dofit) { + + // no need to refill statistic if histogram is dummy + if (this.IgnoreStatsFill()) return false; + + var data = this.CountStat(), + print_name = Math.floor(dostat % 10), + print_entries = Math.floor(dostat / 10) % 10, + print_mean = Math.floor(dostat / 100) % 10, + print_rms = Math.floor(dostat / 1000) % 10, + print_under = Math.floor(dostat / 10000) % 10, + print_over = Math.floor(dostat / 100000) % 10, + print_integral = Math.floor(dostat / 1000000) % 10, + print_skew = Math.floor(dostat / 10000000) % 10, + print_kurt = Math.floor(dostat / 100000000) % 10; + + stat.ClearPave(); + + if (print_name > 0) + stat.AddText(data.name); + + if (print_entries > 0) + stat.AddText("Entries = " + stat.Format(data.entries,"entries")); + + if (print_mean > 0) { + stat.AddText("Mean x = " + stat.Format(data.meanx)); + stat.AddText("Mean y = " + stat.Format(data.meany)); + } + + if (print_rms > 0) { + stat.AddText("Std Dev x = " + stat.Format(data.rmsx)); + stat.AddText("Std Dev y = " + stat.Format(data.rmsy)); + } + + if (print_integral > 0) + stat.AddText("Integral = " + stat.Format(data.matrix[4],"entries")); + + if (print_skew > 0) { + stat.AddText("Skewness x = <undef>"); + stat.AddText("Skewness y = <undef>"); + } + + if (print_kurt > 0) + stat.AddText("Kurt = <undef>"); + + if ((print_under > 0) || (print_over > 0)) { + var m = data.matrix; + + stat.AddText("" + m[6].toFixed(0) + " | " + m[7].toFixed(0) + " | " + m[7].toFixed(0)); + stat.AddText("" + m[3].toFixed(0) + " | " + m[4].toFixed(0) + " | " + m[5].toFixed(0)); + stat.AddText("" + m[0].toFixed(0) + " | " + m[1].toFixed(0) + " | " + m[2].toFixed(0)); + } + + // if (dofit) stat.FillFunctionStat(this.FindFunction('TF1'), dofit); + + return true; + } + + TH2Painter.prototype.DrawBinsColor = function(w,h) { + var histo = this.GetHisto(), + handle = this.PrepareColorDraw(), + colPaths = [], currx = [], curry = [], + colindx, cmd1, cmd2, i, j, binz; + + // now start build + for (i = handle.i1; i < handle.i2; ++i) { + for (j = handle.j1; j < handle.j2; ++j) { + binz = histo.getBinContent(i + 1, j + 1); + colindx = this.getContourColor(binz, true); + if (binz===0) { + if (!this.options.Zero) continue; + if ((colindx === null) && this._show_empty_bins) colindx = 0; + } + if (colindx === null) continue; + + cmd1 = "M"+handle.grx[i]+","+handle.gry[j+1]; + if (colPaths[colindx] === undefined) { + colPaths[colindx] = cmd1; + } else{ + cmd2 = "m" + (handle.grx[i]-currx[colindx]) + "," + (handle.gry[j+1]-curry[colindx]); + colPaths[colindx] += (cmd2.length < cmd1.length) ? cmd2 : cmd1; + } + + currx[colindx] = handle.grx[i]; + curry[colindx] = handle.gry[j+1]; + + colPaths[colindx] += "v" + (handle.gry[j] - handle.gry[j+1]) + + "h" + (handle.grx[i+1] - handle.grx[i]) + + "v" + (handle.gry[j+1] - handle.gry[j]) + "z"; + } + } + + for (colindx=0;colindx<colPaths.length;++colindx) + if (colPaths[colindx] !== undefined) + this.draw_g + .append("svg:path") + .attr("palette-index", colindx) + .attr("fill", this.fPalette.getColor(colindx)) + .attr("d", colPaths[colindx]); + + return handle; + } + + TH2Painter.prototype.BuildContour = function(handle, levels, palette, contour_func) { + var histo = this.GetHisto(), ddd = 0, + painter = this, + kMAXCONTOUR = 2004, + kMAXCOUNT = 2000, + // arguments used in the PaintContourLine + xarr = new Float32Array(2*kMAXCONTOUR), + yarr = new Float32Array(2*kMAXCONTOUR), + itarr = new Int32Array(2*kMAXCONTOUR), + lj = 0, ipoly, poly, polys = [], np, npmax = 0, + x = [0.,0.,0.,0.], y = [0.,0.,0.,0.], zc = [0.,0.,0.,0.], ir = [0,0,0,0], + i, j, k, n, m, ix, ljfill, count, + xsave, ysave, itars, ix, jx; + + function BinarySearch(zc) { + for (var kk=0;kk<levels.length;++kk) + if (zc<levels[kk]) return kk-1; + return levels.length-1; + } + + function PaintContourLine(elev1, icont1, x1, y1, elev2, icont2, x2, y2) { + /* Double_t *xarr, Double_t *yarr, Int_t *itarr, Double_t *levels */ + var vert = (x1 === x2), + tlen = vert ? (y2 - y1) : (x2 - x1), + n = icont1 +1, + tdif = elev2 - elev1, + ii = lj-1, + maxii = kMAXCONTOUR/2 -3 + lj, + icount = 0, + xlen, pdif, diff, elev; + + while (n <= icont2 && ii <= maxii) { +// elev = fH->GetContourLevel(n); + elev = levels[n]; + diff = elev - elev1; + pdif = diff/tdif; + xlen = tlen*pdif; + if (vert) { + xarr[ii] = x1; + yarr[ii] = y1 + xlen; + } else { + xarr[ii] = x1 + xlen; + yarr[ii] = y1; + } + itarr[ii] = n; + icount++; + ii +=2; + n++; + } + return icount; + } + + var arrx = handle.original ? handle.origx : handle.grx, + arry = handle.original ? handle.origy : handle.gry; + + for (j = handle.j1; j < handle.j2-1; ++j) { + + y[1] = y[0] = (arry[j] + arry[j+1])/2; + y[3] = y[2] = (arry[j+1] + arry[j+2])/2; + + for (i = handle.i1; i < handle.i2-1; ++i) { + + zc[0] = histo.getBinContent(i+1, j+1); + zc[1] = histo.getBinContent(i+2, j+1); + zc[2] = histo.getBinContent(i+2, j+2); + zc[3] = histo.getBinContent(i+1, j+2); + + for (k=0;k<4;k++) + ir[k] = BinarySearch(zc[k]); + + if ((ir[0] !== ir[1]) || (ir[1] !== ir[2]) || (ir[2] !== ir[3]) || (ir[3] !== ir[0])) { + x[3] = x[0] = (arrx[i] + arrx[i+1])/2; + x[2] = x[1] = (arrx[i+1] + arrx[i+2])/2; + + if (zc[0] <= zc[1]) n = 0; else n = 1; + if (zc[2] <= zc[3]) m = 2; else m = 3; + if (zc[n] > zc[m]) n = m; + n++; + lj=1; + for (ix=1;ix<=4;ix++) { + m = n%4 + 1; + ljfill = PaintContourLine(zc[n-1],ir[n-1],x[n-1],y[n-1], + zc[m-1],ir[m-1],x[m-1],y[m-1]); + lj += 2*ljfill; + n = m; + } + + if (zc[0] <= zc[1]) n = 0; else n = 1; + if (zc[2] <= zc[3]) m = 2; else m = 3; + if (zc[n] > zc[m]) n = m; + n++; + lj=2; + for (ix=1;ix<=4;ix++) { + if (n == 1) m = 4; + else m = n-1; + ljfill = PaintContourLine(zc[n-1],ir[n-1],x[n-1],y[n-1], + zc[m-1],ir[m-1],x[m-1],y[m-1]); + lj += 2*ljfill; + n = m; + } + // Re-order endpoints + + count = 0; + for (ix=1; ix<=lj-5; ix +=2) { + //count = 0; + while (itarr[ix-1] != itarr[ix]) { + xsave = xarr[ix]; + ysave = yarr[ix]; + itars = itarr[ix]; + for (jx=ix; jx<=lj-5; jx +=2) { + xarr[jx] = xarr[jx+2]; + yarr[jx] = yarr[jx+2]; + itarr[jx] = itarr[jx+2]; + } + xarr[lj-3] = xsave; + yarr[lj-3] = ysave; + itarr[lj-3] = itars; + if (count > kMAXCOUNT) break; + count++; + } + } + + if (count > kMAXCOUNT) continue; + + for (ix=1; ix<=lj-2; ix +=2) { + + ipoly = itarr[ix-1]; + + if ((ipoly >= 0) && (ipoly < levels.length)) { + poly = polys[ipoly]; + if (!poly) + poly = polys[ipoly] = JSROOT.CreateTPolyLine(kMAXCONTOUR*4, true); + + np = poly.fLastPoint; + if (np < poly.fN-2) { + poly.fX[np+1] = Math.round(xarr[ix-1]); poly.fY[np+1] = Math.round(yarr[ix-1]); + poly.fX[np+2] = Math.round(xarr[ix]); poly.fY[np+2] = Math.round(yarr[ix]); + poly.fLastPoint = np+2; + npmax = Math.max(npmax, poly.fLastPoint+1); + } else { + // console.log('reject point??', poly.fLastPoint); + } + } + } + } // end of if (ir[0] + } // end of j + } // end of i + + var polysort = new Int32Array(levels.length), first = 0; + //find first positive contour + for (ipoly=0;ipoly<levels.length;ipoly++) { + if (levels[ipoly] >= 0) { first = ipoly; break; } + } + //store negative contours from 0 to minimum, then all positive contours + k = 0; + for (ipoly=first-1;ipoly>=0;ipoly--) {polysort[k] = ipoly; k++;} + for (ipoly=first;ipoly<levels.length;ipoly++) { polysort[k] = ipoly; k++;} + + var xp = new Float32Array(2*npmax), + yp = new Float32Array(2*npmax); + + for (k=0;k<levels.length;++k) { + + ipoly = polysort[k]; + poly = polys[ipoly]; + if (!poly) continue; + + var colindx = palette.calcColorIndex(ipoly, levels.length), + xx = poly.fX, yy = poly.fY, np = poly.fLastPoint+1, + istart = 0, iminus, iplus, xmin = 0, ymin = 0, nadd; + + while (true) { + + iminus = npmax; + iplus = iminus+1; + xp[iminus]= xx[istart]; yp[iminus] = yy[istart]; + xp[iplus] = xx[istart+1]; yp[iplus] = yy[istart+1]; + xx[istart] = xx[istart+1] = xmin; + yy[istart] = yy[istart+1] = ymin; + while (true) { + nadd = 0; + for (i=2;i<np;i+=2) { + if ((iplus < 2*npmax-1) && (xx[i] === xp[iplus]) && (yy[i] === yp[iplus])) { + iplus++; + xp[iplus] = xx[i+1]; yp[iplus] = yy[i+1]; + xx[i] = xx[i+1] = xmin; + yy[i] = yy[i+1] = ymin; + nadd++; + } + if ((iminus > 0) && (xx[i+1] === xp[iminus]) && (yy[i+1] === yp[iminus])) { + iminus--; + xp[iminus] = xx[i]; yp[iminus] = yy[i]; + xx[i] = xx[i+1] = xmin; + yy[i] = yy[i+1] = ymin; + nadd++; + } + } + if (nadd == 0) break; + } + + if ((iminus+1 < iplus) && (iminus>=0)) + contour_func(colindx, xp, yp, iminus, iplus, ipoly); + + istart = 0; + for (i=2;i<np;i+=2) { + if (xx[i] !== xmin && yy[i] !== ymin) { + istart = i; + break; + } + } + + if (istart === 0) break; + } + } + } + + TH2Painter.prototype.DrawBinsContour = function(frame_w,frame_h) { + var handle = this.PrepareColorDraw({ rounding: false, extra: 100, original: this.options.Proj != 0 }), + levels = this.GetContour(), + palette = this.GetPalette(), + painter = this, main = this.frame_painter(); + + function BuildPath(xp,yp,iminus,iplus) { + var cmd = "", last = null, pnt = null, i; + for (i=iminus;i<=iplus;++i) { + pnt = null; + switch (painter.options.Proj) { + case 1: pnt = main.ProjectAitoff2xy(xp[i], yp[i]); break; + case 2: pnt = main.ProjectMercator2xy(xp[i], yp[i]); break; + case 3: pnt = main.ProjectSinusoidal2xy(xp[i], yp[i]); break; + case 4: pnt = main.ProjectParabolic2xy(xp[i], yp[i]); break; + } + if (pnt) { + pnt.x = main.grx(pnt.x); + pnt.y = main.gry(pnt.y); + } else { + pnt = { x: xp[i], y: yp[i] }; + } + pnt.x = Math.round(pnt.x); + pnt.y = Math.round(pnt.y); + if (!cmd) cmd = "M" + pnt.x + "," + pnt.y; + else if ((pnt.x != last.x) && (pnt.y != last.y)) cmd += "l" + (pnt.x - last.x) + "," + (pnt.y - last.y); + else if (pnt.x != last.x) cmd += "h" + (pnt.x - last.x); + else if (pnt.y != last.y) cmd += "v" + (pnt.y - last.y); + last = pnt; + } + return cmd; + } + + if (this.options.Contour===14) { + var dd = "M0,0h"+frame_w+"v"+frame_h+"h-"+frame_w; + if (this.options.Proj) { + var sz = handle.j2 - handle.j1, xd = new Float32Array(sz*2), yd = new Float32Array(sz*2); + for (var i=0;i<sz;++i) { + xd[i] = handle.origx[handle.i1]; + yd[i] = (handle.origy[handle.j1]*(i+0.5) + handle.origy[handle.j2]*(sz-0.5-i))/sz; + xd[i+sz] = handle.origx[handle.i2]; + yd[i+sz] = (handle.origy[handle.j2]*(i+0.5) + handle.origy[handle.j1]*(sz-0.5-i))/sz; + } + dd = BuildPath(xd,yd,0,2*sz-1); + } + + this.draw_g + .append("svg:path") + .attr("d", dd + "z") + .style('stroke','none') + .style("fill", palette.calcColor(0, levels.length)); + } + + this.BuildContour(handle, levels, palette, + function(colindx,xp,yp,iminus,iplus) { + var icol = palette.getColor(colindx), + fillcolor = icol, lineatt = null; + + switch (painter.options.Contour) { + case 1: break; + case 11: fillcolor = 'none'; lineatt = new JSROOT.TAttLineHandler({ color: icol }); break; + case 12: fillcolor = 'none'; lineatt = new JSROOT.TAttLineHandler({ color:1, style: (colindx%5 + 1), width: 1 }); break; + case 13: fillcolor = 'none'; lineatt = painter.lineatt; break; + case 14: break; + } + + var elem = painter.draw_g + .append("svg:path") + .attr("class","th2_contour") + .attr("d", BuildPath(xp,yp,iminus,iplus) + (fillcolor == 'none' ? "" : "z")) + .style("fill", fillcolor); + + if (lineatt!==null) + elem.call(lineatt.func); + else + elem.style('stroke','none'); + } + ); + + handle.hide_only_zeros = true; // text drawing suppress only zeros + + return handle; + } + + TH2Painter.prototype.CreatePolyBin = function(pmain, bin) { + var cmd = "", ngr, ngraphs = 1, gr = null; + + if (bin.fPoly._typename=='TMultiGraph') + ngraphs = bin.fPoly.fGraphs.arr.length; + else + gr = bin.fPoly; + + for (ngr = 0; ngr < ngraphs; ++ ngr) { + if (!gr || (ngr>0)) gr = bin.fPoly.fGraphs.arr[ngr]; + + var npnts = gr.fNpoints, n, + x = gr.fX, y = gr.fY, + grx = Math.round(pmain.grx(x[0])), + gry = Math.round(pmain.gry(y[0])), + nextx, nexty; + + if ((npnts>2) && (x[0]==x[npnts-1]) && (y[0]==y[npnts-1])) npnts--; + + cmd += "M"+grx+","+gry; + + for (n=1;n<npnts;++n) { + nextx = Math.round(pmain.grx(x[n])); + nexty = Math.round(pmain.gry(y[n])); + if ((grx!==nextx) || (gry!==nexty)) { + if (grx===nextx) cmd += "v" + (nexty - gry); else + if (gry===nexty) cmd += "h" + (nextx - grx); else + cmd += "l" + (nextx - grx) + "," + (nexty - gry); + } + grx = nextx; gry = nexty; + } + + cmd += "z"; + } + + return cmd; + } + + TH2Painter.prototype.DrawPolyBinsColor = function(w,h) { + var histo = this.GetHisto(), + pmain = this.frame_painter(), + colPaths = [], textbins = [], + colindx, cmd, bin, item, + i, len = histo.fBins.arr.length; + + // force recalculations of contours + this.fContour = null; + this.fCustomContour = false; + + // use global coordinates + this.maxbin = this.gmaxbin; + this.minbin = this.gminbin; + this.minposbin = this.gminposbin; + + for (i = 0; i < len; ++ i) { + bin = histo.fBins.arr[i]; + colindx = this.getContourColor(bin.fContent, true); + if (colindx === null) continue; + if (bin.fContent === 0) { + if (!this.options.Zero || !this.options.Line) continue; + colindx = 0; + } + + // check if bin outside visible range + if ((bin.fXmin > pmain.scale_xmax) || (bin.fXmax < pmain.scale_xmin) || + (bin.fYmin > pmain.scale_ymax) || (bin.fYmax < pmain.scale_ymin)) continue; + + cmd = this.CreatePolyBin(pmain, bin); + + if (colPaths[colindx] === undefined) + colPaths[colindx] = cmd; + else + colPaths[colindx] += cmd; + + if (this.options.Text) textbins.push(bin); + } + + for (colindx=0;colindx<colPaths.length;++colindx) + if (colPaths[colindx]) { + item = this.draw_g + .append("svg:path") + .attr("palette-index", colindx) + .attr("fill", colindx ? this.fPalette.getColor(colindx) : "none") + .attr("d", colPaths[colindx]); + if (this.options.Line) + item.call(this.lineatt.func); + } + + if (textbins.length > 0) { + var text_col = this.get_color(histo.fMarkerColor), + text_angle = -1*this.options.TextAngle, + text_g = this.draw_g.append("svg:g").attr("class","th2poly_text"), + text_size = 12; + + if ((histo.fMarkerSize!==1) && text_angle) + text_size = Math.round(0.02*h*histo.fMarkerSize); + + this.StartTextDrawing(42, text_size, text_g, text_size); + + for (i = 0; i < textbins.length; ++ i) { + bin = textbins[i]; + + var posx = Math.round(pmain.x((bin.fXmin + bin.fXmax)/2)), + posy = Math.round(pmain.y((bin.fYmin + bin.fYmax)/2)), + lbl = ""; + + if (!this.options.TextKind) { + lbl = (Math.round(bin.fContent) === bin.fContent) ? bin.fContent.toString() : + JSROOT.FFormat(bin.fContent, JSROOT.gStyle.fPaintTextFormat); + } else { + if (bin.fPoly) lbl = bin.fPoly.fName; + if (lbl === "Graph") lbl = ""; + if (!lbl) lbl = bin.fNumber; + } + + this.DrawText({ align: 22, x: posx, y: posy, rotate: text_angle, text: lbl, color: text_col, latex: 0, draw_g: text_g }); + } + + this.FinishTextDrawing(text_g, null); + } + + return { poly: true }; + } + + TH2Painter.prototype.DrawBinsText = function(w, h, handle) { + var histo = this.GetHisto(), + i,j,binz,colindx,binw,binh,lbl,posx,posy,sizex,sizey; + + if (handle===null) handle = this.PrepareColorDraw({ rounding: false }); + + var text_col = this.get_color(histo.fMarkerColor), + text_angle = -1*this.options.TextAngle, + text_g = this.draw_g.append("svg:g").attr("class","th2_text"), + text_size = 20, text_offset = 0, + profile2d = (this.options.TextKind == "E") && + this.MatchObjectType('TProfile2D') && (typeof histo.getBinEntries=='function'); + + if ((histo.fMarkerSize!==1) && text_angle) + text_size = Math.round(0.02*h*histo.fMarkerSize); + + if (this.options.fBarOffset!==0) text_offset = this.options.fBarOffset*1e-3; + + this.StartTextDrawing(42, text_size, text_g, text_size); + + for (i = handle.i1; i < handle.i2; ++i) + for (j = handle.j1; j < handle.j2; ++j) { + binz = histo.getBinContent(i+1, j+1); + if ((binz === 0) && !this._show_empty_bins) continue; + + binw = handle.grx[i+1] - handle.grx[i]; + binh = handle.gry[j] - handle.gry[j+1]; + + if (profile2d) + binz = histo.getBinEntries(i+1, j+1); + + lbl = (binz === Math.round(binz)) ? binz.toString() : + JSROOT.FFormat(binz, JSROOT.gStyle.fPaintTextFormat); + + if (text_angle /*|| (histo.fMarkerSize!==1)*/) { + posx = Math.round(handle.grx[i] + binw*0.5); + posy = Math.round(handle.gry[j+1] + binh*(0.5 + text_offset)); + sizex = 0; + sizey = 0; + } else { + posx = Math.round(handle.grx[i] + binw*0.1); + posy = Math.round(handle.gry[j+1] + binh*(0.1 + text_offset)); + sizex = Math.round(binw*0.8); + sizey = Math.round(binh*0.8); + } + + this.DrawText({ align: 22, x: posx, y: posy, width: sizex, height: sizey, rotate: text_angle, text: lbl, color: text_col, latex: 0, draw_g: text_g }); + } + + this.FinishTextDrawing(text_g, null); + + handle.hide_only_zeros = true; // text drawing suppress only zeros + + return handle; + } + + TH2Painter.prototype.DrawBinsArrow = function(w, h) { + var histo = this.GetHisto(), cmd = "", + i,j,binz,colindx,binw,binh,lbl, loop, dn = 1e-30, dx, dy, xc,yc, + dxn,dyn,x1,x2,y1,y2, anr,si,co, + handle = this.PrepareColorDraw({ rounding: false }), + scale_x = (handle.grx[handle.i2] - handle.grx[handle.i1])/(handle.i2 - handle.i1 + 1-0.03)/2, + scale_y = (handle.gry[handle.j2] - handle.gry[handle.j1])/(handle.j2 - handle.j1 + 1-0.03)/2; + + for (var loop=0;loop<2;++loop) + for (i = handle.i1; i < handle.i2; ++i) + for (j = handle.j1; j < handle.j2; ++j) { + + if (i === handle.i1) { + dx = histo.getBinContent(i+2, j+1) - histo.getBinContent(i+1, j+1); + } else if (i === handle.i2-1) { + dx = histo.getBinContent(i+1, j+1) - histo.getBinContent(i, j+1); + } else { + dx = 0.5*(histo.getBinContent(i+2, j+1) - histo.getBinContent(i, j+1)); + } + if (j === handle.j1) { + dy = histo.getBinContent(i+1, j+2) - histo.getBinContent(i+1, j+1); + } else if (j === handle.j2-1) { + dy = histo.getBinContent(i+1, j+1) - histo.getBinContent(i+1, j); + } else { + dy = 0.5*(histo.getBinContent(i+1, j+2) - histo.getBinContent(i+1, j)); + } + + if (loop===0) { + dn = Math.max(dn, Math.abs(dx), Math.abs(dy)); + } else { + xc = (handle.grx[i] + handle.grx[i+1])/2; + yc = (handle.gry[j] + handle.gry[j+1])/2; + dxn = scale_x*dx/dn; + dyn = scale_y*dy/dn; + x1 = xc - dxn; + x2 = xc + dxn; + y1 = yc - dyn; + y2 = yc + dyn; + dx = Math.round(x2-x1); + dy = Math.round(y2-y1); + + if ((dx!==0) || (dy!==0)) { + cmd += "M"+Math.round(x1)+","+Math.round(y1)+"l"+dx+","+dy; + + if (Math.abs(dx) > 5 || Math.abs(dy) > 5) { + anr = Math.sqrt(2/(dx*dx + dy*dy)); + si = Math.round(anr*(dx + dy)); + co = Math.round(anr*(dx - dy)); + if ((si!==0) && (co!==0)) + cmd+="l"+(-si)+","+co + "m"+si+","+(-co) + "l"+(-co)+","+(-si); + } + } + } + } + + this.draw_g + .append("svg:path") + .attr("class","th2_arrows") + .attr("d", cmd) + .style("fill", "none") + .call(this.lineatt.func); + + return handle; + } + + + TH2Painter.prototype.DrawBinsBox = function(w,h) { + + var histo = this.GetHisto(), + handle = this.PrepareColorDraw({ rounding: false }), + main = this.frame_painter(); + + if (main.maxbin === main.minbin) { + main.maxbin = this.gmaxbin; + main.minbin = this.gminbin; + main.minposbin = this.gminposbin; + } + if (main.maxbin === main.minbin) + main.minbin = Math.min(0, main.maxbin-1); + + var absmax = Math.max(Math.abs(main.maxbin), Math.abs(main.minbin)), + absmin = Math.max(0, main.minbin), + i, j, binz, absz, res = "", cross = "", btn1 = "", btn2 = "", + colindx, zdiff, dgrx, dgry, xx, yy, ww, hh, cmd1, cmd2, + xyfactor = 1, uselogz = false, logmin = 0, logmax = 1; + + if (this.root_pad().fLogz && (absmax>0)) { + uselogz = true; + logmax = Math.log(absmax); + if (absmin>0) logmin = Math.log(absmin); else + if ((main.minposbin>=1) && (main.minposbin<100)) logmin = Math.log(0.7); else + logmin = (main.minposbin > 0) ? Math.log(0.7*main.minposbin) : logmax - 10; + if (logmin >= logmax) logmin = logmax - 10; + xyfactor = 1. / (logmax - logmin); + } else { + xyfactor = 1. / (absmax - absmin); + } + + // now start build + for (i = handle.i1; i < handle.i2; ++i) { + for (j = handle.j1; j < handle.j2; ++j) { + binz = histo.getBinContent(i + 1, j + 1); + absz = Math.abs(binz); + if ((absz === 0) || (absz < absmin)) continue; + + zdiff = uselogz ? ((absz>0) ? Math.log(absz) - logmin : 0) : (absz - absmin); + // area of the box should be proportional to absolute bin content + zdiff = 0.5 * ((zdiff < 0) ? 1 : (1 - Math.sqrt(zdiff * xyfactor))); + // avoid oversized bins + if (zdiff < 0) zdiff = 0; + + ww = handle.grx[i+1] - handle.grx[i]; + hh = handle.gry[j] - handle.gry[j+1]; + + dgrx = zdiff * ww; + dgry = zdiff * hh; + + xx = Math.round(handle.grx[i] + dgrx); + yy = Math.round(handle.gry[j+1] + dgry); + + ww = Math.max(Math.round(ww - 2*dgrx), 1); + hh = Math.max(Math.round(hh - 2*dgry), 1); + + res += "M"+xx+","+yy + "v"+hh + "h"+ww + "v-"+hh + "z"; + + if ((binz<0) && (this.options.BoxStyle === 10)) + cross += "M"+xx+","+yy + "l"+ww+","+hh + "M"+(xx+ww)+","+yy + "l-"+ww+","+hh; + + if ((this.options.BoxStyle === 11) && (ww>5) && (hh>5)) { + var pww = Math.round(ww*0.1), + phh = Math.round(hh*0.1), + side1 = "M"+xx+","+yy + "h"+ww + "l"+(-pww)+","+phh + "h"+(2*pww-ww) + + "v"+(hh-2*phh)+ "l"+(-pww)+","+phh + "z", + side2 = "M"+(xx+ww)+","+(yy+hh) + "v"+(-hh) + "l"+(-pww)+","+phh + "v"+(hh-2*phh)+ + "h"+(2*pww-ww) + "l"+(-pww)+","+phh + "z"; + if (binz<0) { btn2+=side1; btn1+=side2; } + else { btn1+=side1; btn2+=side2; } + } + } + } + + if (res.length > 0) { + var elem = this.draw_g.append("svg:path") + .attr("d", res) + .call(this.fillatt.func); + if ((this.options.BoxStyle === 11) || !this.fillatt.empty()) + elem.style('stroke','none'); + else + elem.call(this.lineatt.func); + } + + if ((btn1.length>0) && (this.fillatt.color !== 'none')) + this.draw_g.append("svg:path") + .attr("d", btn1) + .style("stroke","none") + .call(this.fillatt.func) + .style("fill", d3.rgb(this.fillatt.color).brighter(0.5).toString()); + + if (btn2.length>0) + this.draw_g.append("svg:path") + .attr("d", btn2) + .style("stroke","none") + .call(this.fillatt.func) + .style("fill", this.fillatt.color === 'none' ? 'red' : d3.rgb(this.fillatt.color).darker(0.5).toString()); + + if (cross.length > 0) { + var elem = this.draw_g.append("svg:path") + .attr("d", cross) + .style("fill", "none"); + if (this.lineatt.color !== 'none') + elem.call(this.lineatt.func); + else + elem.style('stroke','black'); + } + + return handle; + } + + TH2Painter.prototype.DrawCandle = function(w,h) { + var histo = this.GetHisto(), yaxis = this.GetAxis("y"), + handle = this.PrepareColorDraw(), + pmain = this.frame_painter(), // used for axis values conversions + i, j, y, sum0, sum1, sum2, cont, center, counter, integral, w, pnt, + bars = "", markers = "", posy; + + // create attribute only when necessary + if (histo.fMarkerColor === 1) histo.fMarkerColor = histo.fLineColor; + this.createAttMarker({ attr: histo, style: 5 }); + + // reset absolution position for markers + this.markeratt.reset_pos(); + + handle.candle = []; // array of drawn points + + // loop over visible x-bins + for (i = handle.i1; i < handle.i2; ++i) { + sum1 = 0; + //estimate integral + integral = 0; + counter = 0; + for (j = 0; j < this.nbinsy; ++j) { + integral += histo.getBinContent(i+1,j+1); + } + pnt = { bin:i, meany:0, m25y:0, p25y:0, median:0, iqr:0, whiskerp:0, whiskerm:0}; + //estimate quantiles... simple function... not so nice as GetQuantiles + for (j = 0; j < this.nbinsy; ++j) { + cont = histo.getBinContent(i+1,j+1); + posy = yaxis.GetBinCoord(j + 0.5); + if (counter/integral < 0.001 && (counter + cont)/integral >=0.001) pnt.whiskerm = posy; // Lower whisker + if (counter/integral < 0.25 && (counter + cont)/integral >=0.25) pnt.m25y = posy; // Lower edge of box + if (counter/integral < 0.5 && (counter + cont)/integral >=0.5) pnt.median = posy; //Median + if (counter/integral < 0.75 && (counter + cont)/integral >=0.75) pnt.p25y = posy; //Upper edge of box + if (counter/integral < 0.999 && (counter + cont)/integral >=0.999) pnt.whiskerp = posy; // Upper whisker + counter += cont; + y = posy; // center of y bin coordinate + sum1 += cont*y; + } + if (counter > 0) { + pnt.meany = sum1/counter; + } + pnt.iqr = pnt.p25y-pnt.m25y; + + //Whiskers cannot exceed 1.5*iqr from box + if ((pnt.m25y-1.5*pnt.iqr) > pnt.whsikerm) { + pnt.whiskerm = pnt.m25y-1.5*pnt.iqr; + } + if ((pnt.p25y+1.5*pnt.iqr) < pnt.whiskerp) { + pnt.whiskerp = pnt.p25y+1.5*pnt.iqr; + } + + // exclude points with negative y when log scale is specified + if (pmain.logy && (pnt.whiskerm<=0)) continue; + + w = handle.grx[i+1] - handle.grx[i]; + w *= 0.66; + center = (handle.grx[i+1] + handle.grx[i]) / 2 + this.options.fBarOffset/1000*w; + if (this.options.fBarWidth >0) w = w * this.options.fBarWidth / 1000; + + pnt.x1 = Math.round(center - w/2); + pnt.x2 = Math.round(center + w/2); + center = Math.round(center); + + pnt.y0 = Math.round(pmain.gry(pnt.median)); + // mean line + bars += "M" + pnt.x1 + "," + pnt.y0 + "h" + (pnt.x2-pnt.x1); + + pnt.y1 = Math.round(pmain.gry(pnt.p25y)); + pnt.y2 = Math.round(pmain.gry(pnt.m25y)); + + // rectangle + bars += "M" + pnt.x1 + "," + pnt.y1 + + "v" + (pnt.y2-pnt.y1) + "h" + (pnt.x2-pnt.x1) + "v-" + (pnt.y2-pnt.y1) + "z"; + + pnt.yy1 = Math.round(pmain.gry(pnt.whiskerp)); + pnt.yy2 = Math.round(pmain.gry(pnt.whiskerm)); + + // upper part + bars += "M" + center + "," + pnt.y1 + "v" + (pnt.yy1-pnt.y1); + bars += "M" + pnt.x1 + "," + pnt.yy1 + "h" + (pnt.x2-pnt.x1); + + // lower part + bars += "M" + center + "," + pnt.y2 + "v" + (pnt.yy2-pnt.y2); + bars += "M" + pnt.x1 + "," + pnt.yy2 + "h" + (pnt.x2-pnt.x1); + + //estimate outliers + for (j = 0; j < this.nbinsy; ++j) { + cont = histo.getBinContent(i+1,j+1); + posy = yaxis.GetBinCoord(j + 0.5); + if (cont > 0 && posy < pnt.whiskerm) markers += this.markeratt.create(center, posy); + if (cont > 0 && posy > pnt.whiskerp) markers += this.markeratt.create(center, posy); } + + handle.candle.push(pnt); // keep point for the tooltip + } + + if (bars.length > 0) + this.draw_g.append("svg:path") + .attr("d", bars) + .call(this.lineatt.func) + .call(this.fillatt.func); + + if (markers.length > 0) + this.draw_g.append("svg:path") + .attr("d", markers) + .call(this.markeratt.func); + + return handle; + } + + TH2Painter.prototype.DrawBinsScatter = function(w,h) { + var histo = this.GetHisto(), + handle = this.PrepareColorDraw({ rounding: true, pixel_density: true }), + colPaths = [], currx = [], curry = [], cell_w = [], cell_h = [], + colindx, cmd1, cmd2, i, j, binz, cw, ch, factor = 1., + scale = this.options.ScatCoef * ((this.gmaxbin) > 2000 ? 2000. / this.gmaxbin : 1.); + + JSROOT.seed(handle.sumz); + + if (scale*handle.sumz < 1e5) { + // one can use direct drawing of scatter plot without any patterns + + this.createAttMarker({ attr: histo }); + + this.markeratt.reset_pos(); + + var path = "", k, npix; + for (i = handle.i1; i < handle.i2; ++i) { + cw = handle.grx[i+1] - handle.grx[i]; + for (j = handle.j1; j < handle.j2; ++j) { + ch = handle.gry[j] - handle.gry[j+1]; + binz = histo.getBinContent(i + 1, j + 1); + + npix = Math.round(scale*binz); + if (npix<=0) continue; + + for (k=0;k<npix;++k) + path += this.markeratt.create( + Math.round(handle.grx[i] + cw * JSROOT.random()), + Math.round(handle.gry[j+1] + ch * JSROOT.random())); + } + } + + this.draw_g + .append("svg:path") + .attr("d", path) + .call(this.markeratt.func); + + return handle; + } + + // limit filling factor, do not try to produce as many points as filled area; + if (this.maxbin > 0.7) factor = 0.7/this.maxbin; + + var nlevels = Math.round(handle.max - handle.min); + this.CreateContour((nlevels > 50) ? 50 : nlevels, this.minposbin, this.maxbin, this.minposbin); + + // now start build + for (i = handle.i1; i < handle.i2; ++i) { + for (j = handle.j1; j < handle.j2; ++j) { + binz = histo.getBinContent(i + 1, j + 1); + if ((binz <= 0) || (binz < this.minbin)) continue; + + cw = handle.grx[i+1] - handle.grx[i]; + ch = handle.gry[j] - handle.gry[j+1]; + if (cw*ch <= 0) continue; + + colindx = this.getContourIndex(binz/cw/ch); + if (colindx < 0) continue; + + cmd1 = "M"+handle.grx[i]+","+handle.gry[j+1]; + if (colPaths[colindx] === undefined) { + colPaths[colindx] = cmd1; + cell_w[colindx] = cw; + cell_h[colindx] = ch; + } else{ + cmd2 = "m" + (handle.grx[i]-currx[colindx]) + "," + (handle.gry[j+1] - curry[colindx]); + colPaths[colindx] += (cmd2.length < cmd1.length) ? cmd2 : cmd1; + cell_w[colindx] = Math.max(cell_w[colindx], cw); + cell_h[colindx] = Math.max(cell_h[colindx], ch); + } + + currx[colindx] = handle.grx[i]; + curry[colindx] = handle.gry[j+1]; + + colPaths[colindx] += "v"+ch+"h"+cw+"v-"+ch+"z"; + } + } + + var layer = this.svg_frame().select('.main_layer'), + defs = layer.select("defs"); + if (defs.empty() && (colPaths.length>0)) + defs = layer.insert("svg:defs",":first-child"); + + this.createAttMarker({ attr: histo }); + + for (colindx=0;colindx<colPaths.length;++colindx) + if ((colPaths[colindx] !== undefined) && (colindx<this.fContour.length)) { + var pattern_class = "scatter_" + colindx, + pattern = defs.select('.' + pattern_class); + if (pattern.empty()) + pattern = defs.append('svg:pattern') + .attr("class", pattern_class) + .attr("id", "jsroot_scatter_pattern_" + JSROOT.id_counter++) + .attr("patternUnits","userSpaceOnUse"); + else + pattern.selectAll("*").remove(); + + var npix = Math.round(factor*this.fContour[colindx]*cell_w[colindx]*cell_h[colindx]); + if (npix<1) npix = 1; + + var arrx = new Float32Array(npix), arry = new Float32Array(npix); + + if (npix===1) { + arrx[0] = arry[0] = 0.5; + } else { + for (var n=0;n<npix;++n) { + arrx[n] = JSROOT.random(); + arry[n] = JSROOT.random(); + } + } + + // arrx.sort(); + + this.markeratt.reset_pos(); + + var path = ""; + + for (var n=0;n<npix;++n) + path += this.markeratt.create(arrx[n] * cell_w[colindx], arry[n] * cell_h[colindx]); + + pattern.attr("width", cell_w[colindx]) + .attr("height", cell_h[colindx]) + .append("svg:path") + .attr("d",path) + .call(this.markeratt.func); + + this.draw_g + .append("svg:path") + .attr("scatter-index", colindx) + .attr("fill", 'url(#' + pattern.attr("id") + ')') + .attr("d", colPaths[colindx]); + } + + return handle; + } + + TH2Painter.prototype.DrawBins = function() { + + if (!this.draw_content) + return this.RemoveDrawG(); + + this.CheckHistDrawAttributes(); + + this.CreateG(true); + + var w = this.frame_width(), + h = this.frame_height(), + handle = null; + + // if (this.lineatt.color == 'none') this.lineatt.color = 'cyan'; + + if (this.IsTH2Poly()) + handle = this.DrawPolyBinsColor(w, h); + else if (this.options.Scat) + handle = this.DrawBinsScatter(w, h); + else if (this.options.Color) + handle = this.DrawBinsColor(w, h); + else if (this.options.Box) + handle = this.DrawBinsBox(w, h); + else if (this.options.Arrow) + handle = this.DrawBinsArrow(w, h); + else if (this.options.Contour > 0) + handle = this.DrawBinsContour(w, h); + else if (this.options.Candle) + handle = this.DrawCandle(w, h); + + if (this.options.Text) + handle = this.DrawBinsText(w, h, handle); + + if (!handle) + handle = this.DrawBinsScatter(w, h); + + this.tt_handle = handle; + } + + TH2Painter.prototype.GetBinTips = function (i, j) { + var lines = [], pmain = this.frame_painter(), + xaxis = this.GetAxis("y"), yaxis = this.GetAxis("y"), + histo = this.GetHisto(), + binz = histo.getBinContent(i+1,j+1); + + lines.push(this.GetTipName() || "histo<2>"); + + if (pmain.x_kind == 'labels') + lines.push("x = " + pmain.AxisAsText("x", xaxis.GetBinCoord(i))); + else + lines.push("x = [" + pmain.AxisAsText("x", xaxis.GetBinCoord(i)) + ", " + pmain.AxisAsText("x", xaxis.GetBinCoord(i+1)) + ")"); + + if (pmain.y_kind == 'labels') + lines.push("y = " + pmain.AxisAsText("y", yaxis.GetBinCoord(j))); + else + lines.push("y = [" + pmain.AxisAsText("y", yaxis.GetBinCoord(j)) + ", " + pmain.AxisAsText("y", yaxis.GetBinCoord(j+1)) + ")"); + + lines.push("bin = " + i + ", " + j); + + if (histo.$baseh) binz -= histo.$baseh.getBinContent(i+1,j+1); + + if (binz === Math.round(binz)) + lines.push("entries = " + binz); + else + lines.push("entries = " + JSROOT.FFormat(binz, JSROOT.gStyle.fStatFormat)); + + return lines; + } + + TH2Painter.prototype.GetCandleTips = function(p) { + var lines = [], main = this.frame_painter(), xaxis = this.GetAxis("y"); + + lines.push(this.GetTipName() || "histo"); + + lines.push("x = " + main.AxisAsText("x", xaxis.GetBinCoord(p.bin))); + + lines.push('mean y = ' + JSROOT.FFormat(p.meany, JSROOT.gStyle.fStatFormat)) + lines.push('m25 = ' + JSROOT.FFormat(p.m25y, JSROOT.gStyle.fStatFormat)) + lines.push('p25 = ' + JSROOT.FFormat(p.p25y, JSROOT.gStyle.fStatFormat)) + + return lines; + } + + TH2Painter.prototype.ProvidePolyBinHints = function(binindx, realx, realy) { + + var histo = this.GetHisto(), + bin = histo.fBins.arr[binindx], + pmain = this.frame_painter(), + binname = bin.fPoly.fName, + lines = [], numpoints = 0; + + if (binname === "Graph") binname = ""; + if (binname.length === 0) binname = bin.fNumber; + + if ((realx===undefined) && (realy===undefined)) { + realx = realy = 0; + var gr = bin.fPoly, numgraphs = 1; + if (gr._typename === 'TMultiGraph') { numgraphs = bin.fPoly.fGraphs.arr.length; gr = null; } + + for (var ngr=0;ngr<numgraphs;++ngr) { + if (!gr || (ngr>0)) gr = bin.fPoly.fGraphs.arr[ngr]; + + for (var n=0;n<gr.fNpoints;++n) { + ++numpoints; + realx += gr.fX[n]; + realy += gr.fY[n]; + } + } + + if (numpoints > 1) { + realx = realx / numpoints; + realy = realy / numpoints; + } + } + + lines.push(this.GetTipName() || "histo"); + lines.push("x = " + pmain.AxisAsText("x", realx)); + lines.push("y = " + pmain.AxisAsText("y", realy)); + if (numpoints > 0) lines.push("npnts = " + numpoints); + lines.push("bin = " + binname); + if (bin.fContent === Math.round(bin.fContent)) + lines.push("content = " + bin.fContent); + else + lines.push("content = " + JSROOT.FFormat(bin.fContent, JSROOT.gStyle.fStatFormat)); + return lines; + } + + TH2Painter.prototype.ProcessTooltip = function(pnt) { + if (!pnt || !this.draw_content || !this.draw_g || !this.tt_handle || this.options.Proj) { + if (this.draw_g !== null) + this.draw_g.select(".tooltip_bin").remove(); + return null; + } + + var histo = this.GetHisto(), + h = this.tt_handle, i, + ttrect = this.draw_g.select(".tooltip_bin"); + + if (h.poly) { + // process tooltips from TH2Poly + + var pmain = this.frame_painter(), + realx, realy, foundindx = -1; + + if (pmain.grx === pmain.x) realx = pmain.x.invert(pnt.x); + if (pmain.gry === pmain.y) realy = pmain.y.invert(pnt.y); + + if ((realx!==undefined) && (realy!==undefined)) { + var i, len = histo.fBins.arr.length, bin; + + for (i = 0; (i < len) && (foundindx < 0); ++ i) { + bin = histo.fBins.arr[i]; + + // found potential bins candidate + if ((realx < bin.fXmin) || (realx > bin.fXmax) || + (realy < bin.fYmin) || (realy > bin.fYmax)) continue; + + // ignore empty bins with col0 option + if ((bin.fContent === 0) && !this.options.Zero) continue; + + var gr = bin.fPoly, numgraphs = 1; + if (gr._typename === 'TMultiGraph') { numgraphs = bin.fPoly.fGraphs.arr.length; gr = null; } + + for (var ngr=0;ngr<numgraphs;++ngr) { + if (!gr || (ngr>0)) gr = bin.fPoly.fGraphs.arr[ngr]; + if (gr.IsInside(realx,realy)) { + foundindx = i; + break; + } + } + } + } + + if (foundindx < 0) { + ttrect.remove(); + return null; + } + + var res = { name: "histo", title: histo.fTitle || "title", + x: pnt.x, y: pnt.y, + color1: this.lineatt ? this.lineatt.color : 'green', + color2: this.fillatt ? this.fillatt.fillcoloralt('blue') : 'blue', + exact: true, menu: true, + lines: this.ProvidePolyBinHints(foundindx, realx, realy) }; + + if (pnt.disabled) { + ttrect.remove(); + res.changed = true; + } else { + + if (ttrect.empty()) + ttrect = this.draw_g.append("svg:path") + .attr("class","tooltip_bin h1bin") + .style("pointer-events","none"); + + res.changed = ttrect.property("current_bin") !== foundindx; + + if (res.changed) + ttrect.attr("d", this.CreatePolyBin(pmain, bin)) + .style("opacity", "0.7") + .property("current_bin", foundindx); + } + + if (res.changed) + res.user_info = { obj: histo, name: histo.fName || "histo", + bin: foundindx, + cont: bin.fContent, + grx: pnt.x, gry: pnt.y }; + + return res; + + } else + + if (h.candle) { + // process tooltips for candle + + var p; + + for (i=0;i<h.candle.length;++i) { + p = h.candle[i]; + if ((p.x1 <= pnt.x) && (pnt.x <= p.x2) && (p.yy1 <= pnt.y) && (pnt.y <= p.yy2)) break; + } + + if (i>=h.candle.length) { + ttrect.remove(); + return null; + } + + var res = { name: histo.fName || "histo", title: histo.fTitle || "title", + x: pnt.x, y: pnt.y, + color1: this.lineatt ? this.lineatt.color : 'green', + color2: this.fillatt ? this.fillatt.fillcoloralt('blue') : 'blue', + lines: this.GetCandleTips(p), exact: true, menu: true }; + + if (pnt.disabled) { + ttrect.remove(); + res.changed = true; + } else { + + if (ttrect.empty()) + ttrect = this.draw_g.append("svg:rect") + .attr("class","tooltip_bin h1bin") + .style("pointer-events","none"); + + res.changed = ttrect.property("current_bin") !== i; + + if (res.changed) + ttrect.attr("x", p.x1) + .attr("width", p.x2-p.x1) + .attr("y", p.yy1) + .attr("height", p.yy2- p.yy1) + .style("opacity", "0.7") + .property("current_bin", i); + } + + if (res.changed) + res.user_info = { obj: histo, name: histo.fName || "histo", + bin: i+1, cont: p.median, binx: i+1, biny: 1, + grx: pnt.x, gry: pnt.y }; + + return res; + } + + var i, j, binz = 0, colindx = null; + + // search bins position + for (i = h.i1; i < h.i2; ++i) + if ((pnt.x>=h.grx[i]) && (pnt.x<=h.grx[i+1])) break; + + for (j = h.j1; j < h.j2; ++j) + if ((pnt.y>=h.gry[j+1]) && (pnt.y<=h.gry[j])) break; + + if ((i < h.i2) && (j < h.j2)) { + binz = histo.getBinContent(i+1,j+1); + if (this.is_projection) { + colindx = 0; // just to avoid hide + } else if (h.hide_only_zeros) { + colindx = (binz === 0) && !this._show_empty_bins ? null : 0; + } else { + colindx = this.getContourColor(binz, true); + if ((colindx === null) && (binz === 0) && this._show_empty_bins) colindx = 0; + } + } + + if (colindx === null) { + ttrect.remove(); + return null; + } + + var res = { name: histo.fName || "histo", title: histo.fTitle || "title", + x: pnt.x, y: pnt.y, + color1: this.lineatt ? this.lineatt.color : 'green', + color2: this.fillatt ? this.fillatt.fillcoloralt('blue') : 'blue', + lines: this.GetBinTips(i, j), exact: true, menu: true }; + + if (this.options.Color) res.color2 = this.GetPalette().getColor(colindx); + + if (pnt.disabled && !this.is_projection) { + ttrect.remove(); + res.changed = true; + } else { + if (ttrect.empty()) + ttrect = this.draw_g.append("svg:rect") + .attr("class","tooltip_bin h1bin") + .style("pointer-events","none"); + + var i1 = i, i2 = i+1, + j1 = j, j2 = j+1, + x1 = h.grx[i1], x2 = h.grx[i2], + y1 = h.gry[j2], y2 = h.gry[j1], + binid = i*10000 + j; + + if (this.is_projection == "X") { + x1 = 0; x2 = this.frame_width(); + if (this.projection_width > 1) { + var dd = (this.projection_width-1)/2; + if (j2+dd >= h.j2) { j2 = Math.min(Math.round(j2+dd), h.j2); j1 = Math.max(j2 - this.projection_width, h.j1); } + else { j1 = Math.max(Math.round(j1-dd), h.j1); j2 = Math.min(j1 + this.projection_width, h.j2); } + } + y1 = h.gry[j2]; y2 = h.gry[j1]; + binid = j1*777 + j2*333; + } else if (this.is_projection == "Y") { + y1 = 0; y2 = this.frame_height(); + if (this.projection_width > 1) { + var dd = (this.projection_width-1)/2; + if (i2+dd >= h.i2) { i2 = Math.min(Math.round(i2+dd), h.i2); i1 = Math.max(i2 - this.projection_width, h.i1); } + else { i1 = Math.max(Math.round(i1-dd), h.i1); i2 = Math.min(i1 + this.projection_width, h.i2); } + } + x1 = h.grx[i1], x2 = h.grx[i2], + binid = i1*777 + i2*333; + } + + res.changed = ttrect.property("current_bin") !== binid; + + if (res.changed) + ttrect.attr("x", x1) + .attr("width", x2 - x1) + .attr("y", y1) + .attr("height", y2 - y1) + .style("opacity", "0.7") + .property("current_bin", binid); + + if (this.is_projection && res.changed) + this.RedrawProjection(i1, i2, j1, j2); + } + + if (res.changed) + res.user_info = { obj: histo, name: histo.fName || "histo", + bin: histo.getBin(i+1, j+1), cont: binz, binx: i+1, biny: j+1, + grx: pnt.x, gry: pnt.y }; + + return res; + } + + TH2Painter.prototype.CanZoomIn = function(axis,min,max) { + // check if it makes sense to zoom inside specified axis range + + if (axis=="z") return true; + + var obj = this.GetAxis(axis); + + return (obj.FindBin(max,0.5) - obj.FindBin(min,0) > 1); + } + + TH2Painter.prototype.Draw2D = function(call_back, resize) { + + this.mode3d = false; + this.Clear3DScene(); + + // draw new palette, resize frame if required + // var pp = this.DrawColorPalette(this.options.Zscale && (this.options.Color || this.options.Contour), true); + + if (this.DrawAxes()); + this.DrawBins(); + + // redraw palette till the end when contours are available + // if (pp) pp.DrawPave(); + + // this.DrawTitle(); + + // this.UpdateStatWebCanvas(); + + this.AddInteractive(); + + JSROOT.CallBack(call_back); + } + + TH2Painter.prototype.Draw3D = function(call_back, resize) { + this.mode3d = true; + JSROOT.AssertPrerequisites('hist3d', function() { + this.Draw3D(call_back, resize); + }.bind(this)); + } + + TH2Painter.prototype.CallDrawFunc = function(callback, resize) { + + var main = this.frame_painter(); + + if (this.options.Mode3D !== main.mode3d) { + this.options.Mode3D = main.mode3d; + } + + var funcname = this.options.Mode3D ? "Draw3D" : "Draw2D"; + + this[funcname](callback, resize); + } + + TH2Painter.prototype.Redraw = function(resize) { + this.CallDrawFunc(null, resize); + } + + function drawHist2(divid, obj, opt) { + // create painter and add it to canvas + var painter = new TH2Painter(obj); + + painter.PrepareFrame(divid); + + painter.options = { Hist: false, Bar: false, Error: false, ErrorKind: -1, errorX: 0, Zero: false, Mark: false, + Line: false, Fill: false, Lego: 0, Surf: 0, + Text: true, TextAngle: 0, TextKind: "", + fBarOffset: 0, fBarWidth: 1000, BaseLine: false, Mode3D: false, AutoColor: 0, + Color: false, Scat: false, ScatCoef: 1, Candle: "", Box: false, BoxStyle: 0, Arrow: false, Contour: 0, Proj: 0 }; + + if (obj.fOpts.fStyle.fIdx == 1) painter.options.Box = true; + else painter.options.Color = true; + + // here we deciding how histogram will look like and how will be shown + painter.DecodeOptions(opt); + + if (painter.IsTH2Poly()) { + if (painter.options.Mode3D) painter.options.Lego = 12; // lego always 12 + else if (!painter.options.Color) painter.options.Color = true; // default is color + } + + painter._show_empty_bins = false; + + painter._can_move_colz = true; + + painter.ScanContent(); + + // painter.CreateStat(); // only when required + + painter.CallDrawFunc(function() { + //if (!this.options.Mode3D && this.options.AutoZoom) this.AutoZoom(); + // this.FillToolbar(); + //if (this.options.Project && !this.mode3d) + // this.ToggleProjection(this.options.Project); + painter.DrawingReady(); + }); + + return painter; + } + + JSROOT.v7.THistPainter = THistPainter; + JSROOT.v7.TH1Painter = TH1Painter; + JSROOT.v7.TH2Painter = TH2Painter; + + JSROOT.v7.drawHist1 = drawHist1; + JSROOT.v7.drawHist2 = drawHist2; + + return JSROOT; + +})); diff --git a/js/scripts/JSRootPainter.v7more.js b/js/scripts/JSRootPainter.v7more.js new file mode 100644 index 00000000000..6b6720d542d --- /dev/null +++ b/js/scripts/JSRootPainter.v7more.js @@ -0,0 +1,158 @@ +/// @file JSRootPainter.v7more.js +/// JavaScript ROOT v7 graphics for different classes + +(function( factory ) { + if ( typeof define === "function" && define.amd ) { + define( ['JSRootPainter', 'd3'], factory ); + } else + if (typeof exports === 'object' && typeof module !== 'undefined') { + factory(require("./JSRootCore.js"), require("./d3.min.js")); + } else { + + if (typeof d3 != 'object') + throw new Error('This extension requires d3.js', 'JSRootPainter.v7hist.js'); + + if (typeof JSROOT == 'undefined') + throw new Error('JSROOT is not defined', 'JSRootPainter.v7hist.js'); + + if (typeof JSROOT.Painter != 'object') + throw new Error('JSROOT.Painter not defined', 'JSRootPainter.v7hist.js'); + + factory(JSROOT, d3); + } +} (function(JSROOT, d3) { + + "use strict"; + + JSROOT.sources.push("v7more"); + + // ================================================================================= + + + function drawText() { + var text = this.GetObject(), + opts = text.fOpts, + pp = this.canv_painter(), + w = this.pad_width(), + h = this.pad_height(), + use_frame = false, + text_size = opts.fTextSize.fAttr, + text_angle = -opts.fTextAngle.fAttr, + text_align = opts.fTextAlign.fAttr, + text_color = pp.GetNewColor(opts.fTextColor), + text_font = opts.fTextFont.fAttr, + p = this.GetCoordinate(text.fP); + + this.CreateG(use_frame); + + var arg = { align: text_align, x: p.x, y: p.y, text: text.fText, rotate: text_angle, color: text_color, latex: 1 }; + + // if (text.fTextAngle) arg.rotate = -text.fTextAngle; + // if (text._typename == 'TLatex') { arg.latex = 1; fact = 0.9; } else + // if (text._typename == 'TMathText') { arg.latex = 2; fact = 0.8; } + + this.StartTextDrawing(text_font, text_size); + + this.DrawText(arg); + + this.FinishTextDrawing(); + } + + + function drawLine() { + + var line = this.GetObject(), + opts = line.fOpts, + pp = this.canv_painter(), + line_width = opts.fWidth.fAttr, + line_opacity = opts.fOpacity.fAttr, + line_style = opts.fStyle.fAttr, + line_color = pp.GetNewColor(opts.fColor), + p1 = this.GetCoordinate(line.fP1), + p2 = this.GetCoordinate(line.fP2); + + this.CreateG(); + + this.draw_g + .append("svg:line") + .attr("x1", p1.x) + .attr("y1", p1.y) + .attr("x2", p2.x) + .attr("y2", p2.y) + .style("stroke", line_color) + .attr("stroke-width", line_width) + .attr("stroke-opacity", line_opacity) + .style("stroke-dasharray", JSROOT.Painter.root_line_styles[line_style]); + } + + + function drawBox() { + + var box = this.GetObject(), + opts = box.fOpts, + pp = this.canv_painter(), + line_width = opts.fLineWidth.fAttr, + line_opacity = opts.fLineOpacity.fAttr, + line_style = opts.fLineStyle.fAttr, + line_color = pp.GetNewColor(opts.fLineColor), + fill_opacity = opts.fFillOpacity.fAttr, + fill_color = pp.GetNewColor(opts.fFillColor), + fill_style = opts.fFillStyle.fAttr, + round_width = opts.fRoundWidth.fAttr, + round_height = opts.fRoundHeight.fAttr, + p1 = this.GetCoordinate(box.fP1), + p2 = this.GetCoordinate(box.fP2); + + this.CreateG(); + + if (fill_style == 0 ) fill_color = "none"; + + this.draw_g + .append("svg:rect") + .attr("x", p1.x) + .attr("width", p2.x-p1.x) + .attr("y", p2.y) + .attr("height", p1.y-p2.y) + .attr("rx", round_width) + .attr("ry", round_height) + .style("stroke", line_color) + .attr("stroke-width", line_width) + .attr("stroke-opacity", line_opacity) + .attr("fill", fill_color) + .attr("fill-opacity", fill_opacity) + .style("stroke-dasharray", JSROOT.Painter.root_line_styles[line_style]); + } + + + function drawMarker() { + var marker = this.GetObject(), + opts = marker.fOpts, + pp = this.canv_painter(), + marker_size = opts.fSize.fAttr, + marker_opacity = opts.fOpacity.fAttr, + marker_style = opts.fStyle.fAttr, + marker_color = pp.GetNewColor(opts.fColor), + p = this.GetCoordinate(marker.fP); + + var att = new JSROOT.TAttMarkerHandler({ style: marker_style, color: marker_color, size: marker_size }); + + this.CreateG(); + + var path = att.create(p.x, p.y); + + if (path) + this.draw_g.append("svg:path") + .attr("d", path) + .call(att.func); + } + + // ================================================================================ + + JSROOT.v7.drawText = drawText; + JSROOT.v7.drawLine = drawLine; + JSROOT.v7.drawBox = drawBox; + JSROOT.v7.drawMarker = drawMarker; + + return JSROOT; + +})); diff --git a/js/scripts/JSRootTree.js b/js/scripts/JSRootTree.js new file mode 100644 index 00000000000..10b066d52b4 --- /dev/null +++ b/js/scripts/JSRootTree.js @@ -0,0 +1,2588 @@ +/// @file JSRootTree.js +/// Collect all TTree-relevant methods like reading and processing + +(function( factory ) { + if ( typeof define === "function" && define.amd ) { + define( ['JSRootCore', 'JSRootIOEvolution', 'JSRootMath'], factory ); + } else + if (typeof exports === 'object' && typeof module !== 'undefined') { + factory(require("./JSRootCore.js"), require("./JSRootIOEvolution.js"), require("./JSRootMath.js")); + } else { + if (typeof JSROOT == 'undefined') + throw new Error('JSROOT is not defined', 'JSRootTree.js'); + + if (typeof JSROOT.IO != 'object') + throw new Error('JSROOT.IO not defined', 'JSRootTree.js'); + + factory(JSROOT); + } +} (function(JSROOT) { + + "use strict"; + + JSROOT.sources.push("tree"); + + JSROOT.BranchType = { kLeafNode: 0, kBaseClassNode: 1, kObjectNode: 2, kClonesNode: 3, + kSTLNode: 4, kClonesMemberNode: 31, kSTLMemberNode: 41 }; + + JSROOT.IO.BranchBits = { + kDoNotProcess: JSROOT.BIT(10), // Active bit for branches + kIsClone: JSROOT.BIT(11), // to indicate a TBranchClones + kBranchObject: JSROOT.BIT(12), // branch is a TObject* + kBranchAny: JSROOT.BIT(17), // branch is an object* + kAutoDelete: JSROOT.BIT(15), + kDoNotUseBufferMap: JSROOT.BIT(22) // If set, at least one of the entry in the branch will use the buffer's map of classname and objects. + } + + + /** + * @summary class to read data from TTree + * + * @constructor + * @memberof JSROOT + */ + function TSelector() { + this.branches = []; // list of branches to read + this.names = []; // list of member names for each branch in tgtobj + this.directs = []; // indication if only branch without any children should be read + this.break_execution = 0; + this.tgtobj = {}; + } + + /** @summary Add branch to the selector + * @desc Either branch name or branch itself should be specified + * Second parameter defines member name in the tgtobj + * If selector.AddBranch("px", "read_px") is called, + * branch will be read into selector.tgtobj.read_px member + * @param {string} branch - name of branch (or branch object itself} + * @param {string} name - member name in tgtobj where data will be read + */ + + TSelector.prototype.AddBranch = function(branch, name, direct) { + if (!name) + name = (typeof branch === 'string') ? branch : ("br" + this.branches.length); + this.branches.push(branch); + this.names.push(name); + this.directs.push(direct); + return this.branches.length-1; + } + + TSelector.prototype.indexOfBranch = function(branch) { + return this.branches.indexOf(branch); + } + + TSelector.prototype.nameOfBranch = function(indx) { + return this.names[indx]; + } + + TSelector.prototype.ShowProgress = function(value) { + // this function can be used to check current TTree progress + } + + /** @summary call this function to abort processing */ + TSelector.prototype.Abort = function() { + this.break_execution = -1111; + } + + /** @summary function called before start processing + * @abstract + * @param {object} tree - tree object + */ + TSelector.prototype.Begin = function(tree) { + } + + /** @summary function called when next entry extracted from the tree + * @abstract + * @param {number} entry - read entry number + */ + TSelector.prototype.Process = function(entry) { + } + + /** @summary function called at the very end of processing + * @abstract + * @param {boolean} res - true if all data were correctly processed + */ + TSelector.prototype.Terminate = function(res) { + } + + // ================================================================= + + JSROOT.CheckArrayPrototype = function(arr, check_content) { + // return 0 when not array + // 1 - when arbitrary array + // 2 - when plain (1-dim) array with same-type content + if (typeof arr !== 'object') return 0; + var proto = Object.prototype.toString.apply(arr); + if (proto.indexOf('[object')!==0) return 0; + var pos = proto.indexOf('Array]'); + if (pos < 0) return 0; + if (pos > 8) return 2; // this is typed array like Int32Array + + if (!check_content) return 1; // + var typ, plain = true; + for (var k=0;k<arr.length;++k) { + var sub = typeof arr[k]; + if (!typ) typ = sub; + if (sub!==typ) { plain = false; break; } + if ((sub=="object") && JSROOT.CheckArrayPrototype(arr[k])) { plain = false; break; } + } + + return plain ? 2 : 1; + } + + function ArrayIterator(arr, select, tgtobj) { + // class used to iterate over all array indexes until number value + + this.object = arr; + this.value = 0; // value always used in iterator + this.arr = []; // all arrays + this.indx = []; // all indexes + this.cnt = -1; // current index counter + this.tgtobj = tgtobj; + + if (typeof select === 'object') + this.select = select; // remember indexes for selection + else + this.select = []; // empty array, undefined for each dimension means iterate over all indexes + } + + ArrayIterator.prototype.next = function() { + var obj, typ, cnt = this.cnt, seltyp; + + if (cnt >= 0) { + + if (++this.fastindx < this.fastlimit) { + this.value = this.fastarr[this.fastindx]; + return true; + } + + while (--cnt >= 0) { + if ((this.select[cnt]===undefined) && (++this.indx[cnt] < this.arr[cnt].length)) break; + } + if (cnt < 0) return false; + } + + while (true) { + + obj = (cnt < 0) ? this.object : (this.arr[cnt])[this.indx[cnt]]; + + typ = obj ? typeof obj : "any"; + + if (typ === "object") { + if (obj._typename !== undefined) { + if (JSROOT.IsRootCollection(obj)) { obj = obj.arr; typ = "array"; } + else typ = "any"; + } else if (!isNaN(obj.length) && (JSROOT.CheckArrayPrototype(obj)>0)) { + typ = "array"; + } else { + typ = "any"; + } + } + + if (this.select[cnt+1]=="$self$") { + this.value = obj; + this.fastindx = this.fastlimit = 0; + this.cnt = cnt+1; + return true; + } + + if ((typ=="any") && (typeof this.select[cnt+1] === "string")) { + // this is extraction of the member from arbitrary class + this.arr[++cnt] = obj; + this.indx[cnt] = this.select[cnt]; // use member name as index + continue; + } + + if ((typ === "array") && ((obj.length > 0) || (this.select[cnt+1]==="$size$"))) { + this.arr[++cnt] = obj; + switch (this.select[cnt]) { + case undefined: this.indx[cnt] = 0; break; + case "$last$": this.indx[cnt] = obj.length-1; break; + case "$size$": + this.value = obj.length; + this.fastindx = this.fastlimit = 0; + this.cnt = cnt; + return true; + break; + default: + if (!isNaN(this.select[cnt])) { + this.indx[cnt] = this.select[cnt]; + if (this.indx[cnt] < 0) this.indx[cnt] = obj.length-1; + } else { + // this is compile variable as array index - can be any expression + this.select[cnt].Produce(this.tgtobj); + this.indx[cnt] = Math.round(this.select[cnt].get(0)); + } + } + } else { + + if (cnt<0) return false; + + this.value = obj; + if (this.select[cnt]===undefined) { + this.fastarr = this.arr[cnt]; + this.fastindx = this.indx[cnt]; + this.fastlimit = this.fastarr.length; + } else { + this.fastindx = this.fastlimit = 0; // no any iteration on that level + } + + this.cnt = cnt; + return true; + } + } + + return false; + } + + ArrayIterator.prototype.reset = function() { + this.arr = []; + this.indx = []; + delete this.fastarr; + this.cnt = -1; + this.value = 0; + } + + // ============================================================================ + + function TDrawVariable(globals) { + // object with single variable in TTree::Draw expression + this.globals = globals; + + this.code = ""; + this.brindex = []; // index of used branches from selector + this.branches = []; // names of branches in target object + this.brarray = []; // array specifier for each branch + this.func = null; // generic function for variable calculation + + this.kind = undefined; + this.buf = []; // buffer accumulates temporary values + } + + TDrawVariable.prototype.Parse = function(tree,selector,code,only_branch,branch_mode) { + // when only_branch specified, its placed in the front of the expression + + function is_start_symbol(symb) { + if ((symb >= "A") && (symb <= "Z")) return true; + if ((symb >= "a") && (symb <= "z")) return true; + return (symb === "_"); + } + + function is_next_symbol(symb) { + if (is_start_symbol(symb)) return true; + if ((symb >= "0") && (symb <= "9")) return true; + return false; + } + + if (!code) code = ""; // should be empty string at least + + this.code = (only_branch ? only_branch.fName : "") + code; + + var pos = 0, pos2 = 0, br = null; + while ((pos < code.length) || only_branch) { + + var arriter = []; + + if (only_branch) { + br = only_branch; + only_branch = undefined; + } else { + // first try to find branch + while ((pos < code.length) && !is_start_symbol(code[pos])) pos++; + pos2 = pos; + while ((pos2 < code.length) && (is_next_symbol(code[pos2]) || code[pos2]===".")) pos2++; + if (code[pos2]=="$") { + var repl = ""; + switch (code.substr(pos, pos2-pos)) { + case "LocalEntry": + case "Entry": repl = "arg.$globals.entry"; break; + case "Entries": repl = "arg.$globals.entries"; break; + } + if (repl) { + code = code.substr(0, pos) + repl + code.substr(pos2+1); + pos = pos + repl.length; + continue; + } + } + + br = tree.FindBranch(code.substr(pos, pos2-pos), true); + if (!br) { pos = pos2+1; continue; } + + // when full id includes branch name, replace only part of extracted expression + if (br.branch && (br.rest!==undefined)) { + pos2 -= br.rest.length; + branch_mode = br.read_mode; // maybe selection of the sub-object done + br = br.branch; + } + + // when code ends with the point - means object itself will be accessed + // sometime branch name itself ends with the point + if ((pos2>=code.length-1) && (code[code.length-1]===".")) { + arriter.push("$self$"); + pos2 = code.length; + } + } + + // now extract all levels of iterators + while (pos2 < code.length) { + + if ((code[pos2]==="@") && (code.substr(pos2,5)=="@size") && (arriter.length==0)) { + pos2+=5; + branch_mode = true; + break; + } + + if (code[pos2] === ".") { + // this is object member + var prev = ++pos2; + + if ((code[prev]==="@") && (code.substr(prev,5)==="@size")) { + arriter.push("$size$"); + pos2+=5; + break; + } + + if (!is_start_symbol(code[prev])) { + arriter.push("$self$"); // last point means extraction of object itself + break; + } + + while ((pos2 < code.length) && is_next_symbol(code[pos2])) pos2++; + + // this is looks like function call - do not need to extract member with + if (code[pos2]=="(") { pos2 = prev-1; break; } + + // this is selection of member, but probably we need to activate iterator for ROOT collection + if ((arriter.length===0) && br) { + // TODO: if selected member is simple data type - no need to make other checks - just break here + if ((br.fType === JSROOT.BranchType.kClonesNode) || (br.fType === JSROOT.BranchType.kSTLNode)) { + arriter.push(undefined); + } else { + var objclass = JSROOT.IO.GetBranchObjectClass(br, tree, false, true); + if (objclass && JSROOT.IsRootCollection(null, objclass)) arriter.push(undefined); + } + } + arriter.push(code.substr(prev, pos2-prev)); + continue; + } + + if (code[pos2]!=="[") break; + + // simple [] + if (code[pos2+1]=="]") { arriter.push(undefined); pos2+=2; continue; } + + var prev = pos2++, cnt = 0; + while ((pos2 < code.length) && ((code[pos2]!="]") || (cnt>0))) { + if (code[pos2]=='[') cnt++; else if (code[pos2]==']') cnt--; + pos2++; + } + var sub = code.substr(prev+1, pos2-prev-1); + switch(sub) { + case "": + case "$all$": arriter.push(undefined); break; + case "$last$": arriter.push("$last$"); break; + case "$size$": arriter.push("$size$"); break; + case "$first$": arriter.push(0); break; + default: + if (!isNaN(parseInt(sub))) { + arriter.push(parseInt(sub)); + } else { + // try to compile code as draw variable + var subvar = new TDrawVariable(this.globals); + if (!subvar.Parse(tree,selector, sub)) return false; + arriter.push(subvar); + } + } + pos2++; + } + + if (arriter.length===0) arriter = undefined; else + if ((arriter.length===1) && (arriter[0]===undefined)) arriter = true; + + var indx = selector.indexOfBranch(br); + if (indx<0) indx = selector.AddBranch(br, undefined, branch_mode); + + branch_mode = undefined; + + this.brindex.push(indx); + this.branches.push(selector.nameOfBranch(indx)); + this.brarray.push(arriter); + + // this is simple case of direct usage of the branch + if ((pos===0) && (pos2 === code.length) && (this.branches.length===1)) { + this.direct_branch = true; // remember that branch read as is + return true; + } + + var replace = "arg.var" + (this.branches.length-1); + + code = code.substr(0, pos) + replace + code.substr(pos2); + + pos = pos + replace.length; + } + + // support usage of some standard TMath functions + code = code.replace(/TMath::Exp\(/g, 'Math.exp(') + .replace(/TMath::Abs\(/g, 'Math.abs(') + .replace(/TMath::Prob\(/g, 'arg.$math.Prob(') + .replace(/TMath::Gaus\(/g, 'arg.$math.Gaus('); + + this.func = new Function("arg", "return (" + code + ")"); + + return true; + } + + TDrawVariable.prototype.is_dummy = function() { + return (this.branches.length === 0) && !this.func; + } + + TDrawVariable.prototype.Produce = function(obj) { + // after reading tree braches into the object, calculate variable value + + this.length = 1; + this.isarray = false; + + if (this.is_dummy()) { + this.value = 1.; // used as dummy weight variable + this.kind = "number"; + return; + } + + var arg = { $globals: this.globals, $math: JSROOT.Math }, usearrlen = -1, arrs = []; + for (var n=0;n<this.branches.length;++n) { + var name = "var" + n; + arg[name] = obj[this.branches[n]]; + + // try to check if branch is array and need to be iterated + if (this.brarray[n]===undefined) + this.brarray[n] = (JSROOT.CheckArrayPrototype(arg[name]) > 0) || JSROOT.IsRootCollection(arg[name]); + + // no array - no pain + if (this.brarray[n]===false) continue; + + // check if array can be used as is - one dimension and normal values + if ((this.brarray[n]===true) && (JSROOT.CheckArrayPrototype(arg[name], true) === 2)) { + // plain array, can be used as is + arrs[n] = arg[name]; + } else { + var iter = new ArrayIterator(arg[name], this.brarray[n], obj); + arrs[n] = []; + while (iter.next()) arrs[n].push(iter.value); + } + if ((usearrlen < 0) || (usearrlen < arrs[n].length)) usearrlen = arrs[n].length; + } + + if (usearrlen < 0) { + this.value = this.direct_branch ? arg.var0 : this.func(arg); + if (!this.kind) this.kind = typeof this.value; + return; + } + + if (usearrlen == 0) { + // empty array - no any histogram should be filled + this.length = 0; + this.value = 0; + return; + } + + this.length = usearrlen; + this.isarray = true; + + if (this.direct_branch) { + this.value = arrs[0]; // just use array + } else { + this.value = new Array(usearrlen); + + for (var k=0;k<usearrlen;++k) { + for (var n=0;n<this.branches.length;++n) { + if (arrs[n]) arg["var"+n] = arrs[n][k]; + } + this.value[k] = this.func(arg); + } + } + + if (!this.kind) this.kind = typeof this.value[0]; + } + + TDrawVariable.prototype.get = function(indx) { + return this.isarray ? this.value[indx] : this.value; + } + + TDrawVariable.prototype.AppendArray = function(tgtarr) { + // append array to the buffer + + this.buf = this.buf.concat(tgtarr[this.branches[0]]); + } + + // ============================================================================= + + /** + * @summary Selector class for TTree::Draw function + * + * @constructor + * @memberof JSROOT + * @augments JSROOT.TSelector + */ + function TDrawSelector(callback) { + TSelector.call(this); + + this.ndim = 0; + this.vars = []; // array of expression variables + this.cut = null; // cut variable + this.hist = null; + this.histo_callback = callback; + this.histo_drawopt = ""; + this.hist_name = "$htemp"; + this.hist_title = "Result of TTree::Draw"; + this.graph = false; + this.hist_args = []; // arguments for histogram creation + this.arr_limit = 1000; // number of accumulated items before create histogram + this.htype = "F"; + this.monitoring = 0; + this.globals = {}; // object with global parameters, which could be used in any draw expression + this.last_progress = 0; + this.aver_diff = 0; + } + + TDrawSelector.prototype = Object.create(TSelector.prototype); + + TDrawSelector.prototype.ParseParameters = function(tree, args, expr) { + + if (!expr || (typeof expr !== "string")) return ""; + + // parse parameters which defined at the end as expression;par1name:par1value;par2name:par2value + var pos = expr.lastIndexOf(";"); + while (pos>=0) { + var parname = expr.substr(pos+1), parvalue = undefined; + expr = expr.substr(0,pos); + pos = expr.lastIndexOf(";"); + + var separ = parname.indexOf(":"); + if (separ>0) { parvalue = parname.substr(separ+1); parname = parname.substr(0, separ); } + + var intvalue = parseInt(parvalue); + if (!parvalue || isNaN(intvalue)) intvalue = undefined; + + switch (parname) { + case "num": + case "entries": + case "numentries": + if (parvalue==="all") args.numentries = tree.fEntries; else + if (parvalue==="half") args.numentries = Math.round(tree.fEntries/2); else + if (intvalue !== undefined) args.numentries = intvalue; + break; + case "first": + if (intvalue !== undefined) args.firstentry = intvalue; + break; + case "mon": + case "monitor": + args.monitoring = (intvalue !== undefined) ? intvalue : 5000; + break; + case "player": + args.player = true; + break; + case "dump": + args.dump = true; + break; + case "maxseg": + case "maxrange": + if (intvalue) tree.$file.fMaxRanges = intvalue; + break; + case "accum": + if (intvalue) this.arr_limit = intvalue; + break; + case "htype": + if (parvalue && (parvalue.length===1)) { + this.htype = parvalue.toUpperCase(); + if ((this.htype!=="C") && (this.htype!=="S") && (this.htype!=="I") + && (this.htype!=="F") && (this.htype!=="L") && (this.htype!=="D")) this.htype = "F"; + } + break; + case "hbins" : + this.hist_nbins = parseInt(parvalue); + if (isNaN(this.hist_nbins) || (this.hist_nbins<=3)) delete this.hist_nbins; + break; + case "drawopt": + args.drawopt = parvalue; + break; + case "graph": + args.graph = intvalue || true; + break; + } + } + + pos = expr.lastIndexOf(">>"); + if (pos>=0) { + var harg = expr.substr(pos+2).trim(); + expr = expr.substr(0,pos).trim(); + pos = harg.indexOf("("); + if (pos>0) { + this.hist_name = harg.substr(0, pos); + harg = harg.substr(pos); + } + if (harg === "dump") { + args.dump = true; + } else if (harg.indexOf("Graph") == 0) { + args.graph = true; + } else if (pos<0) { + this.hist_name = harg; + } else if ((harg[0]=="(") && (harg[harg.length-1]==")")) { + harg = harg.substr(1,harg.length-2).split(","); + var isok = true; + for (var n=0;n<harg.length;++n) { + harg[n] = (n%3===0) ? parseInt(harg[n]) : parseFloat(harg[n]); + if (isNaN(harg[n])) isok = false; + } + if (isok) this.hist_args = harg; + } + } + + if (args.dump) { + this.dump_values = true; + args.reallocate_objects = true; + if (args.numentries===undefined) args.numentries = 10; + } + + return expr; + } + + TDrawSelector.prototype.ParseDrawExpression = function(tree, args) { + + // parse complete expression + var expr = this.ParseParameters(tree, args, args.expr), cut = ""; + + // parse option for histogram creation + this.hist_title = "drawing '" + expr + "' from " + tree.fName; + + var pos = 0; + if (args.cut) { + cut = args.cut; + } else { + pos = expr.replace(/TMath::/g, 'TMath__').lastIndexOf("::"); // avoid confusion due-to :: in the namespace + if (pos>0) { + cut = expr.substr(pos+2).trim(); + expr = expr.substr(0,pos).trim(); + } + } + + args.parse_expr = expr; + args.parse_cut = cut; + + // var names = expr.split(":"); // to allow usage of ? operator, we need to handle : as well + var names = [], nbr1 = 0, nbr2 = 0, prev = 0; + for (pos=0; pos < expr.length; ++pos) { + switch (expr[pos]) { + case "(" : nbr1++; break; + case ")" : nbr1--; break; + case "[" : nbr2++; break; + case "]" : nbr2--; break; + case ":" : + if (expr[pos+1]==":") { pos++; continue; } + if (!nbr1 && !nbr2 && (pos>prev)) names.push(expr.substr(prev,pos-prev)); + prev = pos+1; + break; + } + } + if (!nbr1 && !nbr2 && (pos>prev)) names.push(expr.substr(prev,pos-prev)); + + if ((names.length < 1) || (names.length > 3)) return false; + + this.ndim = names.length; + + var is_direct = !cut; + + for (var n=0;n<this.ndim;++n) { + this.vars[n] = new TDrawVariable(this.globals); + if (!this.vars[n].Parse(tree, this, names[n])) return false; + if (!this.vars[n].direct_branch) is_direct = false; + } + + this.cut = new TDrawVariable(this.globals); + if (cut) + if (!this.cut.Parse(tree, this, cut)) return false; + + if (!this.branches.length) { + console.warn('no any branch is selected'); + return false; + } + + if (is_direct) this.ProcessArrays = this.ProcessArraysFunc; + + this.monitoring = args.monitoring; + + this.graph = args.graph; + + if (args.drawopt !== undefined) + this.histo_drawopt = args.drawopt; + else + this.histo_drawopt = (this.ndim===2) ? "col" : ""; + + return true; + } + + TDrawSelector.prototype.DrawOnlyBranch = function(tree, branch, expr, args) { + this.ndim = 1; + + if (expr.indexOf("dump")==0) expr = ";" + expr; + + expr = this.ParseParameters(tree, args, expr); + + this.monitoring = args.monitoring; + + if (args.dump) { + this.dump_values = true; + args.reallocate_objects = true; + } + + if (this.dump_values) { + + this.hist = []; // array of dump objects + + this.leaf = args.leaf; + + // branch object remains, therefore we need to copy fields to see them all + this.copy_fields = ((args.branch.fLeaves && (args.branch.fLeaves.arr.length > 1)) || + (args.branch.fBranches && (args.branch.fBranches.arr.length > 0))) && !args.leaf; + + this.AddBranch(branch, "br0", args.direct_branch); // add branch + + this.Process = this.ProcessDump; + + return true; + } + + this.vars[0] = new TDrawVariable(this.globals); + if (!this.vars[0].Parse(tree, this, expr, branch, args.direct_branch)) return false; + this.hist_title = "drawing branch '" + branch.fName + (expr ? "' expr:'" + expr : "") + "' from " + tree.fName; + + this.cut = new TDrawVariable(this.globals); + + if (this.vars[0].direct_branch) this.ProcessArrays = this.ProcessArraysFunc; + + return true; + } + + TDrawSelector.prototype.Begin = function(tree) { + this.globals.entries = tree.fEntries; + + if (this.monitoring) + this.lasttm = new Date().getTime(); + } + + TDrawSelector.prototype.ShowProgress = function(value) { + // this function should be defined not here + + if (typeof document == 'undefined' || !JSROOT.progress) return; + + if ((value===undefined) || isNaN(value)) return JSROOT.progress(); + + if (this.last_progress !== value) { + var diff = value - this.last_progress; + if (!this.aver_diff) this.aver_diff = diff; + this.aver_diff = diff*0.3 + this.aver_diff*0.7; + } + + var ndig = 0; + if (this.aver_diff <= 0) ndig = 0; else + if (this.aver_diff < 0.0001) ndig = 3; else + if (this.aver_diff < 0.001) ndig = 2; else + if (this.aver_diff < 0.01) ndig = 1; + + var main_box = document.createElement("p"), + text_node = document.createTextNode("TTree draw " + (value*100).toFixed(ndig) + " % "), + selector = this; + + main_box.appendChild(text_node); + main_box.title = "Click on element to break drawing"; + + main_box.onclick = function() { + if (++selector.break_execution<3) { + main_box.title = "Tree draw will break after next I/O operation"; + return text_node.nodeValue = "Breaking ... "; + } + selector.Abort(); + JSROOT.progress(); + } + + JSROOT.progress(main_box); + this.last_progress = value; + } + + TDrawSelector.prototype.GetBitsBins = function(nbits, res) { + res.nbins = res.max = nbits; + res.fLabels = JSROOT.Create("THashList"); + for (var k=0;k<nbits;++k) { + var s = JSROOT.Create("TObjString"); + s.fString = k.toString(); + s.fUniqueID = k+1; + res.fLabels.Add(s); + } + return res; + } + + TDrawSelector.prototype.GetMinMaxBins = function(axisid, nbins) { + + var res = { min: 0, max: 0, nbins: nbins, k: 1., fLabels: null, title: "" }; + + if (axisid >= this.ndim) return res; + + var arr = this.vars[axisid].buf; + + res.title = this.vars[axisid].code || ""; + + if (this.vars[axisid].kind === "object") { + // this is any object type + var typename, similar = true, maxbits = 8; + for (var k=0;k<arr.length;++k) { + if (!arr[k]) continue; + if (!typename) typename = arr[k]._typename; + if (typename !== arr[k]._typename) similar = false; // check all object types + if (arr[k].fNbits) maxbits = Math.max(maxbits, arr[k].fNbits+1); + } + + if (typename && similar) { + if ((typename==="TBits") && (axisid===0)) { + this.Fill1DHistogram = this.FillTBitsHistogram; + if (maxbits % 8) maxbits = (maxbits & 0xfff0) + 8; + + if ((this.hist_name === "bits") && (this.hist_args.length == 1) && this.hist_args[0]) + maxbits = this.hist_args[0]; + + return this.GetBitsBins(maxbits, res); + } + } + } + + if (this.vars[axisid].kind === "string") { + res.lbls = []; // all labels + + for (var k=0;k<arr.length;++k) + if (res.lbls.indexOf(arr[k])<0) + res.lbls.push(arr[k]); + + res.lbls.sort(); + res.max = res.nbins = res.lbls.length; + + res.fLabels = JSROOT.Create("THashList"); + for (var k=0;k<res.lbls.length;++k) { + var s = JSROOT.Create("TObjString"); + s.fString = res.lbls[k]; + s.fUniqueID = k+1; + if (s.fString === "") s.fString = "<empty>"; + res.fLabels.Add(s); + } + } else if ((axisid === 0) && (this.hist_name === "bits") && (this.hist_args.length <= 1)) { + this.Fill1DHistogram = this.FillBitsHistogram; + return this.GetBitsBins(this.hist_args[0] || 32, res); + } else if (axisid*3 + 2 < this.hist_args.length) { + res.nbins = this.hist_args[axisid*3]; + res.min = this.hist_args[axisid*3+1]; + res.max = this.hist_args[axisid*3+2]; + } else { + + + + res.min = Math.min.apply(null, arr); + res.max = Math.max.apply(null, arr); + + if (this.hist_nbins) + nbins = res.nbins = this.hist_nbins; + + res.isinteger = (Math.round(res.min)===res.min) && (Math.round(res.max)===res.max); + if (res.isinteger) + for (var k=0;k<arr.length;++k) + if (arr[k]!==Math.round(arr[k])) { res.isinteger = false; break; } + + if (res.isinteger) { + res.min = Math.round(res.min); + res.max = Math.round(res.max); + if (res.max-res.min < nbins*5) { + res.min -= 1; + res.max += 2; + res.nbins = Math.round(res.max - res.min); + } else { + var range = (res.max - res.min + 2), step = Math.floor(range / nbins); + while (step*nbins < range) step++; + res.max = res.min + nbins*step; + } + } else + if (res.min >= res.max) { + res.max = res.min; + if (Math.abs(res.min)<100) { res.min-=1; res.max+=1; } else + if (res.min>0) { res.min*=0.9; res.max*=1.1; } else { res.min*=1.1; res.max*=0.9; } + } else { + res.max += (res.max-res.min)/res.nbins; + } + } + + res.k = res.nbins/(res.max-res.min); + + res.GetBin = function(value) { + var bin = this.lbls ? this.lbls.indexOf(value) : Math.floor((value-this.min)*this.k); + return (bin<0) ? 0 : ((bin>this.nbins) ? this.nbins+1 : bin+1); + } + + return res; + } + + TDrawSelector.prototype.CreateHistogram = function() { + if (this.hist || !this.vars[0].buf) return; + + if (this.dump_values) { + // just create array where dumped valus will be collected + this.hist = []; + + // reassign fill method + this.Fill1DHistogram = this.Fill2DHistogram = this.Fill3DHistogram = this.DumpValue; + } else if (this.graph) { + var N = this.vars[0].buf.length; + + if(this.ndim == 1) { + // A 1-dimensional graph will just have the x axis as an index + this.hist = JSROOT.CreateTGraph(N, Array.from(Array(N).keys()), this.vars[0].buf); + } else if(this.ndim == 2) { + this.hist = JSROOT.CreateTGraph(N,this.vars[0].buf, this.vars[1].buf); + delete this.vars[1].buf; + } + + this.hist.fTitle = this.hist_title; + this.hist.fName = "Graph"; + + } else { + + this.x = this.GetMinMaxBins(0, (this.ndim > 1) ? 50 : 200); + + this.y = this.GetMinMaxBins(1, 50); + + this.z = this.GetMinMaxBins(2, 50); + + switch (this.ndim) { + case 1: this.hist = JSROOT.CreateHistogram("TH1"+this.htype, this.x.nbins); break; + case 2: this.hist = JSROOT.CreateHistogram("TH2"+this.htype, this.x.nbins, this.y.nbins); break; + case 3: this.hist = JSROOT.CreateHistogram("TH3"+this.htype, this.x.nbins, this.y.nbins, this.z.nbins); break; + } + + this.hist.fXaxis.fTitle = this.x.title; + this.hist.fXaxis.fXmin = this.x.min; + this.hist.fXaxis.fXmax = this.x.max; + this.hist.fXaxis.fLabels = this.x.fLabels; + + if (this.ndim > 1) this.hist.fYaxis.fTitle = this.y.title; + this.hist.fYaxis.fXmin = this.y.min; + this.hist.fYaxis.fXmax = this.y.max; + this.hist.fYaxis.fLabels = this.y.fLabels; + + if (this.ndim > 2) this.hist.fZaxis.fTitle = this.z.title; + this.hist.fZaxis.fXmin = this.z.min; + this.hist.fZaxis.fXmax = this.z.max; + this.hist.fZaxis.fLabels = this.z.fLabels; + + this.hist.fName = this.hist_name; + this.hist.fTitle = this.hist_title; + this.hist.$custom_stat = (this.hist_name == "$htemp") ? 111110 : 111111; + } + + var var0 = this.vars[0].buf, cut = this.cut.buf, len = var0.length; + + if (!this.graph) { + switch (this.ndim) { + case 1: + for (var n=0;n<len;++n) + this.Fill1DHistogram(var0[n], cut ? cut[n] : 1.); + break; + case 2: + var var1 = this.vars[1].buf; + for (var n=0;n<len;++n) + this.Fill2DHistogram(var0[n], var1[n], cut ? cut[n] : 1.); + delete this.vars[1].buf; + break; + case 3: + var var1 = this.vars[1].buf, var2 = this.vars[2].buf; + for (var n=0;n<len;++n) + this.Fill3DHistogram(var0[n], var1[n], var2[n], cut ? cut[n] : 1.); + delete this.vars[1].buf; + delete this.vars[2].buf; + break; + } + } + + delete this.vars[0].buf; + delete this.cut.buf; + } + + TDrawSelector.prototype.FillTBitsHistogram = function(xvalue, weight) { + if (!weight || !xvalue || !xvalue.fNbits || !xvalue.fAllBits) return; + + var sz = Math.min(xvalue.fNbits+1, xvalue.fNbytes*8); + + for (var bit=0,mask=1,b=0;bit<sz;++bit) { + if (xvalue.fAllBits[b] && mask) { + if (bit <= this.x.nbins) + this.hist.fArray[bit+1] += weight; + else + this.hist.fArray[this.x.nbins+1] += weight; + } + + mask*=2; + if (mask>=0x100) { mask = 1; ++b; } + } + } + + TDrawSelector.prototype.FillBitsHistogram = function(xvalue, weight) { + if (!weight) return; + + for (var bit=0,mask=1;bit<this.x.nbins;++bit) { + if (xvalue & mask) this.hist.fArray[bit+1] += weight; + mask*=2; + } + } + + TDrawSelector.prototype.Fill1DHistogram = function(xvalue, weight) { + var bin = this.x.GetBin(xvalue); + this.hist.fArray[bin] += weight; + + if (!this.x.lbls) { + this.hist.fTsumw += weight; + this.hist.fTsumwx += weight*xvalue; + this.hist.fTsumwx2 += weight*xvalue*xvalue; + } + } + + TDrawSelector.prototype.Fill2DHistogram = function(xvalue, yvalue, weight) { + var xbin = this.x.GetBin(xvalue), + ybin = this.y.GetBin(yvalue); + + this.hist.fArray[xbin+(this.x.nbins+2)*ybin] += weight; + if (!this.x.lbls && !this.y.lbls) { + this.hist.fTsumw += weight; + this.hist.fTsumwx += weight*xvalue; + this.hist.fTsumwy += weight*yvalue; + this.hist.fTsumwx2 += weight*xvalue*xvalue; + this.hist.fTsumwxy += weight*xvalue*yvalue; + this.hist.fTsumwy2 += weight*yvalue*yvalue; + } + } + + TDrawSelector.prototype.Fill3DHistogram = function(xvalue, yvalue, zvalue, weight) { + var xbin = this.x.GetBin(xvalue), + ybin = this.y.GetBin(yvalue), + zbin = this.z.GetBin(zvalue); + + this.hist.fArray[xbin + (this.x.nbins+2) * (ybin + (this.y.nbins+2)*zbin) ] += weight; + if (!this.x.lbls && !this.y.lbls && !this.z.lbls) { + this.hist.fTsumw += weight; + this.hist.fTsumwx += weight*xvalue; + this.hist.fTsumwy += weight*yvalue; + this.hist.fTsumwz += weight*zvalue; + this.hist.fTsumwx2 += weight*xvalue*xvalue; + this.hist.fTsumwy2 += weight*yvalue*yvalue; + this.hist.fTsumwz2 += weight*zvalue*zvalue; + this.hist.fTsumwxy += weight*xvalue*yvalue; + this.hist.fTsumwxz += weight*xvalue*zvalue; + this.hist.fTsumwyz += weight*yvalue*zvalue; + } + } + + TDrawSelector.prototype.DumpValue = function(v1, v2, v3, v4) { + var obj; + switch (this.ndim) { + case 1: obj = { x: v1, weight: v2 }; break; + case 2: obj = { x: v1, y: v2, weight: v3 }; break; + case 3: obj = { x: v1, y: v2, z: v3, weight: v4 }; break; + } + + if (this.cut.is_dummy()) { + if (this.ndim===1) obj = v1; else delete obj.weight; + } + + this.hist.push(obj); + } + + TDrawSelector.prototype.ProcessArraysFunc = function(entry) { + // function used when all branches can be read as array + // most typical usage - histogramming of single branch + + if (this.arr_limit || this.graph) { + var var0 = this.vars[0], len = this.tgtarr.br0.length, + var1 = this.vars[1], var2 = this.vars[2]; + if ((var0.buf.length===0) && (len>=this.arr_limit) && !this.graph) { + // special use case - first array large enough to create histogram directly base on it + var0.buf = this.tgtarr.br0; + if (var1) var1.buf = this.tgtarr.br1; + if (var2) var2.buf = this.tgtarr.br2; + } else + for (var k=0;k<len;++k) { + var0.buf.push(this.tgtarr.br0[k]); + if (var1) var1.buf.push(this.tgtarr.br1[k]); + if (var2) var2.buf.push(this.tgtarr.br2[k]); + } + var0.kind = "number"; + if (var1) var1.kind = "number"; + if (var2) var2.kind = "number"; + this.cut.buf = null; // do not create buffer for cuts + if (!this.graph && (var0.buf.length >= this.arr_limit)) { + this.CreateHistogram(); + this.arr_limit = 0; + } + } else { + var br0 = this.tgtarr.br0, len = br0.length; + switch(this.ndim) { + case 1: + for (var k=0;k<len;++k) + this.Fill1DHistogram(br0[k], 1.); + break; + case 2: + var br1 = this.tgtarr.br1; + for (var k=0;k<len;++k) + this.Fill2DHistogram(br0[k], br1[k], 1.); + break; + case 3: + var br1 = this.tgtarr.br1, br2 = this.tgtarr.br2; + for (var k=0;k<len;++k) + this.Fill3DHistogram(br0[k], br1[k], br2[k], 1.); + break; + } + } + } + + TDrawSelector.prototype.ProcessDump = function(entry) { + // simple dump of the branch - no need to analyze something + + var res = this.leaf ? this.tgtobj.br0[this.leaf] : this.tgtobj.br0; + + if (res && this.copy_fields) { + if (JSROOT.CheckArrayPrototype(res)===0) { + this.hist.push(JSROOT.extend({}, res)); + } else { + this.hist.push(res); + } + } else { + this.hist.push(res); + } + } + + TDrawSelector.prototype.Process = function(entry) { + + this.globals.entry = entry; // can be used in any expression + + this.cut.Produce(this.tgtobj); + if (!this.dump_values && !this.cut.value) return; + + for (var n=0;n<this.ndim;++n) + this.vars[n].Produce(this.tgtobj); + + var var0 = this.vars[0], var1 = this.vars[1], var2 = this.vars[2], cut = this.cut; + + if (this.graph || this.arr_limit) { + switch(this.ndim) { + case 1: + for (var n0=0;n0<var0.length;++n0) { + var0.buf.push(var0.get(n0)); + cut.buf.push(cut.value); + } + break; + case 2: + for (var n0=0;n0<var0.length;++n0) + for (var n1=0;n1<var1.length;++n1) { + var0.buf.push(var0.get(n0)); + var1.buf.push(var1.get(n1)); + cut.buf.push(cut.value); + } + break; + case 3: + for (var n0=0;n0<var0.length;++n0) + for (var n1=0;n1<var1.length;++n1) + for (var n2=0;n2<var2.length;++n2) { + var0.buf.push(var0.get(n0)); + var1.buf.push(var1.get(n1)); + var2.buf.push(var2.get(n2)); + cut.buf.push(cut.value); + } + break; + } + if (!this.graph && var0.buf.length >= this.arr_limit) { + this.CreateHistogram(); + this.arr_limit = 0; + } + } else if (this.hist) { + switch(this.ndim) { + case 1: + for (var n0=0;n0<var0.length;++n0) + this.Fill1DHistogram(var0.get(n0), cut.value); + break; + case 2: + for (var n0=0;n0<var0.length;++n0) + for (var n1=0;n1<var1.length;++n1) + this.Fill2DHistogram(var0.get(n0), var1.get(n1), cut.value); + break; + case 3: + for (var n0=0;n0<var0.length;++n0) + for (var n1=0;n1<var1.length;++n1) + for (var n2=0;n2<var2.length;++n2) + this.Fill3DHistogram(var0.get(n0), var1.get(n1), var2.get(n2), cut.value); + break; + } + } + + if (this.monitoring && this.hist && !this.dump_values) { + var now = new Date().getTime(); + if (now - this.lasttm > this.monitoring) { + this.lasttm = now; + JSROOT.CallBack(this.histo_callback, this.hist, this.histo_drawopt, true); + } + } + } + + TDrawSelector.prototype.Terminate = function(res) { + if (res && !this.hist) this.CreateHistogram(); + + this.ShowProgress(); + + return JSROOT.CallBack(this.histo_callback, this.hist, this.dump_values ? "inspect" : this.histo_drawopt); + } + + // ====================================================================== + + JSROOT.IO.FindBrachStreamerElement = function(branch, file) { + // return TStreamerElement associated with the branch - if any + // unfortunately, branch.fID is not number of element in streamer info + + if (!branch || !file || (branch._typename!=="TBranchElement") || (branch.fID<0) || (branch.fStreamerType<0)) return null; + + var s_i = file.FindStreamerInfo(branch.fClassName, branch.fClassVersion, branch.fCheckSum), + arr = (s_i && s_i.fElements) ? s_i.fElements.arr : null; + if (!arr) return null; + + var match_name = branch.fName, + pos = match_name.indexOf("["); + if (pos>0) match_name = match_name.substr(0, pos); + pos = match_name.lastIndexOf("."); + if (pos>0) match_name = match_name.substr(pos+1); + + function match_elem(elem) { + if (!elem) return false; + if (elem.fName !== match_name) return false; + if (elem.fType === branch.fStreamerType) return true; + if ((elem.fType === JSROOT.IO.kBool) && (branch.fStreamerType === JSROOT.IO.kUChar)) return true; + if (((branch.fStreamerType===JSROOT.IO.kSTL) || (branch.fStreamerType===JSROOT.IO.kSTL + JSROOT.IO.kOffsetL) || + (branch.fStreamerType===JSROOT.IO.kSTLp) || (branch.fStreamerType===JSROOT.IO.kSTLp + JSROOT.IO.kOffsetL)) + && (elem.fType === JSROOT.IO.kStreamer)) return true; + console.warn('Should match element', elem.fType, 'with branch', branch.fStreamerType); + return false; + } + + // first check branch fID - in many cases gut guess + if (match_elem(arr[branch.fID])) return arr[branch.fID]; + + // console.warn('Missmatch with branch name and extracted element', branch.fName, match_name, (s_elem ? s_elem.fName : "---")); + + for (var k=0;k<arr.length;++k) + if ((k!==branch.fID) && match_elem(arr[k])) return arr[k]; + + console.error('Did not found/match element for branch', branch.fName, 'class', branch.fClassName); + + return null; + } + + + JSROOT.IO.DefineMemberTypeName = function(file, parent_class, member_name) { + // return type name of given member in the class + + var s_i = file.FindStreamerInfo(parent_class), + arr = (s_i && s_i.fElements) ? s_i.fElements.arr : null, + elem = null; + if (!arr) return ""; + + for (var k=0;k<arr.length;++k) { + if (arr[k].fTypeName === "BASE") { + var res = JSROOT.IO.DefineMemberTypeName(file, arr[k].fName, member_name); + if (res) return res; + } else + if (arr[k].fName === member_name) { elem = arr[k]; break; } + } + + if (!elem) return ""; + + var clname = elem.fTypeName; + if (clname[clname.length-1]==="*") clname = clname.substr(0, clname.length-1); + + return clname; + } + + JSROOT.IO.GetBranchObjectClass = function(branch, tree, with_clones, with_leafs) { + // return class name of the object, stored in the branch + + if (!branch || (branch._typename!=="TBranchElement")) return ""; + + if ((branch.fType === JSROOT.BranchType.kLeafNode) && (branch.fID===-2) && (branch.fStreamerType===-1)) { + // object where all sub-branches will be collected + return branch.fClassName; + } + + if (with_clones && branch.fClonesName && ((branch.fType === JSROOT.BranchType.kClonesNode) || (branch.fType === JSROOT.BranchType.kSTLNode))) + return branch.fClonesName; + + var s_elem = JSROOT.IO.FindBrachStreamerElement(branch, tree.$file); + + if ((branch.fType === JSROOT.BranchType.kBaseClassNode) && s_elem && (s_elem.fTypeName==="BASE")) + return s_elem.fName; + + if (branch.fType === JSROOT.BranchType.kObjectNode) { + if (s_elem && ((s_elem.fType === JSROOT.IO.kObject) || (s_elem.fType === JSROOT.IO.kAny))) + return s_elem.fTypeName; + return "TObject"; + } + + if ((branch.fType === JSROOT.BranchType.kLeafNode) && s_elem && with_leafs) { + if ((s_elem.fType === JSROOT.IO.kObject) || (s_elem.fType === JSROOT.IO.kAny)) return s_elem.fTypeName; + if (s_elem.fType === JSROOT.IO.kObjectp) return s_elem.fTypeName.substr(0, s_elem.fTypeName.length-1); + } + + return ""; + } + + JSROOT.IO.MakeMethodsList = function(typename) { + // create fast list to assign all methods to the object + + var methods = JSROOT.getMethods(typename); + + var res = { + names : [], + values : [], + Create : function() { + var obj = {}; + for (var n=0;n<this.names.length;++n) + obj[this.names[n]] = this.values[n]; + return obj; + } + } + + res.names.push("_typename"); res.values.push(typename); + for (var key in methods) { + res.names.push(key); + res.values.push(methods[key]); + } + return res; + } + + JSROOT.IO.DetectBranchMemberClass = function(brlst, prefix, start) { + // try to define classname for the branch member, scanning list of branches + var clname = ""; + for (var kk=(start || 0); kk<brlst.arr.length; ++kk) + if ((brlst.arr[kk].fName.indexOf(prefix)===0) && brlst.arr[kk].fClassName) clname = brlst.arr[kk].fClassName; + return clname; + } + + /** @namespace JSROOT.TreeMethods + * @summary these are TTree methods, which are automatically assigned to every TTree */ + JSROOT.TreeMethods = {}; + + /** @summary Process selector + * @param {object} selector - instance of JSROOT.TSelector class + * @param {object} args - different arguments */ + JSROOT.TreeMethods.Process = function(selector, args) { + // function similar to the TTree::Process + + if (!args) args = {}; + + if (!selector || !this.$file || !selector.branches) { + console.error('required parameter missing for TTree::Process'); + if (selector) selector.Terminate(false); + return false; + } + + // central handle with all information required for reading + var handle = { + tree: this, // keep tree reference + file: this.$file, // keep file reference + selector: selector, // reference on selector + arr: [], // list of branches + curr: -1, // current entry ID + current_entry: -1, // current processed entry + simple_read: true, // all baskets in all used branches are in sync, + process_arrays: true // one can process all branches as arrays + }; + + var namecnt = 0; + + function CreateLeafElem(leaf, name) { + // function creates TStreamerElement which corresponds to the elementary leaf + var datakind = 0; + switch (leaf._typename) { + case 'TLeafF': datakind = JSROOT.IO.kFloat; break; + case 'TLeafD': datakind = JSROOT.IO.kDouble; break; + case 'TLeafO': datakind = JSROOT.IO.kBool; break; + case 'TLeafB': datakind = leaf.fIsUnsigned ? JSROOT.IO.kUChar : JSROOT.IO.kChar; break; + case 'TLeafS': datakind = leaf.fIsUnsigned ? JSROOT.IO.kUShort : JSROOT.IO.kShort; break; + case 'TLeafI': datakind = leaf.fIsUnsigned ? JSROOT.IO.kUInt : JSROOT.IO.kInt; break; + case 'TLeafL': datakind = leaf.fIsUnsigned ? JSROOT.IO.kULong64 : JSROOT.IO.kLong64; break; + case 'TLeafC': datakind = JSROOT.IO.kTString; break; // datakind = leaf.fIsUnsigned ? JSROOT.IO.kUChar : JSROOT.IO.kChar; break; + default: return null; + } + return JSROOT.IO.CreateStreamerElement(name || leaf.fName, datakind); + } + + function FindInHandle(branch) { + for (var k=0;k<handle.arr.length;++k) + if (handle.arr[k].branch === branch) return handle.arr[k]; + return null; + } + + function AddBranchForReading(branch, target_object, target_name, read_mode) { + // central method to add branch for reading + // read_mode == true - read only this branch + // read_mode == '$child$' is just member of object from for STL or clonesarray + // read_mode == '<any class name>' is sub-object from STL or clonesarray, happens when such new object need to be created + // read_mode == '.member_name' select only reading of member_name instead of complete object + + if (typeof branch === 'string') + branch = handle.tree.FindBranch(branch); + + if (!branch) { console.error('Did not found branch'); return null; } + + var item = FindInHandle(branch); + + if (item) { + console.error('Branch already configured for reading', branch.fName); + if (item.tgt !== target_object) console.error('Target object differs'); + return elem; + } + + if (!branch.fEntries) { + console.warn('Branch ', branch.fName, ' does not have entries'); + return null; + } + + // console.log('Add branch', branch.fName); + + item = { + branch: branch, + tgt: target_object, // used target object - can be differ for object members + name: target_name, + index: -1, // index in the list of read branches + member: null, // member to read branch + type: 0, // keep type identifier + curr_entry: -1, // last processed entry + raw : null, // raw buffer for reading + basket : null, // current basket object + curr_basket: 0, // number of basket used for processing + read_entry: -1, // last entry which is already read + staged_entry: -1, // entry which is staged for reading + first_readentry: -1, // first entry to read + staged_basket: 0, // last basket staged for reading + numentries: branch.fEntries, + numbaskets: branch.fWriteBasket, // number of baskets which can be read from the file + counters: null, // branch indexes used as counters + ascounter: [], // list of other branches using that branch as counter + baskets: [], // array for read baskets, + staged_prev: 0, // entry limit of previous I/O request + staged_now: 0, // entry limit of current I/O request + progress_showtm: 0, // last time when progress was showed + GetBasketEntry: function(k) { + if (!this.branch || (k > this.branch.fMaxBaskets)) return 0; + var res = (k < this.branch.fMaxBaskets) ? this.branch.fBasketEntry[k] : 0; + if (res) return res; + var bskt = (k>0) ? this.branch.fBaskets.arr[k-1] : null; + return bskt ? (this.branch.fBasketEntry[k-1] + bskt.fNevBuf) : 0; + }, + GetTarget: function(tgtobj) { + // returns target object which should be used for the branch reading + if (!this.tgt) return tgtobj; + for (var k=0;k<this.tgt.length;++k) { + var sub = this.tgt[k]; + if (!tgtobj[sub.name]) tgtobj[sub.name] = sub.lst.Create(); + tgtobj = tgtobj[sub.name]; + } + return tgtobj; + }, + GetEntry: function(entry) { + // This should be equivalent to TBranch::GetEntry() method + var shift = entry - this.first_entry, off; + if (!this.branch.TestBit(JSROOT.IO.BranchBits.kDoNotUseBufferMap)) + this.raw.ClearObjectMap(); + if (this.basket.fEntryOffset) { + off = this.basket.fEntryOffset[shift]; + if (this.basket.fDisplacement) + this.raw.fDisplacement = this.basket.fDisplacement[shift]; + } else { + off = this.basket.fKeylen + this.basket.fNevBufSize * shift; + } + this.raw.locate(off - this.raw.raw_shift); + + // this.member.func(this.raw, this.GetTarget(tgtobj)); + } + }; + + // last basket can be stored directly with the branch + while (item.GetBasketEntry(item.numbaskets+1)) item.numbaskets++; + + // check all counters if we + var nb_branches = branch.fBranches ? branch.fBranches.arr.length : 0, + nb_leaves = branch.fLeaves ? branch.fLeaves.arr.length : 0, + leaf = (nb_leaves>0) ? branch.fLeaves.arr[0] : null, + elem = null, // TStreamerElement used to create reader + member = null, // member for actual reading of the branch + is_brelem = (branch._typename==="TBranchElement"), + child_scan = 0, // scan child branches after main branch is appended + item_cnt = null, item_cnt2 = null, object_class = ""; + + if (branch.fBranchCount) { + + item_cnt = FindInHandle(branch.fBranchCount); + + if (!item_cnt) + item_cnt = AddBranchForReading(branch.fBranchCount, target_object, "$counter" + namecnt++, true); + + if (!item_cnt) { console.error('Cannot add counter branch', branch.fBranchCount.fName); return null; } + + var BranchCount2 = branch.fBranchCount2; + + if (!BranchCount2 && (branch.fBranchCount.fStreamerType===JSROOT.IO.kSTL) && + ((branch.fStreamerType === JSROOT.IO.kStreamLoop) || (branch.fStreamerType === JSROOT.IO.kOffsetL+JSROOT.IO.kStreamLoop))) { + // special case when count member from kStreamLoop not assigned as fBranchCount2 + var elemd = JSROOT.IO.FindBrachStreamerElement(branch, handle.file), + arrd = branch.fBranchCount.fBranches.arr; + + if (elemd && elemd.fCountName && arrd) + for(var k=0;k<arrd.length;++k) + if (arrd[k].fName === branch.fBranchCount.fName + "." + elemd.fCountName) { + BranchCount2 = arrd[k]; + break; + } + + if (!BranchCount2) console.error('Did not found branch for second counter of kStreamLoop element'); + } + + if (BranchCount2) { + item_cnt2 = FindInHandle(BranchCount2); + + if (!item_cnt2) item_cnt2 = AddBranchForReading(BranchCount2, target_object, "$counter" + namecnt++, true); + + if (!item_cnt2) { console.error('Cannot add counter branch2', BranchCount2.fName); return null; } + } + } else + if (nb_leaves===1 && leaf && leaf.fLeafCount) { + var br_cnt = handle.tree.FindBranch(leaf.fLeafCount.fName); + + if (br_cnt) { + item_cnt = FindInHandle(br_cnt); + + if (!item_cnt) item_cnt = AddBranchForReading(br_cnt, target_object, "$counter" + namecnt++, true); + + if (!item_cnt) { console.error('Cannot add counter branch', br_cnt.fName); return null; } + } + } + + function ScanBranches(lst, master_target, chld_kind) { + if (!lst || !lst.arr.length) return true; + + var match_prefix = branch.fName; + if (match_prefix[match_prefix.length-1] === ".") match_prefix = match_prefix.substr(0,match_prefix.length-1); + if ((typeof read_mode=== "string") && (read_mode[0]==".")) match_prefix += read_mode; + match_prefix+="."; + + for (var k=0;k<lst.arr.length;++k) { + var br = lst.arr[k]; + if ((chld_kind>0) && (br.fType!==chld_kind)) continue; + + if (br.fType === JSROOT.BranchType.kBaseClassNode) { + if (!ScanBranches(br.fBranches, master_target, chld_kind)) return false; + continue; + } + + var elem = JSROOT.IO.FindBrachStreamerElement(br, handle.file); + if (elem && (elem.fTypeName==="BASE")) { + // if branch is data of base class, map it to original target + if (br.fTotBytes && !AddBranchForReading(br, target_object, target_name, read_mode)) return false; + if (!ScanBranches(br.fBranches, master_target, chld_kind)) return false; + continue; + } + + var subname = br.fName, chld_direct = 1; + + if (br.fName.indexOf(match_prefix)===0) { + subname = subname.substr(match_prefix.length); + } else { + if (chld_kind>0) continue; // for defined children names prefix must be present + } + + var p = subname.indexOf('['); + if (p>0) subname = subname.substr(0,p); + p = subname.indexOf('<'); + if (p>0) subname = subname.substr(0,p); + + if (chld_kind > 0) { + chld_direct = "$child$"; + var pp = subname.indexOf("."); + if (pp>0) chld_direct = JSROOT.IO.DetectBranchMemberClass(lst, branch.fName + "." + subname.substr(0,pp+1), k) || "TObject"; + } + + if (!AddBranchForReading(br, master_target, subname, chld_direct)) return false; + } + + return true; + } + + if (branch._typename === "TBranchObject") { + member = { + name: target_name, + typename: branch.fClassName, + virtual: leaf.fVirtual, + func: function(buf,obj) { + var clname = this.typename; + if (this.virtual) clname = buf.ReadFastString(buf.ntou1()+1); + obj[this.name] = buf.ClassStreamer({}, clname); + } + }; + } else + + if ((branch.fType === JSROOT.BranchType.kClonesNode) || (branch.fType === JSROOT.BranchType.kSTLNode)) { + + elem = JSROOT.IO.CreateStreamerElement(target_name, JSROOT.IO.kInt); + + if (!read_mode || ((typeof read_mode==="string") && (read_mode[0]===".")) || (read_mode===1)) { + handle.process_arrays = false; + + member = { + name: target_name, + conttype: branch.fClonesName || "TObject", + reallocate: args.reallocate_objects, + func: function(buf,obj) { + var size = buf.ntoi4(), n = 0; + if (!obj[this.name] || this.reallocate) { + obj[this.name] = new Array(size); + } else { + n = obj[this.name].length; + obj[this.name].length = size; // reallocate array + } + + while (n<size) obj[this.name][n++] = this.methods.Create(); // create new objects + } + } + + if ((typeof read_mode==="string") && (read_mode[0]===".")) { + member.conttype = JSROOT.IO.DetectBranchMemberClass(branch.fBranches, branch.fName+read_mode); + if (!member.conttype) { + console.error('Cannot select object', read_mode, "in the branch", branch.fName); + return null; + } + } + + member.methods = JSROOT.IO.MakeMethodsList(member.conttype); + + child_scan = (branch.fType === JSROOT.BranchType.kClonesNode) ? JSROOT.BranchType.kClonesMemberNode : JSROOT.BranchType.kSTLMemberNode; + } + } else + + if ((object_class = JSROOT.IO.GetBranchObjectClass(branch, handle.tree))) { + + if (read_mode === true) { + console.warn('Object branch ' + object_class + ' can not have data to be read directly'); + return null; + } + + handle.process_arrays = false; + + var newtgt = new Array(target_object ? (target_object.length + 1) : 1); + for (var l=0;l<newtgt.length-1;++l) newtgt[l] = target_object[l]; + newtgt[newtgt.length-1] = { name: target_name, lst: JSROOT.IO.MakeMethodsList(object_class) }; + + if (!ScanBranches(branch.fBranches, newtgt, 0)) return null; + + return item; // this kind of branch does not have baskets and not need to be read + + } else if (is_brelem && (nb_leaves === 1) && (leaf.fName === branch.fName) && (branch.fID==-1)) { + + elem = JSROOT.IO.CreateStreamerElement(target_name, branch.fClassName); + + if (elem.fType === JSROOT.IO.kAny) { + + var streamer = handle.file.GetStreamer(branch.fClassName, { val: branch.fClassVersion, checksum: branch.fCheckSum }); + if (!streamer) { elem = null; console.warn('not found streamer!'); } else + member = { + name: target_name, + typename: branch.fClassName, + streamer: streamer, + func: function(buf,obj) { + var res = { _typename: this.typename }; + for (var n = 0; n < this.streamer.length; ++n) + this.streamer[n].func(buf, res); + obj[this.name] = res; + } + }; + } + + // elem.fType = JSROOT.IO.kAnyP; + + // only STL containers here + // if (!elem.fSTLtype) elem = null; + } else if (is_brelem && (nb_leaves <= 1)) { + + elem = JSROOT.IO.FindBrachStreamerElement(branch, handle.file); + + // this is basic type - can try to solve problem differently + if (!elem && branch.fStreamerType && (branch.fStreamerType < 20)) + elem = JSROOT.IO.CreateStreamerElement(target_name, branch.fStreamerType); + + } else if (nb_leaves === 1) { + // no special constrains for the leaf names + + elem = CreateLeafElem(leaf, target_name); + + } else if ((branch._typename === "TBranch") && (nb_leaves > 1)) { + // branch with many elementary leaves + + var arr = new Array(nb_leaves), isok = true; + for (var l=0;l<nb_leaves;++l) { + arr[l] = CreateLeafElem(branch.fLeaves.arr[l]); + arr[l] = JSROOT.IO.CreateMember(arr[l], handle.file); + if (!arr[l]) isok = false; + } + + if (isok) + member = { + name: target_name, + leaves: arr, + func: function(buf, obj) { + var tgt = obj[this.name], l = 0; + if (!tgt) obj[this.name] = tgt = {}; + while (l<this.leaves.length) + this.leaves[l++].func(buf,tgt); + } + } + } + + if (!elem && !member) { + console.warn('Not supported branch kind', branch.fName, branch._typename); + return null; + } + + if (!member) { + member = JSROOT.IO.CreateMember(elem, handle.file); + + if ((member.base !== undefined) && member.basename) { + // when element represent base class, we need handling which differ from normal IO + member.func = function(buf, obj) { + if (!obj[this.name]) obj[this.name] = { _typename: this.basename }; + buf.ClassStreamer(obj[this.name], this.basename); + }; + } + } + + if (item_cnt && (typeof read_mode === "string")) { + + member.name0 = item_cnt.name; + + var snames = target_name.split("."); + + if (snames.length === 1) { + // no point in the name - just plain array of objects + member.get = function(arr,n) { return arr[n]; } + } else if (read_mode === "$child$") { + console.error('target name contains point, but suppose to be direct child', target_name); + return null; + } else if (snames.length === 2) { + target_name = member.name = snames[1]; + member.name1 = snames[0]; + member.subtype1 = read_mode; + member.methods1 = JSROOT.IO.MakeMethodsList(member.subtype1); + member.get = function(arr,n) { + var obj1 = arr[n][this.name1]; + if (!obj1) obj1 = arr[n][this.name1] = this.methods1.Create(); + return obj1; + } + } else { + // very complex task - we need to reconstruct several embedded members with their types + // try our best - but not all data types can be reconstructed correctly + // while classname is not enough - there can be different versions + + if (!branch.fParentName) { + console.error('Not possible to provide more than 2 parts in the target name', target_name); + return null; + } + + target_name = member.name = snames.pop(); // use last element + member.snames = snames; // remember all sub-names + member.smethods = []; // and special handles to create missing objects + + var parent_class = branch.fParentName; // unfortunately, without version + + for (var k=0;k<snames.length;++k) { + var chld_class = JSROOT.IO.DefineMemberTypeName(handle.file, parent_class, snames[k]); + member.smethods[k] = JSROOT.IO.MakeMethodsList(chld_class || "AbstractClass"); + parent_class = chld_class; + } + member.get = function(arr,n) { + var obj1 = arr[n][this.snames[0]]; + if (!obj1) obj1 = arr[n][this.snames[0]] = this.smethods[0].Create(); + for (var k=1;k<this.snames.length;++k) { + var obj2 = obj1[this.snames[k]]; + if (!obj2) obj2 = obj1[this.snames[k]] = this.smethods[k].Create(); + obj1 = obj2; + } + return obj1; + } + } + + // case when target is sub-object and need to be created before + + + if (member.objs_branch_func) { + // STL branch provides special function for the reading + member.func = member.objs_branch_func; + } else { + member.func0 = member.func; + + member.func = function(buf,obj) { + var arr = obj[this.name0], n = 0; // objects array where reading is done + while(n<arr.length) + this.func0(buf,this.get(arr,n++)); // read all individual object with standard functions + } + } + + } else if (item_cnt) { + + handle.process_arrays = false; + + if ((elem.fType === JSROOT.IO.kDouble32) || (elem.fType === JSROOT.IO.kFloat16)) { + // special handling for compressed floats + + member.stl_size = item_cnt.name; + member.func = function(buf, obj) { + obj[this.name] = this.readarr(buf, obj[this.stl_size]); + } + + } else + if (((elem.fType === JSROOT.IO.kOffsetP+JSROOT.IO.kDouble32) || (elem.fType === JSROOT.IO.kOffsetP+JSROOT.IO.kFloat16)) && branch.fBranchCount2) { + // special handling for variable arrays of compressed floats in branch - not tested + + member.stl_size = item_cnt.name; + member.arr_size = item_cnt2.name; + member.func = function(buf, obj) { + var sz0 = obj[this.stl_size], sz1 = obj[this.arr_size], arr = new Array(sz0); + for (var n=0;n<sz0;++n) + arr[n] = (buf.ntou1() === 1) ? this.readarr(buf, sz1[n]) : []; + obj[this.name] = arr; + } + + } else + // special handling of simple arrays + if (((elem.fType > 0) && (elem.fType < JSROOT.IO.kOffsetL)) || (elem.fType === JSROOT.IO.kTString) || + (((elem.fType > JSROOT.IO.kOffsetP) && (elem.fType < JSROOT.IO.kOffsetP + JSROOT.IO.kOffsetL)) && branch.fBranchCount2)) { + + member = { + name: target_name, + stl_size: item_cnt.name, + type: elem.fType, + func: function(buf, obj) { + obj[this.name] = buf.ReadFastArray(obj[this.stl_size], this.type); + } + }; + + if (branch.fBranchCount2) { + member.type -= JSROOT.IO.kOffsetP; + member.arr_size = item_cnt2.name; + member.func = function(buf, obj) { + var sz0 = obj[this.stl_size], sz1 = obj[this.arr_size], arr = new Array(sz0); + for (var n=0;n<sz0;++n) + arr[n] = (buf.ntou1() === 1) ? buf.ReadFastArray(sz1[n], this.type) : []; + obj[this.name] = arr; + } + } + + } else + if ((elem.fType > JSROOT.IO.kOffsetP) && (elem.fType < JSROOT.IO.kOffsetP + JSROOT.IO.kOffsetL) && member.cntname) { + + member.cntname = item_cnt.name; + } else + if (elem.fType == JSROOT.IO.kStreamer) { + // with streamers one need to extend existing array + + if (item_cnt2) + throw new Error('Second branch counter not supported yet with JSROOT.IO.kStreamer'); + + // function provided by normal I/O + member.func = member.branch_func; + member.stl_size = item_cnt.name; + } else + if ((elem.fType === JSROOT.IO.kStreamLoop) || (elem.fType === JSROOT.IO.kOffsetL+JSROOT.IO.kStreamLoop)) { + if (item_cnt2) { + // special solution for kStreamLoop + member.stl_size = item_cnt.name; + member.cntname = item_cnt2.name; + member.func = member.branch_func; // this is special function, provided by base I/O + } else { + member.cntname = item_cnt.name; + } + } else { + + member.name = "$stl_member"; + + var loop_size_name; + + if (item_cnt2) { + if (member.cntname) { + loop_size_name = item_cnt2.name; + member.cntname = "$loop_size"; + } else { + throw new Error('Second branch counter not used - very BAD'); + } + } + + var stlmember = { + name: target_name, + stl_size: item_cnt.name, + loop_size: loop_size_name, + member0: member, + func: function(buf, obj) { + var cnt = obj[this.stl_size], arr = new Array(cnt), n = 0; + for (var n=0;n<cnt;++n) { + if (this.loop_size) obj.$loop_size = obj[this.loop_size][n]; + this.member0.func(buf, obj); + arr[n] = obj.$stl_member; + } + delete obj.$stl_member; + delete obj.$loop_size; + obj[this.name] = arr; + } + }; + + member = stlmember; + } + } + + // set name used to store result + member.name = target_name; + + item.member = member; // member for reading + if (elem) item.type = elem.fType; + item.index = handle.arr.length; // index in the global list of branches + + if (item_cnt) { + item.counters = [ item_cnt.index ]; + item_cnt.ascounter.push(item.index); + + if (item_cnt2) { + item.counters.push(item_cnt2.index); + item_cnt2.ascounter.push(item.index); + } + } + + handle.arr.push(item); + + // now one should add all other child branches + if (child_scan) + if (!ScanBranches(branch.fBranches, target_object, child_scan)) return null; + + return item; + } + + // main loop to add all branches from selector for reading + for (var nn=0; nn<selector.branches.length; ++nn) { + + var item = AddBranchForReading(selector.branches[nn], undefined, selector.names[nn], selector.directs[nn]); + + if (!item) { + selector.Terminate(false); + return false; + } + } + + // check if simple reading can be performed and there are direct data in branch + + for (var h=1; (h < handle.arr.length) && handle.simple_read; ++h) { + + var item = handle.arr[h], item0 = handle.arr[0]; + + if ((item.numentries !== item0.numentries) || (item.numbaskets !== item0.numbaskets)) handle.simple_read = false; + for (var n=0;n<item.numbaskets;++n) + if (item.GetBasketEntry(n) !== item0.GetBasketEntry(n)) handle.simple_read = false; + } + + // now calculate entries range + + handle.firstentry = handle.lastentry = 0; + for (var nn = 0; nn < handle.arr.length; ++nn) { + var branch = handle.arr[nn].branch, e1 = branch.fFirstEntry; + if (e1 === undefined) e1 = (branch.fBasketBytes[0] ? branch.fBasketEntry[0] : 0); + handle.firstentry = Math.max(handle.firstentry, e1); + handle.lastentry = (nn===0) ? (e1 + branch.fEntries) : Math.min(handle.lastentry, e1 + branch.fEntries); + } + + if (handle.firstentry >= handle.lastentry) { + console.warn('No any common events for selected branches'); + selector.Terminate(false); + return false; + } + + handle.process_min = handle.firstentry; + handle.process_max = handle.lastentry; + + if (!isNaN(args.firstentry) && (args.firstentry>handle.firstentry) && (args.firstentry < handle.lastentry)) + handle.process_min = args.firstentry; + + handle.current_entry = handle.staged_now = handle.process_min; + + if (!isNaN(args.numentries) && (args.numentries>0)) { + var max = handle.process_min + args.numentries; + if (max<handle.process_max) handle.process_max = max; + } + + if ((typeof selector.ProcessArrays === 'function') && handle.simple_read) { + // this is indication that selector can process arrays of values + // only strictly-matched tree structure can be used for that + + for (var k=0;k<handle.arr.length;++k) { + var elem = handle.arr[k]; + if ((elem.type<=0) || (elem.type >= JSROOT.IO.kOffsetL) || (elem.type === JSROOT.IO.kCharStar)) handle.process_arrays = false; + } + + if (handle.process_arrays) { + // create other members for fast processing + + selector.tgtarr = {}; // object with arrays + + for(var nn=0;nn<handle.arr.length;++nn) { + var item = handle.arr[nn], + elem = JSROOT.IO.CreateStreamerElement(item.name, item.type); + + elem.fType = item.type + JSROOT.IO.kOffsetL; + elem.fArrayLength = 10; + elem.fArrayDim = 1; + elem.fMaxIndex[0] = 10; // 10 if artificial number, will be replaced during reading + + item.arrmember = JSROOT.IO.CreateMember(elem, handle.file); + } + } + } else { + handle.process_arrays = false; + } + + function ReadBaskets(bitems, baskets_call_back) { + // read basket with tree data, selecting different files + + var places = [], filename = ""; + + function ExtractPlaces() { + // extract places to read and define file name + + places = []; filename = ""; + + for (var n=0;n<bitems.length;++n) { + if (bitems[n].done) continue; + + var branch = bitems[n].branch; + + if (places.length===0) + filename = branch.fFileName; + else + if (filename !== branch.fFileName) continue; + + bitems[n].selected = true; // mark which item was selected for reading + + places.push(branch.fBasketSeek[bitems[n].basket], branch.fBasketBytes[bitems[n].basket]); + } + + return places.length > 0; + } + + function ReadProgress(value) { + + if ((handle.staged_prev === handle.staged_now) || + (handle.process_max <= handle.process_min)) return; + + var tm = new Date().getTime(); + + if (tm - handle.progress_showtm < 500) return; // no need to show very often + + handle.progress_showtm = tm; + + var portion = (handle.staged_prev + value * (handle.staged_now - handle.staged_prev)) / + (handle.process_max - handle.process_min); + + handle.selector.ShowProgress(portion); + } + + function ProcessBlobs(blobs) { + if (!blobs || ((places.length>2) && (blobs.length*2 !== places.length))) + return JSROOT.CallBack(baskets_call_back, null); + + var baskets = [], n = 0; + + for (var k=0;k<bitems.length;++k) { + if (!bitems[k].selected) continue; + + bitems[k].selected = false; + bitems[k].done = true; + + var blob = (places.length > 2) ? blobs[n++] : blobs, + buf = JSROOT.CreateTBuffer(blob, 0, handle.file), + basket = buf.ClassStreamer({}, "TBasket"); + + if (basket.fNbytes !== bitems[k].branch.fBasketBytes[bitems[k].basket]) + console.error('mismatch in read basket sizes', bitems[k].branch.fBasketBytes[bitems[k].basket]); + + // items[k].obj = basket; // keep basket object itself if necessary + + bitems[k].bskt_obj = basket; // only number of entries in the basket are relevant for the moment + + if (basket.fKeylen + basket.fObjlen === basket.fNbytes) { + // use data from original blob + buf.raw_shift = 0; + } else { + // unpack data and create new blob + var objblob = JSROOT.R__unzip(blob, basket.fObjlen, false, buf.o); + + if (objblob) { + buf = JSROOT.CreateTBuffer(objblob, 0, handle.file); + buf.raw_shift = basket.fKeylen; + buf.fTagOffset = basket.fKeylen; + } else { + throw new Error('FAIL TO UNPACK'); + } + } + + bitems[k].raw = buf; // here already unpacked buffer + + if (bitems[k].branch.fEntryOffsetLen > 0) + buf.ReadBasketEntryOffset(basket, buf.raw_shift); + } + + if (ExtractPlaces()) + handle.file.ReadBuffer(places, ProcessBlobs, filename, ReadProgress); + else + JSROOT.CallBack(baskets_call_back, bitems); + } + + // extract places where to read + if (ExtractPlaces()) + handle.file.ReadBuffer(places, ProcessBlobs, filename, ReadProgress); + else + JSROOT.CallBack(baskets_call_back, null); + } + + function ReadNextBaskets() { + + var totalsz = 0, bitems = [], isany = true, is_direct = false, min_staged = handle.process_max; + + while ((totalsz < 1e6) && isany) { + isany = false; + // very important, loop over branches in reverse order + // let check counter branch after reading of normal branch is prepared + for (var n=handle.arr.length-1; n>=0; --n) { + var elem = handle.arr[n]; + + while (elem.staged_basket < elem.numbaskets) { + + var k = elem.staged_basket++; + + // no need to read more baskets, process_max is not included + if (elem.GetBasketEntry(k) >= handle.process_max) break; + + // check which baskets need to be read + if (elem.first_readentry < 0) { + var lmt = elem.GetBasketEntry(k+1), + not_needed = (lmt <= handle.process_min); + + //for (var d=0;d<elem.ascounter.length;++d) { + // var dep = handle.arr[elem.ascounter[d]]; // dependent element + // if (dep.first_readentry < lmt) not_needed = false; // check that counter provide required data + //} + + if (not_needed) continue; // if that basket not required, check next + + elem.curr_basket = k; // basket where reading will start + + elem.first_readentry = elem.GetBasketEntry(k); // remember which entry will be read first + } + + // check if basket already loaded in the branch + + var bitem = { + id: n, // to find which element we are reading + branch: elem.branch, + basket: k, + raw: null // here should be result + }; + + var bskt = elem.branch.fBaskets.arr[k]; + if (bskt) { + bitem.raw = bskt.fBufferRef; + if (bitem.raw) + bitem.raw.locate(0); // reset pointer - same branch may be read several times + else + bitem.raw = JSROOT.CreateTBuffer(null, 0, handle.file); // create dummy buffer - basket has no data + bitem.raw.raw_shift = bskt.fKeylen; + + if (bskt.fBufferRef && (elem.branch.fEntryOffsetLen > 0)) + bitem.raw.ReadBasketEntryOffset(bskt, bitem.raw.raw_shift); + + bitem.bskt_obj = bskt; + is_direct = true; + elem.baskets[k] = bitem; + } else { + bitems.push(bitem); + totalsz += elem.branch.fBasketBytes[k]; + isany = true; + } + + elem.staged_entry = elem.GetBasketEntry(k+1); + + min_staged = Math.min(min_staged, elem.staged_entry); + + break; + } + } + } + + if ((totalsz === 0) && !is_direct) + return handle.selector.Terminate(true); + + handle.staged_prev = handle.staged_now; + handle.staged_now = min_staged; + + var portion = 0; + if (handle.process_max > handle.process_min) + portion = (handle.staged_prev - handle.process_min)/ (handle.process_max - handle.process_min); + + handle.selector.ShowProgress(portion); + + handle.progress_showtm = new Date().getTime(); + + if (totalsz > 0) return ReadBaskets(bitems, ProcessBaskets); + + if (is_direct) return ProcessBaskets([]); // directly process baskets + + throw new Error("No any data is requested - never come here"); + } + + function ProcessBaskets(bitems) { + // this is call-back when next baskets are read + + if ((handle.selector.break_execution !== 0) || (bitems===null)) + return handle.selector.Terminate(false); + + // redistribute read baskets over branches + for(var n=0;n<bitems.length;++n) + handle.arr[bitems[n].id].baskets[bitems[n].basket] = bitems[n]; + + // now process baskets + + var isanyprocessed = false; + + while(true) { + + var loopentries = 100000000, min_curr = handle.process_max, n, elem; + + // first loop used to check if all required data exists + for (n=0;n<handle.arr.length;++n) { + + elem = handle.arr[n]; + + if (!elem.raw || !elem.basket || (elem.first_entry + elem.basket.fNevBuf <= handle.current_entry)) { + delete elem.raw; + delete elem.basket; + + if ((elem.curr_basket >= elem.numbaskets)) { + if (n==0) return handle.selector.Terminate(true); + continue; // ignore non-master branch + } + + // this is single response from the tree, includes branch, bakset number, raw data + var bitem = elem.baskets[elem.curr_basket]; + + // basket not read + if (!bitem) { + // no data, but no any event processed - problem + if (!isanyprocessed) { + console.warn('no data?', elem.branch.fName, elem.curr_basket); + return handle.selector.Terminate(false); + } + + // try to read next portion of tree data + return ReadNextBaskets(); + } + + elem.raw = bitem.raw; + elem.basket = bitem.bskt_obj; + // elem.nev = bitem.fNevBuf; // number of entries in raw buffer + elem.first_entry = elem.GetBasketEntry(bitem.basket); + + bitem.raw = null; // remove reference on raw buffer + bitem.branch = null; // remove reference on the branch + bitem.bskt_obj = null; // remove reference on the branch + elem.baskets[elem.curr_basket++] = undefined; // remove from array + } + + // define how much entries can be processed before next raw buffer will be finished + loopentries = Math.min(loopentries, elem.first_entry + elem.basket.fNevBuf - handle.current_entry); + } + + // second loop extracts all required data + + // do not read too much + if (handle.current_entry + loopentries > handle.process_max) + loopentries = handle.process_max - handle.current_entry; + + if (handle.process_arrays && (loopentries>1)) { + // special case - read all data from baskets as arrays + + for (n=0;n<handle.arr.length;++n) { + elem = handle.arr[n]; + + elem.GetEntry(handle.current_entry); + + elem.arrmember.arrlength = loopentries; + elem.arrmember.func(elem.raw, handle.selector.tgtarr); + + elem.raw = null; + } + + handle.selector.ProcessArrays(handle.current_entry); + + handle.current_entry += loopentries; + + isanyprocessed = true; + } else + + // main processing loop + while(loopentries--) { + + for (n=0;n<handle.arr.length;++n) { + elem = handle.arr[n]; + + // locate buffer offset at proper place + elem.GetEntry(handle.current_entry); + + elem.member.func(elem.raw, elem.GetTarget(handle.selector.tgtobj)); + } + + handle.selector.Process(handle.current_entry); + + handle.current_entry++; + + isanyprocessed = true; + } + + if (handle.current_entry >= handle.process_max) + return handle.selector.Terminate(true); + } + } + + // call begin before first entry is read + handle.selector.Begin(this); + + ReadNextBaskets(); + + return true; // indicate that reading of tree will be performed + } + + /** @summary Search branch with specified name + * @desc if complex enabled, search branch and rest part + * @private */ + JSROOT.TreeMethods.FindBranch = function(name, complex, lst) { + + var top_search = false, search = name, res = null; + + if (lst===undefined) { + top_search = true; + lst = this.fBranches; + var pos = search.indexOf("["); + if (pos>0) search = search.substr(0,pos); + } + + if (!lst || (lst.arr.length===0)) return null; + + for (var n=0;n<lst.arr.length;++n) { + var brname = lst.arr[n].fName; + if (brname[brname.length-1] == "]") + brname = brname.substr(0, brname.indexOf("[")); + + // special case when branch name includes STL map name + if ((search.indexOf(brname)!==0) && (brname.indexOf("<")>0)) { + var p1 = brname.indexOf("<"), p2 = brname.lastIndexOf(">"); + brname = brname.substr(0, p1) + brname.substr(p2+1); + } + + if (brname === search) { res = { branch: lst.arr[n], rest:"" }; break; } + + if (search.indexOf(brname)!==0) continue; + + // this is a case when branch name is in the begin of the search string + + // check where point is + var pnt = brname.length; + if (brname[pnt-1] === '.') pnt--; + if (search[pnt] !== '.') continue; + + res = this.FindBranch(search, complex, lst.arr[n].fBranches); + if (!res) res = this.FindBranch(search.substr(pnt+1), complex, lst.arr[n].fBranches); + + if (!res) res = { branch: lst.arr[n], rest: search.substr(pnt) }; + + break; + } + + if (!top_search || !res) return res; + + if (name.length > search.length) res.rest += name.substr(search.length); + + if (!complex && (res.rest.length>0)) return null; + + return complex ? res : res.branch; + } + + /** @summary this is JSROOT implementation of TTree::Draw + * @disc in callback returns histogram and draw options + * @param {object} args - different setting or simply draw expression + * @param {string} args.expr - draw expression + * @param {string} [args.cut=undefined] - cut expression (also can be part of 'expr' after '::') + * @param {string} [args.drawopt=undefined] - draw options for result histogram + * @param {number} [args.firstentry=0] - first entry to process + * @param {number} [args.numentries=undefined] - number of entries to process, all by default + * @param {object} [args.branch=undefined] - TBranch object from TTree itself for the direct drawing + * @param {function} result_callback - function called when draw is completed + */ + JSROOT.TreeMethods.Draw = function(args, result_callback) { + + if (typeof args === 'string') args = { expr: args }; + + if (!args.expr) args.expr = ""; + + // special debugging code + if (args.expr === "testio") + return this.IOTest(args, result_callback); + + var selector = new TDrawSelector(result_callback); + + if (args.branch) { + if (!selector.DrawOnlyBranch(this, args.branch, args.expr, args)) selector = null; + } else { + if (!selector.ParseDrawExpression(this, args)) selector = null; + } + + if (!selector) + return JSROOT.CallBack(result_callback, null); + + return this.Process(selector, args); + } + + JSROOT.TreeMethods.IOTest = function(args, result_callback) { + // generic I/O test for all branches in the tree + + if (!args.names && !args.bracnhes) { + + args.branches = []; + args.names = []; + args.nchilds = []; + args.nbr = 0; + + function CollectBranches(obj, prntname) { + if (!obj || !obj.fBranches) return 0; + + var cnt = 0; + + for (var n=0;n<obj.fBranches.arr.length;++n) { + var br = obj.fBranches.arr[n], + name = (prntname ? prntname + "/" : "") + br.fName; + args.branches.push(br); + args.names.push(name); + args.nchilds.push(0); + var pos = args.nchilds.length-1; + cnt += br.fLeaves ? br.fLeaves.arr.length : 0; + var nchld = CollectBranches(br, name); + + cnt += nchld; + args.nchilds[pos] = nchld; + + } + return cnt; + } + + var numleaves = CollectBranches(this); + + args.names.push("Total are " + args.branches.length + " branches with " + numleaves + " leaves"); + } + + args.lasttm = new Date().getTime(); + args.lastnbr = args.nbr; + + var tree = this; + + function TestNextBranch() { + + var selector = new TSelector; + + selector.AddBranch(args.branches[args.nbr], "br0"); + + selector.Process = function() { + if (this.tgtobj.br0 === undefined) + this.fail = true; + } + + selector.Terminate = function(res) { + if (typeof res !== 'string') + res = (!res || this.fails) ? "FAIL" : "ok"; + + args.names[args.nbr] = res + " " + args.names[args.nbr]; + args.nbr++; + + if (args.nbr >= args.branches.length) { + JSROOT.progress(); + return JSROOT.CallBack(result_callback, args.names, "inspect"); + } + + var now = new Date().getTime(); + + if ((now - args.lasttm > 5000) || (args.nbr - args.lastnbr > 50)) + setTimeout(tree.IOTest.bind(tree,args,result_callback), 100); // use timeout to avoid deep recursion + else + TestNextBranch(); + } + + JSROOT.progress("br " + args.nbr + "/" + args.branches.length + " " + args.names[args.nbr]); + + var br = args.branches[args.nbr], + object_class = JSROOT.IO.GetBranchObjectClass(br, tree), + num = br.fEntries, + skip_branch = (!br.fLeaves || (br.fLeaves.arr.length === 0)); + + if (object_class) skip_branch = (args.nchilds[args.nbr]>100); + + // skip_branch = args.nchilds[args.nbr]>1; + + if (skip_branch || (num<=0)) { + // ignore empty branches or objects with too-many subbranch + // if (object_class) console.log('Ignore branch', br.fName, 'class', object_class, 'with', args.nchilds[args.nbr],'subbranches'); + selector.Terminate("ignore"); + } else { + + var drawargs = { numentries: 10 }, + first = br.fFirstEntry || 0, + last = br.fEntryNumber || (first+num); + + if (num < drawargs.numentries) { + drawargs.numentries = num; + } else { + // select randomly first entry to test I/O + drawargs.firstentry = first + Math.round((last-first-drawargs.numentries)*Math.random()); + } + + // keep console output for debug purposes + console.log('test branch', br.fName, 'first', (drawargs.firstentry || 0), "num", drawargs.numentries); + + tree.Process(selector, drawargs); + } + } + + TestNextBranch(); + } + + + JSROOT.TSelector = TSelector; + JSROOT.TDrawVariable = TDrawVariable; + JSROOT.TDrawSelector = TDrawSelector; + + return JSROOT; + +})); diff --git a/js/scripts/ThreeCSG.js b/js/scripts/ThreeCSG.js new file mode 100644 index 00000000000..c83942fa8bb --- /dev/null +++ b/js/scripts/ThreeCSG.js @@ -0,0 +1,905 @@ +(function( factory ) { + if ( typeof define === "function" && define.amd ) { + define( [ 'threejs' ], factory ); + } else + if (typeof exports === 'object' && typeof module !== 'undefined') { + factory(require("./three.min.js"), exports); + } else { + + if (typeof THREE == 'undefined') + throw new Error('THREE is not defined', 'ThreeCSG.js'); + + ThreeBSP = factory(THREE); + } +} (function(THREE, ThreeBSP) { + + "use strict"; + + if (!ThreeBSP) ThreeBSP = {}; + + var EPSILON = 1e-5, + COPLANAR = 0, + FRONT = 1, + BACK = 2, + SPANNING = 3; + + ThreeBSP.Geometry = function( geometry, transfer_matrix, nodeid, flippedMesh ) { + // Convert THREE.Geometry to ThreeBSP + + if ( geometry instanceof THREE.Geometry ) { + this.matrix = null; // new THREE.Matrix4; not create matrix when do not needed + } else if ( geometry instanceof THREE.Mesh ) { + // #todo: add hierarchy support + geometry.updateMatrix(); + transfer_matrix = this.matrix = geometry.matrix.clone(); + geometry = geometry.geometry; + } else if ( geometry instanceof ThreeBSP.Node ) { + this.tree = geometry; + this.matrix = null; // new THREE.Matrix4; + return this; + } else if ( geometry instanceof THREE.BufferGeometry ) { + var pos_buf = geometry.getAttribute('position').array, + norm_buf = geometry.getAttribute('normal').array, + polygons = [], polygon, vert1, vert2, vert3; + + for (var i=0; i < pos_buf.length; i+=9) { + polygon = new ThreeBSP.Polygon; + + vert1 = new ThreeBSP.Vertex( pos_buf[i], pos_buf[i+1], pos_buf[i+2], norm_buf[i], norm_buf[i+1], norm_buf[i+2]); + if (transfer_matrix) vert1.applyMatrix4(transfer_matrix); + + vert2 = new ThreeBSP.Vertex( pos_buf[i+3], pos_buf[i+4], pos_buf[i+5], norm_buf[i+3], norm_buf[i+4], norm_buf[i+5]); + if (transfer_matrix) vert2.applyMatrix4(transfer_matrix); + + vert3 = new ThreeBSP.Vertex( pos_buf[i+6], pos_buf[i+7], pos_buf[i+8], norm_buf[i+6], norm_buf[i+7], norm_buf[i+8]); + if (transfer_matrix) vert3.applyMatrix4(transfer_matrix); + + if (flippedMesh) polygon.vertices.push( vert1, vert3, vert2 ); + else polygon.vertices.push( vert1, vert2, vert3 ); + + polygon.calculateProperties(); + polygons.push( polygon ); + } + + this.tree = new ThreeBSP.Node( polygons, nodeid ); + if (nodeid!==undefined) this.maxid = this.tree.maxnodeid; + return this; + + } else if (geometry.polygons && (geometry.polygons[0] instanceof ThreeBSP.Polygon)) { + var polygons = geometry.polygons; + + for (var i=0;i<polygons.length;++i) { + var polygon = polygons[i]; + if (transfer_matrix) { + for (var n=0;n<polygon.vertices.length;++n) + polygon.vertices[n].applyMatrix4(transfer_matrix); + } + + polygon.calculateProperties(); + } + + this.tree = new ThreeBSP.Node( polygons, nodeid ); + if (nodeid!==undefined) this.maxid = this.tree.maxnodeid; + return this; + + } else { + throw 'ThreeBSP: Given geometry is unsupported'; + } + + var polygons = [], + nfaces = geometry.faces.length, + face, polygon, vertex; + + for (var i = 0; i < nfaces; ++i ) { + face = geometry.faces[i]; + // faceVertexUvs = geometry.faceVertexUvs[0][i]; + polygon = new ThreeBSP.Polygon; + + if ( face instanceof THREE.Face3 ) { + vertex = geometry.vertices[ face.a ]; + // uvs = faceVertexUvs ? new THREE.Vector2( faceVertexUvs[0].x, faceVertexUvs[0].y ) : null; + vertex = new ThreeBSP.Vertex( vertex.x, vertex.y, vertex.z, face.vertexNormals[0].x, face.vertexNormals[0].y, face.vertexNormals[0].z /*face.normal , uvs */ ); + if (transfer_matrix) vertex.applyMatrix4(transfer_matrix); + polygon.vertices.push( vertex ); + + vertex = geometry.vertices[ face.b ]; + //uvs = faceVertexUvs ? new THREE.Vector2( faceVertexUvs[1].x, faceVertexUvs[1].y ) : null; + vertex = new ThreeBSP.Vertex( vertex.x, vertex.y, vertex.z, face.vertexNormals[1].x, face.vertexNormals[1].y, face.vertexNormals[1].z/*face.normal , uvs */ ); + if (transfer_matrix) vertex.applyMatrix4(transfer_matrix); + polygon.vertices.push( vertex ); + + vertex = geometry.vertices[ face.c ]; + // uvs = faceVertexUvs ? new THREE.Vector2( faceVertexUvs[2].x, faceVertexUvs[2].y ) : null; + vertex = new ThreeBSP.Vertex( vertex.x, vertex.y, vertex.z, face.vertexNormals[2].x, face.vertexNormals[2].y, face.vertexNormals[2].z /*face.normal, uvs */ ); + if (transfer_matrix) vertex.applyMatrix4(transfer_matrix); + polygon.vertices.push( vertex ); + } else if ( typeof THREE.Face4 ) { + vertex = geometry.vertices[ face.a ]; + // uvs = faceVertexUvs ? new THREE.Vector2( faceVertexUvs[0].x, faceVertexUvs[0].y ) : null; + vertex = new ThreeBSP.Vertex( vertex.x, vertex.y, vertex.z, face.vertexNormals[0].x, face.vertexNormals[0].y, face.vertexNormals[0].z /*, uvs */ ); + if (transfer_matrix) vertex.applyMatrix4(transfer_matrix); + polygon.vertices.push( vertex ); + + vertex = geometry.vertices[ face.b ]; + // uvs = faceVertexUvs ? new THREE.Vector2( faceVertexUvs[1].x, faceVertexUvs[1].y ) : null; + vertex = new ThreeBSP.Vertex( vertex.x, vertex.y, vertex.z, face.vertexNormals[1].x, face.vertexNormals[1].y, face.vertexNormals[1].z /*, uvs */ ); + if (transfer_matrix) vertex.applyMatrix4(transfer_matrix); + polygon.vertices.push( vertex ); + + vertex = geometry.vertices[ face.c ]; + // uvs = faceVertexUvs ? new THREE.Vector2( faceVertexUvs[2].x, faceVertexUvs[2].y ) : null; + vertex = new ThreeBSP.Vertex( vertex.x, vertex.y, vertex.z, face.vertexNormals[2].x, face.vertexNormals[2].y, face.vertexNormals[2].z /*, uvs */ ); + if (transfer_matrix) vertex.applyMatrix4(transfer_matrix); + polygon.vertices.push( vertex ); + + vertex = geometry.vertices[ face.d ]; + // uvs = faceVertexUvs ? new THREE.Vector2( faceVertexUvs[3].x, faceVertexUvs[3].y ) : null; + vertex = new ThreeBSP.Vertex( vertex.x, vertex.y, vertex.z, face.vertexNormals[3].x, face.vertexNormals[3].y, face.vertexNormals[3].z /*, uvs */ ); + if (transfer_matrix) vertex.applyMatrix4(transfer_matrix); + polygon.vertices.push( vertex ); + } else { + throw 'Invalid face type at index ' + i; + } + + polygon.calculateProperties(); + polygons.push( polygon ); + } + + this.tree = new ThreeBSP.Node( polygons, nodeid ); + if (nodeid!==undefined) this.maxid = this.tree.maxnodeid; + } + + ThreeBSP.Geometry.prototype.subtract = function( other_tree ) { + var a = this.tree.clone(), + b = other_tree.tree.clone(); + + a.invert(); + a.clipTo( b ); + b.clipTo( a ); + b.invert(); + b.clipTo( a ); + b.invert(); + a.build( b.allPolygons() ); + a.invert(); + a = new ThreeBSP.Geometry( a ); + a.matrix = this.matrix; + return a; + } + + ThreeBSP.Geometry.prototype.union = function( other_tree ) { + var a = this.tree.clone(), + b = other_tree.tree.clone(); + + a.clipTo( b ); + b.clipTo( a ); + b.invert(); + b.clipTo( a ); + b.invert(); + a.build( b.allPolygons() ); + a = new ThreeBSP.Geometry( a ); + a.matrix = this.matrix; + return a; + } + + ThreeBSP.Geometry.prototype.intersect = function( other_tree ) { + var a = this.tree.clone(), + b = other_tree.tree.clone(); + + a.invert(); + b.clipTo( a ); + b.invert(); + a.clipTo( b ); + b.clipTo( a ); + a.build( b.allPolygons() ); + a.invert(); + a = new ThreeBSP.Geometry( a ); + a.matrix = this.matrix; + return a; + } + + ThreeBSP.Geometry.prototype.tryToCompress = function(polygons) { + + if (this.maxid === undefined) return; + + var arr = [], parts, foundpair, + nreduce = 0, n, len = polygons.length, + p, p1, p2, i1, i2; + + // sort out polygons + for (n=0;n<len;++n) { + p = polygons[n]; + if (p.id === undefined) continue; + if (arr[p.id] === undefined) arr[p.id] = []; + + arr[p.id].push(p); + } + + for(n=0; n<arr.length; ++n) { + parts = arr[n]; + if (parts===undefined) continue; + + len = parts.length; + + foundpair = (len > 1); + + while (foundpair) { + foundpair = false; + + for (i1 = 0; i1<len-1; ++i1) { + p1 = parts[i1]; + if (!p1 || !p1.parent) continue; + for (i2 = i1+1; i2 < len; ++i2) { + p2 = parts[i2]; + if (p2 && (p1.parent === p2.parent) && (p1.nsign === p2.nsign)) { + + if (p1.nsign !== p1.parent.nsign) p1.parent.flip(); + + nreduce++; + parts[i1] = p1.parent; + parts[i2] = null; + if (p1.parent.vertices.length < 3) console.log('something wrong with parent'); + foundpair = true; + break; + } + } + } + } + } + + if (nreduce>0) { + polygons.splice(0, polygons.length); + + for(n=0;n<arr.length;++n) { + parts = arr[n]; + if (parts !== undefined) + for (i1=0,len=parts.length; i1<len;++i1) + if (parts[i1]) polygons.push(parts[i1]); + } + + } + } + + ThreeBSP.Geometry.prototype.direct_subtract = function( other_tree ) { + var a = this.tree, + b = other_tree.tree; + a.invert(); + a.clipTo( b ); + b.clipTo( a ); + b.invert(); + b.clipTo( a ); + b.invert(); + a.build( b.collectPolygons([]) ); + a.invert(); + return this; + } + + ThreeBSP.Geometry.prototype.direct_union = function( other_tree ) { + var a = this.tree, + b = other_tree.tree; + + a.clipTo( b ); + b.clipTo( a ); + b.invert(); + b.clipTo( a ); + b.invert(); + a.build( b.collectPolygons([]) ); + return this; + } + + ThreeBSP.Geometry.prototype.direct_intersect = function( other_tree ) { + var a = this.tree, + b = other_tree.tree; + + a.invert(); + b.clipTo( a ); + b.invert(); + a.clipTo( b ); + b.clipTo( a ); + a.build( b.collectPolygons([]) ); + a.invert(); + return this; + } + + ThreeBSP.CreateNormal = function(axis_name, pos, size) { + // create geometry to make cut on specified axis + + var vert1, vert2, vert3; + + if (!size || (size<10000)) size = 10000; + + switch(axis_name) { + case "x": + vert1 = new ThreeBSP.Vertex(pos, -3*size, size, 1, 0, 0), + vert3 = new ThreeBSP.Vertex(pos, size, size, 1, 0, 0), + vert2 = new ThreeBSP.Vertex(pos, size, -3*size, 1, 0, 0); + break; + case "y": + vert1 = new ThreeBSP.Vertex(-3*size, pos, size, 0, 1, 0), + vert2 = new ThreeBSP.Vertex( size, pos, size, 0, 1, 0), + vert3 = new ThreeBSP.Vertex( size, pos, -3*size, 0, 1, 0); + break; + case "z": + vert1 = new ThreeBSP.Vertex(-3*size, size, pos, 0, 0, 1), + vert3 = new ThreeBSP.Vertex( size, size, pos, 0, 0, 1), + vert2 = new ThreeBSP.Vertex( size, -3*size, pos, 0, 0, 1); + break; + } + + var polygon = new ThreeBSP.Polygon([vert1, vert2, vert3]); + polygon.calculateProperties(); + + var node = new ThreeBSP.Node([polygon]); + + return new ThreeBSP.Geometry(node); + } + + + ThreeBSP.Geometry.prototype.cut_from_plane = function( other_tree) { + // just cut peaces from second geometry, which just simple plane + + var a = this.tree, + b = other_tree.tree; + + a.invert(); + b.clipTo( a ); + + return this; + } + + + ThreeBSP.Geometry.prototype.toGeometry = function() { + var i, j, + matrix = this.matrix ? new THREE.Matrix4().getInverse( this.matrix ) : null, + geometry = new THREE.Geometry(), + polygons = this.tree.collectPolygons([]), + polygon_count = polygons.length, + polygon, polygon_vertice_count, + vertice_dict = {}, + vertex_idx_a, vertex_idx_b, vertex_idx_c, + vertex, face; + + for ( i = 0; i < polygon_count; ++i ) { + polygon = polygons[i]; + polygon_vertice_count = polygon.vertices.length; + + for ( j = 2; j < polygon_vertice_count; ++j ) { + // verticeUvs = []; + + vertex = polygon.vertices[0]; + // verticeUvs.push( new THREE.Vector2( vertex.uv.x, vertex.uv.y ) ); + vertex = new THREE.Vector3( vertex.x, vertex.y, vertex.z ); + if (matrix) vertex.applyMatrix4(matrix); + + if ( typeof vertice_dict[ vertex.x + ',' + vertex.y + ',' + vertex.z ] !== 'undefined' ) { + vertex_idx_a = vertice_dict[ vertex.x + ',' + vertex.y + ',' + vertex.z ]; + } else { + geometry.vertices.push( vertex ); + vertex_idx_a = vertice_dict[ vertex.x + ',' + vertex.y + ',' + vertex.z ] = geometry.vertices.length - 1; + } + + vertex = polygon.vertices[j-1]; + // verticeUvs.push( new THREE.Vector2( vertex.uv.x, vertex.uv.y ) ); + vertex = new THREE.Vector3( vertex.x, vertex.y, vertex.z ); + if (matrix) vertex.applyMatrix4(matrix); + if ( typeof vertice_dict[ vertex.x + ',' + vertex.y + ',' + vertex.z ] !== 'undefined' ) { + vertex_idx_b = vertice_dict[ vertex.x + ',' + vertex.y + ',' + vertex.z ]; + } else { + geometry.vertices.push( vertex ); + vertex_idx_b = vertice_dict[ vertex.x + ',' + vertex.y + ',' + vertex.z ] = geometry.vertices.length - 1; + } + + vertex = polygon.vertices[j]; + // verticeUvs.push( new THREE.Vector2( vertex.uv.x, vertex.uv.y ) ); + vertex = new THREE.Vector3( vertex.x, vertex.y, vertex.z ); + if (matrix) vertex.applyMatrix4(matrix); + if ( typeof vertice_dict[ vertex.x + ',' + vertex.y + ',' + vertex.z ] !== 'undefined' ) { + vertex_idx_c = vertice_dict[ vertex.x + ',' + vertex.y + ',' + vertex.z ]; + } else { + geometry.vertices.push( vertex ); + vertex_idx_c = vertice_dict[ vertex.x + ',' + vertex.y + ',' + vertex.z ] = geometry.vertices.length - 1; + } + + face = new THREE.Face3( + vertex_idx_a, + vertex_idx_b, + vertex_idx_c, + new THREE.Vector3( polygon.normal.x, polygon.normal.y, polygon.normal.z ) + ); + + geometry.faces.push( face ); + // geometry.faceVertexUvs[0].push( verticeUvs ); + } + + } + return geometry; + } + + ThreeBSP.Geometry.prototype.scale = function(x,y,z) { + // try to scale as THREE.BufferGeometry + var polygons = this.tree.collectPolygons([]); + + for (var i = 0; i < polygons.length; ++i) { + var polygon = polygons[i]; + for (var k=0; k < polygon.vertices.length; ++k) { + var v = polygon.vertices[k]; + v.x *= x; + v.y *= y; + v.z *= z; + } + delete polygon.normal; + polygon.calculateProperties(); + } + } + + ThreeBSP.Geometry.prototype.toPolygons = function() { + var polygons = this.tree.collectPolygons([]); + + this.tryToCompress(polygons); + + for (var i = 0; i < polygons.length; ++i ) { + delete polygons[i].id; + delete polygons[i].parent; + } + + return polygons; + } + + ThreeBSP.Geometry.prototype.toBufferGeometry = function() { + return ThreeBSP.CreateBufferGeometry(this.toPolygons()); + } + + ThreeBSP.CreateBufferGeometry = function(polygons) { + var i, j, polygon_count = polygons.length, buf_size = 0; + + for ( i = 0; i < polygon_count; ++i ) + buf_size += (polygons[i].vertices.length - 2) * 9; + + var positions_buf = new Float32Array(buf_size), + normals_buf = new Float32Array(buf_size), + iii = 0, polygon; + + function CopyVertex(vertex) { + + positions_buf[iii] = vertex.x; + positions_buf[iii+1] = vertex.y; + positions_buf[iii+2] = vertex.z; + + normals_buf[iii] = polygon.nsign * vertex.nx; + normals_buf[iii+1] = polygon.nsign * vertex.ny; + normals_buf[iii+2] = polygon.nsign * vertex.nz; + iii+=3; + } + + for ( i = 0; i < polygon_count; ++i ) { + polygon = polygons[i]; + for ( j = 2; j < polygon.vertices.length; ++j ) { + CopyVertex(polygon.vertices[0]); + CopyVertex(polygon.vertices[j-1]); + CopyVertex(polygon.vertices[j]); + } + } + + var geometry = new THREE.BufferGeometry(); + geometry.addAttribute( 'position', new THREE.BufferAttribute( positions_buf, 3 ) ); + geometry.addAttribute( 'normal', new THREE.BufferAttribute( normals_buf, 3 ) ); + + // geometry.computeVertexNormals(); + return geometry; + } + + ThreeBSP.Geometry.prototype.toMesh = function( material ) { + var geometry = this.toGeometry(), + mesh = new THREE.Mesh( geometry, material ); + + if (this.matrix) { + mesh.position.setFromMatrixPosition( this.matrix ); + mesh.rotation.setFromRotationMatrix( this.matrix ); + } + + return mesh; + } + + ThreeBSP.Polygon = function( vertices, normal, w ) { + if ( !( vertices instanceof Array ) ) { + vertices = []; + } + + this.vertices = vertices; + this.nsign = 1; + if ( vertices.length > 0 ) { + this.calculateProperties(); + } else { + this.normal = this.w = undefined; + } + } + + ThreeBSP.Polygon.prototype.copyProperties = function(parent, more) { + this.normal = parent.normal; // .clone(); + this.w = parent.w; + this.nsign = parent.nsign; + if (more && (parent.id !== undefined)) { + this.id = parent.id; + this.parent = parent; + } + return this; + } + + ThreeBSP.Polygon.prototype.calculateProperties = function() { + if (this.normal) return; + + var a = this.vertices[0], + b = this.vertices[1], + c = this.vertices[2]; + + this.nsign = 1; + + this.normal = b.clone().subtract( a ).cross( + c.clone().subtract( a ) + ).normalize(); + + this.w = this.normal.clone().dot( a ); + return this; + } + + ThreeBSP.Polygon.prototype.clone = function() { + var vertice_count = this.vertices.length, + polygon = new ThreeBSP.Polygon; + + for (var i = 0; i < vertice_count; ++i ) + polygon.vertices.push( this.vertices[i].clone() ); + + return polygon.copyProperties(this); + } + + ThreeBSP.Polygon.prototype.flip = function() { + + /// normal is not changed, only sign variable + //this.normal.multiplyScalar( -1 ); + //this.w *= -1; + + this.nsign *= -1; + + this.vertices.reverse(); + + return this; + } + + ThreeBSP.Polygon.prototype.classifyVertex = function( vertex ) { + var side_value = this.nsign * (this.normal.dot( vertex ) - this.w); + + if ( side_value < -EPSILON ) return BACK; + if ( side_value > EPSILON ) return FRONT; + return COPLANAR; + } + + ThreeBSP.Polygon.prototype.classifySide = function( polygon ) { + var i, classification, + num_positive = 0, num_negative = 0, + vertice_count = polygon.vertices.length; + + for ( i = 0; i < vertice_count; ++i ) { + classification = this.classifyVertex( polygon.vertices[i] ); + if ( classification === FRONT ) { + ++num_positive; + } else if ( classification === BACK ) { + ++num_negative; + } + } + + if ( num_positive > 0 && num_negative === 0 ) return FRONT; + if ( num_positive === 0 && num_negative > 0 ) return BACK; + if ( num_positive === 0 && num_negative === 0 ) return COPLANAR; + return SPANNING; + } + + ThreeBSP.Polygon.prototype.splitPolygon = function( polygon, coplanar_front, coplanar_back, front, back ) { + var classification = this.classifySide( polygon ); + + if ( classification === COPLANAR ) { + + ( (this.nsign * polygon.nsign * this.normal.dot( polygon.normal ) > 0) ? coplanar_front : coplanar_back ).push( polygon ); + + } else if ( classification === FRONT ) { + + front.push( polygon ); + + } else if ( classification === BACK ) { + + back.push( polygon ); + + } else { + + var vertice_count = polygon.vertices.length, + nnx = this.normal.x, + nny = this.normal.y, + nnz = this.normal.z, + i, j, ti, tj, vi, vj, + t, v, + f = [], b = []; + + for ( i = 0; i < vertice_count; ++i ) { + + j = (i + 1) % vertice_count; + vi = polygon.vertices[i]; + vj = polygon.vertices[j]; + ti = this.classifyVertex( vi ); + tj = this.classifyVertex( vj ); + + if ( ti != BACK ) f.push( vi ); + if ( ti != FRONT ) b.push( vi ); + if ( (ti | tj) === SPANNING ) { + // t = ( this.w - this.normal.dot( vi ) ) / this.normal.dot( vj.clone().subtract( vi ) ); + //v = vi.clone().lerp( vj, t ); + + t = (this.w - (nnx*vi.x + nny*vi.y + nnz*vi.z)) / (nnx*(vj.x-vi.x) + nny*(vj.y-vi.y) + nnz*(vj.z-vi.z)); + + v = vi.interpolate( vj, t ); + f.push( v ); + b.push( v ); + } + } + + //if ( f.length >= 3 ) front.push( new ThreeBSP.Polygon( f ).calculateProperties() ); + //if ( b.length >= 3 ) back.push( new ThreeBSP.Polygon( b ).calculateProperties() ); + if ( f.length >= 3 ) front.push( new ThreeBSP.Polygon( f ).copyProperties(polygon, true) ); + if ( b.length >= 3 ) back.push( new ThreeBSP.Polygon( b ).copyProperties(polygon, true) ); + } + } + + ThreeBSP.Vertex = function(x, y, z, nx, ny, nz) { + this.x = x; + this.y = y; + this.z = z; + this.nx = nx; + this.ny = ny; + this.nz = nz; + } + + ThreeBSP.Vertex.prototype.setnormal = function ( nx, ny, nz ) { + this.nx = nx; + this.ny = ny; + this.nz = nz; + } + + ThreeBSP.Vertex.prototype.clone = function() { + return new ThreeBSP.Vertex( this.x, this.y, this.z, this.nx, this.ny, this.nz); + } + + ThreeBSP.Vertex.prototype.add = function( vertex ) { + this.x += vertex.x; + this.y += vertex.y; + this.z += vertex.z; + return this; + } + + ThreeBSP.Vertex.prototype.subtract = function( vertex ) { + this.x -= vertex.x; + this.y -= vertex.y; + this.z -= vertex.z; + return this; + } + + ThreeBSP.Vertex.prototype.multiplyScalar = function( scalar ) { + this.x *= scalar; + this.y *= scalar; + this.z *= scalar; + return this; + } + + ThreeBSP.Vertex.prototype.cross = function( vertex ) { + var x = this.x, + y = this.y, + z = this.z; + + this.x = y * vertex.z - z * vertex.y; + this.y = z * vertex.x - x * vertex.z; + this.z = x * vertex.y - y * vertex.x; + + return this; + } + + ThreeBSP.Vertex.prototype.normalize = function() { + var length = Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z ); + + this.x /= length; + this.y /= length; + this.z /= length; + + return this; + } + + ThreeBSP.Vertex.prototype.dot = function( vertex ) { + return this.x*vertex.x + this.y*vertex.y + this.z*vertex.z; + } + + ThreeBSP.Vertex.prototype.diff = function( vertex ) { + var dx = (this.x - vertex.x), + dy = (this.y - vertex.y), + dz = (this.z - vertex.z), + len2 = this.x*this.x + this.y*this.y + this.z*this.z; + + return (dx*dx + dy*dy + dz*dz) / (len2>0 ? len2 : 1e-10); + } + +/* + ThreeBSP.Vertex.prototype.lerp = function( a, t ) { + this.add( + a.clone().subtract( this ).multiplyScalar( t ) + ); + + this.normal.add( + a.normal.clone().sub( this.normal ).multiplyScalar( t ) + ); + + //this.uv.add( + // a.uv.clone().sub( this.uv ).multiplyScalar( t ) + //); + + return this; + }; + ThreeBSP.Vertex.prototype.interpolate = function( other, t ) { + return this.clone().lerp( other, t ); + }; +*/ + + ThreeBSP.Vertex.prototype.interpolate = function( a, t ) { + var t1 = 1-t; + return new ThreeBSP.Vertex(this.x*t1 + a.x*t, this.y*t1 + a.y*t, this.z*t1 + a.z*t, + this.nx*t1 + a.nx*t, this.ny*t1 + a.ny*t, this.nz*t1 + a.nz*t); + } + + ThreeBSP.Vertex.prototype.applyMatrix4 = function ( m ) { + + // input: THREE.Matrix4 affine matrix + + var x = this.x, y = this.y, z = this.z, e = m.elements; + + this.x = e[0] * x + e[4] * y + e[8] * z + e[12]; + this.y = e[1] * x + e[5] * y + e[9] * z + e[13]; + this.z = e[2] * x + e[6] * y + e[10] * z + e[14]; + + x = this.nx; y = this.ny; z = this.nz; + + this.nx = e[0] * x + e[4] * y + e[8] * z; + this.ny = e[1] * x + e[5] * y + e[9] * z; + this.nz = e[2] * x + e[6] * y + e[10] * z; + + return this; + } + + // ================================================================================================ + + ThreeBSP.Node = function( polygons, nodeid ) { + this.polygons = []; + this.front = this.back = undefined; + + if ( !(polygons instanceof Array) || polygons.length === 0 ) return; + + this.divider = polygons[0].clone(); + + var polygon_count = polygons.length, + front = [], back = []; + + for (var i = 0; i < polygon_count; ++i ) { + if (nodeid!==undefined) { + polygons[i].id = nodeid++; + delete polygons[i].parent; + } + + this.divider.splitPolygon( polygons[i], this.polygons, this.polygons, front, back ); + } + + if (nodeid !== undefined) this.maxnodeid = nodeid; + + if ( front.length > 0 ) + this.front = new ThreeBSP.Node( front ); + + if ( back.length > 0 ) + this.back = new ThreeBSP.Node( back ); + } + + ThreeBSP.Node.isConvex = function( polygons ) { + var i, j, len = polygons.length; + for ( i = 0; i < len; ++i ) + for ( j = 0; j < len; ++j ) + if ( i !== j && polygons[i].classifySide( polygons[j] ) !== BACK ) return false; + return true; + } + + ThreeBSP.Node.prototype.build = function( polygons ) { + var polygon_count = polygons.length, + front = [], back = []; + + if ( !this.divider ) + this.divider = polygons[0].clone(); + + for (var i = 0; i < polygon_count; ++i ) + this.divider.splitPolygon( polygons[i], this.polygons, this.polygons, front, back ); + + if ( front.length > 0 ) { + if ( !this.front ) this.front = new ThreeBSP.Node(); + this.front.build( front ); + } + + if ( back.length > 0 ) { + if ( !this.back ) this.back = new ThreeBSP.Node(); + this.back.build( back ); + } + } + + ThreeBSP.Node.prototype.collectPolygons = function(arr) { + var len = this.polygons.length; + for (var i=0;i<len;++i) arr.push(this.polygons[i]); + if ( this.front ) this.front.collectPolygons(arr); + if ( this.back ) this.back.collectPolygons(arr); + return arr; + } + + ThreeBSP.Node.prototype.allPolygons = function() { + var polygons = this.polygons.slice(); + if ( this.front ) polygons = polygons.concat( this.front.allPolygons() ); + if ( this.back ) polygons = polygons.concat( this.back.allPolygons() ); + return polygons; + } + + ThreeBSP.Node.prototype.numPolygons = function() { + var res = this.polygons.length; + if ( this.front ) res += this.front.numPolygons(); + if ( this.back ) res += this.back.numPolygons(); + return res; + } + + ThreeBSP.Node.prototype.clone = function() { + var node = new ThreeBSP.Node(); + + node.divider = this.divider.clone(); + node.polygons = this.polygons.map( function( polygon ) { return polygon.clone(); } ); + node.front = this.front && this.front.clone(); + node.back = this.back && this.back.clone(); + + return node; + } + + ThreeBSP.Node.prototype.invert = function() { + var polygon_count = this.polygons.length; + + for (var i = 0; i < polygon_count; ++i ) + this.polygons[i].flip(); + + this.divider.flip(); + if ( this.front ) this.front.invert(); + if ( this.back ) this.back.invert(); + + var temp = this.front; + this.front = this.back; + this.back = temp; + + return this; + } + + ThreeBSP.Node.prototype.clipPolygons = function( polygons ) { + + if ( !this.divider ) return polygons.slice(); + + var polygon_count = polygons.length, front = [], back = []; + + for (var i = 0; i < polygon_count; ++i ) + this.divider.splitPolygon( polygons[i], front, back, front, back ); + + if ( this.front ) front = this.front.clipPolygons( front ); + if ( this.back ) back = this.back.clipPolygons( back ); + else back = []; + + return front.concat( back ); + } + + ThreeBSP.Node.prototype.clipTo = function( node ) { + this.polygons = node.clipPolygons( this.polygons ); + if ( this.front ) this.front.clipTo( node ); + if ( this.back ) this.back.clipTo( node ); + } + + return ThreeBSP; + +})); + diff --git a/js/scripts/d3.LICENSE b/js/scripts/d3.LICENSE new file mode 100644 index 00000000000..1d9d875edb4 --- /dev/null +++ b/js/scripts/d3.LICENSE @@ -0,0 +1,27 @@ +Copyright 2010-2017 Mike Bostock +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the author nor the names of contributors may be used to + endorse or promote products derived from this software without specific prior + written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/js/scripts/d3.min.js b/js/scripts/d3.min.js new file mode 100644 index 00000000000..2a54e040498 --- /dev/null +++ b/js/scripts/d3.min.js @@ -0,0 +1,2 @@ +// https://d3js.org v5.7.0 Copyright 2018 Mike Bostock +!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n(t.d3=t.d3||{})}(this,function(t){"use strict";function n(t,n){return t<n?-1:t>n?1:t>=n?0:NaN}function e(t){var e;return 1===t.length&&(e=t,t=function(t,r){return n(e(t),r)}),{left:function(n,e,r,i){for(null==r&&(r=0),null==i&&(i=n.length);r<i;){var o=r+i>>>1;t(n[o],e)<0?r=o+1:i=o}return r},right:function(n,e,r,i){for(null==r&&(r=0),null==i&&(i=n.length);r<i;){var o=r+i>>>1;t(n[o],e)>0?i=o:r=o+1}return r}}}var r=e(n),i=r.right,o=r.left;function a(t,n){return[t,n]}function u(t){return null===t?NaN:+t}function f(t,n){var e,r,i=t.length,o=0,a=-1,f=0,c=0;if(null==n)for(;++a<i;)isNaN(e=u(t[a]))||(c+=(r=e-f)*(e-(f+=r/++o)));else for(;++a<i;)isNaN(e=u(n(t[a],a,t)))||(c+=(r=e-f)*(e-(f+=r/++o)));if(o>1)return c/(o-1)}function c(t,n){var e=f(t,n);return e?Math.sqrt(e):e}function s(t,n){var e,r,i,o=t.length,a=-1;if(null==n){for(;++a<o;)if(null!=(e=t[a])&&e>=e)for(r=i=e;++a<o;)null!=(e=t[a])&&(r>e&&(r=e),i<e&&(i=e))}else for(;++a<o;)if(null!=(e=n(t[a],a,t))&&e>=e)for(r=i=e;++a<o;)null!=(e=n(t[a],a,t))&&(r>e&&(r=e),i<e&&(i=e));return[r,i]}var l=Array.prototype,h=l.slice,d=l.map;function p(t){return function(){return t}}function v(t){return t}function g(t,n,e){t=+t,n=+n,e=(i=arguments.length)<2?(n=t,t=0,1):i<3?1:+e;for(var r=-1,i=0|Math.max(0,Math.ceil((n-t)/e)),o=new Array(i);++r<i;)o[r]=t+r*e;return o}var y=Math.sqrt(50),_=Math.sqrt(10),b=Math.sqrt(2);function m(t,n,e){var r,i,o,a,u=-1;if(e=+e,(t=+t)===(n=+n)&&e>0)return[t];if((r=n<t)&&(i=t,t=n,n=i),0===(a=x(t,n,e))||!isFinite(a))return[];if(a>0)for(t=Math.ceil(t/a),n=Math.floor(n/a),o=new Array(i=Math.ceil(n-t+1));++u<i;)o[u]=(t+u)*a;else for(t=Math.floor(t*a),n=Math.ceil(n*a),o=new Array(i=Math.ceil(t-n+1));++u<i;)o[u]=(t-u)/a;return r&&o.reverse(),o}function x(t,n,e){var r=(n-t)/Math.max(0,e),i=Math.floor(Math.log(r)/Math.LN10),o=r/Math.pow(10,i);return i>=0?(o>=y?10:o>=_?5:o>=b?2:1)*Math.pow(10,i):-Math.pow(10,-i)/(o>=y?10:o>=_?5:o>=b?2:1)}function w(t,n,e){var r=Math.abs(n-t)/Math.max(0,e),i=Math.pow(10,Math.floor(Math.log(r)/Math.LN10)),o=r/i;return o>=y?i*=10:o>=_?i*=5:o>=b&&(i*=2),n<t?-i:i}function M(t){return Math.ceil(Math.log(t.length)/Math.LN2)+1}function A(t,n,e){if(null==e&&(e=u),r=t.length){if((n=+n)<=0||r<2)return+e(t[0],0,t);if(n>=1)return+e(t[r-1],r-1,t);var r,i=(r-1)*n,o=Math.floor(i),a=+e(t[o],o,t);return a+(+e(t[o+1],o+1,t)-a)*(i-o)}}function T(t,n){var e,r,i=t.length,o=-1;if(null==n){for(;++o<i;)if(null!=(e=t[o])&&e>=e)for(r=e;++o<i;)null!=(e=t[o])&&e>r&&(r=e)}else for(;++o<i;)if(null!=(e=n(t[o],o,t))&&e>=e)for(r=e;++o<i;)null!=(e=n(t[o],o,t))&&e>r&&(r=e);return r}function N(t){for(var n,e,r,i=t.length,o=-1,a=0;++o<i;)a+=t[o].length;for(e=new Array(a);--i>=0;)for(n=(r=t[i]).length;--n>=0;)e[--a]=r[n];return e}function S(t,n){var e,r,i=t.length,o=-1;if(null==n){for(;++o<i;)if(null!=(e=t[o])&&e>=e)for(r=e;++o<i;)null!=(e=t[o])&&r>e&&(r=e)}else for(;++o<i;)if(null!=(e=n(t[o],o,t))&&e>=e)for(r=e;++o<i;)null!=(e=n(t[o],o,t))&&r>e&&(r=e);return r}function E(t){if(!(i=t.length))return[];for(var n=-1,e=S(t,k),r=new Array(e);++n<e;)for(var i,o=-1,a=r[n]=new Array(i);++o<i;)a[o]=t[o][n];return r}function k(t){return t.length}var C=Array.prototype.slice;function P(t){return t}var z=1,R=2,L=3,D=4,U=1e-6;function q(t){return"translate("+(t+.5)+",0)"}function O(t){return"translate(0,"+(t+.5)+")"}function Y(){return!this.__axis}function B(t,n){var e=[],r=null,i=null,o=6,a=6,u=3,f=t===z||t===D?-1:1,c=t===D||t===R?"x":"y",s=t===z||t===L?q:O;function l(l){var h=null==r?n.ticks?n.ticks.apply(n,e):n.domain():r,d=null==i?n.tickFormat?n.tickFormat.apply(n,e):P:i,p=Math.max(o,0)+u,v=n.range(),g=+v[0]+.5,y=+v[v.length-1]+.5,_=(n.bandwidth?function(t){var n=Math.max(0,t.bandwidth()-1)/2;return t.round()&&(n=Math.round(n)),function(e){return+t(e)+n}}:function(t){return function(n){return+t(n)}})(n.copy()),b=l.selection?l.selection():l,m=b.selectAll(".domain").data([null]),x=b.selectAll(".tick").data(h,n).order(),w=x.exit(),M=x.enter().append("g").attr("class","tick"),A=x.select("line"),T=x.select("text");m=m.merge(m.enter().insert("path",".tick").attr("class","domain").attr("stroke","currentColor")),x=x.merge(M),A=A.merge(M.append("line").attr("stroke","currentColor").attr(c+"2",f*o)),T=T.merge(M.append("text").attr("fill","currentColor").attr(c,f*p).attr("dy",t===z?"0em":t===L?"0.71em":"0.32em")),l!==b&&(m=m.transition(l),x=x.transition(l),A=A.transition(l),T=T.transition(l),w=w.transition(l).attr("opacity",U).attr("transform",function(t){return isFinite(t=_(t))?s(t):this.getAttribute("transform")}),M.attr("opacity",U).attr("transform",function(t){var n=this.parentNode.__axis;return s(n&&isFinite(n=n(t))?n:_(t))})),w.remove(),m.attr("d",t===D||t==R?a?"M"+f*a+","+g+"H0.5V"+y+"H"+f*a:"M0.5,"+g+"V"+y:a?"M"+g+","+f*a+"V0.5H"+y+"V"+f*a:"M"+g+",0.5H"+y),x.attr("opacity",1).attr("transform",function(t){return s(_(t))}),A.attr(c+"2",f*o),T.attr(c,f*p).text(d),b.filter(Y).attr("fill","none").attr("font-size",10).attr("font-family","sans-serif").attr("text-anchor",t===R?"start":t===D?"end":"middle"),b.each(function(){this.__axis=_})}return l.scale=function(t){return arguments.length?(n=t,l):n},l.ticks=function(){return e=C.call(arguments),l},l.tickArguments=function(t){return arguments.length?(e=null==t?[]:C.call(t),l):e.slice()},l.tickValues=function(t){return arguments.length?(r=null==t?null:C.call(t),l):r&&r.slice()},l.tickFormat=function(t){return arguments.length?(i=t,l):i},l.tickSize=function(t){return arguments.length?(o=a=+t,l):o},l.tickSizeInner=function(t){return arguments.length?(o=+t,l):o},l.tickSizeOuter=function(t){return arguments.length?(a=+t,l):a},l.tickPadding=function(t){return arguments.length?(u=+t,l):u},l}var F={value:function(){}};function I(){for(var t,n=0,e=arguments.length,r={};n<e;++n){if(!(t=arguments[n]+"")||t in r)throw new Error("illegal type: "+t);r[t]=[]}return new H(r)}function H(t){this._=t}function j(t,n){for(var e,r=0,i=t.length;r<i;++r)if((e=t[r]).name===n)return e.value}function X(t,n,e){for(var r=0,i=t.length;r<i;++r)if(t[r].name===n){t[r]=F,t=t.slice(0,r).concat(t.slice(r+1));break}return null!=e&&t.push({name:n,value:e}),t}H.prototype=I.prototype={constructor:H,on:function(t,n){var e,r,i=this._,o=(r=i,(t+"").trim().split(/^|\s+/).map(function(t){var n="",e=t.indexOf(".");if(e>=0&&(n=t.slice(e+1),t=t.slice(0,e)),t&&!r.hasOwnProperty(t))throw new Error("unknown type: "+t);return{type:t,name:n}})),a=-1,u=o.length;if(!(arguments.length<2)){if(null!=n&&"function"!=typeof n)throw new Error("invalid callback: "+n);for(;++a<u;)if(e=(t=o[a]).type)i[e]=X(i[e],t.name,n);else if(null==n)for(e in i)i[e]=X(i[e],t.name,null);return this}for(;++a<u;)if((e=(t=o[a]).type)&&(e=j(i[e],t.name)))return e},copy:function(){var t={},n=this._;for(var e in n)t[e]=n[e].slice();return new H(t)},call:function(t,n){if((e=arguments.length-2)>0)for(var e,r,i=new Array(e),o=0;o<e;++o)i[o]=arguments[o+2];if(!this._.hasOwnProperty(t))throw new Error("unknown type: "+t);for(o=0,e=(r=this._[t]).length;o<e;++o)r[o].value.apply(n,i)},apply:function(t,n,e){if(!this._.hasOwnProperty(t))throw new Error("unknown type: "+t);for(var r=this._[t],i=0,o=r.length;i<o;++i)r[i].value.apply(n,e)}};var G="http://www.w3.org/1999/xhtml",V={svg:"http://www.w3.org/2000/svg",xhtml:G,xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"};function $(t){var n=t+="",e=n.indexOf(":");return e>=0&&"xmlns"!==(n=t.slice(0,e))&&(t=t.slice(e+1)),V.hasOwnProperty(n)?{space:V[n],local:t}:t}function W(t){var n=$(t);return(n.local?function(t){return function(){return this.ownerDocument.createElementNS(t.space,t.local)}}:function(t){return function(){var n=this.ownerDocument,e=this.namespaceURI;return e===G&&n.documentElement.namespaceURI===G?n.createElement(t):n.createElementNS(e,t)}})(n)}function Z(){}function Q(t){return null==t?Z:function(){return this.querySelector(t)}}function J(){return[]}function K(t){return null==t?J:function(){return this.querySelectorAll(t)}}var tt=function(t){return function(){return this.matches(t)}};if("undefined"!=typeof document){var nt=document.documentElement;if(!nt.matches){var et=nt.webkitMatchesSelector||nt.msMatchesSelector||nt.mozMatchesSelector||nt.oMatchesSelector;tt=function(t){return function(){return et.call(this,t)}}}}var rt=tt;function it(t){return new Array(t.length)}function ot(t,n){this.ownerDocument=t.ownerDocument,this.namespaceURI=t.namespaceURI,this._next=null,this._parent=t,this.__data__=n}ot.prototype={constructor:ot,appendChild:function(t){return this._parent.insertBefore(t,this._next)},insertBefore:function(t,n){return this._parent.insertBefore(t,n)},querySelector:function(t){return this._parent.querySelector(t)},querySelectorAll:function(t){return this._parent.querySelectorAll(t)}};var at="$";function ut(t,n,e,r,i,o){for(var a,u=0,f=n.length,c=o.length;u<c;++u)(a=n[u])?(a.__data__=o[u],r[u]=a):e[u]=new ot(t,o[u]);for(;u<f;++u)(a=n[u])&&(i[u]=a)}function ft(t,n,e,r,i,o,a){var u,f,c,s={},l=n.length,h=o.length,d=new Array(l);for(u=0;u<l;++u)(f=n[u])&&(d[u]=c=at+a.call(f,f.__data__,u,n),c in s?i[u]=f:s[c]=f);for(u=0;u<h;++u)(f=s[c=at+a.call(t,o[u],u,o)])?(r[u]=f,f.__data__=o[u],s[c]=null):e[u]=new ot(t,o[u]);for(u=0;u<l;++u)(f=n[u])&&s[d[u]]===f&&(i[u]=f)}function ct(t,n){return t<n?-1:t>n?1:t>=n?0:NaN}function st(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView}function lt(t,n){return t.style.getPropertyValue(n)||st(t).getComputedStyle(t,null).getPropertyValue(n)}function ht(t){return t.trim().split(/^|\s+/)}function dt(t){return t.classList||new pt(t)}function pt(t){this._node=t,this._names=ht(t.getAttribute("class")||"")}function vt(t,n){for(var e=dt(t),r=-1,i=n.length;++r<i;)e.add(n[r])}function gt(t,n){for(var e=dt(t),r=-1,i=n.length;++r<i;)e.remove(n[r])}function yt(){this.textContent=""}function _t(){this.innerHTML=""}function bt(){this.nextSibling&&this.parentNode.appendChild(this)}function mt(){this.previousSibling&&this.parentNode.insertBefore(this,this.parentNode.firstChild)}function xt(){return null}function wt(){var t=this.parentNode;t&&t.removeChild(this)}function Mt(){return this.parentNode.insertBefore(this.cloneNode(!1),this.nextSibling)}function At(){return this.parentNode.insertBefore(this.cloneNode(!0),this.nextSibling)}pt.prototype={add:function(t){this._names.indexOf(t)<0&&(this._names.push(t),this._node.setAttribute("class",this._names.join(" ")))},remove:function(t){var n=this._names.indexOf(t);n>=0&&(this._names.splice(n,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};var Tt={};(t.event=null,"undefined"!=typeof document)&&("onmouseenter"in document.documentElement||(Tt={mouseenter:"mouseover",mouseleave:"mouseout"}));function Nt(t,n,e){return t=St(t,n,e),function(n){var e=n.relatedTarget;e&&(e===this||8&e.compareDocumentPosition(this))||t.call(this,n)}}function St(n,e,r){return function(i){var o=t.event;t.event=i;try{n.call(this,this.__data__,e,r)}finally{t.event=o}}}function Et(t){return function(){var n=this.__on;if(n){for(var e,r=0,i=-1,o=n.length;r<o;++r)e=n[r],t.type&&e.type!==t.type||e.name!==t.name?n[++i]=e:this.removeEventListener(e.type,e.listener,e.capture);++i?n.length=i:delete this.__on}}}function kt(t,n,e){var r=Tt.hasOwnProperty(t.type)?Nt:St;return function(i,o,a){var u,f=this.__on,c=r(n,o,a);if(f)for(var s=0,l=f.length;s<l;++s)if((u=f[s]).type===t.type&&u.name===t.name)return this.removeEventListener(u.type,u.listener,u.capture),this.addEventListener(u.type,u.listener=c,u.capture=e),void(u.value=n);this.addEventListener(t.type,c,e),u={type:t.type,name:t.name,value:n,listener:c,capture:e},f?f.push(u):this.__on=[u]}}function Ct(n,e,r,i){var o=t.event;n.sourceEvent=t.event,t.event=n;try{return e.apply(r,i)}finally{t.event=o}}function Pt(t,n,e){var r=st(t),i=r.CustomEvent;"function"==typeof i?i=new i(n,e):(i=r.document.createEvent("Event"),e?(i.initEvent(n,e.bubbles,e.cancelable),i.detail=e.detail):i.initEvent(n,!1,!1)),t.dispatchEvent(i)}var zt=[null];function Rt(t,n){this._groups=t,this._parents=n}function Lt(){return new Rt([[document.documentElement]],zt)}function Dt(t){return"string"==typeof t?new Rt([[document.querySelector(t)]],[document.documentElement]):new Rt([[t]],zt)}Rt.prototype=Lt.prototype={constructor:Rt,select:function(t){"function"!=typeof t&&(t=Q(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,a,u=n[i],f=u.length,c=r[i]=new Array(f),s=0;s<f;++s)(o=u[s])&&(a=t.call(o,o.__data__,s,u))&&("__data__"in o&&(a.__data__=o.__data__),c[s]=a);return new Rt(r,this._parents)},selectAll:function(t){"function"!=typeof t&&(t=K(t));for(var n=this._groups,e=n.length,r=[],i=[],o=0;o<e;++o)for(var a,u=n[o],f=u.length,c=0;c<f;++c)(a=u[c])&&(r.push(t.call(a,a.__data__,c,u)),i.push(a));return new Rt(r,i)},filter:function(t){"function"!=typeof t&&(t=rt(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,a=n[i],u=a.length,f=r[i]=[],c=0;c<u;++c)(o=a[c])&&t.call(o,o.__data__,c,a)&&f.push(o);return new Rt(r,this._parents)},data:function(t,n){if(!t)return p=new Array(this.size()),s=-1,this.each(function(t){p[++s]=t}),p;var e,r=n?ft:ut,i=this._parents,o=this._groups;"function"!=typeof t&&(e=t,t=function(){return e});for(var a=o.length,u=new Array(a),f=new Array(a),c=new Array(a),s=0;s<a;++s){var l=i[s],h=o[s],d=h.length,p=t.call(l,l&&l.__data__,s,i),v=p.length,g=f[s]=new Array(v),y=u[s]=new Array(v);r(l,h,g,y,c[s]=new Array(d),p,n);for(var _,b,m=0,x=0;m<v;++m)if(_=g[m]){for(m>=x&&(x=m+1);!(b=y[x])&&++x<v;);_._next=b||null}}return(u=new Rt(u,i))._enter=f,u._exit=c,u},enter:function(){return new Rt(this._enter||this._groups.map(it),this._parents)},exit:function(){return new Rt(this._exit||this._groups.map(it),this._parents)},merge:function(t){for(var n=this._groups,e=t._groups,r=n.length,i=e.length,o=Math.min(r,i),a=new Array(r),u=0;u<o;++u)for(var f,c=n[u],s=e[u],l=c.length,h=a[u]=new Array(l),d=0;d<l;++d)(f=c[d]||s[d])&&(h[d]=f);for(;u<r;++u)a[u]=n[u];return new Rt(a,this._parents)},order:function(){for(var t=this._groups,n=-1,e=t.length;++n<e;)for(var r,i=t[n],o=i.length-1,a=i[o];--o>=0;)(r=i[o])&&(a&&a!==r.nextSibling&&a.parentNode.insertBefore(r,a),a=r);return this},sort:function(t){function n(n,e){return n&&e?t(n.__data__,e.__data__):!n-!e}t||(t=ct);for(var e=this._groups,r=e.length,i=new Array(r),o=0;o<r;++o){for(var a,u=e[o],f=u.length,c=i[o]=new Array(f),s=0;s<f;++s)(a=u[s])&&(c[s]=a);c.sort(n)}return new Rt(i,this._parents).order()},call:function(){var t=arguments[0];return arguments[0]=this,t.apply(null,arguments),this},nodes:function(){var t=new Array(this.size()),n=-1;return this.each(function(){t[++n]=this}),t},node:function(){for(var t=this._groups,n=0,e=t.length;n<e;++n)for(var r=t[n],i=0,o=r.length;i<o;++i){var a=r[i];if(a)return a}return null},size:function(){var t=0;return this.each(function(){++t}),t},empty:function(){return!this.node()},each:function(t){for(var n=this._groups,e=0,r=n.length;e<r;++e)for(var i,o=n[e],a=0,u=o.length;a<u;++a)(i=o[a])&&t.call(i,i.__data__,a,o);return this},attr:function(t,n){var e=$(t);if(arguments.length<2){var r=this.node();return e.local?r.getAttributeNS(e.space,e.local):r.getAttribute(e)}return this.each((null==n?e.local?function(t){return function(){this.removeAttributeNS(t.space,t.local)}}:function(t){return function(){this.removeAttribute(t)}}:"function"==typeof n?e.local?function(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttributeNS(t.space,t.local):this.setAttributeNS(t.space,t.local,e)}}:function(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttribute(t):this.setAttribute(t,e)}}:e.local?function(t,n){return function(){this.setAttributeNS(t.space,t.local,n)}}:function(t,n){return function(){this.setAttribute(t,n)}})(e,n))},style:function(t,n,e){return arguments.length>1?this.each((null==n?function(t){return function(){this.style.removeProperty(t)}}:"function"==typeof n?function(t,n,e){return function(){var r=n.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,e)}}:function(t,n,e){return function(){this.style.setProperty(t,n,e)}})(t,n,null==e?"":e)):lt(this.node(),t)},property:function(t,n){return arguments.length>1?this.each((null==n?function(t){return function(){delete this[t]}}:"function"==typeof n?function(t,n){return function(){var e=n.apply(this,arguments);null==e?delete this[t]:this[t]=e}}:function(t,n){return function(){this[t]=n}})(t,n)):this.node()[t]},classed:function(t,n){var e=ht(t+"");if(arguments.length<2){for(var r=dt(this.node()),i=-1,o=e.length;++i<o;)if(!r.contains(e[i]))return!1;return!0}return this.each(("function"==typeof n?function(t,n){return function(){(n.apply(this,arguments)?vt:gt)(this,t)}}:n?function(t){return function(){vt(this,t)}}:function(t){return function(){gt(this,t)}})(e,n))},text:function(t){return arguments.length?this.each(null==t?yt:("function"==typeof t?function(t){return function(){var n=t.apply(this,arguments);this.textContent=null==n?"":n}}:function(t){return function(){this.textContent=t}})(t)):this.node().textContent},html:function(t){return arguments.length?this.each(null==t?_t:("function"==typeof t?function(t){return function(){var n=t.apply(this,arguments);this.innerHTML=null==n?"":n}}:function(t){return function(){this.innerHTML=t}})(t)):this.node().innerHTML},raise:function(){return this.each(bt)},lower:function(){return this.each(mt)},append:function(t){var n="function"==typeof t?t:W(t);return this.select(function(){return this.appendChild(n.apply(this,arguments))})},insert:function(t,n){var e="function"==typeof t?t:W(t),r=null==n?xt:"function"==typeof n?n:Q(n);return this.select(function(){return this.insertBefore(e.apply(this,arguments),r.apply(this,arguments)||null)})},remove:function(){return this.each(wt)},clone:function(t){return this.select(t?At:Mt)},datum:function(t){return arguments.length?this.property("__data__",t):this.node().__data__},on:function(t,n,e){var r,i,o=function(t){return t.trim().split(/^|\s+/).map(function(t){var n="",e=t.indexOf(".");return e>=0&&(n=t.slice(e+1),t=t.slice(0,e)),{type:t,name:n}})}(t+""),a=o.length;if(!(arguments.length<2)){for(u=n?kt:Et,null==e&&(e=!1),r=0;r<a;++r)this.each(u(o[r],n,e));return this}var u=this.node().__on;if(u)for(var f,c=0,s=u.length;c<s;++c)for(r=0,f=u[c];r<a;++r)if((i=o[r]).type===f.type&&i.name===f.name)return f.value},dispatch:function(t,n){return this.each(("function"==typeof n?function(t,n){return function(){return Pt(this,t,n.apply(this,arguments))}}:function(t,n){return function(){return Pt(this,t,n)}})(t,n))}};var Ut=0;function qt(){return new Ot}function Ot(){this._="@"+(++Ut).toString(36)}function Yt(){for(var n,e=t.event;n=e.sourceEvent;)e=n;return e}function Bt(t,n){var e=t.ownerSVGElement||t;if(e.createSVGPoint){var r=e.createSVGPoint();return r.x=n.clientX,r.y=n.clientY,[(r=r.matrixTransform(t.getScreenCTM().inverse())).x,r.y]}var i=t.getBoundingClientRect();return[n.clientX-i.left-t.clientLeft,n.clientY-i.top-t.clientTop]}function Ft(t){var n=Yt();return n.changedTouches&&(n=n.changedTouches[0]),Bt(t,n)}function It(t,n,e){arguments.length<3&&(e=n,n=Yt().changedTouches);for(var r,i=0,o=n?n.length:0;i<o;++i)if((r=n[i]).identifier===e)return Bt(t,r);return null}function Ht(){t.event.stopImmediatePropagation()}function jt(){t.event.preventDefault(),t.event.stopImmediatePropagation()}function Xt(t){var n=t.document.documentElement,e=Dt(t).on("dragstart.drag",jt,!0);"onselectstart"in n?e.on("selectstart.drag",jt,!0):(n.__noselect=n.style.MozUserSelect,n.style.MozUserSelect="none")}function Gt(t,n){var e=t.document.documentElement,r=Dt(t).on("dragstart.drag",null);n&&(r.on("click.drag",jt,!0),setTimeout(function(){r.on("click.drag",null)},0)),"onselectstart"in e?r.on("selectstart.drag",null):(e.style.MozUserSelect=e.__noselect,delete e.__noselect)}function Vt(t){return function(){return t}}function $t(t,n,e,r,i,o,a,u,f,c){this.target=t,this.type=n,this.subject=e,this.identifier=r,this.active=i,this.x=o,this.y=a,this.dx=u,this.dy=f,this._=c}function Wt(){return!t.event.button}function Zt(){return this.parentNode}function Qt(n){return null==n?{x:t.event.x,y:t.event.y}:n}function Jt(){return"ontouchstart"in this}function Kt(t,n,e){t.prototype=n.prototype=e,e.constructor=t}function tn(t,n){var e=Object.create(t.prototype);for(var r in n)e[r]=n[r];return e}function nn(){}Ot.prototype=qt.prototype={constructor:Ot,get:function(t){for(var n=this._;!(n in t);)if(!(t=t.parentNode))return;return t[n]},set:function(t,n){return t[this._]=n},remove:function(t){return this._ in t&&delete t[this._]},toString:function(){return this._}},$t.prototype.on=function(){var t=this._.on.apply(this._,arguments);return t===this._?this:t};var en="\\s*([+-]?\\d+)\\s*",rn="\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\s*",on="\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)%\\s*",an=/^#([0-9a-f]{3})$/,un=/^#([0-9a-f]{6})$/,fn=new RegExp("^rgb\\("+[en,en,en]+"\\)$"),cn=new RegExp("^rgb\\("+[on,on,on]+"\\)$"),sn=new RegExp("^rgba\\("+[en,en,en,rn]+"\\)$"),ln=new RegExp("^rgba\\("+[on,on,on,rn]+"\\)$"),hn=new RegExp("^hsl\\("+[rn,on,on]+"\\)$"),dn=new RegExp("^hsla\\("+[rn,on,on,rn]+"\\)$"),pn={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074};function vn(t){var n;return t=(t+"").trim().toLowerCase(),(n=an.exec(t))?new mn((n=parseInt(n[1],16))>>8&15|n>>4&240,n>>4&15|240&n,(15&n)<<4|15&n,1):(n=un.exec(t))?gn(parseInt(n[1],16)):(n=fn.exec(t))?new mn(n[1],n[2],n[3],1):(n=cn.exec(t))?new mn(255*n[1]/100,255*n[2]/100,255*n[3]/100,1):(n=sn.exec(t))?yn(n[1],n[2],n[3],n[4]):(n=ln.exec(t))?yn(255*n[1]/100,255*n[2]/100,255*n[3]/100,n[4]):(n=hn.exec(t))?wn(n[1],n[2]/100,n[3]/100,1):(n=dn.exec(t))?wn(n[1],n[2]/100,n[3]/100,n[4]):pn.hasOwnProperty(t)?gn(pn[t]):"transparent"===t?new mn(NaN,NaN,NaN,0):null}function gn(t){return new mn(t>>16&255,t>>8&255,255&t,1)}function yn(t,n,e,r){return r<=0&&(t=n=e=NaN),new mn(t,n,e,r)}function _n(t){return t instanceof nn||(t=vn(t)),t?new mn((t=t.rgb()).r,t.g,t.b,t.opacity):new mn}function bn(t,n,e,r){return 1===arguments.length?_n(t):new mn(t,n,e,null==r?1:r)}function mn(t,n,e,r){this.r=+t,this.g=+n,this.b=+e,this.opacity=+r}function xn(t){return((t=Math.max(0,Math.min(255,Math.round(t)||0)))<16?"0":"")+t.toString(16)}function wn(t,n,e,r){return r<=0?t=n=e=NaN:e<=0||e>=1?t=n=NaN:n<=0&&(t=NaN),new An(t,n,e,r)}function Mn(t,n,e,r){return 1===arguments.length?function(t){if(t instanceof An)return new An(t.h,t.s,t.l,t.opacity);if(t instanceof nn||(t=vn(t)),!t)return new An;if(t instanceof An)return t;var n=(t=t.rgb()).r/255,e=t.g/255,r=t.b/255,i=Math.min(n,e,r),o=Math.max(n,e,r),a=NaN,u=o-i,f=(o+i)/2;return u?(a=n===o?(e-r)/u+6*(e<r):e===o?(r-n)/u+2:(n-e)/u+4,u/=f<.5?o+i:2-o-i,a*=60):u=f>0&&f<1?0:a,new An(a,u,f,t.opacity)}(t):new An(t,n,e,null==r?1:r)}function An(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function Tn(t,n,e){return 255*(t<60?n+(e-n)*t/60:t<180?e:t<240?n+(e-n)*(240-t)/60:n)}Kt(nn,vn,{displayable:function(){return this.rgb().displayable()},hex:function(){return this.rgb().hex()},toString:function(){return this.rgb()+""}}),Kt(mn,bn,tn(nn,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new mn(this.r*t,this.g*t,this.b*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new mn(this.r*t,this.g*t,this.b*t,this.opacity)},rgb:function(){return this},displayable:function(){return 0<=this.r&&this.r<=255&&0<=this.g&&this.g<=255&&0<=this.b&&this.b<=255&&0<=this.opacity&&this.opacity<=1},hex:function(){return"#"+xn(this.r)+xn(this.g)+xn(this.b)},toString:function(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"rgb(":"rgba(")+Math.max(0,Math.min(255,Math.round(this.r)||0))+", "+Math.max(0,Math.min(255,Math.round(this.g)||0))+", "+Math.max(0,Math.min(255,Math.round(this.b)||0))+(1===t?")":", "+t+")")}})),Kt(An,Mn,tn(nn,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new An(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new An(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=this.h%360+360*(this.h<0),n=isNaN(t)||isNaN(this.s)?0:this.s,e=this.l,r=e+(e<.5?e:1-e)*n,i=2*e-r;return new mn(Tn(t>=240?t-240:t+120,i,r),Tn(t,i,r),Tn(t<120?t+240:t-120,i,r),this.opacity)},displayable:function(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1}}));var Nn=Math.PI/180,Sn=180/Math.PI,En=.96422,kn=1,Cn=.82521,Pn=4/29,zn=6/29,Rn=3*zn*zn,Ln=zn*zn*zn;function Dn(t){if(t instanceof qn)return new qn(t.l,t.a,t.b,t.opacity);if(t instanceof jn){if(isNaN(t.h))return new qn(t.l,0,0,t.opacity);var n=t.h*Nn;return new qn(t.l,Math.cos(n)*t.c,Math.sin(n)*t.c,t.opacity)}t instanceof mn||(t=_n(t));var e,r,i=Fn(t.r),o=Fn(t.g),a=Fn(t.b),u=On((.2225045*i+.7168786*o+.0606169*a)/kn);return i===o&&o===a?e=r=u:(e=On((.4360747*i+.3850649*o+.1430804*a)/En),r=On((.0139322*i+.0971045*o+.7141733*a)/Cn)),new qn(116*u-16,500*(e-u),200*(u-r),t.opacity)}function Un(t,n,e,r){return 1===arguments.length?Dn(t):new qn(t,n,e,null==r?1:r)}function qn(t,n,e,r){this.l=+t,this.a=+n,this.b=+e,this.opacity=+r}function On(t){return t>Ln?Math.pow(t,1/3):t/Rn+Pn}function Yn(t){return t>zn?t*t*t:Rn*(t-Pn)}function Bn(t){return 255*(t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055)}function Fn(t){return(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function In(t){if(t instanceof jn)return new jn(t.h,t.c,t.l,t.opacity);if(t instanceof qn||(t=Dn(t)),0===t.a&&0===t.b)return new jn(NaN,0,t.l,t.opacity);var n=Math.atan2(t.b,t.a)*Sn;return new jn(n<0?n+360:n,Math.sqrt(t.a*t.a+t.b*t.b),t.l,t.opacity)}function Hn(t,n,e,r){return 1===arguments.length?In(t):new jn(t,n,e,null==r?1:r)}function jn(t,n,e,r){this.h=+t,this.c=+n,this.l=+e,this.opacity=+r}Kt(qn,Un,tn(nn,{brighter:function(t){return new qn(this.l+18*(null==t?1:t),this.a,this.b,this.opacity)},darker:function(t){return new qn(this.l-18*(null==t?1:t),this.a,this.b,this.opacity)},rgb:function(){var t=(this.l+16)/116,n=isNaN(this.a)?t:t+this.a/500,e=isNaN(this.b)?t:t-this.b/200;return new mn(Bn(3.1338561*(n=En*Yn(n))-1.6168667*(t=kn*Yn(t))-.4906146*(e=Cn*Yn(e))),Bn(-.9787684*n+1.9161415*t+.033454*e),Bn(.0719453*n-.2289914*t+1.4052427*e),this.opacity)}})),Kt(jn,Hn,tn(nn,{brighter:function(t){return new jn(this.h,this.c,this.l+18*(null==t?1:t),this.opacity)},darker:function(t){return new jn(this.h,this.c,this.l-18*(null==t?1:t),this.opacity)},rgb:function(){return Dn(this).rgb()}}));var Xn=-.14861,Gn=1.78277,Vn=-.29227,$n=-.90649,Wn=1.97294,Zn=Wn*$n,Qn=Wn*Gn,Jn=Gn*Vn-$n*Xn;function Kn(t,n,e,r){return 1===arguments.length?function(t){if(t instanceof te)return new te(t.h,t.s,t.l,t.opacity);t instanceof mn||(t=_n(t));var n=t.r/255,e=t.g/255,r=t.b/255,i=(Jn*r+Zn*n-Qn*e)/(Jn+Zn-Qn),o=r-i,a=(Wn*(e-i)-Vn*o)/$n,u=Math.sqrt(a*a+o*o)/(Wn*i*(1-i)),f=u?Math.atan2(a,o)*Sn-120:NaN;return new te(f<0?f+360:f,u,i,t.opacity)}(t):new te(t,n,e,null==r?1:r)}function te(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function ne(t,n,e,r,i){var o=t*t,a=o*t;return((1-3*t+3*o-a)*n+(4-6*o+3*a)*e+(1+3*t+3*o-3*a)*r+a*i)/6}function ee(t){var n=t.length-1;return function(e){var r=e<=0?e=0:e>=1?(e=1,n-1):Math.floor(e*n),i=t[r],o=t[r+1],a=r>0?t[r-1]:2*i-o,u=r<n-1?t[r+2]:2*o-i;return ne((e-r/n)*n,a,i,o,u)}}function re(t){var n=t.length;return function(e){var r=Math.floor(((e%=1)<0?++e:e)*n),i=t[(r+n-1)%n],o=t[r%n],a=t[(r+1)%n],u=t[(r+2)%n];return ne((e-r/n)*n,i,o,a,u)}}function ie(t){return function(){return t}}function oe(t,n){return function(e){return t+e*n}}function ae(t,n){var e=n-t;return e?oe(t,e>180||e<-180?e-360*Math.round(e/360):e):ie(isNaN(t)?n:t)}function ue(t){return 1==(t=+t)?fe:function(n,e){return e-n?function(t,n,e){return t=Math.pow(t,e),n=Math.pow(n,e)-t,e=1/e,function(r){return Math.pow(t+r*n,e)}}(n,e,t):ie(isNaN(n)?e:n)}}function fe(t,n){var e=n-t;return e?oe(t,e):ie(isNaN(t)?n:t)}Kt(te,Kn,tn(nn,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new te(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new te(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=isNaN(this.h)?0:(this.h+120)*Nn,n=+this.l,e=isNaN(this.s)?0:this.s*n*(1-n),r=Math.cos(t),i=Math.sin(t);return new mn(255*(n+e*(Xn*r+Gn*i)),255*(n+e*(Vn*r+$n*i)),255*(n+e*(Wn*r)),this.opacity)}}));var ce=function t(n){var e=ue(n);function r(t,n){var r=e((t=bn(t)).r,(n=bn(n)).r),i=e(t.g,n.g),o=e(t.b,n.b),a=fe(t.opacity,n.opacity);return function(n){return t.r=r(n),t.g=i(n),t.b=o(n),t.opacity=a(n),t+""}}return r.gamma=t,r}(1);function se(t){return function(n){var e,r,i=n.length,o=new Array(i),a=new Array(i),u=new Array(i);for(e=0;e<i;++e)r=bn(n[e]),o[e]=r.r||0,a[e]=r.g||0,u[e]=r.b||0;return o=t(o),a=t(a),u=t(u),r.opacity=1,function(t){return r.r=o(t),r.g=a(t),r.b=u(t),r+""}}}var le=se(ee),he=se(re);function de(t,n){var e,r=n?n.length:0,i=t?Math.min(r,t.length):0,o=new Array(i),a=new Array(r);for(e=0;e<i;++e)o[e]=me(t[e],n[e]);for(;e<r;++e)a[e]=n[e];return function(t){for(e=0;e<i;++e)a[e]=o[e](t);return a}}function pe(t,n){var e=new Date;return n-=t=+t,function(r){return e.setTime(t+n*r),e}}function ve(t,n){return n-=t=+t,function(e){return t+n*e}}function ge(t,n){var e,r={},i={};for(e in null!==t&&"object"==typeof t||(t={}),null!==n&&"object"==typeof n||(n={}),n)e in t?r[e]=me(t[e],n[e]):i[e]=n[e];return function(t){for(e in r)i[e]=r[e](t);return i}}var ye=/[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,_e=new RegExp(ye.source,"g");function be(t,n){var e,r,i,o=ye.lastIndex=_e.lastIndex=0,a=-1,u=[],f=[];for(t+="",n+="";(e=ye.exec(t))&&(r=_e.exec(n));)(i=r.index)>o&&(i=n.slice(o,i),u[a]?u[a]+=i:u[++a]=i),(e=e[0])===(r=r[0])?u[a]?u[a]+=r:u[++a]=r:(u[++a]=null,f.push({i:a,x:ve(e,r)})),o=_e.lastIndex;return o<n.length&&(i=n.slice(o),u[a]?u[a]+=i:u[++a]=i),u.length<2?f[0]?function(t){return function(n){return t(n)+""}}(f[0].x):function(t){return function(){return t}}(n):(n=f.length,function(t){for(var e,r=0;r<n;++r)u[(e=f[r]).i]=e.x(t);return u.join("")})}function me(t,n){var e,r=typeof n;return null==n||"boolean"===r?ie(n):("number"===r?ve:"string"===r?(e=vn(n))?(n=e,ce):be:n instanceof vn?ce:n instanceof Date?pe:Array.isArray(n)?de:"function"!=typeof n.valueOf&&"function"!=typeof n.toString||isNaN(n)?ge:ve)(t,n)}function xe(t,n){return n-=t=+t,function(e){return Math.round(t+n*e)}}var we,Me,Ae,Te,Ne=180/Math.PI,Se={translateX:0,translateY:0,rotate:0,skewX:0,scaleX:1,scaleY:1};function Ee(t,n,e,r,i,o){var a,u,f;return(a=Math.sqrt(t*t+n*n))&&(t/=a,n/=a),(f=t*e+n*r)&&(e-=t*f,r-=n*f),(u=Math.sqrt(e*e+r*r))&&(e/=u,r/=u,f/=u),t*r<n*e&&(t=-t,n=-n,f=-f,a=-a),{translateX:i,translateY:o,rotate:Math.atan2(n,t)*Ne,skewX:Math.atan(f)*Ne,scaleX:a,scaleY:u}}function ke(t,n,e,r){function i(t){return t.length?t.pop()+" ":""}return function(o,a){var u=[],f=[];return o=t(o),a=t(a),function(t,r,i,o,a,u){if(t!==i||r!==o){var f=a.push("translate(",null,n,null,e);u.push({i:f-4,x:ve(t,i)},{i:f-2,x:ve(r,o)})}else(i||o)&&a.push("translate("+i+n+o+e)}(o.translateX,o.translateY,a.translateX,a.translateY,u,f),function(t,n,e,o){t!==n?(t-n>180?n+=360:n-t>180&&(t+=360),o.push({i:e.push(i(e)+"rotate(",null,r)-2,x:ve(t,n)})):n&&e.push(i(e)+"rotate("+n+r)}(o.rotate,a.rotate,u,f),function(t,n,e,o){t!==n?o.push({i:e.push(i(e)+"skewX(",null,r)-2,x:ve(t,n)}):n&&e.push(i(e)+"skewX("+n+r)}(o.skewX,a.skewX,u,f),function(t,n,e,r,o,a){if(t!==e||n!==r){var u=o.push(i(o)+"scale(",null,",",null,")");a.push({i:u-4,x:ve(t,e)},{i:u-2,x:ve(n,r)})}else 1===e&&1===r||o.push(i(o)+"scale("+e+","+r+")")}(o.scaleX,o.scaleY,a.scaleX,a.scaleY,u,f),o=a=null,function(t){for(var n,e=-1,r=f.length;++e<r;)u[(n=f[e]).i]=n.x(t);return u.join("")}}}var Ce=ke(function(t){return"none"===t?Se:(we||(we=document.createElement("DIV"),Me=document.documentElement,Ae=document.defaultView),we.style.transform=t,t=Ae.getComputedStyle(Me.appendChild(we),null).getPropertyValue("transform"),Me.removeChild(we),Ee(+(t=t.slice(7,-1).split(","))[0],+t[1],+t[2],+t[3],+t[4],+t[5]))},"px, ","px)","deg)"),Pe=ke(function(t){return null==t?Se:(Te||(Te=document.createElementNS("http://www.w3.org/2000/svg","g")),Te.setAttribute("transform",t),(t=Te.transform.baseVal.consolidate())?Ee((t=t.matrix).a,t.b,t.c,t.d,t.e,t.f):Se)},", ",")",")"),ze=Math.SQRT2,Re=2,Le=4,De=1e-12;function Ue(t){return((t=Math.exp(t))+1/t)/2}function qe(t,n){var e,r,i=t[0],o=t[1],a=t[2],u=n[0],f=n[1],c=n[2],s=u-i,l=f-o,h=s*s+l*l;if(h<De)r=Math.log(c/a)/ze,e=function(t){return[i+t*s,o+t*l,a*Math.exp(ze*t*r)]};else{var d=Math.sqrt(h),p=(c*c-a*a+Le*h)/(2*a*Re*d),v=(c*c-a*a-Le*h)/(2*c*Re*d),g=Math.log(Math.sqrt(p*p+1)-p),y=Math.log(Math.sqrt(v*v+1)-v);r=(y-g)/ze,e=function(t){var n,e=t*r,u=Ue(g),f=a/(Re*d)*(u*(n=ze*e+g,((n=Math.exp(2*n))-1)/(n+1))-function(t){return((t=Math.exp(t))-1/t)/2}(g));return[i+f*s,o+f*l,a*u/Ue(ze*e+g)]}}return e.duration=1e3*r,e}function Oe(t){return function(n,e){var r=t((n=Mn(n)).h,(e=Mn(e)).h),i=fe(n.s,e.s),o=fe(n.l,e.l),a=fe(n.opacity,e.opacity);return function(t){return n.h=r(t),n.s=i(t),n.l=o(t),n.opacity=a(t),n+""}}}var Ye=Oe(ae),Be=Oe(fe);function Fe(t){return function(n,e){var r=t((n=Hn(n)).h,(e=Hn(e)).h),i=fe(n.c,e.c),o=fe(n.l,e.l),a=fe(n.opacity,e.opacity);return function(t){return n.h=r(t),n.c=i(t),n.l=o(t),n.opacity=a(t),n+""}}}var Ie=Fe(ae),He=Fe(fe);function je(t){return function n(e){function r(n,r){var i=t((n=Kn(n)).h,(r=Kn(r)).h),o=fe(n.s,r.s),a=fe(n.l,r.l),u=fe(n.opacity,r.opacity);return function(t){return n.h=i(t),n.s=o(t),n.l=a(Math.pow(t,e)),n.opacity=u(t),n+""}}return e=+e,r.gamma=n,r}(1)}var Xe=je(ae),Ge=je(fe);var Ve,$e,We=0,Ze=0,Qe=0,Je=1e3,Ke=0,tr=0,nr=0,er="object"==typeof performance&&performance.now?performance:Date,rr="object"==typeof window&&window.requestAnimationFrame?window.requestAnimationFrame.bind(window):function(t){setTimeout(t,17)};function ir(){return tr||(rr(or),tr=er.now()+nr)}function or(){tr=0}function ar(){this._call=this._time=this._next=null}function ur(t,n,e){var r=new ar;return r.restart(t,n,e),r}function fr(){ir(),++We;for(var t,n=Ve;n;)(t=tr-n._time)>=0&&n._call.call(null,t),n=n._next;--We}function cr(){tr=(Ke=er.now())+nr,We=Ze=0;try{fr()}finally{We=0,function(){var t,n,e=Ve,r=1/0;for(;e;)e._call?(r>e._time&&(r=e._time),t=e,e=e._next):(n=e._next,e._next=null,e=t?t._next=n:Ve=n);$e=t,lr(r)}(),tr=0}}function sr(){var t=er.now(),n=t-Ke;n>Je&&(nr-=n,Ke=t)}function lr(t){We||(Ze&&(Ze=clearTimeout(Ze)),t-tr>24?(t<1/0&&(Ze=setTimeout(cr,t-er.now()-nr)),Qe&&(Qe=clearInterval(Qe))):(Qe||(Ke=er.now(),Qe=setInterval(sr,Je)),We=1,rr(cr)))}function hr(t,n,e){var r=new ar;return n=null==n?0:+n,r.restart(function(e){r.stop(),t(e+n)},n,e),r}ar.prototype=ur.prototype={constructor:ar,restart:function(t,n,e){if("function"!=typeof t)throw new TypeError("callback is not a function");e=(null==e?ir():+e)+(null==n?0:+n),this._next||$e===this||($e?$e._next=this:Ve=this,$e=this),this._call=t,this._time=e,lr()},stop:function(){this._call&&(this._call=null,this._time=1/0,lr())}};var dr=I("start","end","interrupt"),pr=[],vr=0,gr=1,yr=2,_r=3,br=4,mr=5,xr=6;function wr(t,n,e,r,i,o){var a=t.__transition;if(a){if(e in a)return}else t.__transition={};!function(t,n,e){var r,i=t.__transition;function o(f){var c,s,l,h;if(e.state!==gr)return u();for(c in i)if((h=i[c]).name===e.name){if(h.state===_r)return hr(o);h.state===br?(h.state=xr,h.timer.stop(),h.on.call("interrupt",t,t.__data__,h.index,h.group),delete i[c]):+c<n&&(h.state=xr,h.timer.stop(),delete i[c])}if(hr(function(){e.state===_r&&(e.state=br,e.timer.restart(a,e.delay,e.time),a(f))}),e.state=yr,e.on.call("start",t,t.__data__,e.index,e.group),e.state===yr){for(e.state=_r,r=new Array(l=e.tween.length),c=0,s=-1;c<l;++c)(h=e.tween[c].value.call(t,t.__data__,e.index,e.group))&&(r[++s]=h);r.length=s+1}}function a(n){for(var i=n<e.duration?e.ease.call(null,n/e.duration):(e.timer.restart(u),e.state=mr,1),o=-1,a=r.length;++o<a;)r[o].call(null,i);e.state===mr&&(e.on.call("end",t,t.__data__,e.index,e.group),u())}function u(){for(var r in e.state=xr,e.timer.stop(),delete i[n],i)return;delete t.__transition}i[n]=e,e.timer=ur(function(t){e.state=gr,e.timer.restart(o,e.delay,e.time),e.delay<=t&&o(t-e.delay)},0,e.time)}(t,e,{name:n,index:r,group:i,on:dr,tween:pr,time:o.time,delay:o.delay,duration:o.duration,ease:o.ease,timer:null,state:vr})}function Mr(t,n){var e=Tr(t,n);if(e.state>vr)throw new Error("too late; already scheduled");return e}function Ar(t,n){var e=Tr(t,n);if(e.state>yr)throw new Error("too late; already started");return e}function Tr(t,n){var e=t.__transition;if(!e||!(e=e[n]))throw new Error("transition not found");return e}function Nr(t,n){var e,r,i,o=t.__transition,a=!0;if(o){for(i in n=null==n?null:n+"",o)(e=o[i]).name===n?(r=e.state>yr&&e.state<mr,e.state=xr,e.timer.stop(),r&&e.on.call("interrupt",t,t.__data__,e.index,e.group),delete o[i]):a=!1;a&&delete t.__transition}}function Sr(t,n,e){var r=t._id;return t.each(function(){var t=Ar(this,r);(t.value||(t.value={}))[n]=e.apply(this,arguments)}),function(t){return Tr(t,r).value[n]}}function Er(t,n){var e;return("number"==typeof n?ve:n instanceof vn?ce:(e=vn(n))?(n=e,ce):be)(t,n)}var kr=Lt.prototype.constructor;var Cr=0;function Pr(t,n,e,r){this._groups=t,this._parents=n,this._name=e,this._id=r}function zr(t){return Lt().transition(t)}function Rr(){return++Cr}var Lr=Lt.prototype;function Dr(t){return((t*=2)<=1?t*t:--t*(2-t)+1)/2}function Ur(t){return((t*=2)<=1?t*t*t:(t-=2)*t*t+2)/2}Pr.prototype=zr.prototype={constructor:Pr,select:function(t){var n=this._name,e=this._id;"function"!=typeof t&&(t=Q(t));for(var r=this._groups,i=r.length,o=new Array(i),a=0;a<i;++a)for(var u,f,c=r[a],s=c.length,l=o[a]=new Array(s),h=0;h<s;++h)(u=c[h])&&(f=t.call(u,u.__data__,h,c))&&("__data__"in u&&(f.__data__=u.__data__),l[h]=f,wr(l[h],n,e,h,l,Tr(u,e)));return new Pr(o,this._parents,n,e)},selectAll:function(t){var n=this._name,e=this._id;"function"!=typeof t&&(t=K(t));for(var r=this._groups,i=r.length,o=[],a=[],u=0;u<i;++u)for(var f,c=r[u],s=c.length,l=0;l<s;++l)if(f=c[l]){for(var h,d=t.call(f,f.__data__,l,c),p=Tr(f,e),v=0,g=d.length;v<g;++v)(h=d[v])&&wr(h,n,e,v,d,p);o.push(d),a.push(f)}return new Pr(o,a,n,e)},filter:function(t){"function"!=typeof t&&(t=rt(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,a=n[i],u=a.length,f=r[i]=[],c=0;c<u;++c)(o=a[c])&&t.call(o,o.__data__,c,a)&&f.push(o);return new Pr(r,this._parents,this._name,this._id)},merge:function(t){if(t._id!==this._id)throw new Error;for(var n=this._groups,e=t._groups,r=n.length,i=e.length,o=Math.min(r,i),a=new Array(r),u=0;u<o;++u)for(var f,c=n[u],s=e[u],l=c.length,h=a[u]=new Array(l),d=0;d<l;++d)(f=c[d]||s[d])&&(h[d]=f);for(;u<r;++u)a[u]=n[u];return new Pr(a,this._parents,this._name,this._id)},selection:function(){return new kr(this._groups,this._parents)},transition:function(){for(var t=this._name,n=this._id,e=Rr(),r=this._groups,i=r.length,o=0;o<i;++o)for(var a,u=r[o],f=u.length,c=0;c<f;++c)if(a=u[c]){var s=Tr(a,n);wr(a,t,e,c,u,{time:s.time+s.delay+s.duration,delay:0,duration:s.duration,ease:s.ease})}return new Pr(r,this._parents,t,e)},call:Lr.call,nodes:Lr.nodes,node:Lr.node,size:Lr.size,empty:Lr.empty,each:Lr.each,on:function(t,n){var e=this._id;return arguments.length<2?Tr(this.node(),e).on.on(t):this.each(function(t,n,e){var r,i,o=function(t){return(t+"").trim().split(/^|\s+/).every(function(t){var n=t.indexOf(".");return n>=0&&(t=t.slice(0,n)),!t||"start"===t})}(n)?Mr:Ar;return function(){var a=o(this,t),u=a.on;u!==r&&(i=(r=u).copy()).on(n,e),a.on=i}}(e,t,n))},attr:function(t,n){var e=$(t),r="transform"===e?Pe:Er;return this.attrTween(t,"function"==typeof n?(e.local?function(t,n,e){var r,i,o;return function(){var a,u=e(this);if(null!=u)return(a=this.getAttributeNS(t.space,t.local))===u?null:a===r&&u===i?o:o=n(r=a,i=u);this.removeAttributeNS(t.space,t.local)}}:function(t,n,e){var r,i,o;return function(){var a,u=e(this);if(null!=u)return(a=this.getAttribute(t))===u?null:a===r&&u===i?o:o=n(r=a,i=u);this.removeAttribute(t)}})(e,r,Sr(this,"attr."+t,n)):null==n?(e.local?function(t){return function(){this.removeAttributeNS(t.space,t.local)}}:function(t){return function(){this.removeAttribute(t)}})(e):(e.local?function(t,n,e){var r,i;return function(){var o=this.getAttributeNS(t.space,t.local);return o===e?null:o===r?i:i=n(r=o,e)}}:function(t,n,e){var r,i;return function(){var o=this.getAttribute(t);return o===e?null:o===r?i:i=n(r=o,e)}})(e,r,n+""))},attrTween:function(t,n){var e="attr."+t;if(arguments.length<2)return(e=this.tween(e))&&e._value;if(null==n)return this.tween(e,null);if("function"!=typeof n)throw new Error;var r=$(t);return this.tween(e,(r.local?function(t,n){function e(){var e=this,r=n.apply(e,arguments);return r&&function(n){e.setAttributeNS(t.space,t.local,r(n))}}return e._value=n,e}:function(t,n){function e(){var e=this,r=n.apply(e,arguments);return r&&function(n){e.setAttribute(t,r(n))}}return e._value=n,e})(r,n))},style:function(t,n,e){var r="transform"==(t+="")?Ce:Er;return null==n?this.styleTween(t,function(t,n){var e,r,i;return function(){var o=lt(this,t),a=(this.style.removeProperty(t),lt(this,t));return o===a?null:o===e&&a===r?i:i=n(e=o,r=a)}}(t,r)).on("end.style."+t,function(t){return function(){this.style.removeProperty(t)}}(t)):this.styleTween(t,"function"==typeof n?function(t,n,e){var r,i,o;return function(){var a=lt(this,t),u=e(this);return null==u&&(this.style.removeProperty(t),u=lt(this,t)),a===u?null:a===r&&u===i?o:o=n(r=a,i=u)}}(t,r,Sr(this,"style."+t,n)):function(t,n,e){var r,i;return function(){var o=lt(this,t);return o===e?null:o===r?i:i=n(r=o,e)}}(t,r,n+""),e)},styleTween:function(t,n,e){var r="style."+(t+="");if(arguments.length<2)return(r=this.tween(r))&&r._value;if(null==n)return this.tween(r,null);if("function"!=typeof n)throw new Error;return this.tween(r,function(t,n,e){function r(){var r=this,i=n.apply(r,arguments);return i&&function(n){r.style.setProperty(t,i(n),e)}}return r._value=n,r}(t,n,null==e?"":e))},text:function(t){return this.tween("text","function"==typeof t?function(t){return function(){var n=t(this);this.textContent=null==n?"":n}}(Sr(this,"text",t)):function(t){return function(){this.textContent=t}}(null==t?"":t+""))},remove:function(){return this.on("end.remove",(t=this._id,function(){var n=this.parentNode;for(var e in this.__transition)if(+e!==t)return;n&&n.removeChild(this)}));var t},tween:function(t,n){var e=this._id;if(t+="",arguments.length<2){for(var r,i=Tr(this.node(),e).tween,o=0,a=i.length;o<a;++o)if((r=i[o]).name===t)return r.value;return null}return this.each((null==n?function(t,n){var e,r;return function(){var i=Ar(this,t),o=i.tween;if(o!==e)for(var a=0,u=(r=e=o).length;a<u;++a)if(r[a].name===n){(r=r.slice()).splice(a,1);break}i.tween=r}}:function(t,n,e){var r,i;if("function"!=typeof e)throw new Error;return function(){var o=Ar(this,t),a=o.tween;if(a!==r){i=(r=a).slice();for(var u={name:n,value:e},f=0,c=i.length;f<c;++f)if(i[f].name===n){i[f]=u;break}f===c&&i.push(u)}o.tween=i}})(e,t,n))},delay:function(t){var n=this._id;return arguments.length?this.each(("function"==typeof t?function(t,n){return function(){Mr(this,t).delay=+n.apply(this,arguments)}}:function(t,n){return n=+n,function(){Mr(this,t).delay=n}})(n,t)):Tr(this.node(),n).delay},duration:function(t){var n=this._id;return arguments.length?this.each(("function"==typeof t?function(t,n){return function(){Ar(this,t).duration=+n.apply(this,arguments)}}:function(t,n){return n=+n,function(){Ar(this,t).duration=n}})(n,t)):Tr(this.node(),n).duration},ease:function(t){var n=this._id;return arguments.length?this.each(function(t,n){if("function"!=typeof n)throw new Error;return function(){Ar(this,t).ease=n}}(n,t)):Tr(this.node(),n).ease}};var qr=function t(n){function e(t){return Math.pow(t,n)}return n=+n,e.exponent=t,e}(3),Or=function t(n){function e(t){return 1-Math.pow(1-t,n)}return n=+n,e.exponent=t,e}(3),Yr=function t(n){function e(t){return((t*=2)<=1?Math.pow(t,n):2-Math.pow(2-t,n))/2}return n=+n,e.exponent=t,e}(3),Br=Math.PI,Fr=Br/2;function Ir(t){return(1-Math.cos(Br*t))/2}function Hr(t){return((t*=2)<=1?Math.pow(2,10*t-10):2-Math.pow(2,10-10*t))/2}function jr(t){return((t*=2)<=1?1-Math.sqrt(1-t*t):Math.sqrt(1-(t-=2)*t)+1)/2}var Xr=4/11,Gr=6/11,Vr=8/11,$r=.75,Wr=9/11,Zr=10/11,Qr=.9375,Jr=21/22,Kr=63/64,ti=1/Xr/Xr;function ni(t){return(t=+t)<Xr?ti*t*t:t<Vr?ti*(t-=Gr)*t+$r:t<Zr?ti*(t-=Wr)*t+Qr:ti*(t-=Jr)*t+Kr}var ei=function t(n){function e(t){return t*t*((n+1)*t-n)}return n=+n,e.overshoot=t,e}(1.70158),ri=function t(n){function e(t){return--t*t*((n+1)*t+n)+1}return n=+n,e.overshoot=t,e}(1.70158),ii=function t(n){function e(t){return((t*=2)<1?t*t*((n+1)*t-n):(t-=2)*t*((n+1)*t+n)+2)/2}return n=+n,e.overshoot=t,e}(1.70158),oi=2*Math.PI,ai=function t(n,e){var r=Math.asin(1/(n=Math.max(1,n)))*(e/=oi);function i(t){return n*Math.pow(2,10*--t)*Math.sin((r-t)/e)}return i.amplitude=function(n){return t(n,e*oi)},i.period=function(e){return t(n,e)},i}(1,.3),ui=function t(n,e){var r=Math.asin(1/(n=Math.max(1,n)))*(e/=oi);function i(t){return 1-n*Math.pow(2,-10*(t=+t))*Math.sin((t+r)/e)}return i.amplitude=function(n){return t(n,e*oi)},i.period=function(e){return t(n,e)},i}(1,.3),fi=function t(n,e){var r=Math.asin(1/(n=Math.max(1,n)))*(e/=oi);function i(t){return((t=2*t-1)<0?n*Math.pow(2,10*t)*Math.sin((r-t)/e):2-n*Math.pow(2,-10*t)*Math.sin((r+t)/e))/2}return i.amplitude=function(n){return t(n,e*oi)},i.period=function(e){return t(n,e)},i}(1,.3),ci={time:null,delay:0,duration:250,ease:Ur};function si(t,n){for(var e;!(e=t.__transition)||!(e=e[n]);)if(!(t=t.parentNode))return ci.time=ir(),ci;return e}Lt.prototype.interrupt=function(t){return this.each(function(){Nr(this,t)})},Lt.prototype.transition=function(t){var n,e;t instanceof Pr?(n=t._id,t=t._name):(n=Rr(),(e=ci).time=ir(),t=null==t?null:t+"");for(var r=this._groups,i=r.length,o=0;o<i;++o)for(var a,u=r[o],f=u.length,c=0;c<f;++c)(a=u[c])&&wr(a,t,n,c,u,e||si(a,n));return new Pr(r,this._parents,t,n)};var li=[null];function hi(t){return function(){return t}}function di(t,n,e){this.target=t,this.type=n,this.selection=e}function pi(){t.event.stopImmediatePropagation()}function vi(){t.event.preventDefault(),t.event.stopImmediatePropagation()}var gi={name:"drag"},yi={name:"space"},_i={name:"handle"},bi={name:"center"},mi={name:"x",handles:["e","w"].map(Ei),input:function(t,n){return t&&[[t[0],n[0][1]],[t[1],n[1][1]]]},output:function(t){return t&&[t[0][0],t[1][0]]}},xi={name:"y",handles:["n","s"].map(Ei),input:function(t,n){return t&&[[n[0][0],t[0]],[n[1][0],t[1]]]},output:function(t){return t&&[t[0][1],t[1][1]]}},wi={name:"xy",handles:["n","e","s","w","nw","ne","se","sw"].map(Ei),input:function(t){return t},output:function(t){return t}},Mi={overlay:"crosshair",selection:"move",n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},Ai={e:"w",w:"e",nw:"ne",ne:"nw",se:"sw",sw:"se"},Ti={n:"s",s:"n",nw:"sw",ne:"se",se:"ne",sw:"nw"},Ni={overlay:1,selection:1,n:null,e:1,s:null,w:-1,nw:-1,ne:1,se:1,sw:-1},Si={overlay:1,selection:1,n:-1,e:null,s:1,w:null,nw:-1,ne:-1,se:1,sw:1};function Ei(t){return{type:t}}function ki(){return!t.event.button}function Ci(){var t=this.ownerSVGElement||this;return[[0,0],[t.width.baseVal.value,t.height.baseVal.value]]}function Pi(t){for(;!t.__brush;)if(!(t=t.parentNode))return;return t.__brush}function zi(t){return t[0][0]===t[1][0]||t[0][1]===t[1][1]}function Ri(n){var e,r=Ci,i=ki,o=I(u,"start","brush","end"),a=6;function u(t){var e=t.property("__brush",h).selectAll(".overlay").data([Ei("overlay")]);e.enter().append("rect").attr("class","overlay").attr("pointer-events","all").attr("cursor",Mi.overlay).merge(e).each(function(){var t=Pi(this).extent;Dt(this).attr("x",t[0][0]).attr("y",t[0][1]).attr("width",t[1][0]-t[0][0]).attr("height",t[1][1]-t[0][1])}),t.selectAll(".selection").data([Ei("selection")]).enter().append("rect").attr("class","selection").attr("cursor",Mi.selection).attr("fill","#777").attr("fill-opacity",.3).attr("stroke","#fff").attr("shape-rendering","crispEdges");var r=t.selectAll(".handle").data(n.handles,function(t){return t.type});r.exit().remove(),r.enter().append("rect").attr("class",function(t){return"handle handle--"+t.type}).attr("cursor",function(t){return Mi[t.type]}),t.each(f).attr("fill","none").attr("pointer-events","all").style("-webkit-tap-highlight-color","rgba(0,0,0,0)").on("mousedown.brush touchstart.brush",l)}function f(){var t=Dt(this),n=Pi(this).selection;n?(t.selectAll(".selection").style("display",null).attr("x",n[0][0]).attr("y",n[0][1]).attr("width",n[1][0]-n[0][0]).attr("height",n[1][1]-n[0][1]),t.selectAll(".handle").style("display",null).attr("x",function(t){return"e"===t.type[t.type.length-1]?n[1][0]-a/2:n[0][0]-a/2}).attr("y",function(t){return"s"===t.type[0]?n[1][1]-a/2:n[0][1]-a/2}).attr("width",function(t){return"n"===t.type||"s"===t.type?n[1][0]-n[0][0]+a:a}).attr("height",function(t){return"e"===t.type||"w"===t.type?n[1][1]-n[0][1]+a:a})):t.selectAll(".selection,.handle").style("display","none").attr("x",null).attr("y",null).attr("width",null).attr("height",null)}function c(t,n){return t.__brush.emitter||new s(t,n)}function s(t,n){this.that=t,this.args=n,this.state=t.__brush,this.active=0}function l(){if(t.event.touches){if(t.event.changedTouches.length<t.event.touches.length)return vi()}else if(e)return;if(i.apply(this,arguments)){var r,o,a,u,s,l,h,d,p,v,g,y,_,b=this,m=t.event.target.__data__.type,x="selection"===(t.event.metaKey?m="overlay":m)?gi:t.event.altKey?bi:_i,w=n===xi?null:Ni[m],M=n===mi?null:Si[m],A=Pi(b),T=A.extent,N=A.selection,S=T[0][0],E=T[0][1],k=T[1][0],C=T[1][1],P=w&&M&&t.event.shiftKey,z=Ft(b),R=z,L=c(b,arguments).beforestart();"overlay"===m?A.selection=N=[[r=n===xi?S:z[0],a=n===mi?E:z[1]],[s=n===xi?k:r,h=n===mi?C:a]]:(r=N[0][0],a=N[0][1],s=N[1][0],h=N[1][1]),o=r,u=a,l=s,d=h;var D=Dt(b).attr("pointer-events","none"),U=D.selectAll(".overlay").attr("cursor",Mi[m]);if(t.event.touches)D.on("touchmove.brush",O,!0).on("touchend.brush touchcancel.brush",B,!0);else{var q=Dt(t.event.view).on("keydown.brush",function(){switch(t.event.keyCode){case 16:P=w&&M;break;case 18:x===_i&&(w&&(s=l-p*w,r=o+p*w),M&&(h=d-v*M,a=u+v*M),x=bi,Y());break;case 32:x!==_i&&x!==bi||(w<0?s=l-p:w>0&&(r=o-p),M<0?h=d-v:M>0&&(a=u-v),x=yi,U.attr("cursor",Mi.selection),Y());break;default:return}vi()},!0).on("keyup.brush",function(){switch(t.event.keyCode){case 16:P&&(y=_=P=!1,Y());break;case 18:x===bi&&(w<0?s=l:w>0&&(r=o),M<0?h=d:M>0&&(a=u),x=_i,Y());break;case 32:x===yi&&(t.event.altKey?(w&&(s=l-p*w,r=o+p*w),M&&(h=d-v*M,a=u+v*M),x=bi):(w<0?s=l:w>0&&(r=o),M<0?h=d:M>0&&(a=u),x=_i),U.attr("cursor",Mi[m]),Y());break;default:return}vi()},!0).on("mousemove.brush",O,!0).on("mouseup.brush",B,!0);Xt(t.event.view)}pi(),Nr(b),f.call(b),L.start()}function O(){var t=Ft(b);!P||y||_||(Math.abs(t[0]-R[0])>Math.abs(t[1]-R[1])?_=!0:y=!0),R=t,g=!0,vi(),Y()}function Y(){var t;switch(p=R[0]-z[0],v=R[1]-z[1],x){case yi:case gi:w&&(p=Math.max(S-r,Math.min(k-s,p)),o=r+p,l=s+p),M&&(v=Math.max(E-a,Math.min(C-h,v)),u=a+v,d=h+v);break;case _i:w<0?(p=Math.max(S-r,Math.min(k-r,p)),o=r+p,l=s):w>0&&(p=Math.max(S-s,Math.min(k-s,p)),o=r,l=s+p),M<0?(v=Math.max(E-a,Math.min(C-a,v)),u=a+v,d=h):M>0&&(v=Math.max(E-h,Math.min(C-h,v)),u=a,d=h+v);break;case bi:w&&(o=Math.max(S,Math.min(k,r-p*w)),l=Math.max(S,Math.min(k,s+p*w))),M&&(u=Math.max(E,Math.min(C,a-v*M)),d=Math.max(E,Math.min(C,h+v*M)))}l<o&&(w*=-1,t=r,r=s,s=t,t=o,o=l,l=t,m in Ai&&U.attr("cursor",Mi[m=Ai[m]])),d<u&&(M*=-1,t=a,a=h,h=t,t=u,u=d,d=t,m in Ti&&U.attr("cursor",Mi[m=Ti[m]])),A.selection&&(N=A.selection),y&&(o=N[0][0],l=N[1][0]),_&&(u=N[0][1],d=N[1][1]),N[0][0]===o&&N[0][1]===u&&N[1][0]===l&&N[1][1]===d||(A.selection=[[o,u],[l,d]],f.call(b),L.brush())}function B(){if(pi(),t.event.touches){if(t.event.touches.length)return;e&&clearTimeout(e),e=setTimeout(function(){e=null},500),D.on("touchmove.brush touchend.brush touchcancel.brush",null)}else Gt(t.event.view,g),q.on("keydown.brush keyup.brush mousemove.brush mouseup.brush",null);D.attr("pointer-events","all"),U.attr("cursor",Mi.overlay),A.selection&&(N=A.selection),zi(N)&&(A.selection=null,f.call(b)),L.end()}}function h(){var t=this.__brush||{selection:null};return t.extent=r.apply(this,arguments),t.dim=n,t}return u.move=function(t,e){t.selection?t.on("start.brush",function(){c(this,arguments).beforestart().start()}).on("interrupt.brush end.brush",function(){c(this,arguments).end()}).tween("brush",function(){var t=this,r=t.__brush,i=c(t,arguments),o=r.selection,a=n.input("function"==typeof e?e.apply(this,arguments):e,r.extent),u=me(o,a);function s(n){r.selection=1===n&&zi(a)?null:u(n),f.call(t),i.brush()}return o&&a?s:s(1)}):t.each(function(){var t=arguments,r=this.__brush,i=n.input("function"==typeof e?e.apply(this,t):e,r.extent),o=c(this,t).beforestart();Nr(this),r.selection=null==i||zi(i)?null:i,f.call(this),o.start().brush().end()})},s.prototype={beforestart:function(){return 1==++this.active&&(this.state.emitter=this,this.starting=!0),this},start:function(){return this.starting&&(this.starting=!1,this.emit("start")),this},brush:function(){return this.emit("brush"),this},end:function(){return 0==--this.active&&(delete this.state.emitter,this.emit("end")),this},emit:function(t){Ct(new di(u,t,n.output(this.state.selection)),o.apply,o,[t,this.that,this.args])}},u.extent=function(t){return arguments.length?(r="function"==typeof t?t:hi([[+t[0][0],+t[0][1]],[+t[1][0],+t[1][1]]]),u):r},u.filter=function(t){return arguments.length?(i="function"==typeof t?t:hi(!!t),u):i},u.handleSize=function(t){return arguments.length?(a=+t,u):a},u.on=function(){var t=o.on.apply(o,arguments);return t===o?u:t},u}var Li=Math.cos,Di=Math.sin,Ui=Math.PI,qi=Ui/2,Oi=2*Ui,Yi=Math.max;var Bi=Array.prototype.slice;function Fi(t){return function(){return t}}var Ii=Math.PI,Hi=2*Ii,ji=Hi-1e-6;function Xi(){this._x0=this._y0=this._x1=this._y1=null,this._=""}function Gi(){return new Xi}function Vi(t){return t.source}function $i(t){return t.target}function Wi(t){return t.radius}function Zi(t){return t.startAngle}function Qi(t){return t.endAngle}Xi.prototype=Gi.prototype={constructor:Xi,moveTo:function(t,n){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+n)},closePath:function(){null!==this._x1&&(this._x1=this._x0,this._y1=this._y0,this._+="Z")},lineTo:function(t,n){this._+="L"+(this._x1=+t)+","+(this._y1=+n)},quadraticCurveTo:function(t,n,e,r){this._+="Q"+ +t+","+ +n+","+(this._x1=+e)+","+(this._y1=+r)},bezierCurveTo:function(t,n,e,r,i,o){this._+="C"+ +t+","+ +n+","+ +e+","+ +r+","+(this._x1=+i)+","+(this._y1=+o)},arcTo:function(t,n,e,r,i){t=+t,n=+n,e=+e,r=+r,i=+i;var o=this._x1,a=this._y1,u=e-t,f=r-n,c=o-t,s=a-n,l=c*c+s*s;if(i<0)throw new Error("negative radius: "+i);if(null===this._x1)this._+="M"+(this._x1=t)+","+(this._y1=n);else if(l>1e-6)if(Math.abs(s*u-f*c)>1e-6&&i){var h=e-o,d=r-a,p=u*u+f*f,v=h*h+d*d,g=Math.sqrt(p),y=Math.sqrt(l),_=i*Math.tan((Ii-Math.acos((p+l-v)/(2*g*y)))/2),b=_/y,m=_/g;Math.abs(b-1)>1e-6&&(this._+="L"+(t+b*c)+","+(n+b*s)),this._+="A"+i+","+i+",0,0,"+ +(s*h>c*d)+","+(this._x1=t+m*u)+","+(this._y1=n+m*f)}else this._+="L"+(this._x1=t)+","+(this._y1=n);else;},arc:function(t,n,e,r,i,o){t=+t,n=+n;var a=(e=+e)*Math.cos(r),u=e*Math.sin(r),f=t+a,c=n+u,s=1^o,l=o?r-i:i-r;if(e<0)throw new Error("negative radius: "+e);null===this._x1?this._+="M"+f+","+c:(Math.abs(this._x1-f)>1e-6||Math.abs(this._y1-c)>1e-6)&&(this._+="L"+f+","+c),e&&(l<0&&(l=l%Hi+Hi),l>ji?this._+="A"+e+","+e+",0,1,"+s+","+(t-a)+","+(n-u)+"A"+e+","+e+",0,1,"+s+","+(this._x1=f)+","+(this._y1=c):l>1e-6&&(this._+="A"+e+","+e+",0,"+ +(l>=Ii)+","+s+","+(this._x1=t+e*Math.cos(i))+","+(this._y1=n+e*Math.sin(i))))},rect:function(t,n,e,r){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+n)+"h"+ +e+"v"+ +r+"h"+-e+"Z"},toString:function(){return this._}};function Ji(){}function Ki(t,n){var e=new Ji;if(t instanceof Ji)t.each(function(t,n){e.set(n,t)});else if(Array.isArray(t)){var r,i=-1,o=t.length;if(null==n)for(;++i<o;)e.set(i,t[i]);else for(;++i<o;)e.set(n(r=t[i],i,t),r)}else if(t)for(var a in t)e.set(a,t[a]);return e}function to(){return{}}function no(t,n,e){t[n]=e}function eo(){return Ki()}function ro(t,n,e){t.set(n,e)}function io(){}Ji.prototype=Ki.prototype={constructor:Ji,has:function(t){return"$"+t in this},get:function(t){return this["$"+t]},set:function(t,n){return this["$"+t]=n,this},remove:function(t){var n="$"+t;return n in this&&delete this[n]},clear:function(){for(var t in this)"$"===t[0]&&delete this[t]},keys:function(){var t=[];for(var n in this)"$"===n[0]&&t.push(n.slice(1));return t},values:function(){var t=[];for(var n in this)"$"===n[0]&&t.push(this[n]);return t},entries:function(){var t=[];for(var n in this)"$"===n[0]&&t.push({key:n.slice(1),value:this[n]});return t},size:function(){var t=0;for(var n in this)"$"===n[0]&&++t;return t},empty:function(){for(var t in this)if("$"===t[0])return!1;return!0},each:function(t){for(var n in this)"$"===n[0]&&t(this[n],n.slice(1),this)}};var oo=Ki.prototype;function ao(t,n){var e=new io;if(t instanceof io)t.each(function(t){e.add(t)});else if(t){var r=-1,i=t.length;if(null==n)for(;++r<i;)e.add(t[r]);else for(;++r<i;)e.add(n(t[r],r,t))}return e}io.prototype=ao.prototype={constructor:io,has:oo.has,add:function(t){return this["$"+(t+="")]=t,this},remove:oo.remove,clear:oo.clear,values:oo.keys,size:oo.size,empty:oo.empty,each:oo.each};var uo=Array.prototype.slice;function fo(t,n){return t-n}function co(t){return function(){return t}}function so(t,n){for(var e,r=-1,i=n.length;++r<i;)if(e=lo(t,n[r]))return e;return 0}function lo(t,n){for(var e=n[0],r=n[1],i=-1,o=0,a=t.length,u=a-1;o<a;u=o++){var f=t[o],c=f[0],s=f[1],l=t[u],h=l[0],d=l[1];if(ho(f,l,n))return 0;s>r!=d>r&&e<(h-c)*(r-s)/(d-s)+c&&(i=-i)}return i}function ho(t,n,e){var r,i,o,a;return function(t,n,e){return(n[0]-t[0])*(e[1]-t[1])==(e[0]-t[0])*(n[1]-t[1])}(t,n,e)&&(i=t[r=+(t[0]===n[0])],o=e[r],a=n[r],i<=o&&o<=a||a<=o&&o<=i)}function po(){}var vo=[[],[[[1,1.5],[.5,1]]],[[[1.5,1],[1,1.5]]],[[[1.5,1],[.5,1]]],[[[1,.5],[1.5,1]]],[[[1,1.5],[.5,1]],[[1,.5],[1.5,1]]],[[[1,.5],[1,1.5]]],[[[1,.5],[.5,1]]],[[[.5,1],[1,.5]]],[[[1,1.5],[1,.5]]],[[[.5,1],[1,.5]],[[1.5,1],[1,1.5]]],[[[1.5,1],[1,.5]]],[[[.5,1],[1.5,1]]],[[[1,1.5],[1.5,1]]],[[[.5,1],[1,1.5]]],[]];function go(){var t=1,n=1,e=M,r=u;function i(t){var n=e(t);if(Array.isArray(n))n=n.slice().sort(fo);else{var r=s(t),i=r[0],a=r[1];n=w(i,a,n),n=g(Math.floor(i/n)*n,Math.floor(a/n)*n,n)}return n.map(function(n){return o(t,n)})}function o(e,i){var o=[],u=[];return function(e,r,i){var o,u,f,c,s,l,h=new Array,d=new Array;o=u=-1,c=e[0]>=r,vo[c<<1].forEach(p);for(;++o<t-1;)f=c,c=e[o+1]>=r,vo[f|c<<1].forEach(p);vo[c<<0].forEach(p);for(;++u<n-1;){for(o=-1,c=e[u*t+t]>=r,s=e[u*t]>=r,vo[c<<1|s<<2].forEach(p);++o<t-1;)f=c,c=e[u*t+t+o+1]>=r,l=s,s=e[u*t+o+1]>=r,vo[f|c<<1|s<<2|l<<3].forEach(p);vo[c|s<<3].forEach(p)}o=-1,s=e[u*t]>=r,vo[s<<2].forEach(p);for(;++o<t-1;)l=s,s=e[u*t+o+1]>=r,vo[s<<2|l<<3].forEach(p);function p(t){var n,e,r=[t[0][0]+o,t[0][1]+u],f=[t[1][0]+o,t[1][1]+u],c=a(r),s=a(f);(n=d[c])?(e=h[s])?(delete d[n.end],delete h[e.start],n===e?(n.ring.push(f),i(n.ring)):h[n.start]=d[e.end]={start:n.start,end:e.end,ring:n.ring.concat(e.ring)}):(delete d[n.end],n.ring.push(f),d[n.end=s]=n):(n=h[s])?(e=d[c])?(delete h[n.start],delete d[e.end],n===e?(n.ring.push(f),i(n.ring)):h[e.start]=d[n.end]={start:e.start,end:n.end,ring:e.ring.concat(n.ring)}):(delete h[n.start],n.ring.unshift(r),h[n.start=c]=n):h[c]=d[s]={start:c,end:s,ring:[r,f]}}vo[s<<3].forEach(p)}(e,i,function(t){r(t,e,i),function(t){for(var n=0,e=t.length,r=t[e-1][1]*t[0][0]-t[e-1][0]*t[0][1];++n<e;)r+=t[n-1][1]*t[n][0]-t[n-1][0]*t[n][1];return r}(t)>0?o.push([t]):u.push(t)}),u.forEach(function(t){for(var n,e=0,r=o.length;e<r;++e)if(-1!==so((n=o[e])[0],t))return void n.push(t)}),{type:"MultiPolygon",value:i,coordinates:o}}function a(n){return 2*n[0]+n[1]*(t+1)*4}function u(e,r,i){e.forEach(function(e){var o,a=e[0],u=e[1],f=0|a,c=0|u,s=r[c*t+f];a>0&&a<t&&f===a&&(o=r[c*t+f-1],e[0]=a+(i-o)/(s-o)-.5),u>0&&u<n&&c===u&&(o=r[(c-1)*t+f],e[1]=u+(i-o)/(s-o)-.5)})}return i.contour=o,i.size=function(e){if(!arguments.length)return[t,n];var r=Math.ceil(e[0]),o=Math.ceil(e[1]);if(!(r>0&&o>0))throw new Error("invalid size");return t=r,n=o,i},i.thresholds=function(t){return arguments.length?(e="function"==typeof t?t:Array.isArray(t)?co(uo.call(t)):co(t),i):e},i.smooth=function(t){return arguments.length?(r=t?u:po,i):r===u},i}function yo(t,n,e){for(var r=t.width,i=t.height,o=1+(e<<1),a=0;a<i;++a)for(var u=0,f=0;u<r+e;++u)u<r&&(f+=t.data[u+a*r]),u>=e&&(u>=o&&(f-=t.data[u-o+a*r]),n.data[u-e+a*r]=f/Math.min(u+1,r-1+o-u,o))}function _o(t,n,e){for(var r=t.width,i=t.height,o=1+(e<<1),a=0;a<r;++a)for(var u=0,f=0;u<i+e;++u)u<i&&(f+=t.data[a+u*r]),u>=e&&(u>=o&&(f-=t.data[a+(u-o)*r]),n.data[a+(u-e)*r]=f/Math.min(u+1,i-1+o-u,o))}function bo(t){return t[0]}function mo(t){return t[1]}function xo(){return 1}var wo={},Mo={},Ao=34,To=10,No=13;function So(t){return new Function("d","return {"+t.map(function(t,n){return JSON.stringify(t)+": d["+n+"]"}).join(",")+"}")}function Eo(t){var n=new RegExp('["'+t+"\n\r]"),e=t.charCodeAt(0);function r(t,n){var r,i=[],o=t.length,a=0,u=0,f=o<=0,c=!1;function s(){if(f)return Mo;if(c)return c=!1,wo;var n,r,i=a;if(t.charCodeAt(i)===Ao){for(;a++<o&&t.charCodeAt(a)!==Ao||t.charCodeAt(++a)===Ao;);return(n=a)>=o?f=!0:(r=t.charCodeAt(a++))===To?c=!0:r===No&&(c=!0,t.charCodeAt(a)===To&&++a),t.slice(i+1,n-1).replace(/""/g,'"')}for(;a<o;){if((r=t.charCodeAt(n=a++))===To)c=!0;else if(r===No)c=!0,t.charCodeAt(a)===To&&++a;else if(r!==e)continue;return t.slice(i,n)}return f=!0,t.slice(i,o)}for(t.charCodeAt(o-1)===To&&--o,t.charCodeAt(o-1)===No&&--o;(r=s())!==Mo;){for(var l=[];r!==wo&&r!==Mo;)l.push(r),r=s();n&&null==(l=n(l,u++))||i.push(l)}return i}function i(n){return n.map(o).join(t)}function o(t){return null==t?"":n.test(t+="")?'"'+t.replace(/"/g,'""')+'"':t}return{parse:function(t,n){var e,i,o=r(t,function(t,r){if(e)return e(t,r-1);i=t,e=n?function(t,n){var e=So(t);return function(r,i){return n(e(r),i,t)}}(t,n):So(t)});return o.columns=i||[],o},parseRows:r,format:function(n,e){return null==e&&(e=function(t){var n=Object.create(null),e=[];return t.forEach(function(t){for(var r in t)r in n||e.push(n[r]=r)}),e}(n)),[e.map(o).join(t)].concat(n.map(function(n){return e.map(function(t){return o(n[t])}).join(t)})).join("\n")},formatRows:function(t){return t.map(i).join("\n")}}}var ko=Eo(","),Co=ko.parse,Po=ko.parseRows,zo=ko.format,Ro=ko.formatRows,Lo=Eo("\t"),Do=Lo.parse,Uo=Lo.parseRows,qo=Lo.format,Oo=Lo.formatRows;function Yo(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);return t.blob()}function Bo(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);return t.arrayBuffer()}function Fo(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);return t.text()}function Io(t,n){return fetch(t,n).then(Fo)}function Ho(t){return function(n,e,r){return 2===arguments.length&&"function"==typeof e&&(r=e,e=void 0),Io(n,e).then(function(n){return t(n,r)})}}var jo=Ho(Co),Xo=Ho(Do);function Go(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);return t.json()}function Vo(t){return function(n,e){return Io(n,e).then(function(n){return(new DOMParser).parseFromString(n,t)})}}var $o=Vo("application/xml"),Wo=Vo("text/html"),Zo=Vo("image/svg+xml");function Qo(t){return function(){return t}}function Jo(){return 1e-6*(Math.random()-.5)}function Ko(t,n,e,r){if(isNaN(n)||isNaN(e))return t;var i,o,a,u,f,c,s,l,h,d=t._root,p={data:r},v=t._x0,g=t._y0,y=t._x1,_=t._y1;if(!d)return t._root=p,t;for(;d.length;)if((c=n>=(o=(v+y)/2))?v=o:y=o,(s=e>=(a=(g+_)/2))?g=a:_=a,i=d,!(d=d[l=s<<1|c]))return i[l]=p,t;if(u=+t._x.call(null,d.data),f=+t._y.call(null,d.data),n===u&&e===f)return p.next=d,i?i[l]=p:t._root=p,t;do{i=i?i[l]=new Array(4):t._root=new Array(4),(c=n>=(o=(v+y)/2))?v=o:y=o,(s=e>=(a=(g+_)/2))?g=a:_=a}while((l=s<<1|c)==(h=(f>=a)<<1|u>=o));return i[h]=d,i[l]=p,t}function ta(t,n,e,r,i){this.node=t,this.x0=n,this.y0=e,this.x1=r,this.y1=i}function na(t){return t[0]}function ea(t){return t[1]}function ra(t,n,e){var r=new ia(null==n?na:n,null==e?ea:e,NaN,NaN,NaN,NaN);return null==t?r:r.addAll(t)}function ia(t,n,e,r,i,o){this._x=t,this._y=n,this._x0=e,this._y0=r,this._x1=i,this._y1=o,this._root=void 0}function oa(t){for(var n={data:t.data},e=n;t=t.next;)e=e.next={data:t.data};return n}var aa=ra.prototype=ia.prototype;function ua(t){return t.x+t.vx}function fa(t){return t.y+t.vy}function ca(t){return t.index}function sa(t,n){var e=t.get(n);if(!e)throw new Error("missing: "+n);return e}function la(t){return t.x}function ha(t){return t.y}aa.copy=function(){var t,n,e=new ia(this._x,this._y,this._x0,this._y0,this._x1,this._y1),r=this._root;if(!r)return e;if(!r.length)return e._root=oa(r),e;for(t=[{source:r,target:e._root=new Array(4)}];r=t.pop();)for(var i=0;i<4;++i)(n=r.source[i])&&(n.length?t.push({source:n,target:r.target[i]=new Array(4)}):r.target[i]=oa(n));return e},aa.add=function(t){var n=+this._x.call(null,t),e=+this._y.call(null,t);return Ko(this.cover(n,e),n,e,t)},aa.addAll=function(t){var n,e,r,i,o=t.length,a=new Array(o),u=new Array(o),f=1/0,c=1/0,s=-1/0,l=-1/0;for(e=0;e<o;++e)isNaN(r=+this._x.call(null,n=t[e]))||isNaN(i=+this._y.call(null,n))||(a[e]=r,u[e]=i,r<f&&(f=r),r>s&&(s=r),i<c&&(c=i),i>l&&(l=i));for(s<f&&(f=this._x0,s=this._x1),l<c&&(c=this._y0,l=this._y1),this.cover(f,c).cover(s,l),e=0;e<o;++e)Ko(this,a[e],u[e],t[e]);return this},aa.cover=function(t,n){if(isNaN(t=+t)||isNaN(n=+n))return this;var e=this._x0,r=this._y0,i=this._x1,o=this._y1;if(isNaN(e))i=(e=Math.floor(t))+1,o=(r=Math.floor(n))+1;else{if(!(e>t||t>i||r>n||n>o))return this;var a,u,f=i-e,c=this._root;switch(u=(n<(r+o)/2)<<1|t<(e+i)/2){case 0:do{(a=new Array(4))[u]=c,c=a}while(o=r+(f*=2),t>(i=e+f)||n>o);break;case 1:do{(a=new Array(4))[u]=c,c=a}while(o=r+(f*=2),(e=i-f)>t||n>o);break;case 2:do{(a=new Array(4))[u]=c,c=a}while(r=o-(f*=2),t>(i=e+f)||r>n);break;case 3:do{(a=new Array(4))[u]=c,c=a}while(r=o-(f*=2),(e=i-f)>t||r>n)}this._root&&this._root.length&&(this._root=c)}return this._x0=e,this._y0=r,this._x1=i,this._y1=o,this},aa.data=function(){var t=[];return this.visit(function(n){if(!n.length)do{t.push(n.data)}while(n=n.next)}),t},aa.extent=function(t){return arguments.length?this.cover(+t[0][0],+t[0][1]).cover(+t[1][0],+t[1][1]):isNaN(this._x0)?void 0:[[this._x0,this._y0],[this._x1,this._y1]]},aa.find=function(t,n,e){var r,i,o,a,u,f,c,s=this._x0,l=this._y0,h=this._x1,d=this._y1,p=[],v=this._root;for(v&&p.push(new ta(v,s,l,h,d)),null==e?e=1/0:(s=t-e,l=n-e,h=t+e,d=n+e,e*=e);f=p.pop();)if(!(!(v=f.node)||(i=f.x0)>h||(o=f.y0)>d||(a=f.x1)<s||(u=f.y1)<l))if(v.length){var g=(i+a)/2,y=(o+u)/2;p.push(new ta(v[3],g,y,a,u),new ta(v[2],i,y,g,u),new ta(v[1],g,o,a,y),new ta(v[0],i,o,g,y)),(c=(n>=y)<<1|t>=g)&&(f=p[p.length-1],p[p.length-1]=p[p.length-1-c],p[p.length-1-c]=f)}else{var _=t-+this._x.call(null,v.data),b=n-+this._y.call(null,v.data),m=_*_+b*b;if(m<e){var x=Math.sqrt(e=m);s=t-x,l=n-x,h=t+x,d=n+x,r=v.data}}return r},aa.remove=function(t){if(isNaN(o=+this._x.call(null,t))||isNaN(a=+this._y.call(null,t)))return this;var n,e,r,i,o,a,u,f,c,s,l,h,d=this._root,p=this._x0,v=this._y0,g=this._x1,y=this._y1;if(!d)return this;if(d.length)for(;;){if((c=o>=(u=(p+g)/2))?p=u:g=u,(s=a>=(f=(v+y)/2))?v=f:y=f,n=d,!(d=d[l=s<<1|c]))return this;if(!d.length)break;(n[l+1&3]||n[l+2&3]||n[l+3&3])&&(e=n,h=l)}for(;d.data!==t;)if(r=d,!(d=d.next))return this;return(i=d.next)&&delete d.next,r?(i?r.next=i:delete r.next,this):n?(i?n[l]=i:delete n[l],(d=n[0]||n[1]||n[2]||n[3])&&d===(n[3]||n[2]||n[1]||n[0])&&!d.length&&(e?e[h]=d:this._root=d),this):(this._root=i,this)},aa.removeAll=function(t){for(var n=0,e=t.length;n<e;++n)this.remove(t[n]);return this},aa.root=function(){return this._root},aa.size=function(){var t=0;return this.visit(function(n){if(!n.length)do{++t}while(n=n.next)}),t},aa.visit=function(t){var n,e,r,i,o,a,u=[],f=this._root;for(f&&u.push(new ta(f,this._x0,this._y0,this._x1,this._y1));n=u.pop();)if(!t(f=n.node,r=n.x0,i=n.y0,o=n.x1,a=n.y1)&&f.length){var c=(r+o)/2,s=(i+a)/2;(e=f[3])&&u.push(new ta(e,c,s,o,a)),(e=f[2])&&u.push(new ta(e,r,s,c,a)),(e=f[1])&&u.push(new ta(e,c,i,o,s)),(e=f[0])&&u.push(new ta(e,r,i,c,s))}return this},aa.visitAfter=function(t){var n,e=[],r=[];for(this._root&&e.push(new ta(this._root,this._x0,this._y0,this._x1,this._y1));n=e.pop();){var i=n.node;if(i.length){var o,a=n.x0,u=n.y0,f=n.x1,c=n.y1,s=(a+f)/2,l=(u+c)/2;(o=i[0])&&e.push(new ta(o,a,u,s,l)),(o=i[1])&&e.push(new ta(o,s,u,f,l)),(o=i[2])&&e.push(new ta(o,a,l,s,c)),(o=i[3])&&e.push(new ta(o,s,l,f,c))}r.push(n)}for(;n=r.pop();)t(n.node,n.x0,n.y0,n.x1,n.y1);return this},aa.x=function(t){return arguments.length?(this._x=t,this):this._x},aa.y=function(t){return arguments.length?(this._y=t,this):this._y};var da=10,pa=Math.PI*(3-Math.sqrt(5));function va(t,n){if((e=(t=n?t.toExponential(n-1):t.toExponential()).indexOf("e"))<0)return null;var e,r=t.slice(0,e);return[r.length>1?r[0]+r.slice(2):r,+t.slice(e+1)]}function ga(t){return(t=va(Math.abs(t)))?t[1]:NaN}var ya,_a=/^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;function ba(t){return new ma(t)}function ma(t){if(!(n=_a.exec(t)))throw new Error("invalid format: "+t);var n;this.fill=n[1]||" ",this.align=n[2]||">",this.sign=n[3]||"-",this.symbol=n[4]||"",this.zero=!!n[5],this.width=n[6]&&+n[6],this.comma=!!n[7],this.precision=n[8]&&+n[8].slice(1),this.trim=!!n[9],this.type=n[10]||""}function xa(t,n){var e=va(t,n);if(!e)return t+"";var r=e[0],i=e[1];return i<0?"0."+new Array(-i).join("0")+r:r.length>i+1?r.slice(0,i+1)+"."+r.slice(i+1):r+new Array(i-r.length+2).join("0")}ba.prototype=ma.prototype,ma.prototype.toString=function(){return this.fill+this.align+this.sign+this.symbol+(this.zero?"0":"")+(null==this.width?"":Math.max(1,0|this.width))+(this.comma?",":"")+(null==this.precision?"":"."+Math.max(0,0|this.precision))+(this.trim?"~":"")+this.type};var wa={"%":function(t,n){return(100*t).toFixed(n)},b:function(t){return Math.round(t).toString(2)},c:function(t){return t+""},d:function(t){return Math.round(t).toString(10)},e:function(t,n){return t.toExponential(n)},f:function(t,n){return t.toFixed(n)},g:function(t,n){return t.toPrecision(n)},o:function(t){return Math.round(t).toString(8)},p:function(t,n){return xa(100*t,n)},r:xa,s:function(t,n){var e=va(t,n);if(!e)return t+"";var r=e[0],i=e[1],o=i-(ya=3*Math.max(-8,Math.min(8,Math.floor(i/3))))+1,a=r.length;return o===a?r:o>a?r+new Array(o-a+1).join("0"):o>0?r.slice(0,o)+"."+r.slice(o):"0."+new Array(1-o).join("0")+va(t,Math.max(0,n+o-1))[0]},X:function(t){return Math.round(t).toString(16).toUpperCase()},x:function(t){return Math.round(t).toString(16)}};function Ma(t){return t}var Aa,Ta=["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"];function Na(t){var n,e,r=t.grouping&&t.thousands?(n=t.grouping,e=t.thousands,function(t,r){for(var i=t.length,o=[],a=0,u=n[0],f=0;i>0&&u>0&&(f+u+1>r&&(u=Math.max(1,r-f)),o.push(t.substring(i-=u,i+u)),!((f+=u+1)>r));)u=n[a=(a+1)%n.length];return o.reverse().join(e)}):Ma,i=t.currency,o=t.decimal,a=t.numerals?function(t){return function(n){return n.replace(/[0-9]/g,function(n){return t[+n]})}}(t.numerals):Ma,u=t.percent||"%";function f(t){var n=(t=ba(t)).fill,e=t.align,f=t.sign,c=t.symbol,s=t.zero,l=t.width,h=t.comma,d=t.precision,p=t.trim,v=t.type;"n"===v?(h=!0,v="g"):wa[v]||(null==d&&(d=12),p=!0,v="g"),(s||"0"===n&&"="===e)&&(s=!0,n="0",e="=");var g="$"===c?i[0]:"#"===c&&/[boxX]/.test(v)?"0"+v.toLowerCase():"",y="$"===c?i[1]:/[%p]/.test(v)?u:"",_=wa[v],b=/[defgprs%]/.test(v);function m(t){var i,u,c,m=g,x=y;if("c"===v)x=_(t)+x,t="";else{var w=(t=+t)<0;if(t=_(Math.abs(t),d),p&&(t=function(t){t:for(var n,e=t.length,r=1,i=-1;r<e;++r)switch(t[r]){case".":i=n=r;break;case"0":0===i&&(i=r),n=r;break;default:if(i>0){if(!+t[r])break t;i=0}}return i>0?t.slice(0,i)+t.slice(n+1):t}(t)),w&&0==+t&&(w=!1),m=(w?"("===f?f:"-":"-"===f||"("===f?"":f)+m,x=("s"===v?Ta[8+ya/3]:"")+x+(w&&"("===f?")":""),b)for(i=-1,u=t.length;++i<u;)if(48>(c=t.charCodeAt(i))||c>57){x=(46===c?o+t.slice(i+1):t.slice(i))+x,t=t.slice(0,i);break}}h&&!s&&(t=r(t,1/0));var M=m.length+t.length+x.length,A=M<l?new Array(l-M+1).join(n):"";switch(h&&s&&(t=r(A+t,A.length?l-x.length:1/0),A=""),e){case"<":t=m+t+x+A;break;case"=":t=m+A+t+x;break;case"^":t=A.slice(0,M=A.length>>1)+m+t+x+A.slice(M);break;default:t=A+m+t+x}return a(t)}return d=null==d?6:/[gprs]/.test(v)?Math.max(1,Math.min(21,d)):Math.max(0,Math.min(20,d)),m.toString=function(){return t+""},m}return{format:f,formatPrefix:function(t,n){var e=f(((t=ba(t)).type="f",t)),r=3*Math.max(-8,Math.min(8,Math.floor(ga(n)/3))),i=Math.pow(10,-r),o=Ta[8+r/3];return function(t){return e(i*t)+o}}}}function Sa(n){return Aa=Na(n),t.format=Aa.format,t.formatPrefix=Aa.formatPrefix,Aa}function Ea(t){return Math.max(0,-ga(Math.abs(t)))}function ka(t,n){return Math.max(0,3*Math.max(-8,Math.min(8,Math.floor(ga(n)/3)))-ga(Math.abs(t)))}function Ca(t,n){return t=Math.abs(t),n=Math.abs(n)-t,Math.max(0,ga(n)-ga(t))+1}function Pa(){return new za}function za(){this.reset()}Sa({decimal:".",thousands:",",grouping:[3],currency:["$",""]}),za.prototype={constructor:za,reset:function(){this.s=this.t=0},add:function(t){La(Ra,t,this.t),La(this,Ra.s,this.s),this.s?this.t+=Ra.t:this.s=Ra.t},valueOf:function(){return this.s}};var Ra=new za;function La(t,n,e){var r=t.s=n+e,i=r-n,o=r-i;t.t=n-o+(e-i)}var Da=1e-6,Ua=1e-12,qa=Math.PI,Oa=qa/2,Ya=qa/4,Ba=2*qa,Fa=180/qa,Ia=qa/180,Ha=Math.abs,ja=Math.atan,Xa=Math.atan2,Ga=Math.cos,Va=Math.ceil,$a=Math.exp,Wa=Math.log,Za=Math.pow,Qa=Math.sin,Ja=Math.sign||function(t){return t>0?1:t<0?-1:0},Ka=Math.sqrt,tu=Math.tan;function nu(t){return t>1?0:t<-1?qa:Math.acos(t)}function eu(t){return t>1?Oa:t<-1?-Oa:Math.asin(t)}function ru(t){return(t=Qa(t/2))*t}function iu(){}function ou(t,n){t&&uu.hasOwnProperty(t.type)&&uu[t.type](t,n)}var au={Feature:function(t,n){ou(t.geometry,n)},FeatureCollection:function(t,n){for(var e=t.features,r=-1,i=e.length;++r<i;)ou(e[r].geometry,n)}},uu={Sphere:function(t,n){n.sphere()},Point:function(t,n){t=t.coordinates,n.point(t[0],t[1],t[2])},MultiPoint:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)t=e[r],n.point(t[0],t[1],t[2])},LineString:function(t,n){fu(t.coordinates,n,0)},MultiLineString:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)fu(e[r],n,0)},Polygon:function(t,n){cu(t.coordinates,n)},MultiPolygon:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)cu(e[r],n)},GeometryCollection:function(t,n){for(var e=t.geometries,r=-1,i=e.length;++r<i;)ou(e[r],n)}};function fu(t,n,e){var r,i=-1,o=t.length-e;for(n.lineStart();++i<o;)r=t[i],n.point(r[0],r[1],r[2]);n.lineEnd()}function cu(t,n){var e=-1,r=t.length;for(n.polygonStart();++e<r;)fu(t[e],n,1);n.polygonEnd()}function su(t,n){t&&au.hasOwnProperty(t.type)?au[t.type](t,n):ou(t,n)}var lu,hu,du,pu,vu,gu=Pa(),yu=Pa(),_u={point:iu,lineStart:iu,lineEnd:iu,polygonStart:function(){gu.reset(),_u.lineStart=bu,_u.lineEnd=mu},polygonEnd:function(){var t=+gu;yu.add(t<0?Ba+t:t),this.lineStart=this.lineEnd=this.point=iu},sphere:function(){yu.add(Ba)}};function bu(){_u.point=xu}function mu(){wu(lu,hu)}function xu(t,n){_u.point=wu,lu=t,hu=n,du=t*=Ia,pu=Ga(n=(n*=Ia)/2+Ya),vu=Qa(n)}function wu(t,n){var e=(t*=Ia)-du,r=e>=0?1:-1,i=r*e,o=Ga(n=(n*=Ia)/2+Ya),a=Qa(n),u=vu*a,f=pu*o+u*Ga(i),c=u*r*Qa(i);gu.add(Xa(c,f)),du=t,pu=o,vu=a}function Mu(t){return[Xa(t[1],t[0]),eu(t[2])]}function Au(t){var n=t[0],e=t[1],r=Ga(e);return[r*Ga(n),r*Qa(n),Qa(e)]}function Tu(t,n){return t[0]*n[0]+t[1]*n[1]+t[2]*n[2]}function Nu(t,n){return[t[1]*n[2]-t[2]*n[1],t[2]*n[0]-t[0]*n[2],t[0]*n[1]-t[1]*n[0]]}function Su(t,n){t[0]+=n[0],t[1]+=n[1],t[2]+=n[2]}function Eu(t,n){return[t[0]*n,t[1]*n,t[2]*n]}function ku(t){var n=Ka(t[0]*t[0]+t[1]*t[1]+t[2]*t[2]);t[0]/=n,t[1]/=n,t[2]/=n}var Cu,Pu,zu,Ru,Lu,Du,Uu,qu,Ou,Yu,Bu,Fu,Iu,Hu,ju,Xu,Gu,Vu,$u,Wu,Zu,Qu,Ju,Ku,tf,nf,ef=Pa(),rf={point:of,lineStart:uf,lineEnd:ff,polygonStart:function(){rf.point=cf,rf.lineStart=sf,rf.lineEnd=lf,ef.reset(),_u.polygonStart()},polygonEnd:function(){_u.polygonEnd(),rf.point=of,rf.lineStart=uf,rf.lineEnd=ff,gu<0?(Cu=-(zu=180),Pu=-(Ru=90)):ef>Da?Ru=90:ef<-Da&&(Pu=-90),Yu[0]=Cu,Yu[1]=zu}};function of(t,n){Ou.push(Yu=[Cu=t,zu=t]),n<Pu&&(Pu=n),n>Ru&&(Ru=n)}function af(t,n){var e=Au([t*Ia,n*Ia]);if(qu){var r=Nu(qu,e),i=Nu([r[1],-r[0],0],r);ku(i),i=Mu(i);var o,a=t-Lu,u=a>0?1:-1,f=i[0]*Fa*u,c=Ha(a)>180;c^(u*Lu<f&&f<u*t)?(o=i[1]*Fa)>Ru&&(Ru=o):c^(u*Lu<(f=(f+360)%360-180)&&f<u*t)?(o=-i[1]*Fa)<Pu&&(Pu=o):(n<Pu&&(Pu=n),n>Ru&&(Ru=n)),c?t<Lu?hf(Cu,t)>hf(Cu,zu)&&(zu=t):hf(t,zu)>hf(Cu,zu)&&(Cu=t):zu>=Cu?(t<Cu&&(Cu=t),t>zu&&(zu=t)):t>Lu?hf(Cu,t)>hf(Cu,zu)&&(zu=t):hf(t,zu)>hf(Cu,zu)&&(Cu=t)}else Ou.push(Yu=[Cu=t,zu=t]);n<Pu&&(Pu=n),n>Ru&&(Ru=n),qu=e,Lu=t}function uf(){rf.point=af}function ff(){Yu[0]=Cu,Yu[1]=zu,rf.point=of,qu=null}function cf(t,n){if(qu){var e=t-Lu;ef.add(Ha(e)>180?e+(e>0?360:-360):e)}else Du=t,Uu=n;_u.point(t,n),af(t,n)}function sf(){_u.lineStart()}function lf(){cf(Du,Uu),_u.lineEnd(),Ha(ef)>Da&&(Cu=-(zu=180)),Yu[0]=Cu,Yu[1]=zu,qu=null}function hf(t,n){return(n-=t)<0?n+360:n}function df(t,n){return t[0]-n[0]}function pf(t,n){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:n<t[0]||t[1]<n}var vf={sphere:iu,point:gf,lineStart:_f,lineEnd:xf,polygonStart:function(){vf.lineStart=wf,vf.lineEnd=Mf},polygonEnd:function(){vf.lineStart=_f,vf.lineEnd=xf}};function gf(t,n){t*=Ia;var e=Ga(n*=Ia);yf(e*Ga(t),e*Qa(t),Qa(n))}function yf(t,n,e){Iu+=(t-Iu)/++Bu,Hu+=(n-Hu)/Bu,ju+=(e-ju)/Bu}function _f(){vf.point=bf}function bf(t,n){t*=Ia;var e=Ga(n*=Ia);Ku=e*Ga(t),tf=e*Qa(t),nf=Qa(n),vf.point=mf,yf(Ku,tf,nf)}function mf(t,n){t*=Ia;var e=Ga(n*=Ia),r=e*Ga(t),i=e*Qa(t),o=Qa(n),a=Xa(Ka((a=tf*o-nf*i)*a+(a=nf*r-Ku*o)*a+(a=Ku*i-tf*r)*a),Ku*r+tf*i+nf*o);Fu+=a,Xu+=a*(Ku+(Ku=r)),Gu+=a*(tf+(tf=i)),Vu+=a*(nf+(nf=o)),yf(Ku,tf,nf)}function xf(){vf.point=gf}function wf(){vf.point=Af}function Mf(){Tf(Qu,Ju),vf.point=gf}function Af(t,n){Qu=t,Ju=n,t*=Ia,n*=Ia,vf.point=Tf;var e=Ga(n);Ku=e*Ga(t),tf=e*Qa(t),nf=Qa(n),yf(Ku,tf,nf)}function Tf(t,n){t*=Ia;var e=Ga(n*=Ia),r=e*Ga(t),i=e*Qa(t),o=Qa(n),a=tf*o-nf*i,u=nf*r-Ku*o,f=Ku*i-tf*r,c=Ka(a*a+u*u+f*f),s=eu(c),l=c&&-s/c;$u+=l*a,Wu+=l*u,Zu+=l*f,Fu+=s,Xu+=s*(Ku+(Ku=r)),Gu+=s*(tf+(tf=i)),Vu+=s*(nf+(nf=o)),yf(Ku,tf,nf)}function Nf(t){return function(){return t}}function Sf(t,n){function e(e,r){return e=t(e,r),n(e[0],e[1])}return t.invert&&n.invert&&(e.invert=function(e,r){return(e=n.invert(e,r))&&t.invert(e[0],e[1])}),e}function Ef(t,n){return[t>qa?t-Ba:t<-qa?t+Ba:t,n]}function kf(t,n,e){return(t%=Ba)?n||e?Sf(Pf(t),zf(n,e)):Pf(t):n||e?zf(n,e):Ef}function Cf(t){return function(n,e){return[(n+=t)>qa?n-Ba:n<-qa?n+Ba:n,e]}}function Pf(t){var n=Cf(t);return n.invert=Cf(-t),n}function zf(t,n){var e=Ga(t),r=Qa(t),i=Ga(n),o=Qa(n);function a(t,n){var a=Ga(n),u=Ga(t)*a,f=Qa(t)*a,c=Qa(n),s=c*e+u*r;return[Xa(f*i-s*o,u*e-c*r),eu(s*i+f*o)]}return a.invert=function(t,n){var a=Ga(n),u=Ga(t)*a,f=Qa(t)*a,c=Qa(n),s=c*i-f*o;return[Xa(f*i+c*o,u*e+s*r),eu(s*e-u*r)]},a}function Rf(t){function n(n){return(n=t(n[0]*Ia,n[1]*Ia))[0]*=Fa,n[1]*=Fa,n}return t=kf(t[0]*Ia,t[1]*Ia,t.length>2?t[2]*Ia:0),n.invert=function(n){return(n=t.invert(n[0]*Ia,n[1]*Ia))[0]*=Fa,n[1]*=Fa,n},n}function Lf(t,n,e,r,i,o){if(e){var a=Ga(n),u=Qa(n),f=r*e;null==i?(i=n+r*Ba,o=n-f/2):(i=Df(a,i),o=Df(a,o),(r>0?i<o:i>o)&&(i+=r*Ba));for(var c,s=i;r>0?s>o:s<o;s-=f)c=Mu([a,-u*Ga(s),-u*Qa(s)]),t.point(c[0],c[1])}}function Df(t,n){(n=Au(n))[0]-=t,ku(n);var e=nu(-n[1]);return((-n[2]<0?-e:e)+Ba-Da)%Ba}function Uf(){var t,n=[];return{point:function(n,e){t.push([n,e])},lineStart:function(){n.push(t=[])},lineEnd:iu,rejoin:function(){n.length>1&&n.push(n.pop().concat(n.shift()))},result:function(){var e=n;return n=[],t=null,e}}}function qf(t,n){return Ha(t[0]-n[0])<Da&&Ha(t[1]-n[1])<Da}function Of(t,n,e,r){this.x=t,this.z=n,this.o=e,this.e=r,this.v=!1,this.n=this.p=null}function Yf(t,n,e,r,i){var o,a,u=[],f=[];if(t.forEach(function(t){if(!((n=t.length-1)<=0)){var n,e,r=t[0],a=t[n];if(qf(r,a)){for(i.lineStart(),o=0;o<n;++o)i.point((r=t[o])[0],r[1]);i.lineEnd()}else u.push(e=new Of(r,t,null,!0)),f.push(e.o=new Of(r,null,e,!1)),u.push(e=new Of(a,t,null,!1)),f.push(e.o=new Of(a,null,e,!0))}}),u.length){for(f.sort(n),Bf(u),Bf(f),o=0,a=f.length;o<a;++o)f[o].e=e=!e;for(var c,s,l=u[0];;){for(var h=l,d=!0;h.v;)if((h=h.n)===l)return;c=h.z,i.lineStart();do{if(h.v=h.o.v=!0,h.e){if(d)for(o=0,a=c.length;o<a;++o)i.point((s=c[o])[0],s[1]);else r(h.x,h.n.x,1,i);h=h.n}else{if(d)for(c=h.p.z,o=c.length-1;o>=0;--o)i.point((s=c[o])[0],s[1]);else r(h.x,h.p.x,-1,i);h=h.p}c=(h=h.o).z,d=!d}while(!h.v);i.lineEnd()}}}function Bf(t){if(n=t.length){for(var n,e,r=0,i=t[0];++r<n;)i.n=e=t[r],e.p=i,i=e;i.n=e=t[0],e.p=i}}Ef.invert=Ef;var Ff=Pa();function If(t,n){var e=n[0],r=n[1],i=Qa(r),o=[Qa(e),-Ga(e),0],a=0,u=0;Ff.reset(),1===i?r=Oa+Da:-1===i&&(r=-Oa-Da);for(var f=0,c=t.length;f<c;++f)if(l=(s=t[f]).length)for(var s,l,h=s[l-1],d=h[0],p=h[1]/2+Ya,v=Qa(p),g=Ga(p),y=0;y<l;++y,d=b,v=x,g=w,h=_){var _=s[y],b=_[0],m=_[1]/2+Ya,x=Qa(m),w=Ga(m),M=b-d,A=M>=0?1:-1,T=A*M,N=T>qa,S=v*x;if(Ff.add(Xa(S*A*Qa(T),g*w+S*Ga(T))),a+=N?M+A*Ba:M,N^d>=e^b>=e){var E=Nu(Au(h),Au(_));ku(E);var k=Nu(o,E);ku(k);var C=(N^M>=0?-1:1)*eu(k[2]);(r>C||r===C&&(E[0]||E[1]))&&(u+=N^M>=0?1:-1)}}return(a<-Da||a<Da&&Ff<-Da)^1&u}function Hf(t,n,e,r){return function(i){var o,a,u,f=n(i),c=Uf(),s=n(c),l=!1,h={point:d,lineStart:v,lineEnd:g,polygonStart:function(){h.point=y,h.lineStart=_,h.lineEnd=b,a=[],o=[]},polygonEnd:function(){h.point=d,h.lineStart=v,h.lineEnd=g,a=N(a);var t=If(o,r);a.length?(l||(i.polygonStart(),l=!0),Yf(a,Xf,t,e,i)):t&&(l||(i.polygonStart(),l=!0),i.lineStart(),e(null,null,1,i),i.lineEnd()),l&&(i.polygonEnd(),l=!1),a=o=null},sphere:function(){i.polygonStart(),i.lineStart(),e(null,null,1,i),i.lineEnd(),i.polygonEnd()}};function d(n,e){t(n,e)&&i.point(n,e)}function p(t,n){f.point(t,n)}function v(){h.point=p,f.lineStart()}function g(){h.point=d,f.lineEnd()}function y(t,n){u.push([t,n]),s.point(t,n)}function _(){s.lineStart(),u=[]}function b(){y(u[0][0],u[0][1]),s.lineEnd();var t,n,e,r,f=s.clean(),h=c.result(),d=h.length;if(u.pop(),o.push(u),u=null,d)if(1&f){if((n=(e=h[0]).length-1)>0){for(l||(i.polygonStart(),l=!0),i.lineStart(),t=0;t<n;++t)i.point((r=e[t])[0],r[1]);i.lineEnd()}}else d>1&&2&f&&h.push(h.pop().concat(h.shift())),a.push(h.filter(jf))}return h}}function jf(t){return t.length>1}function Xf(t,n){return((t=t.x)[0]<0?t[1]-Oa-Da:Oa-t[1])-((n=n.x)[0]<0?n[1]-Oa-Da:Oa-n[1])}var Gf=Hf(function(){return!0},function(t){var n,e=NaN,r=NaN,i=NaN;return{lineStart:function(){t.lineStart(),n=1},point:function(o,a){var u=o>0?qa:-qa,f=Ha(o-e);Ha(f-qa)<Da?(t.point(e,r=(r+a)/2>0?Oa:-Oa),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(u,r),t.point(o,r),n=0):i!==u&&f>=qa&&(Ha(e-i)<Da&&(e-=i*Da),Ha(o-u)<Da&&(o-=u*Da),r=function(t,n,e,r){var i,o,a=Qa(t-e);return Ha(a)>Da?ja((Qa(n)*(o=Ga(r))*Qa(e)-Qa(r)*(i=Ga(n))*Qa(t))/(i*o*a)):(n+r)/2}(e,r,o,a),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(u,r),n=0),t.point(e=o,r=a),i=u},lineEnd:function(){t.lineEnd(),e=r=NaN},clean:function(){return 2-n}}},function(t,n,e,r){var i;if(null==t)i=e*Oa,r.point(-qa,i),r.point(0,i),r.point(qa,i),r.point(qa,0),r.point(qa,-i),r.point(0,-i),r.point(-qa,-i),r.point(-qa,0),r.point(-qa,i);else if(Ha(t[0]-n[0])>Da){var o=t[0]<n[0]?qa:-qa;i=e*o/2,r.point(-o,i),r.point(0,i),r.point(o,i)}else r.point(n[0],n[1])},[-qa,-Oa]);function Vf(t){var n=Ga(t),e=6*Ia,r=n>0,i=Ha(n)>Da;function o(t,e){return Ga(t)*Ga(e)>n}function a(t,e,r){var i=[1,0,0],o=Nu(Au(t),Au(e)),a=Tu(o,o),u=o[0],f=a-u*u;if(!f)return!r&&t;var c=n*a/f,s=-n*u/f,l=Nu(i,o),h=Eu(i,c);Su(h,Eu(o,s));var d=l,p=Tu(h,d),v=Tu(d,d),g=p*p-v*(Tu(h,h)-1);if(!(g<0)){var y=Ka(g),_=Eu(d,(-p-y)/v);if(Su(_,h),_=Mu(_),!r)return _;var b,m=t[0],x=e[0],w=t[1],M=e[1];x<m&&(b=m,m=x,x=b);var A=x-m,T=Ha(A-qa)<Da;if(!T&&M<w&&(b=w,w=M,M=b),T||A<Da?T?w+M>0^_[1]<(Ha(_[0]-m)<Da?w:M):w<=_[1]&&_[1]<=M:A>qa^(m<=_[0]&&_[0]<=x)){var N=Eu(d,(-p+y)/v);return Su(N,h),[_,Mu(N)]}}}function u(n,e){var i=r?t:qa-t,o=0;return n<-i?o|=1:n>i&&(o|=2),e<-i?o|=4:e>i&&(o|=8),o}return Hf(o,function(t){var n,e,f,c,s;return{lineStart:function(){c=f=!1,s=1},point:function(l,h){var d,p=[l,h],v=o(l,h),g=r?v?0:u(l,h):v?u(l+(l<0?qa:-qa),h):0;if(!n&&(c=f=v)&&t.lineStart(),v!==f&&(!(d=a(n,p))||qf(n,d)||qf(p,d))&&(p[0]+=Da,p[1]+=Da,v=o(p[0],p[1])),v!==f)s=0,v?(t.lineStart(),d=a(p,n),t.point(d[0],d[1])):(d=a(n,p),t.point(d[0],d[1]),t.lineEnd()),n=d;else if(i&&n&&r^v){var y;g&e||!(y=a(p,n,!0))||(s=0,r?(t.lineStart(),t.point(y[0][0],y[0][1]),t.point(y[1][0],y[1][1]),t.lineEnd()):(t.point(y[1][0],y[1][1]),t.lineEnd(),t.lineStart(),t.point(y[0][0],y[0][1])))}!v||n&&qf(n,p)||t.point(p[0],p[1]),n=p,f=v,e=g},lineEnd:function(){f&&t.lineEnd(),n=null},clean:function(){return s|(c&&f)<<1}}},function(n,r,i,o){Lf(o,t,e,i,n,r)},r?[0,-t]:[-qa,t-qa])}var $f=1e9,Wf=-$f;function Zf(t,n,e,r){function i(i,o){return t<=i&&i<=e&&n<=o&&o<=r}function o(i,o,u,c){var s=0,l=0;if(null==i||(s=a(i,u))!==(l=a(o,u))||f(i,o)<0^u>0)do{c.point(0===s||3===s?t:e,s>1?r:n)}while((s=(s+u+4)%4)!==l);else c.point(o[0],o[1])}function a(r,i){return Ha(r[0]-t)<Da?i>0?0:3:Ha(r[0]-e)<Da?i>0?2:1:Ha(r[1]-n)<Da?i>0?1:0:i>0?3:2}function u(t,n){return f(t.x,n.x)}function f(t,n){var e=a(t,1),r=a(n,1);return e!==r?e-r:0===e?n[1]-t[1]:1===e?t[0]-n[0]:2===e?t[1]-n[1]:n[0]-t[0]}return function(a){var f,c,s,l,h,d,p,v,g,y,_,b=a,m=Uf(),x={point:w,lineStart:function(){x.point=M,c&&c.push(s=[]);y=!0,g=!1,p=v=NaN},lineEnd:function(){f&&(M(l,h),d&&g&&m.rejoin(),f.push(m.result()));x.point=w,g&&b.lineEnd()},polygonStart:function(){b=m,f=[],c=[],_=!0},polygonEnd:function(){var n=function(){for(var n=0,e=0,i=c.length;e<i;++e)for(var o,a,u=c[e],f=1,s=u.length,l=u[0],h=l[0],d=l[1];f<s;++f)o=h,a=d,l=u[f],h=l[0],d=l[1],a<=r?d>r&&(h-o)*(r-a)>(d-a)*(t-o)&&++n:d<=r&&(h-o)*(r-a)<(d-a)*(t-o)&&--n;return n}(),e=_&&n,i=(f=N(f)).length;(e||i)&&(a.polygonStart(),e&&(a.lineStart(),o(null,null,1,a),a.lineEnd()),i&&Yf(f,u,n,o,a),a.polygonEnd());b=a,f=c=s=null}};function w(t,n){i(t,n)&&b.point(t,n)}function M(o,a){var u=i(o,a);if(c&&s.push([o,a]),y)l=o,h=a,d=u,y=!1,u&&(b.lineStart(),b.point(o,a));else if(u&&g)b.point(o,a);else{var f=[p=Math.max(Wf,Math.min($f,p)),v=Math.max(Wf,Math.min($f,v))],m=[o=Math.max(Wf,Math.min($f,o)),a=Math.max(Wf,Math.min($f,a))];!function(t,n,e,r,i,o){var a,u=t[0],f=t[1],c=0,s=1,l=n[0]-u,h=n[1]-f;if(a=e-u,l||!(a>0)){if(a/=l,l<0){if(a<c)return;a<s&&(s=a)}else if(l>0){if(a>s)return;a>c&&(c=a)}if(a=i-u,l||!(a<0)){if(a/=l,l<0){if(a>s)return;a>c&&(c=a)}else if(l>0){if(a<c)return;a<s&&(s=a)}if(a=r-f,h||!(a>0)){if(a/=h,h<0){if(a<c)return;a<s&&(s=a)}else if(h>0){if(a>s)return;a>c&&(c=a)}if(a=o-f,h||!(a<0)){if(a/=h,h<0){if(a>s)return;a>c&&(c=a)}else if(h>0){if(a<c)return;a<s&&(s=a)}return c>0&&(t[0]=u+c*l,t[1]=f+c*h),s<1&&(n[0]=u+s*l,n[1]=f+s*h),!0}}}}}(f,m,t,n,e,r)?u&&(b.lineStart(),b.point(o,a),_=!1):(g||(b.lineStart(),b.point(f[0],f[1])),b.point(m[0],m[1]),u||b.lineEnd(),_=!1)}p=o,v=a,g=u}return x}}var Qf,Jf,Kf,tc=Pa(),nc={sphere:iu,point:iu,lineStart:function(){nc.point=rc,nc.lineEnd=ec},lineEnd:iu,polygonStart:iu,polygonEnd:iu};function ec(){nc.point=nc.lineEnd=iu}function rc(t,n){Qf=t*=Ia,Jf=Qa(n*=Ia),Kf=Ga(n),nc.point=ic}function ic(t,n){t*=Ia;var e=Qa(n*=Ia),r=Ga(n),i=Ha(t-Qf),o=Ga(i),a=r*Qa(i),u=Kf*e-Jf*r*o,f=Jf*e+Kf*r*o;tc.add(Xa(Ka(a*a+u*u),f)),Qf=t,Jf=e,Kf=r}function oc(t){return tc.reset(),su(t,nc),+tc}var ac=[null,null],uc={type:"LineString",coordinates:ac};function fc(t,n){return ac[0]=t,ac[1]=n,oc(uc)}var cc={Feature:function(t,n){return lc(t.geometry,n)},FeatureCollection:function(t,n){for(var e=t.features,r=-1,i=e.length;++r<i;)if(lc(e[r].geometry,n))return!0;return!1}},sc={Sphere:function(){return!0},Point:function(t,n){return hc(t.coordinates,n)},MultiPoint:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)if(hc(e[r],n))return!0;return!1},LineString:function(t,n){return dc(t.coordinates,n)},MultiLineString:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)if(dc(e[r],n))return!0;return!1},Polygon:function(t,n){return pc(t.coordinates,n)},MultiPolygon:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)if(pc(e[r],n))return!0;return!1},GeometryCollection:function(t,n){for(var e=t.geometries,r=-1,i=e.length;++r<i;)if(lc(e[r],n))return!0;return!1}};function lc(t,n){return!(!t||!sc.hasOwnProperty(t.type))&&sc[t.type](t,n)}function hc(t,n){return 0===fc(t,n)}function dc(t,n){var e=fc(t[0],t[1]);return fc(t[0],n)+fc(n,t[1])<=e+Da}function pc(t,n){return!!If(t.map(vc),gc(n))}function vc(t){return(t=t.map(gc)).pop(),t}function gc(t){return[t[0]*Ia,t[1]*Ia]}function yc(t,n,e){var r=g(t,n-Da,e).concat(n);return function(t){return r.map(function(n){return[t,n]})}}function _c(t,n,e){var r=g(t,n-Da,e).concat(n);return function(t){return r.map(function(n){return[n,t]})}}function bc(){var t,n,e,r,i,o,a,u,f,c,s,l,h=10,d=h,p=90,v=360,y=2.5;function _(){return{type:"MultiLineString",coordinates:b()}}function b(){return g(Va(r/p)*p,e,p).map(s).concat(g(Va(u/v)*v,a,v).map(l)).concat(g(Va(n/h)*h,t,h).filter(function(t){return Ha(t%p)>Da}).map(f)).concat(g(Va(o/d)*d,i,d).filter(function(t){return Ha(t%v)>Da}).map(c))}return _.lines=function(){return b().map(function(t){return{type:"LineString",coordinates:t}})},_.outline=function(){return{type:"Polygon",coordinates:[s(r).concat(l(a).slice(1),s(e).reverse().slice(1),l(u).reverse().slice(1))]}},_.extent=function(t){return arguments.length?_.extentMajor(t).extentMinor(t):_.extentMinor()},_.extentMajor=function(t){return arguments.length?(r=+t[0][0],e=+t[1][0],u=+t[0][1],a=+t[1][1],r>e&&(t=r,r=e,e=t),u>a&&(t=u,u=a,a=t),_.precision(y)):[[r,u],[e,a]]},_.extentMinor=function(e){return arguments.length?(n=+e[0][0],t=+e[1][0],o=+e[0][1],i=+e[1][1],n>t&&(e=n,n=t,t=e),o>i&&(e=o,o=i,i=e),_.precision(y)):[[n,o],[t,i]]},_.step=function(t){return arguments.length?_.stepMajor(t).stepMinor(t):_.stepMinor()},_.stepMajor=function(t){return arguments.length?(p=+t[0],v=+t[1],_):[p,v]},_.stepMinor=function(t){return arguments.length?(h=+t[0],d=+t[1],_):[h,d]},_.precision=function(h){return arguments.length?(y=+h,f=yc(o,i,90),c=_c(n,t,y),s=yc(u,a,90),l=_c(r,e,y),_):y},_.extentMajor([[-180,-90+Da],[180,90-Da]]).extentMinor([[-180,-80-Da],[180,80+Da]])}function mc(t){return t}var xc,wc,Mc,Ac,Tc=Pa(),Nc=Pa(),Sc={point:iu,lineStart:iu,lineEnd:iu,polygonStart:function(){Sc.lineStart=Ec,Sc.lineEnd=Pc},polygonEnd:function(){Sc.lineStart=Sc.lineEnd=Sc.point=iu,Tc.add(Ha(Nc)),Nc.reset()},result:function(){var t=Tc/2;return Tc.reset(),t}};function Ec(){Sc.point=kc}function kc(t,n){Sc.point=Cc,xc=Mc=t,wc=Ac=n}function Cc(t,n){Nc.add(Ac*t-Mc*n),Mc=t,Ac=n}function Pc(){Cc(xc,wc)}var zc=1/0,Rc=zc,Lc=-zc,Dc=Lc,Uc={point:function(t,n){t<zc&&(zc=t);t>Lc&&(Lc=t);n<Rc&&(Rc=n);n>Dc&&(Dc=n)},lineStart:iu,lineEnd:iu,polygonStart:iu,polygonEnd:iu,result:function(){var t=[[zc,Rc],[Lc,Dc]];return Lc=Dc=-(Rc=zc=1/0),t}};var qc,Oc,Yc,Bc,Fc=0,Ic=0,Hc=0,jc=0,Xc=0,Gc=0,Vc=0,$c=0,Wc=0,Zc={point:Qc,lineStart:Jc,lineEnd:ns,polygonStart:function(){Zc.lineStart=es,Zc.lineEnd=rs},polygonEnd:function(){Zc.point=Qc,Zc.lineStart=Jc,Zc.lineEnd=ns},result:function(){var t=Wc?[Vc/Wc,$c/Wc]:Gc?[jc/Gc,Xc/Gc]:Hc?[Fc/Hc,Ic/Hc]:[NaN,NaN];return Fc=Ic=Hc=jc=Xc=Gc=Vc=$c=Wc=0,t}};function Qc(t,n){Fc+=t,Ic+=n,++Hc}function Jc(){Zc.point=Kc}function Kc(t,n){Zc.point=ts,Qc(Yc=t,Bc=n)}function ts(t,n){var e=t-Yc,r=n-Bc,i=Ka(e*e+r*r);jc+=i*(Yc+t)/2,Xc+=i*(Bc+n)/2,Gc+=i,Qc(Yc=t,Bc=n)}function ns(){Zc.point=Qc}function es(){Zc.point=is}function rs(){os(qc,Oc)}function is(t,n){Zc.point=os,Qc(qc=Yc=t,Oc=Bc=n)}function os(t,n){var e=t-Yc,r=n-Bc,i=Ka(e*e+r*r);jc+=i*(Yc+t)/2,Xc+=i*(Bc+n)/2,Gc+=i,Vc+=(i=Bc*t-Yc*n)*(Yc+t),$c+=i*(Bc+n),Wc+=3*i,Qc(Yc=t,Bc=n)}function as(t){this._context=t}as.prototype={_radius:4.5,pointRadius:function(t){return this._radius=t,this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._context.closePath(),this._point=NaN},point:function(t,n){switch(this._point){case 0:this._context.moveTo(t,n),this._point=1;break;case 1:this._context.lineTo(t,n);break;default:this._context.moveTo(t+this._radius,n),this._context.arc(t,n,this._radius,0,Ba)}},result:iu};var us,fs,cs,ss,ls,hs=Pa(),ds={point:iu,lineStart:function(){ds.point=ps},lineEnd:function(){us&&vs(fs,cs),ds.point=iu},polygonStart:function(){us=!0},polygonEnd:function(){us=null},result:function(){var t=+hs;return hs.reset(),t}};function ps(t,n){ds.point=vs,fs=ss=t,cs=ls=n}function vs(t,n){ss-=t,ls-=n,hs.add(Ka(ss*ss+ls*ls)),ss=t,ls=n}function gs(){this._string=[]}function ys(t){return"m0,"+t+"a"+t+","+t+" 0 1,1 0,"+-2*t+"a"+t+","+t+" 0 1,1 0,"+2*t+"z"}function _s(t){return function(n){var e=new bs;for(var r in t)e[r]=t[r];return e.stream=n,e}}function bs(){}function ms(t,n,e){var r=t.clipExtent&&t.clipExtent();return t.scale(150).translate([0,0]),null!=r&&t.clipExtent(null),su(e,t.stream(Uc)),n(Uc.result()),null!=r&&t.clipExtent(r),t}function xs(t,n,e){return ms(t,function(e){var r=n[1][0]-n[0][0],i=n[1][1]-n[0][1],o=Math.min(r/(e[1][0]-e[0][0]),i/(e[1][1]-e[0][1])),a=+n[0][0]+(r-o*(e[1][0]+e[0][0]))/2,u=+n[0][1]+(i-o*(e[1][1]+e[0][1]))/2;t.scale(150*o).translate([a,u])},e)}function ws(t,n,e){return xs(t,[[0,0],n],e)}function Ms(t,n,e){return ms(t,function(e){var r=+n,i=r/(e[1][0]-e[0][0]),o=(r-i*(e[1][0]+e[0][0]))/2,a=-i*e[0][1];t.scale(150*i).translate([o,a])},e)}function As(t,n,e){return ms(t,function(e){var r=+n,i=r/(e[1][1]-e[0][1]),o=-i*e[0][0],a=(r-i*(e[1][1]+e[0][1]))/2;t.scale(150*i).translate([o,a])},e)}gs.prototype={_radius:4.5,_circle:ys(4.5),pointRadius:function(t){return(t=+t)!==this._radius&&(this._radius=t,this._circle=null),this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._string.push("Z"),this._point=NaN},point:function(t,n){switch(this._point){case 0:this._string.push("M",t,",",n),this._point=1;break;case 1:this._string.push("L",t,",",n);break;default:null==this._circle&&(this._circle=ys(this._radius)),this._string.push("M",t,",",n,this._circle)}},result:function(){if(this._string.length){var t=this._string.join("");return this._string=[],t}return null}},bs.prototype={constructor:bs,point:function(t,n){this.stream.point(t,n)},sphere:function(){this.stream.sphere()},lineStart:function(){this.stream.lineStart()},lineEnd:function(){this.stream.lineEnd()},polygonStart:function(){this.stream.polygonStart()},polygonEnd:function(){this.stream.polygonEnd()}};var Ts=16,Ns=Ga(30*Ia);function Ss(t,n){return+n?function(t,n){function e(r,i,o,a,u,f,c,s,l,h,d,p,v,g){var y=c-r,_=s-i,b=y*y+_*_;if(b>4*n&&v--){var m=a+h,x=u+d,w=f+p,M=Ka(m*m+x*x+w*w),A=eu(w/=M),T=Ha(Ha(w)-1)<Da||Ha(o-l)<Da?(o+l)/2:Xa(x,m),N=t(T,A),S=N[0],E=N[1],k=S-r,C=E-i,P=_*k-y*C;(P*P/b>n||Ha((y*k+_*C)/b-.5)>.3||a*h+u*d+f*p<Ns)&&(e(r,i,o,a,u,f,S,E,T,m/=M,x/=M,w,v,g),g.point(S,E),e(S,E,T,m,x,w,c,s,l,h,d,p,v,g))}}return function(n){var r,i,o,a,u,f,c,s,l,h,d,p,v={point:g,lineStart:y,lineEnd:b,polygonStart:function(){n.polygonStart(),v.lineStart=m},polygonEnd:function(){n.polygonEnd(),v.lineStart=y}};function g(e,r){e=t(e,r),n.point(e[0],e[1])}function y(){s=NaN,v.point=_,n.lineStart()}function _(r,i){var o=Au([r,i]),a=t(r,i);e(s,l,c,h,d,p,s=a[0],l=a[1],c=r,h=o[0],d=o[1],p=o[2],Ts,n),n.point(s,l)}function b(){v.point=g,n.lineEnd()}function m(){y(),v.point=x,v.lineEnd=w}function x(t,n){_(r=t,n),i=s,o=l,a=h,u=d,f=p,v.point=_}function w(){e(s,l,c,h,d,p,i,o,r,a,u,f,Ts,n),v.lineEnd=b,b()}return v}}(t,n):function(t){return _s({point:function(n,e){n=t(n,e),this.stream.point(n[0],n[1])}})}(t)}var Es=_s({point:function(t,n){this.stream.point(t*Ia,n*Ia)}});function ks(t,n,e,r){var i=Ga(r),o=Qa(r),a=i*t,u=o*t,f=i/t,c=o/t,s=(o*e-i*n)/t,l=(o*n+i*e)/t;function h(t,r){return[a*t-u*r+n,e-u*t-a*r]}return h.invert=function(t,n){return[f*t-c*n+s,l-c*t-f*n]},h}function Cs(t){return Ps(function(){return t})()}function Ps(t){var n,e,r,i,o,a,u,f,c,s,l=150,h=480,d=250,p=0,v=0,g=0,y=0,_=0,b=0,m=null,x=Gf,w=null,M=mc,A=.5;function T(t){return f(t[0]*Ia,t[1]*Ia)}function N(t){return(t=f.invert(t[0],t[1]))&&[t[0]*Fa,t[1]*Fa]}function S(){var t=ks(l,0,0,b).apply(null,n(p,v)),r=(b?ks:function(t,n,e){function r(r,i){return[n+t*r,e-t*i]}return r.invert=function(r,i){return[(r-n)/t,(e-i)/t]},r})(l,h-t[0],d-t[1],b);return e=kf(g,y,_),u=Sf(n,r),f=Sf(e,u),a=Ss(u,A),E()}function E(){return c=s=null,T}return T.stream=function(t){return c&&s===t?c:c=Es(function(t){return _s({point:function(n,e){var r=t(n,e);return this.stream.point(r[0],r[1])}})}(e)(x(a(M(s=t)))))},T.preclip=function(t){return arguments.length?(x=t,m=void 0,E()):x},T.postclip=function(t){return arguments.length?(M=t,w=r=i=o=null,E()):M},T.clipAngle=function(t){return arguments.length?(x=+t?Vf(m=t*Ia):(m=null,Gf),E()):m*Fa},T.clipExtent=function(t){return arguments.length?(M=null==t?(w=r=i=o=null,mc):Zf(w=+t[0][0],r=+t[0][1],i=+t[1][0],o=+t[1][1]),E()):null==w?null:[[w,r],[i,o]]},T.scale=function(t){return arguments.length?(l=+t,S()):l},T.translate=function(t){return arguments.length?(h=+t[0],d=+t[1],S()):[h,d]},T.center=function(t){return arguments.length?(p=t[0]%360*Ia,v=t[1]%360*Ia,S()):[p*Fa,v*Fa]},T.rotate=function(t){return arguments.length?(g=t[0]%360*Ia,y=t[1]%360*Ia,_=t.length>2?t[2]%360*Ia:0,S()):[g*Fa,y*Fa,_*Fa]},T.angle=function(t){return arguments.length?(b=t%360*Ia,S()):b*Fa},T.precision=function(t){return arguments.length?(a=Ss(u,A=t*t),E()):Ka(A)},T.fitExtent=function(t,n){return xs(T,t,n)},T.fitSize=function(t,n){return ws(T,t,n)},T.fitWidth=function(t,n){return Ms(T,t,n)},T.fitHeight=function(t,n){return As(T,t,n)},function(){return n=t.apply(this,arguments),T.invert=n.invert&&N,S()}}function zs(t){var n=0,e=qa/3,r=Ps(t),i=r(n,e);return i.parallels=function(t){return arguments.length?r(n=t[0]*Ia,e=t[1]*Ia):[n*Fa,e*Fa]},i}function Rs(t,n){var e=Qa(t),r=(e+Qa(n))/2;if(Ha(r)<Da)return function(t){var n=Ga(t);function e(t,e){return[t*n,Qa(e)/n]}return e.invert=function(t,e){return[t/n,eu(e*n)]},e}(t);var i=1+e*(2*r-e),o=Ka(i)/r;function a(t,n){var e=Ka(i-2*r*Qa(n))/r;return[e*Qa(t*=r),o-e*Ga(t)]}return a.invert=function(t,n){var e=o-n;return[Xa(t,Ha(e))/r*Ja(e),eu((i-(t*t+e*e)*r*r)/(2*r))]},a}function Ls(){return zs(Rs).scale(155.424).center([0,33.6442])}function Ds(){return Ls().parallels([29.5,45.5]).scale(1070).translate([480,250]).rotate([96,0]).center([-.6,38.7])}function Us(t){return function(n,e){var r=Ga(n),i=Ga(e),o=t(r*i);return[o*i*Qa(n),o*Qa(e)]}}function qs(t){return function(n,e){var r=Ka(n*n+e*e),i=t(r),o=Qa(i),a=Ga(i);return[Xa(n*o,r*a),eu(r&&e*o/r)]}}var Os=Us(function(t){return Ka(2/(1+t))});Os.invert=qs(function(t){return 2*eu(t/2)});var Ys=Us(function(t){return(t=nu(t))&&t/Qa(t)});function Bs(t,n){return[t,Wa(tu((Oa+n)/2))]}function Fs(t){var n,e,r,i=Cs(t),o=i.center,a=i.scale,u=i.translate,f=i.clipExtent,c=null;function s(){var o=qa*a(),u=i(Rf(i.rotate()).invert([0,0]));return f(null==c?[[u[0]-o,u[1]-o],[u[0]+o,u[1]+o]]:t===Bs?[[Math.max(u[0]-o,c),n],[Math.min(u[0]+o,e),r]]:[[c,Math.max(u[1]-o,n)],[e,Math.min(u[1]+o,r)]])}return i.scale=function(t){return arguments.length?(a(t),s()):a()},i.translate=function(t){return arguments.length?(u(t),s()):u()},i.center=function(t){return arguments.length?(o(t),s()):o()},i.clipExtent=function(t){return arguments.length?(null==t?c=n=e=r=null:(c=+t[0][0],n=+t[0][1],e=+t[1][0],r=+t[1][1]),s()):null==c?null:[[c,n],[e,r]]},s()}function Is(t){return tu((Oa+t)/2)}function Hs(t,n){var e=Ga(t),r=t===n?Qa(t):Wa(e/Ga(n))/Wa(Is(n)/Is(t)),i=e*Za(Is(t),r)/r;if(!r)return Bs;function o(t,n){i>0?n<-Oa+Da&&(n=-Oa+Da):n>Oa-Da&&(n=Oa-Da);var e=i/Za(Is(n),r);return[e*Qa(r*t),i-e*Ga(r*t)]}return o.invert=function(t,n){var e=i-n,o=Ja(r)*Ka(t*t+e*e);return[Xa(t,Ha(e))/r*Ja(e),2*ja(Za(i/o,1/r))-Oa]},o}function js(t,n){return[t,n]}function Xs(t,n){var e=Ga(t),r=t===n?Qa(t):(e-Ga(n))/(n-t),i=e/r+t;if(Ha(r)<Da)return js;function o(t,n){var e=i-n,o=r*t;return[e*Qa(o),i-e*Ga(o)]}return o.invert=function(t,n){var e=i-n;return[Xa(t,Ha(e))/r*Ja(e),i-Ja(r)*Ka(t*t+e*e)]},o}Ys.invert=qs(function(t){return t}),Bs.invert=function(t,n){return[t,2*ja($a(n))-Oa]},js.invert=js;var Gs=1.340264,Vs=-.081106,$s=893e-6,Ws=.003796,Zs=Ka(3)/2;function Qs(t,n){var e=eu(Zs*Qa(n)),r=e*e,i=r*r*r;return[t*Ga(e)/(Zs*(Gs+3*Vs*r+i*(7*$s+9*Ws*r))),e*(Gs+Vs*r+i*($s+Ws*r))]}function Js(t,n){var e=Ga(n),r=Ga(t)*e;return[e*Qa(t)/r,Qa(n)/r]}function Ks(t,n,e,r){return 1===t&&1===n&&0===e&&0===r?mc:_s({point:function(i,o){this.stream.point(i*t+e,o*n+r)}})}function tl(t,n){var e=n*n,r=e*e;return[t*(.8707-.131979*e+r*(r*(.003971*e-.001529*r)-.013791)),n*(1.007226+e*(.015085+r*(.028874*e-.044475-.005916*r)))]}function nl(t,n){return[Ga(n)*Qa(t),Qa(n)]}function el(t,n){var e=Ga(n),r=1+Ga(t)*e;return[e*Qa(t)/r,Qa(n)/r]}function rl(t,n){return[Wa(tu((Oa+n)/2)),-t]}function il(t,n){return t.parent===n.parent?1:2}function ol(t,n){return t+n.x}function al(t,n){return Math.max(t,n.y)}function ul(t){var n=0,e=t.children,r=e&&e.length;if(r)for(;--r>=0;)n+=e[r].value;else n=1;t.value=n}function fl(t,n){var e,r,i,o,a,u=new hl(t),f=+t.value&&(u.value=t.value),c=[u];for(null==n&&(n=cl);e=c.pop();)if(f&&(e.value=+e.data.value),(i=n(e.data))&&(a=i.length))for(e.children=new Array(a),o=a-1;o>=0;--o)c.push(r=e.children[o]=new hl(i[o])),r.parent=e,r.depth=e.depth+1;return u.eachBefore(ll)}function cl(t){return t.children}function sl(t){t.data=t.data.data}function ll(t){var n=0;do{t.height=n}while((t=t.parent)&&t.height<++n)}function hl(t){this.data=t,this.depth=this.height=0,this.parent=null}Qs.invert=function(t,n){for(var e,r=n,i=r*r,o=i*i*i,a=0;a<12&&(o=(i=(r-=e=(r*(Gs+Vs*i+o*($s+Ws*i))-n)/(Gs+3*Vs*i+o*(7*$s+9*Ws*i)))*r)*i*i,!(Ha(e)<Ua));++a);return[Zs*t*(Gs+3*Vs*i+o*(7*$s+9*Ws*i))/Ga(r),eu(Qa(r)/Zs)]},Js.invert=qs(ja),tl.invert=function(t,n){var e,r=n,i=25;do{var o=r*r,a=o*o;r-=e=(r*(1.007226+o*(.015085+a*(.028874*o-.044475-.005916*a)))-n)/(1.007226+o*(.045255+a*(.259866*o-.311325-.005916*11*a)))}while(Ha(e)>Da&&--i>0);return[t/(.8707+(o=r*r)*(o*(o*o*o*(.003971-.001529*o)-.013791)-.131979)),r]},nl.invert=qs(eu),el.invert=qs(function(t){return 2*ja(t)}),rl.invert=function(t,n){return[-n,2*ja($a(t))-Oa]},hl.prototype=fl.prototype={constructor:hl,count:function(){return this.eachAfter(ul)},each:function(t){var n,e,r,i,o=this,a=[o];do{for(n=a.reverse(),a=[];o=n.pop();)if(t(o),e=o.children)for(r=0,i=e.length;r<i;++r)a.push(e[r])}while(a.length);return this},eachAfter:function(t){for(var n,e,r,i=this,o=[i],a=[];i=o.pop();)if(a.push(i),n=i.children)for(e=0,r=n.length;e<r;++e)o.push(n[e]);for(;i=a.pop();)t(i);return this},eachBefore:function(t){for(var n,e,r=this,i=[r];r=i.pop();)if(t(r),n=r.children)for(e=n.length-1;e>=0;--e)i.push(n[e]);return this},sum:function(t){return this.eachAfter(function(n){for(var e=+t(n.data)||0,r=n.children,i=r&&r.length;--i>=0;)e+=r[i].value;n.value=e})},sort:function(t){return this.eachBefore(function(n){n.children&&n.children.sort(t)})},path:function(t){for(var n=this,e=function(t,n){if(t===n)return t;var e=t.ancestors(),r=n.ancestors(),i=null;for(t=e.pop(),n=r.pop();t===n;)i=t,t=e.pop(),n=r.pop();return i}(n,t),r=[n];n!==e;)n=n.parent,r.push(n);for(var i=r.length;t!==e;)r.splice(i,0,t),t=t.parent;return r},ancestors:function(){for(var t=this,n=[t];t=t.parent;)n.push(t);return n},descendants:function(){var t=[];return this.each(function(n){t.push(n)}),t},leaves:function(){var t=[];return this.eachBefore(function(n){n.children||t.push(n)}),t},links:function(){var t=this,n=[];return t.each(function(e){e!==t&&n.push({source:e.parent,target:e})}),n},copy:function(){return fl(this).eachBefore(sl)}};var dl=Array.prototype.slice;function pl(t){for(var n,e,r=0,i=(t=function(t){for(var n,e,r=t.length;r;)e=Math.random()*r--|0,n=t[r],t[r]=t[e],t[e]=n;return t}(dl.call(t))).length,o=[];r<i;)n=t[r],e&&yl(e,n)?++r:(e=bl(o=vl(o,n)),r=0);return e}function vl(t,n){var e,r;if(_l(n,t))return[n];for(e=0;e<t.length;++e)if(gl(n,t[e])&&_l(ml(t[e],n),t))return[t[e],n];for(e=0;e<t.length-1;++e)for(r=e+1;r<t.length;++r)if(gl(ml(t[e],t[r]),n)&&gl(ml(t[e],n),t[r])&&gl(ml(t[r],n),t[e])&&_l(xl(t[e],t[r],n),t))return[t[e],t[r],n];throw new Error}function gl(t,n){var e=t.r-n.r,r=n.x-t.x,i=n.y-t.y;return e<0||e*e<r*r+i*i}function yl(t,n){var e=t.r-n.r+1e-6,r=n.x-t.x,i=n.y-t.y;return e>0&&e*e>r*r+i*i}function _l(t,n){for(var e=0;e<n.length;++e)if(!yl(t,n[e]))return!1;return!0}function bl(t){switch(t.length){case 1:return{x:(n=t[0]).x,y:n.y,r:n.r};case 2:return ml(t[0],t[1]);case 3:return xl(t[0],t[1],t[2])}var n}function ml(t,n){var e=t.x,r=t.y,i=t.r,o=n.x,a=n.y,u=n.r,f=o-e,c=a-r,s=u-i,l=Math.sqrt(f*f+c*c);return{x:(e+o+f/l*s)/2,y:(r+a+c/l*s)/2,r:(l+i+u)/2}}function xl(t,n,e){var r=t.x,i=t.y,o=t.r,a=n.x,u=n.y,f=n.r,c=e.x,s=e.y,l=e.r,h=r-a,d=r-c,p=i-u,v=i-s,g=f-o,y=l-o,_=r*r+i*i-o*o,b=_-a*a-u*u+f*f,m=_-c*c-s*s+l*l,x=d*p-h*v,w=(p*m-v*b)/(2*x)-r,M=(v*g-p*y)/x,A=(d*b-h*m)/(2*x)-i,T=(h*y-d*g)/x,N=M*M+T*T-1,S=2*(o+w*M+A*T),E=w*w+A*A-o*o,k=-(N?(S+Math.sqrt(S*S-4*N*E))/(2*N):E/S);return{x:r+w+M*k,y:i+A+T*k,r:k}}function wl(t,n,e){var r,i,o,a,u=t.x-n.x,f=t.y-n.y,c=u*u+f*f;c?(i=n.r+e.r,i*=i,a=t.r+e.r,i>(a*=a)?(r=(c+a-i)/(2*c),o=Math.sqrt(Math.max(0,a/c-r*r)),e.x=t.x-r*u-o*f,e.y=t.y-r*f+o*u):(r=(c+i-a)/(2*c),o=Math.sqrt(Math.max(0,i/c-r*r)),e.x=n.x+r*u-o*f,e.y=n.y+r*f+o*u)):(e.x=n.x+e.r,e.y=n.y)}function Ml(t,n){var e=t.r+n.r-1e-6,r=n.x-t.x,i=n.y-t.y;return e>0&&e*e>r*r+i*i}function Al(t){var n=t._,e=t.next._,r=n.r+e.r,i=(n.x*e.r+e.x*n.r)/r,o=(n.y*e.r+e.y*n.r)/r;return i*i+o*o}function Tl(t){this._=t,this.next=null,this.previous=null}function Nl(t){if(!(i=t.length))return 0;var n,e,r,i,o,a,u,f,c,s,l;if((n=t[0]).x=0,n.y=0,!(i>1))return n.r;if(e=t[1],n.x=-e.r,e.x=n.r,e.y=0,!(i>2))return n.r+e.r;wl(e,n,r=t[2]),n=new Tl(n),e=new Tl(e),r=new Tl(r),n.next=r.previous=e,e.next=n.previous=r,r.next=e.previous=n;t:for(u=3;u<i;++u){wl(n._,e._,r=t[u]),r=new Tl(r),f=e.next,c=n.previous,s=e._.r,l=n._.r;do{if(s<=l){if(Ml(f._,r._)){e=f,n.next=e,e.previous=n,--u;continue t}s+=f._.r,f=f.next}else{if(Ml(c._,r._)){(n=c).next=e,e.previous=n,--u;continue t}l+=c._.r,c=c.previous}}while(f!==c.next);for(r.previous=n,r.next=e,n.next=e.previous=e=r,o=Al(n);(r=r.next)!==e;)(a=Al(r))<o&&(n=r,o=a);e=n.next}for(n=[e._],r=e;(r=r.next)!==e;)n.push(r._);for(r=pl(n),u=0;u<i;++u)(n=t[u]).x-=r.x,n.y-=r.y;return r.r}function Sl(t){if("function"!=typeof t)throw new Error;return t}function El(){return 0}function kl(t){return function(){return t}}function Cl(t){return Math.sqrt(t.value)}function Pl(t){return function(n){n.children||(n.r=Math.max(0,+t(n)||0))}}function zl(t,n){return function(e){if(r=e.children){var r,i,o,a=r.length,u=t(e)*n||0;if(u)for(i=0;i<a;++i)r[i].r+=u;if(o=Nl(r),u)for(i=0;i<a;++i)r[i].r-=u;e.r=o+u}}}function Rl(t){return function(n){var e=n.parent;n.r*=t,e&&(n.x=e.x+t*n.x,n.y=e.y+t*n.y)}}function Ll(t){t.x0=Math.round(t.x0),t.y0=Math.round(t.y0),t.x1=Math.round(t.x1),t.y1=Math.round(t.y1)}function Dl(t,n,e,r,i){for(var o,a=t.children,u=-1,f=a.length,c=t.value&&(r-n)/t.value;++u<f;)(o=a[u]).y0=e,o.y1=i,o.x0=n,o.x1=n+=o.value*c}var Ul="$",ql={depth:-1},Ol={};function Yl(t){return t.id}function Bl(t){return t.parentId}function Fl(t,n){return t.parent===n.parent?1:2}function Il(t){var n=t.children;return n?n[0]:t.t}function Hl(t){var n=t.children;return n?n[n.length-1]:t.t}function jl(t,n,e){var r=e/(n.i-t.i);n.c-=r,n.s+=e,t.c+=r,n.z+=e,n.m+=e}function Xl(t,n,e){return t.a.parent===n.parent?t.a:e}function Gl(t,n){this._=t,this.parent=null,this.children=null,this.A=null,this.a=this,this.z=0,this.m=0,this.c=0,this.s=0,this.t=null,this.i=n}function Vl(t,n,e,r,i){for(var o,a=t.children,u=-1,f=a.length,c=t.value&&(i-e)/t.value;++u<f;)(o=a[u]).x0=n,o.x1=r,o.y0=e,o.y1=e+=o.value*c}Gl.prototype=Object.create(hl.prototype);var $l=(1+Math.sqrt(5))/2;function Wl(t,n,e,r,i,o){for(var a,u,f,c,s,l,h,d,p,v,g,y=[],_=n.children,b=0,m=0,x=_.length,w=n.value;b<x;){f=i-e,c=o-r;do{s=_[m++].value}while(!s&&m<x);for(l=h=s,g=s*s*(v=Math.max(c/f,f/c)/(w*t)),p=Math.max(h/g,g/l);m<x;++m){if(s+=u=_[m].value,u<l&&(l=u),u>h&&(h=u),g=s*s*v,(d=Math.max(h/g,g/l))>p){s-=u;break}p=d}y.push(a={value:s,dice:f<c,children:_.slice(b,m)}),a.dice?Dl(a,e,r,i,w?r+=c*s/w:o):Vl(a,e,r,w?e+=f*s/w:i,o),w-=s,b=m}return y}var Zl=function t(n){function e(t,e,r,i,o){Wl(n,t,e,r,i,o)}return e.ratio=function(n){return t((n=+n)>1?n:1)},e}($l);var Ql=function t(n){function e(t,e,r,i,o){if((a=t._squarify)&&a.ratio===n)for(var a,u,f,c,s,l=-1,h=a.length,d=t.value;++l<h;){for(f=(u=a[l]).children,c=u.value=0,s=f.length;c<s;++c)u.value+=f[c].value;u.dice?Dl(u,e,r,i,r+=(o-r)*u.value/d):Vl(u,e,r,e+=(i-e)*u.value/d,o),d-=u.value}else t._squarify=a=Wl(n,t,e,r,i,o),a.ratio=n}return e.ratio=function(n){return t((n=+n)>1?n:1)},e}($l);function Jl(t,n){return t[0]-n[0]||t[1]-n[1]}function Kl(t){for(var n,e,r,i=t.length,o=[0,1],a=2,u=2;u<i;++u){for(;a>1&&(n=t[o[a-2]],e=t[o[a-1]],r=t[u],(e[0]-n[0])*(r[1]-n[1])-(e[1]-n[1])*(r[0]-n[0])<=0);)--a;o[a++]=u}return o.slice(0,a)}function th(){return Math.random()}var nh=function t(n){function e(t,e){return t=null==t?0:+t,e=null==e?1:+e,1===arguments.length?(e=t,t=0):e-=t,function(){return n()*e+t}}return e.source=t,e}(th),eh=function t(n){function e(t,e){var r,i;return t=null==t?0:+t,e=null==e?1:+e,function(){var o;if(null!=r)o=r,r=null;else do{r=2*n()-1,o=2*n()-1,i=r*r+o*o}while(!i||i>1);return t+e*o*Math.sqrt(-2*Math.log(i)/i)}}return e.source=t,e}(th),rh=function t(n){function e(){var t=eh.source(n).apply(this,arguments);return function(){return Math.exp(t())}}return e.source=t,e}(th),ih=function t(n){function e(t){return function(){for(var e=0,r=0;r<t;++r)e+=n();return e}}return e.source=t,e}(th),oh=function t(n){function e(t){var e=ih.source(n)(t);return function(){return e()/t}}return e.source=t,e}(th),ah=function t(n){function e(t){return function(){return-Math.log(1-n())/t}}return e.source=t,e}(th),uh=Array.prototype,fh=uh.map,ch=uh.slice,sh={name:"implicit"};function lh(t){var n=Ki(),e=[],r=sh;function i(i){var o=i+"",a=n.get(o);if(!a){if(r!==sh)return r;n.set(o,a=e.push(i))}return t[(a-1)%t.length]}return t=null==t?[]:ch.call(t),i.domain=function(t){if(!arguments.length)return e.slice();e=[],n=Ki();for(var r,o,a=-1,u=t.length;++a<u;)n.has(o=(r=t[a])+"")||n.set(o,e.push(r));return i},i.range=function(n){return arguments.length?(t=ch.call(n),i):t.slice()},i.unknown=function(t){return arguments.length?(r=t,i):r},i.copy=function(){return lh().domain(e).range(t).unknown(r)},i}function hh(){var t,n,e=lh().unknown(void 0),r=e.domain,i=e.range,o=[0,1],a=!1,u=0,f=0,c=.5;function s(){var e=r().length,s=o[1]<o[0],l=o[s-0],h=o[1-s];t=(h-l)/Math.max(1,e-u+2*f),a&&(t=Math.floor(t)),l+=(h-l-t*(e-u))*c,n=t*(1-u),a&&(l=Math.round(l),n=Math.round(n));var d=g(e).map(function(n){return l+t*n});return i(s?d.reverse():d)}return delete e.unknown,e.domain=function(t){return arguments.length?(r(t),s()):r()},e.range=function(t){return arguments.length?(o=[+t[0],+t[1]],s()):o.slice()},e.rangeRound=function(t){return o=[+t[0],+t[1]],a=!0,s()},e.bandwidth=function(){return n},e.step=function(){return t},e.round=function(t){return arguments.length?(a=!!t,s()):a},e.padding=function(t){return arguments.length?(u=f=Math.max(0,Math.min(1,t)),s()):u},e.paddingInner=function(t){return arguments.length?(u=Math.max(0,Math.min(1,t)),s()):u},e.paddingOuter=function(t){return arguments.length?(f=Math.max(0,Math.min(1,t)),s()):f},e.align=function(t){return arguments.length?(c=Math.max(0,Math.min(1,t)),s()):c},e.copy=function(){return hh().domain(r()).range(o).round(a).paddingInner(u).paddingOuter(f).align(c)},s()}function dh(t){return function(){return t}}function ph(t){return+t}var vh=[0,1];function gh(t,n){return(n-=t=+t)?function(e){return(e-t)/n}:dh(n)}function yh(t,n,e,r){var i=t[0],o=t[1],a=n[0],u=n[1];return o<i?(i=e(o,i),a=r(u,a)):(i=e(i,o),a=r(a,u)),function(t){return a(i(t))}}function _h(t,n,e,r){var o=Math.min(t.length,n.length)-1,a=new Array(o),u=new Array(o),f=-1;for(t[o]<t[0]&&(t=t.slice().reverse(),n=n.slice().reverse());++f<o;)a[f]=e(t[f],t[f+1]),u[f]=r(n[f],n[f+1]);return function(n){var e=i(t,n,1,o)-1;return u[e](a[e](n))}}function bh(t,n){return n.domain(t.domain()).range(t.range()).interpolate(t.interpolate()).clamp(t.clamp())}function mh(t,n){var e,r,i,o=vh,a=vh,u=me,f=!1;function c(){return e=Math.min(o.length,a.length)>2?_h:yh,r=i=null,s}function s(n){return(r||(r=e(o,a,f?function(t){return function(n,e){var r=t(n=+n,e=+e);return function(t){return t<=n?0:t>=e?1:r(t)}}}(t):t,u)))(+n)}return s.invert=function(t){return(i||(i=e(a,o,gh,f?function(t){return function(n,e){var r=t(n=+n,e=+e);return function(t){return t<=0?n:t>=1?e:r(t)}}}(n):n)))(+t)},s.domain=function(t){return arguments.length?(o=fh.call(t,ph),c()):o.slice()},s.range=function(t){return arguments.length?(a=ch.call(t),c()):a.slice()},s.rangeRound=function(t){return a=ch.call(t),u=xe,c()},s.clamp=function(t){return arguments.length?(f=!!t,c()):f},s.interpolate=function(t){return arguments.length?(u=t,c()):u},c()}function xh(n){var e=n.domain;return n.ticks=function(t){var n=e();return m(n[0],n[n.length-1],null==t?10:t)},n.tickFormat=function(n,r){return function(n,e,r){var i,o=n[0],a=n[n.length-1],u=w(o,a,null==e?10:e);switch((r=ba(null==r?",f":r)).type){case"s":var f=Math.max(Math.abs(o),Math.abs(a));return null!=r.precision||isNaN(i=ka(u,f))||(r.precision=i),t.formatPrefix(r,f);case"":case"e":case"g":case"p":case"r":null!=r.precision||isNaN(i=Ca(u,Math.max(Math.abs(o),Math.abs(a))))||(r.precision=i-("e"===r.type));break;case"f":case"%":null!=r.precision||isNaN(i=Ea(u))||(r.precision=i-2*("%"===r.type))}return t.format(r)}(e(),n,r)},n.nice=function(t){null==t&&(t=10);var r,i=e(),o=0,a=i.length-1,u=i[o],f=i[a];return f<u&&(r=u,u=f,f=r,r=o,o=a,a=r),(r=x(u,f,t))>0?r=x(u=Math.floor(u/r)*r,f=Math.ceil(f/r)*r,t):r<0&&(r=x(u=Math.ceil(u*r)/r,f=Math.floor(f*r)/r,t)),r>0?(i[o]=Math.floor(u/r)*r,i[a]=Math.ceil(f/r)*r,e(i)):r<0&&(i[o]=Math.ceil(u*r)/r,i[a]=Math.floor(f*r)/r,e(i)),n},n}function wh(t,n){var e,r=0,i=(t=t.slice()).length-1,o=t[r],a=t[i];return a<o&&(e=r,r=i,i=e,e=o,o=a,a=e),t[r]=n.floor(o),t[i]=n.ceil(a),t}function Mh(t,n){return(n=Math.log(n/t))?function(e){return Math.log(e/t)/n}:dh(n)}function Ah(t,n){return t<0?function(e){return-Math.pow(-n,e)*Math.pow(-t,1-e)}:function(e){return Math.pow(n,e)*Math.pow(t,1-e)}}function Th(t){return isFinite(t)?+("1e"+t):t<0?0:t}function Nh(t){return 10===t?Th:t===Math.E?Math.exp:function(n){return Math.pow(t,n)}}function Sh(t){return t===Math.E?Math.log:10===t&&Math.log10||2===t&&Math.log2||(t=Math.log(t),function(n){return Math.log(n)/t})}function Eh(t){return function(n){return-t(-n)}}function kh(t,n){return t<0?-Math.pow(-t,n):Math.pow(t,n)}function Ch(){var t=1,n=mh(function(n,e){return(e=kh(e,t)-(n=kh(n,t)))?function(r){return(kh(r,t)-n)/e}:dh(e)},function(n,e){return e=kh(e,t)-(n=kh(n,t)),function(r){return kh(n+e*r,1/t)}}),e=n.domain;return n.exponent=function(n){return arguments.length?(t=+n,e(e())):t},n.copy=function(){return bh(n,Ch().exponent(t))},xh(n)}var Ph=new Date,zh=new Date;function Rh(t,n,e,r){function i(n){return t(n=new Date(+n)),n}return i.floor=i,i.ceil=function(e){return t(e=new Date(e-1)),n(e,1),t(e),e},i.round=function(t){var n=i(t),e=i.ceil(t);return t-n<e-t?n:e},i.offset=function(t,e){return n(t=new Date(+t),null==e?1:Math.floor(e)),t},i.range=function(e,r,o){var a,u=[];if(e=i.ceil(e),o=null==o?1:Math.floor(o),!(e<r&&o>0))return u;do{u.push(a=new Date(+e)),n(e,o),t(e)}while(a<e&&e<r);return u},i.filter=function(e){return Rh(function(n){if(n>=n)for(;t(n),!e(n);)n.setTime(n-1)},function(t,r){if(t>=t)if(r<0)for(;++r<=0;)for(;n(t,-1),!e(t););else for(;--r>=0;)for(;n(t,1),!e(t););})},e&&(i.count=function(n,r){return Ph.setTime(+n),zh.setTime(+r),t(Ph),t(zh),Math.floor(e(Ph,zh))},i.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?i.filter(r?function(n){return r(n)%t==0}:function(n){return i.count(0,n)%t==0}):i:null}),i}var Lh=Rh(function(){},function(t,n){t.setTime(+t+n)},function(t,n){return n-t});Lh.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?Rh(function(n){n.setTime(Math.floor(n/t)*t)},function(n,e){n.setTime(+n+e*t)},function(n,e){return(e-n)/t}):Lh:null};var Dh=Lh.range,Uh=6e4,qh=6048e5,Oh=Rh(function(t){t.setTime(1e3*Math.floor(t/1e3))},function(t,n){t.setTime(+t+1e3*n)},function(t,n){return(n-t)/1e3},function(t){return t.getUTCSeconds()}),Yh=Oh.range,Bh=Rh(function(t){t.setTime(Math.floor(t/Uh)*Uh)},function(t,n){t.setTime(+t+n*Uh)},function(t,n){return(n-t)/Uh},function(t){return t.getMinutes()}),Fh=Bh.range,Ih=Rh(function(t){var n=t.getTimezoneOffset()*Uh%36e5;n<0&&(n+=36e5),t.setTime(36e5*Math.floor((+t-n)/36e5)+n)},function(t,n){t.setTime(+t+36e5*n)},function(t,n){return(n-t)/36e5},function(t){return t.getHours()}),Hh=Ih.range,jh=Rh(function(t){t.setHours(0,0,0,0)},function(t,n){t.setDate(t.getDate()+n)},function(t,n){return(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*Uh)/864e5},function(t){return t.getDate()-1}),Xh=jh.range;function Gh(t){return Rh(function(n){n.setDate(n.getDate()-(n.getDay()+7-t)%7),n.setHours(0,0,0,0)},function(t,n){t.setDate(t.getDate()+7*n)},function(t,n){return(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*Uh)/qh})}var Vh=Gh(0),$h=Gh(1),Wh=Gh(2),Zh=Gh(3),Qh=Gh(4),Jh=Gh(5),Kh=Gh(6),td=Vh.range,nd=$h.range,ed=Wh.range,rd=Zh.range,id=Qh.range,od=Jh.range,ad=Kh.range,ud=Rh(function(t){t.setDate(1),t.setHours(0,0,0,0)},function(t,n){t.setMonth(t.getMonth()+n)},function(t,n){return n.getMonth()-t.getMonth()+12*(n.getFullYear()-t.getFullYear())},function(t){return t.getMonth()}),fd=ud.range,cd=Rh(function(t){t.setMonth(0,1),t.setHours(0,0,0,0)},function(t,n){t.setFullYear(t.getFullYear()+n)},function(t,n){return n.getFullYear()-t.getFullYear()},function(t){return t.getFullYear()});cd.every=function(t){return isFinite(t=Math.floor(t))&&t>0?Rh(function(n){n.setFullYear(Math.floor(n.getFullYear()/t)*t),n.setMonth(0,1),n.setHours(0,0,0,0)},function(n,e){n.setFullYear(n.getFullYear()+e*t)}):null};var sd=cd.range,ld=Rh(function(t){t.setUTCSeconds(0,0)},function(t,n){t.setTime(+t+n*Uh)},function(t,n){return(n-t)/Uh},function(t){return t.getUTCMinutes()}),hd=ld.range,dd=Rh(function(t){t.setUTCMinutes(0,0,0)},function(t,n){t.setTime(+t+36e5*n)},function(t,n){return(n-t)/36e5},function(t){return t.getUTCHours()}),pd=dd.range,vd=Rh(function(t){t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCDate(t.getUTCDate()+n)},function(t,n){return(n-t)/864e5},function(t){return t.getUTCDate()-1}),gd=vd.range;function yd(t){return Rh(function(n){n.setUTCDate(n.getUTCDate()-(n.getUTCDay()+7-t)%7),n.setUTCHours(0,0,0,0)},function(t,n){t.setUTCDate(t.getUTCDate()+7*n)},function(t,n){return(n-t)/qh})}var _d=yd(0),bd=yd(1),md=yd(2),xd=yd(3),wd=yd(4),Md=yd(5),Ad=yd(6),Td=_d.range,Nd=bd.range,Sd=md.range,Ed=xd.range,kd=wd.range,Cd=Md.range,Pd=Ad.range,zd=Rh(function(t){t.setUTCDate(1),t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCMonth(t.getUTCMonth()+n)},function(t,n){return n.getUTCMonth()-t.getUTCMonth()+12*(n.getUTCFullYear()-t.getUTCFullYear())},function(t){return t.getUTCMonth()}),Rd=zd.range,Ld=Rh(function(t){t.setUTCMonth(0,1),t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCFullYear(t.getUTCFullYear()+n)},function(t,n){return n.getUTCFullYear()-t.getUTCFullYear()},function(t){return t.getUTCFullYear()});Ld.every=function(t){return isFinite(t=Math.floor(t))&&t>0?Rh(function(n){n.setUTCFullYear(Math.floor(n.getUTCFullYear()/t)*t),n.setUTCMonth(0,1),n.setUTCHours(0,0,0,0)},function(n,e){n.setUTCFullYear(n.getUTCFullYear()+e*t)}):null};var Dd=Ld.range;function Ud(t){if(0<=t.y&&t.y<100){var n=new Date(-1,t.m,t.d,t.H,t.M,t.S,t.L);return n.setFullYear(t.y),n}return new Date(t.y,t.m,t.d,t.H,t.M,t.S,t.L)}function qd(t){if(0<=t.y&&t.y<100){var n=new Date(Date.UTC(-1,t.m,t.d,t.H,t.M,t.S,t.L));return n.setUTCFullYear(t.y),n}return new Date(Date.UTC(t.y,t.m,t.d,t.H,t.M,t.S,t.L))}function Od(t){return{y:t,m:0,d:1,H:0,M:0,S:0,L:0}}function Yd(t){var n=t.dateTime,e=t.date,r=t.time,i=t.periods,o=t.days,a=t.shortDays,u=t.months,f=t.shortMonths,c=Vd(i),s=$d(i),l=Vd(o),h=$d(o),d=Vd(a),p=$d(a),v=Vd(u),g=$d(u),y=Vd(f),_=$d(f),b={a:function(t){return a[t.getDay()]},A:function(t){return o[t.getDay()]},b:function(t){return f[t.getMonth()]},B:function(t){return u[t.getMonth()]},c:null,d:pp,e:pp,f:bp,H:vp,I:gp,j:yp,L:_p,m:mp,M:xp,p:function(t){return i[+(t.getHours()>=12)]},Q:Wp,s:Zp,S:wp,u:Mp,U:Ap,V:Tp,w:Np,W:Sp,x:null,X:null,y:Ep,Y:kp,Z:Cp,"%":$p},m={a:function(t){return a[t.getUTCDay()]},A:function(t){return o[t.getUTCDay()]},b:function(t){return f[t.getUTCMonth()]},B:function(t){return u[t.getUTCMonth()]},c:null,d:Pp,e:Pp,f:Up,H:zp,I:Rp,j:Lp,L:Dp,m:qp,M:Op,p:function(t){return i[+(t.getUTCHours()>=12)]},Q:Wp,s:Zp,S:Yp,u:Bp,U:Fp,V:Ip,w:Hp,W:jp,x:null,X:null,y:Xp,Y:Gp,Z:Vp,"%":$p},x={a:function(t,n,e){var r=d.exec(n.slice(e));return r?(t.w=p[r[0].toLowerCase()],e+r[0].length):-1},A:function(t,n,e){var r=l.exec(n.slice(e));return r?(t.w=h[r[0].toLowerCase()],e+r[0].length):-1},b:function(t,n,e){var r=y.exec(n.slice(e));return r?(t.m=_[r[0].toLowerCase()],e+r[0].length):-1},B:function(t,n,e){var r=v.exec(n.slice(e));return r?(t.m=g[r[0].toLowerCase()],e+r[0].length):-1},c:function(t,e,r){return A(t,n,e,r)},d:ip,e:ip,f:sp,H:ap,I:ap,j:op,L:cp,m:rp,M:up,p:function(t,n,e){var r=c.exec(n.slice(e));return r?(t.p=s[r[0].toLowerCase()],e+r[0].length):-1},Q:hp,s:dp,S:fp,u:Zd,U:Qd,V:Jd,w:Wd,W:Kd,x:function(t,n,r){return A(t,e,n,r)},X:function(t,n,e){return A(t,r,n,e)},y:np,Y:tp,Z:ep,"%":lp};function w(t,n){return function(e){var r,i,o,a=[],u=-1,f=0,c=t.length;for(e instanceof Date||(e=new Date(+e));++u<c;)37===t.charCodeAt(u)&&(a.push(t.slice(f,u)),null!=(i=Fd[r=t.charAt(++u)])?r=t.charAt(++u):i="e"===r?" ":"0",(o=n[r])&&(r=o(e,i)),a.push(r),f=u+1);return a.push(t.slice(f,u)),a.join("")}}function M(t,n){return function(e){var r,i,o=Od(1900);if(A(o,t,e+="",0)!=e.length)return null;if("Q"in o)return new Date(o.Q);if("p"in o&&(o.H=o.H%12+12*o.p),"V"in o){if(o.V<1||o.V>53)return null;"w"in o||(o.w=1),"Z"in o?(i=(r=qd(Od(o.y))).getUTCDay(),r=i>4||0===i?bd.ceil(r):bd(r),r=vd.offset(r,7*(o.V-1)),o.y=r.getUTCFullYear(),o.m=r.getUTCMonth(),o.d=r.getUTCDate()+(o.w+6)%7):(i=(r=n(Od(o.y))).getDay(),r=i>4||0===i?$h.ceil(r):$h(r),r=jh.offset(r,7*(o.V-1)),o.y=r.getFullYear(),o.m=r.getMonth(),o.d=r.getDate()+(o.w+6)%7)}else("W"in o||"U"in o)&&("w"in o||(o.w="u"in o?o.u%7:"W"in o?1:0),i="Z"in o?qd(Od(o.y)).getUTCDay():n(Od(o.y)).getDay(),o.m=0,o.d="W"in o?(o.w+6)%7+7*o.W-(i+5)%7:o.w+7*o.U-(i+6)%7);return"Z"in o?(o.H+=o.Z/100|0,o.M+=o.Z%100,qd(o)):n(o)}}function A(t,n,e,r){for(var i,o,a=0,u=n.length,f=e.length;a<u;){if(r>=f)return-1;if(37===(i=n.charCodeAt(a++))){if(i=n.charAt(a++),!(o=x[i in Fd?n.charAt(a++):i])||(r=o(t,e,r))<0)return-1}else if(i!=e.charCodeAt(r++))return-1}return r}return b.x=w(e,b),b.X=w(r,b),b.c=w(n,b),m.x=w(e,m),m.X=w(r,m),m.c=w(n,m),{format:function(t){var n=w(t+="",b);return n.toString=function(){return t},n},parse:function(t){var n=M(t+="",Ud);return n.toString=function(){return t},n},utcFormat:function(t){var n=w(t+="",m);return n.toString=function(){return t},n},utcParse:function(t){var n=M(t,qd);return n.toString=function(){return t},n}}}var Bd,Fd={"-":"",_:" ",0:"0"},Id=/^\s*\d+/,Hd=/^%/,jd=/[\\^$*+?|[\]().{}]/g;function Xd(t,n,e){var r=t<0?"-":"",i=(r?-t:t)+"",o=i.length;return r+(o<e?new Array(e-o+1).join(n)+i:i)}function Gd(t){return t.replace(jd,"\\$&")}function Vd(t){return new RegExp("^(?:"+t.map(Gd).join("|")+")","i")}function $d(t){for(var n={},e=-1,r=t.length;++e<r;)n[t[e].toLowerCase()]=e;return n}function Wd(t,n,e){var r=Id.exec(n.slice(e,e+1));return r?(t.w=+r[0],e+r[0].length):-1}function Zd(t,n,e){var r=Id.exec(n.slice(e,e+1));return r?(t.u=+r[0],e+r[0].length):-1}function Qd(t,n,e){var r=Id.exec(n.slice(e,e+2));return r?(t.U=+r[0],e+r[0].length):-1}function Jd(t,n,e){var r=Id.exec(n.slice(e,e+2));return r?(t.V=+r[0],e+r[0].length):-1}function Kd(t,n,e){var r=Id.exec(n.slice(e,e+2));return r?(t.W=+r[0],e+r[0].length):-1}function tp(t,n,e){var r=Id.exec(n.slice(e,e+4));return r?(t.y=+r[0],e+r[0].length):-1}function np(t,n,e){var r=Id.exec(n.slice(e,e+2));return r?(t.y=+r[0]+(+r[0]>68?1900:2e3),e+r[0].length):-1}function ep(t,n,e){var r=/^(Z)|([+-]\d\d)(?::?(\d\d))?/.exec(n.slice(e,e+6));return r?(t.Z=r[1]?0:-(r[2]+(r[3]||"00")),e+r[0].length):-1}function rp(t,n,e){var r=Id.exec(n.slice(e,e+2));return r?(t.m=r[0]-1,e+r[0].length):-1}function ip(t,n,e){var r=Id.exec(n.slice(e,e+2));return r?(t.d=+r[0],e+r[0].length):-1}function op(t,n,e){var r=Id.exec(n.slice(e,e+3));return r?(t.m=0,t.d=+r[0],e+r[0].length):-1}function ap(t,n,e){var r=Id.exec(n.slice(e,e+2));return r?(t.H=+r[0],e+r[0].length):-1}function up(t,n,e){var r=Id.exec(n.slice(e,e+2));return r?(t.M=+r[0],e+r[0].length):-1}function fp(t,n,e){var r=Id.exec(n.slice(e,e+2));return r?(t.S=+r[0],e+r[0].length):-1}function cp(t,n,e){var r=Id.exec(n.slice(e,e+3));return r?(t.L=+r[0],e+r[0].length):-1}function sp(t,n,e){var r=Id.exec(n.slice(e,e+6));return r?(t.L=Math.floor(r[0]/1e3),e+r[0].length):-1}function lp(t,n,e){var r=Hd.exec(n.slice(e,e+1));return r?e+r[0].length:-1}function hp(t,n,e){var r=Id.exec(n.slice(e));return r?(t.Q=+r[0],e+r[0].length):-1}function dp(t,n,e){var r=Id.exec(n.slice(e));return r?(t.Q=1e3*+r[0],e+r[0].length):-1}function pp(t,n){return Xd(t.getDate(),n,2)}function vp(t,n){return Xd(t.getHours(),n,2)}function gp(t,n){return Xd(t.getHours()%12||12,n,2)}function yp(t,n){return Xd(1+jh.count(cd(t),t),n,3)}function _p(t,n){return Xd(t.getMilliseconds(),n,3)}function bp(t,n){return _p(t,n)+"000"}function mp(t,n){return Xd(t.getMonth()+1,n,2)}function xp(t,n){return Xd(t.getMinutes(),n,2)}function wp(t,n){return Xd(t.getSeconds(),n,2)}function Mp(t){var n=t.getDay();return 0===n?7:n}function Ap(t,n){return Xd(Vh.count(cd(t),t),n,2)}function Tp(t,n){var e=t.getDay();return t=e>=4||0===e?Qh(t):Qh.ceil(t),Xd(Qh.count(cd(t),t)+(4===cd(t).getDay()),n,2)}function Np(t){return t.getDay()}function Sp(t,n){return Xd($h.count(cd(t),t),n,2)}function Ep(t,n){return Xd(t.getFullYear()%100,n,2)}function kp(t,n){return Xd(t.getFullYear()%1e4,n,4)}function Cp(t){var n=t.getTimezoneOffset();return(n>0?"-":(n*=-1,"+"))+Xd(n/60|0,"0",2)+Xd(n%60,"0",2)}function Pp(t,n){return Xd(t.getUTCDate(),n,2)}function zp(t,n){return Xd(t.getUTCHours(),n,2)}function Rp(t,n){return Xd(t.getUTCHours()%12||12,n,2)}function Lp(t,n){return Xd(1+vd.count(Ld(t),t),n,3)}function Dp(t,n){return Xd(t.getUTCMilliseconds(),n,3)}function Up(t,n){return Dp(t,n)+"000"}function qp(t,n){return Xd(t.getUTCMonth()+1,n,2)}function Op(t,n){return Xd(t.getUTCMinutes(),n,2)}function Yp(t,n){return Xd(t.getUTCSeconds(),n,2)}function Bp(t){var n=t.getUTCDay();return 0===n?7:n}function Fp(t,n){return Xd(_d.count(Ld(t),t),n,2)}function Ip(t,n){var e=t.getUTCDay();return t=e>=4||0===e?wd(t):wd.ceil(t),Xd(wd.count(Ld(t),t)+(4===Ld(t).getUTCDay()),n,2)}function Hp(t){return t.getUTCDay()}function jp(t,n){return Xd(bd.count(Ld(t),t),n,2)}function Xp(t,n){return Xd(t.getUTCFullYear()%100,n,2)}function Gp(t,n){return Xd(t.getUTCFullYear()%1e4,n,4)}function Vp(){return"+0000"}function $p(){return"%"}function Wp(t){return+t}function Zp(t){return Math.floor(+t/1e3)}function Qp(n){return Bd=Yd(n),t.timeFormat=Bd.format,t.timeParse=Bd.parse,t.utcFormat=Bd.utcFormat,t.utcParse=Bd.utcParse,Bd}Qp({dateTime:"%x, %X",date:"%-m/%-d/%Y",time:"%-I:%M:%S %p",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});var Jp=Date.prototype.toISOString?function(t){return t.toISOString()}:t.utcFormat("%Y-%m-%dT%H:%M:%S.%LZ");var Kp=+new Date("2000-01-01T00:00:00.000Z")?function(t){var n=new Date(t);return isNaN(n)?null:n}:t.utcParse("%Y-%m-%dT%H:%M:%S.%LZ"),tv=1e3,nv=60*tv,ev=60*nv,rv=24*ev,iv=7*rv,ov=30*rv,av=365*rv;function uv(t){return new Date(t)}function fv(t){return t instanceof Date?+t:+new Date(+t)}function cv(t,n,r,i,o,a,u,f,c){var s=mh(gh,ve),l=s.invert,h=s.domain,d=c(".%L"),p=c(":%S"),v=c("%I:%M"),g=c("%I %p"),y=c("%a %d"),_=c("%b %d"),b=c("%B"),m=c("%Y"),x=[[u,1,tv],[u,5,5*tv],[u,15,15*tv],[u,30,30*tv],[a,1,nv],[a,5,5*nv],[a,15,15*nv],[a,30,30*nv],[o,1,ev],[o,3,3*ev],[o,6,6*ev],[o,12,12*ev],[i,1,rv],[i,2,2*rv],[r,1,iv],[n,1,ov],[n,3,3*ov],[t,1,av]];function M(e){return(u(e)<e?d:a(e)<e?p:o(e)<e?v:i(e)<e?g:n(e)<e?r(e)<e?y:_:t(e)<e?b:m)(e)}function A(n,r,i,o){if(null==n&&(n=10),"number"==typeof n){var a=Math.abs(i-r)/n,u=e(function(t){return t[2]}).right(x,a);u===x.length?(o=w(r/av,i/av,n),n=t):u?(o=(u=x[a/x[u-1][2]<x[u][2]/a?u-1:u])[1],n=u[0]):(o=Math.max(w(r,i,n),1),n=f)}return null==o?n:n.every(o)}return s.invert=function(t){return new Date(l(t))},s.domain=function(t){return arguments.length?h(fh.call(t,fv)):h().map(uv)},s.ticks=function(t,n){var e,r=h(),i=r[0],o=r[r.length-1],a=o<i;return a&&(e=i,i=o,o=e),e=(e=A(t,i,o,n))?e.range(i,o+1):[],a?e.reverse():e},s.tickFormat=function(t,n){return null==n?M:c(n)},s.nice=function(t,n){var e=h();return(t=A(t,e[0],e[e.length-1],n))?h(wh(e,t)):s},s.copy=function(){return bh(s,cv(t,n,r,i,o,a,u,f,c))},s}function sv(t){for(var n=t.length/6|0,e=new Array(n),r=0;r<n;)e[r]="#"+t.slice(6*r,6*++r);return e}var lv=sv("1f77b4ff7f0e2ca02cd627289467bd8c564be377c27f7f7fbcbd2217becf"),hv=sv("7fc97fbeaed4fdc086ffff99386cb0f0027fbf5b17666666"),dv=sv("1b9e77d95f027570b3e7298a66a61ee6ab02a6761d666666"),pv=sv("a6cee31f78b4b2df8a33a02cfb9a99e31a1cfdbf6fff7f00cab2d66a3d9affff99b15928"),vv=sv("fbb4aeb3cde3ccebc5decbe4fed9a6ffffcce5d8bdfddaecf2f2f2"),gv=sv("b3e2cdfdcdaccbd5e8f4cae4e6f5c9fff2aef1e2cccccccc"),yv=sv("e41a1c377eb84daf4a984ea3ff7f00ffff33a65628f781bf999999"),_v=sv("66c2a5fc8d628da0cbe78ac3a6d854ffd92fe5c494b3b3b3"),bv=sv("8dd3c7ffffb3bebadafb807280b1d3fdb462b3de69fccde5d9d9d9bc80bdccebc5ffed6f");function mv(t){return le(t[t.length-1])}var xv=new Array(3).concat("d8b365f5f5f55ab4ac","a6611adfc27d80cdc1018571","a6611adfc27df5f5f580cdc1018571","8c510ad8b365f6e8c3c7eae55ab4ac01665e","8c510ad8b365f6e8c3f5f5f5c7eae55ab4ac01665e","8c510abf812ddfc27df6e8c3c7eae580cdc135978f01665e","8c510abf812ddfc27df6e8c3f5f5f5c7eae580cdc135978f01665e","5430058c510abf812ddfc27df6e8c3c7eae580cdc135978f01665e003c30","5430058c510abf812ddfc27df6e8c3f5f5f5c7eae580cdc135978f01665e003c30").map(sv),wv=mv(xv),Mv=new Array(3).concat("af8dc3f7f7f77fbf7b","7b3294c2a5cfa6dba0008837","7b3294c2a5cff7f7f7a6dba0008837","762a83af8dc3e7d4e8d9f0d37fbf7b1b7837","762a83af8dc3e7d4e8f7f7f7d9f0d37fbf7b1b7837","762a839970abc2a5cfe7d4e8d9f0d3a6dba05aae611b7837","762a839970abc2a5cfe7d4e8f7f7f7d9f0d3a6dba05aae611b7837","40004b762a839970abc2a5cfe7d4e8d9f0d3a6dba05aae611b783700441b","40004b762a839970abc2a5cfe7d4e8f7f7f7d9f0d3a6dba05aae611b783700441b").map(sv),Av=mv(Mv),Tv=new Array(3).concat("e9a3c9f7f7f7a1d76a","d01c8bf1b6dab8e1864dac26","d01c8bf1b6daf7f7f7b8e1864dac26","c51b7de9a3c9fde0efe6f5d0a1d76a4d9221","c51b7de9a3c9fde0eff7f7f7e6f5d0a1d76a4d9221","c51b7dde77aef1b6dafde0efe6f5d0b8e1867fbc414d9221","c51b7dde77aef1b6dafde0eff7f7f7e6f5d0b8e1867fbc414d9221","8e0152c51b7dde77aef1b6dafde0efe6f5d0b8e1867fbc414d9221276419","8e0152c51b7dde77aef1b6dafde0eff7f7f7e6f5d0b8e1867fbc414d9221276419").map(sv),Nv=mv(Tv),Sv=new Array(3).concat("998ec3f7f7f7f1a340","5e3c99b2abd2fdb863e66101","5e3c99b2abd2f7f7f7fdb863e66101","542788998ec3d8daebfee0b6f1a340b35806","542788998ec3d8daebf7f7f7fee0b6f1a340b35806","5427888073acb2abd2d8daebfee0b6fdb863e08214b35806","5427888073acb2abd2d8daebf7f7f7fee0b6fdb863e08214b35806","2d004b5427888073acb2abd2d8daebfee0b6fdb863e08214b358067f3b08","2d004b5427888073acb2abd2d8daebf7f7f7fee0b6fdb863e08214b358067f3b08").map(sv),Ev=mv(Sv),kv=new Array(3).concat("ef8a62f7f7f767a9cf","ca0020f4a58292c5de0571b0","ca0020f4a582f7f7f792c5de0571b0","b2182bef8a62fddbc7d1e5f067a9cf2166ac","b2182bef8a62fddbc7f7f7f7d1e5f067a9cf2166ac","b2182bd6604df4a582fddbc7d1e5f092c5de4393c32166ac","b2182bd6604df4a582fddbc7f7f7f7d1e5f092c5de4393c32166ac","67001fb2182bd6604df4a582fddbc7d1e5f092c5de4393c32166ac053061","67001fb2182bd6604df4a582fddbc7f7f7f7d1e5f092c5de4393c32166ac053061").map(sv),Cv=mv(kv),Pv=new Array(3).concat("ef8a62ffffff999999","ca0020f4a582bababa404040","ca0020f4a582ffffffbababa404040","b2182bef8a62fddbc7e0e0e09999994d4d4d","b2182bef8a62fddbc7ffffffe0e0e09999994d4d4d","b2182bd6604df4a582fddbc7e0e0e0bababa8787874d4d4d","b2182bd6604df4a582fddbc7ffffffe0e0e0bababa8787874d4d4d","67001fb2182bd6604df4a582fddbc7e0e0e0bababa8787874d4d4d1a1a1a","67001fb2182bd6604df4a582fddbc7ffffffe0e0e0bababa8787874d4d4d1a1a1a").map(sv),zv=mv(Pv),Rv=new Array(3).concat("fc8d59ffffbf91bfdb","d7191cfdae61abd9e92c7bb6","d7191cfdae61ffffbfabd9e92c7bb6","d73027fc8d59fee090e0f3f891bfdb4575b4","d73027fc8d59fee090ffffbfe0f3f891bfdb4575b4","d73027f46d43fdae61fee090e0f3f8abd9e974add14575b4","d73027f46d43fdae61fee090ffffbfe0f3f8abd9e974add14575b4","a50026d73027f46d43fdae61fee090e0f3f8abd9e974add14575b4313695","a50026d73027f46d43fdae61fee090ffffbfe0f3f8abd9e974add14575b4313695").map(sv),Lv=mv(Rv),Dv=new Array(3).concat("fc8d59ffffbf91cf60","d7191cfdae61a6d96a1a9641","d7191cfdae61ffffbfa6d96a1a9641","d73027fc8d59fee08bd9ef8b91cf601a9850","d73027fc8d59fee08bffffbfd9ef8b91cf601a9850","d73027f46d43fdae61fee08bd9ef8ba6d96a66bd631a9850","d73027f46d43fdae61fee08bffffbfd9ef8ba6d96a66bd631a9850","a50026d73027f46d43fdae61fee08bd9ef8ba6d96a66bd631a9850006837","a50026d73027f46d43fdae61fee08bffffbfd9ef8ba6d96a66bd631a9850006837").map(sv),Uv=mv(Dv),qv=new Array(3).concat("fc8d59ffffbf99d594","d7191cfdae61abdda42b83ba","d7191cfdae61ffffbfabdda42b83ba","d53e4ffc8d59fee08be6f59899d5943288bd","d53e4ffc8d59fee08bffffbfe6f59899d5943288bd","d53e4ff46d43fdae61fee08be6f598abdda466c2a53288bd","d53e4ff46d43fdae61fee08bffffbfe6f598abdda466c2a53288bd","9e0142d53e4ff46d43fdae61fee08be6f598abdda466c2a53288bd5e4fa2","9e0142d53e4ff46d43fdae61fee08bffffbfe6f598abdda466c2a53288bd5e4fa2").map(sv),Ov=mv(qv),Yv=new Array(3).concat("e5f5f999d8c92ca25f","edf8fbb2e2e266c2a4238b45","edf8fbb2e2e266c2a42ca25f006d2c","edf8fbccece699d8c966c2a42ca25f006d2c","edf8fbccece699d8c966c2a441ae76238b45005824","f7fcfde5f5f9ccece699d8c966c2a441ae76238b45005824","f7fcfde5f5f9ccece699d8c966c2a441ae76238b45006d2c00441b").map(sv),Bv=mv(Yv),Fv=new Array(3).concat("e0ecf49ebcda8856a7","edf8fbb3cde38c96c688419d","edf8fbb3cde38c96c68856a7810f7c","edf8fbbfd3e69ebcda8c96c68856a7810f7c","edf8fbbfd3e69ebcda8c96c68c6bb188419d6e016b","f7fcfde0ecf4bfd3e69ebcda8c96c68c6bb188419d6e016b","f7fcfde0ecf4bfd3e69ebcda8c96c68c6bb188419d810f7c4d004b").map(sv),Iv=mv(Fv),Hv=new Array(3).concat("e0f3dba8ddb543a2ca","f0f9e8bae4bc7bccc42b8cbe","f0f9e8bae4bc7bccc443a2ca0868ac","f0f9e8ccebc5a8ddb57bccc443a2ca0868ac","f0f9e8ccebc5a8ddb57bccc44eb3d32b8cbe08589e","f7fcf0e0f3dbccebc5a8ddb57bccc44eb3d32b8cbe08589e","f7fcf0e0f3dbccebc5a8ddb57bccc44eb3d32b8cbe0868ac084081").map(sv),jv=mv(Hv),Xv=new Array(3).concat("fee8c8fdbb84e34a33","fef0d9fdcc8afc8d59d7301f","fef0d9fdcc8afc8d59e34a33b30000","fef0d9fdd49efdbb84fc8d59e34a33b30000","fef0d9fdd49efdbb84fc8d59ef6548d7301f990000","fff7ecfee8c8fdd49efdbb84fc8d59ef6548d7301f990000","fff7ecfee8c8fdd49efdbb84fc8d59ef6548d7301fb300007f0000").map(sv),Gv=mv(Xv),Vv=new Array(3).concat("ece2f0a6bddb1c9099","f6eff7bdc9e167a9cf02818a","f6eff7bdc9e167a9cf1c9099016c59","f6eff7d0d1e6a6bddb67a9cf1c9099016c59","f6eff7d0d1e6a6bddb67a9cf3690c002818a016450","fff7fbece2f0d0d1e6a6bddb67a9cf3690c002818a016450","fff7fbece2f0d0d1e6a6bddb67a9cf3690c002818a016c59014636").map(sv),$v=mv(Vv),Wv=new Array(3).concat("ece7f2a6bddb2b8cbe","f1eef6bdc9e174a9cf0570b0","f1eef6bdc9e174a9cf2b8cbe045a8d","f1eef6d0d1e6a6bddb74a9cf2b8cbe045a8d","f1eef6d0d1e6a6bddb74a9cf3690c00570b0034e7b","fff7fbece7f2d0d1e6a6bddb74a9cf3690c00570b0034e7b","fff7fbece7f2d0d1e6a6bddb74a9cf3690c00570b0045a8d023858").map(sv),Zv=mv(Wv),Qv=new Array(3).concat("e7e1efc994c7dd1c77","f1eef6d7b5d8df65b0ce1256","f1eef6d7b5d8df65b0dd1c77980043","f1eef6d4b9dac994c7df65b0dd1c77980043","f1eef6d4b9dac994c7df65b0e7298ace125691003f","f7f4f9e7e1efd4b9dac994c7df65b0e7298ace125691003f","f7f4f9e7e1efd4b9dac994c7df65b0e7298ace125698004367001f").map(sv),Jv=mv(Qv),Kv=new Array(3).concat("fde0ddfa9fb5c51b8a","feebe2fbb4b9f768a1ae017e","feebe2fbb4b9f768a1c51b8a7a0177","feebe2fcc5c0fa9fb5f768a1c51b8a7a0177","feebe2fcc5c0fa9fb5f768a1dd3497ae017e7a0177","fff7f3fde0ddfcc5c0fa9fb5f768a1dd3497ae017e7a0177","fff7f3fde0ddfcc5c0fa9fb5f768a1dd3497ae017e7a017749006a").map(sv),tg=mv(Kv),ng=new Array(3).concat("edf8b17fcdbb2c7fb8","ffffcca1dab441b6c4225ea8","ffffcca1dab441b6c42c7fb8253494","ffffccc7e9b47fcdbb41b6c42c7fb8253494","ffffccc7e9b47fcdbb41b6c41d91c0225ea80c2c84","ffffd9edf8b1c7e9b47fcdbb41b6c41d91c0225ea80c2c84","ffffd9edf8b1c7e9b47fcdbb41b6c41d91c0225ea8253494081d58").map(sv),eg=mv(ng),rg=new Array(3).concat("f7fcb9addd8e31a354","ffffccc2e69978c679238443","ffffccc2e69978c67931a354006837","ffffccd9f0a3addd8e78c67931a354006837","ffffccd9f0a3addd8e78c67941ab5d238443005a32","ffffe5f7fcb9d9f0a3addd8e78c67941ab5d238443005a32","ffffe5f7fcb9d9f0a3addd8e78c67941ab5d238443006837004529").map(sv),ig=mv(rg),og=new Array(3).concat("fff7bcfec44fd95f0e","ffffd4fed98efe9929cc4c02","ffffd4fed98efe9929d95f0e993404","ffffd4fee391fec44ffe9929d95f0e993404","ffffd4fee391fec44ffe9929ec7014cc4c028c2d04","ffffe5fff7bcfee391fec44ffe9929ec7014cc4c028c2d04","ffffe5fff7bcfee391fec44ffe9929ec7014cc4c02993404662506").map(sv),ag=mv(og),ug=new Array(3).concat("ffeda0feb24cf03b20","ffffb2fecc5cfd8d3ce31a1c","ffffb2fecc5cfd8d3cf03b20bd0026","ffffb2fed976feb24cfd8d3cf03b20bd0026","ffffb2fed976feb24cfd8d3cfc4e2ae31a1cb10026","ffffccffeda0fed976feb24cfd8d3cfc4e2ae31a1cb10026","ffffccffeda0fed976feb24cfd8d3cfc4e2ae31a1cbd0026800026").map(sv),fg=mv(ug),cg=new Array(3).concat("deebf79ecae13182bd","eff3ffbdd7e76baed62171b5","eff3ffbdd7e76baed63182bd08519c","eff3ffc6dbef9ecae16baed63182bd08519c","eff3ffc6dbef9ecae16baed64292c62171b5084594","f7fbffdeebf7c6dbef9ecae16baed64292c62171b5084594","f7fbffdeebf7c6dbef9ecae16baed64292c62171b508519c08306b").map(sv),sg=mv(cg),lg=new Array(3).concat("e5f5e0a1d99b31a354","edf8e9bae4b374c476238b45","edf8e9bae4b374c47631a354006d2c","edf8e9c7e9c0a1d99b74c47631a354006d2c","edf8e9c7e9c0a1d99b74c47641ab5d238b45005a32","f7fcf5e5f5e0c7e9c0a1d99b74c47641ab5d238b45005a32","f7fcf5e5f5e0c7e9c0a1d99b74c47641ab5d238b45006d2c00441b").map(sv),hg=mv(lg),dg=new Array(3).concat("f0f0f0bdbdbd636363","f7f7f7cccccc969696525252","f7f7f7cccccc969696636363252525","f7f7f7d9d9d9bdbdbd969696636363252525","f7f7f7d9d9d9bdbdbd969696737373525252252525","fffffff0f0f0d9d9d9bdbdbd969696737373525252252525","fffffff0f0f0d9d9d9bdbdbd969696737373525252252525000000").map(sv),pg=mv(dg),vg=new Array(3).concat("efedf5bcbddc756bb1","f2f0f7cbc9e29e9ac86a51a3","f2f0f7cbc9e29e9ac8756bb154278f","f2f0f7dadaebbcbddc9e9ac8756bb154278f","f2f0f7dadaebbcbddc9e9ac8807dba6a51a34a1486","fcfbfdefedf5dadaebbcbddc9e9ac8807dba6a51a34a1486","fcfbfdefedf5dadaebbcbddc9e9ac8807dba6a51a354278f3f007d").map(sv),gg=mv(vg),yg=new Array(3).concat("fee0d2fc9272de2d26","fee5d9fcae91fb6a4acb181d","fee5d9fcae91fb6a4ade2d26a50f15","fee5d9fcbba1fc9272fb6a4ade2d26a50f15","fee5d9fcbba1fc9272fb6a4aef3b2ccb181d99000d","fff5f0fee0d2fcbba1fc9272fb6a4aef3b2ccb181d99000d","fff5f0fee0d2fcbba1fc9272fb6a4aef3b2ccb181da50f1567000d").map(sv),_g=mv(yg),bg=new Array(3).concat("fee6cefdae6be6550d","feeddefdbe85fd8d3cd94701","feeddefdbe85fd8d3ce6550da63603","feeddefdd0a2fdae6bfd8d3ce6550da63603","feeddefdd0a2fdae6bfd8d3cf16913d948018c2d04","fff5ebfee6cefdd0a2fdae6bfd8d3cf16913d948018c2d04","fff5ebfee6cefdd0a2fdae6bfd8d3cf16913d94801a636037f2704").map(sv),mg=mv(bg),xg=Ge(Kn(300,.5,0),Kn(-240,.5,1)),wg=Ge(Kn(-100,.75,.35),Kn(80,1.5,.8)),Mg=Ge(Kn(260,.75,.35),Kn(80,1.5,.8)),Ag=Kn();var Tg=bn(),Ng=Math.PI/3,Sg=2*Math.PI/3;function Eg(t){var n=t.length;return function(e){return t[Math.max(0,Math.min(n-1,Math.floor(e*n)))]}}var kg=Eg(sv("44015444025645045745055946075a46085c460a5d460b5e470d60470e6147106347116447136548146748166848176948186a481a6c481b6d481c6e481d6f481f70482071482173482374482475482576482677482878482979472a7a472c7a472d7b472e7c472f7d46307e46327e46337f463480453581453781453882443983443a83443b84433d84433e85423f854240864241864142874144874045884046883f47883f48893e49893e4a893e4c8a3d4d8a3d4e8a3c4f8a3c508b3b518b3b528b3a538b3a548c39558c39568c38588c38598c375a8c375b8d365c8d365d8d355e8d355f8d34608d34618d33628d33638d32648e32658e31668e31678e31688e30698e306a8e2f6b8e2f6c8e2e6d8e2e6e8e2e6f8e2d708e2d718e2c718e2c728e2c738e2b748e2b758e2a768e2a778e2a788e29798e297a8e297b8e287c8e287d8e277e8e277f8e27808e26818e26828e26828e25838e25848e25858e24868e24878e23888e23898e238a8d228b8d228c8d228d8d218e8d218f8d21908d21918c20928c20928c20938c1f948c1f958b1f968b1f978b1f988b1f998a1f9a8a1e9b8a1e9c891e9d891f9e891f9f881fa0881fa1881fa1871fa28720a38620a48621a58521a68522a78522a88423a98324aa8325ab8225ac8226ad8127ad8128ae8029af7f2ab07f2cb17e2db27d2eb37c2fb47c31b57b32b67a34b67935b77937b87838b9773aba763bbb753dbc743fbc7340bd7242be7144bf7046c06f48c16e4ac16d4cc26c4ec36b50c46a52c56954c56856c66758c7655ac8645cc8635ec96260ca6063cb5f65cb5e67cc5c69cd5b6ccd5a6ece5870cf5773d05675d05477d1537ad1517cd2507fd34e81d34d84d44b86d54989d5488bd6468ed64590d74393d74195d84098d83e9bd93c9dd93ba0da39a2da37a5db36a8db34aadc32addc30b0dd2fb2dd2db5de2bb8de29bade28bddf26c0df25c2df23c5e021c8e020cae11fcde11dd0e11cd2e21bd5e21ad8e219dae319dde318dfe318e2e418e5e419e7e419eae51aece51befe51cf1e51df4e61ef6e620f8e621fbe723fde725")),Cg=Eg(sv("00000401000501010601010802010902020b02020d03030f03031204041405041606051806051a07061c08071e0907200a08220b09240c09260d0a290e0b2b100b2d110c2f120d31130d34140e36150e38160f3b180f3d19103f1a10421c10441d11471e114920114b21114e22115024125325125527125829115a2a115c2c115f2d11612f116331116533106734106936106b38106c390f6e3b0f703d0f713f0f72400f74420f75440f764510774710784910784a10794c117a4e117b4f127b51127c52137c54137d56147d57157e59157e5a167e5c167f5d177f5f187f601880621980641a80651a80671b80681c816a1c816b1d816d1d816e1e81701f81721f817320817521817621817822817922827b23827c23827e24828025828125818326818426818627818827818928818b29818c29818e2a81902a81912b81932b80942c80962c80982d80992d809b2e7f9c2e7f9e2f7fa02f7fa1307ea3307ea5317ea6317da8327daa337dab337cad347cae347bb0357bb2357bb3367ab5367ab73779b83779ba3878bc3978bd3977bf3a77c03a76c23b75c43c75c53c74c73d73c83e73ca3e72cc3f71cd4071cf4070d0416fd2426fd3436ed5446dd6456cd8456cd9466bdb476adc4869de4968df4a68e04c67e24d66e34e65e44f64e55064e75263e85362e95462ea5661eb5760ec5860ed5a5fee5b5eef5d5ef05f5ef1605df2625df2645cf3655cf4675cf4695cf56b5cf66c5cf66e5cf7705cf7725cf8745cf8765cf9785df9795df97b5dfa7d5efa7f5efa815ffb835ffb8560fb8761fc8961fc8a62fc8c63fc8e64fc9065fd9266fd9467fd9668fd9869fd9a6afd9b6bfe9d6cfe9f6dfea16efea36ffea571fea772fea973feaa74feac76feae77feb078feb27afeb47bfeb67cfeb77efeb97ffebb81febd82febf84fec185fec287fec488fec68afec88cfeca8dfecc8ffecd90fecf92fed194fed395fed597fed799fed89afdda9cfddc9efddea0fde0a1fde2a3fde3a5fde5a7fde7a9fde9aafdebacfcecaefceeb0fcf0b2fcf2b4fcf4b6fcf6b8fcf7b9fcf9bbfcfbbdfcfdbf")),Pg=Eg(sv("00000401000501010601010802010a02020c02020e03021004031204031405041706041907051b08051d09061f0a07220b07240c08260d08290e092b10092d110a30120a32140b34150b37160b39180c3c190c3e1b0c411c0c431e0c451f0c48210c4a230c4c240c4f260c51280b53290b552b0b572d0b592f0a5b310a5c320a5e340a5f3609613809623909633b09643d09653e0966400a67420a68440a68450a69470b6a490b6a4a0c6b4c0c6b4d0d6c4f0d6c510e6c520e6d540f6d550f6d57106e59106e5a116e5c126e5d126e5f136e61136e62146e64156e65156e67166e69166e6a176e6c186e6d186e6f196e71196e721a6e741a6e751b6e771c6d781c6d7a1d6d7c1d6d7d1e6d7f1e6c801f6c82206c84206b85216b87216b88226a8a226a8c23698d23698f24699025689225689326679526679727669827669a28659b29649d29649f2a63a02a63a22b62a32c61a52c60a62d60a82e5fa92e5eab2f5ead305dae305cb0315bb1325ab3325ab43359b63458b73557b93556ba3655bc3754bd3853bf3952c03a51c13a50c33b4fc43c4ec63d4dc73e4cc83f4bca404acb4149cc4248ce4347cf4446d04545d24644d34743d44842d54a41d74b3fd84c3ed94d3dda4e3cdb503bdd513ade5238df5337e05536e15635e25734e35933e45a31e55c30e65d2fe75e2ee8602de9612bea632aeb6429eb6628ec6726ed6925ee6a24ef6c23ef6e21f06f20f1711ff1731df2741cf3761bf37819f47918f57b17f57d15f67e14f68013f78212f78410f8850ff8870ef8890cf98b0bf98c0af98e09fa9008fa9207fa9407fb9606fb9706fb9906fb9b06fb9d07fc9f07fca108fca309fca50afca60cfca80dfcaa0ffcac11fcae12fcb014fcb216fcb418fbb61afbb81dfbba1ffbbc21fbbe23fac026fac228fac42afac62df9c72ff9c932f9cb35f8cd37f8cf3af7d13df7d340f6d543f6d746f5d949f5db4cf4dd4ff4df53f4e156f3e35af3e55df2e661f2e865f2ea69f1ec6df1ed71f1ef75f1f179f2f27df2f482f3f586f3f68af4f88ef5f992f6fa96f8fb9af9fc9dfafda1fcffa4")),zg=Eg(sv("0d088710078813078916078a19068c1b068d1d068e20068f2206902406912605912805922a05932c05942e05952f059631059733059735049837049938049a3a049a3c049b3e049c3f049c41049d43039e44039e46039f48039f4903a04b03a14c02a14e02a25002a25102a35302a35502a45601a45801a45901a55b01a55c01a65e01a66001a66100a76300a76400a76600a76700a86900a86a00a86c00a86e00a86f00a87100a87201a87401a87501a87701a87801a87a02a87b02a87d03a87e03a88004a88104a78305a78405a78606a68707a68808a68a09a58b0aa58d0ba58e0ca48f0da4910ea3920fa39410a29511a19613a19814a099159f9a169f9c179e9d189d9e199da01a9ca11b9ba21d9aa31e9aa51f99a62098a72197a82296aa2395ab2494ac2694ad2793ae2892b02991b12a90b22b8fb32c8eb42e8db52f8cb6308bb7318ab83289ba3388bb3488bc3587bd3786be3885bf3984c03a83c13b82c23c81c33d80c43e7fc5407ec6417dc7427cc8437bc9447aca457acb4679cc4778cc4977cd4a76ce4b75cf4c74d04d73d14e72d24f71d35171d45270d5536fd5546ed6556dd7566cd8576bd9586ada5a6ada5b69db5c68dc5d67dd5e66de5f65de6164df6263e06363e16462e26561e26660e3685fe4695ee56a5de56b5de66c5ce76e5be76f5ae87059e97158e97257ea7457eb7556eb7655ec7754ed7953ed7a52ee7b51ef7c51ef7e50f07f4ff0804ef1814df1834cf2844bf3854bf3874af48849f48948f58b47f58c46f68d45f68f44f79044f79143f79342f89441f89540f9973ff9983ef99a3efa9b3dfa9c3cfa9e3bfb9f3afba139fba238fca338fca537fca636fca835fca934fdab33fdac33fdae32fdaf31fdb130fdb22ffdb42ffdb52efeb72dfeb82cfeba2cfebb2bfebd2afebe2afec029fdc229fdc328fdc527fdc627fdc827fdca26fdcb26fccd25fcce25fcd025fcd225fbd324fbd524fbd724fad824fada24f9dc24f9dd25f8df25f8e125f7e225f7e425f6e626f6e826f5e926f5eb27f4ed27f3ee27f3f027f2f227f1f426f1f525f0f724f0f921"));function Rg(t){return function(){return t}}var Lg=Math.abs,Dg=Math.atan2,Ug=Math.cos,qg=Math.max,Og=Math.min,Yg=Math.sin,Bg=Math.sqrt,Fg=1e-12,Ig=Math.PI,Hg=Ig/2,jg=2*Ig;function Xg(t){return t>=1?Hg:t<=-1?-Hg:Math.asin(t)}function Gg(t){return t.innerRadius}function Vg(t){return t.outerRadius}function $g(t){return t.startAngle}function Wg(t){return t.endAngle}function Zg(t){return t&&t.padAngle}function Qg(t,n,e,r,i,o,a){var u=t-e,f=n-r,c=(a?o:-o)/Bg(u*u+f*f),s=c*f,l=-c*u,h=t+s,d=n+l,p=e+s,v=r+l,g=(h+p)/2,y=(d+v)/2,_=p-h,b=v-d,m=_*_+b*b,x=i-o,w=h*v-p*d,M=(b<0?-1:1)*Bg(qg(0,x*x*m-w*w)),A=(w*b-_*M)/m,T=(-w*_-b*M)/m,N=(w*b+_*M)/m,S=(-w*_+b*M)/m,E=A-g,k=T-y,C=N-g,P=S-y;return E*E+k*k>C*C+P*P&&(A=N,T=S),{cx:A,cy:T,x01:-s,y01:-l,x11:A*(i/x-1),y11:T*(i/x-1)}}function Jg(t){this._context=t}function Kg(t){return new Jg(t)}function ty(t){return t[0]}function ny(t){return t[1]}function ey(){var t=ty,n=ny,e=Rg(!0),r=null,i=Kg,o=null;function a(a){var u,f,c,s=a.length,l=!1;for(null==r&&(o=i(c=Gi())),u=0;u<=s;++u)!(u<s&&e(f=a[u],u,a))===l&&((l=!l)?o.lineStart():o.lineEnd()),l&&o.point(+t(f,u,a),+n(f,u,a));if(c)return o=null,c+""||null}return a.x=function(n){return arguments.length?(t="function"==typeof n?n:Rg(+n),a):t},a.y=function(t){return arguments.length?(n="function"==typeof t?t:Rg(+t),a):n},a.defined=function(t){return arguments.length?(e="function"==typeof t?t:Rg(!!t),a):e},a.curve=function(t){return arguments.length?(i=t,null!=r&&(o=i(r)),a):i},a.context=function(t){return arguments.length?(null==t?r=o=null:o=i(r=t),a):r},a}function ry(){var t=ty,n=null,e=Rg(0),r=ny,i=Rg(!0),o=null,a=Kg,u=null;function f(f){var c,s,l,h,d,p=f.length,v=!1,g=new Array(p),y=new Array(p);for(null==o&&(u=a(d=Gi())),c=0;c<=p;++c){if(!(c<p&&i(h=f[c],c,f))===v)if(v=!v)s=c,u.areaStart(),u.lineStart();else{for(u.lineEnd(),u.lineStart(),l=c-1;l>=s;--l)u.point(g[l],y[l]);u.lineEnd(),u.areaEnd()}v&&(g[c]=+t(h,c,f),y[c]=+e(h,c,f),u.point(n?+n(h,c,f):g[c],r?+r(h,c,f):y[c]))}if(d)return u=null,d+""||null}function c(){return ey().defined(i).curve(a).context(o)}return f.x=function(e){return arguments.length?(t="function"==typeof e?e:Rg(+e),n=null,f):t},f.x0=function(n){return arguments.length?(t="function"==typeof n?n:Rg(+n),f):t},f.x1=function(t){return arguments.length?(n=null==t?null:"function"==typeof t?t:Rg(+t),f):n},f.y=function(t){return arguments.length?(e="function"==typeof t?t:Rg(+t),r=null,f):e},f.y0=function(t){return arguments.length?(e="function"==typeof t?t:Rg(+t),f):e},f.y1=function(t){return arguments.length?(r=null==t?null:"function"==typeof t?t:Rg(+t),f):r},f.lineX0=f.lineY0=function(){return c().x(t).y(e)},f.lineY1=function(){return c().x(t).y(r)},f.lineX1=function(){return c().x(n).y(e)},f.defined=function(t){return arguments.length?(i="function"==typeof t?t:Rg(!!t),f):i},f.curve=function(t){return arguments.length?(a=t,null!=o&&(u=a(o)),f):a},f.context=function(t){return arguments.length?(null==t?o=u=null:u=a(o=t),f):o},f}function iy(t,n){return n<t?-1:n>t?1:n>=t?0:NaN}function oy(t){return t}Jg.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:this._context.lineTo(t,n)}}};var ay=fy(Kg);function uy(t){this._curve=t}function fy(t){function n(n){return new uy(t(n))}return n._curve=t,n}function cy(t){var n=t.curve;return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t.curve=function(t){return arguments.length?n(fy(t)):n()._curve},t}function sy(){return cy(ey().curve(ay))}function ly(){var t=ry().curve(ay),n=t.curve,e=t.lineX0,r=t.lineX1,i=t.lineY0,o=t.lineY1;return t.angle=t.x,delete t.x,t.startAngle=t.x0,delete t.x0,t.endAngle=t.x1,delete t.x1,t.radius=t.y,delete t.y,t.innerRadius=t.y0,delete t.y0,t.outerRadius=t.y1,delete t.y1,t.lineStartAngle=function(){return cy(e())},delete t.lineX0,t.lineEndAngle=function(){return cy(r())},delete t.lineX1,t.lineInnerRadius=function(){return cy(i())},delete t.lineY0,t.lineOuterRadius=function(){return cy(o())},delete t.lineY1,t.curve=function(t){return arguments.length?n(fy(t)):n()._curve},t}function hy(t,n){return[(n=+n)*Math.cos(t-=Math.PI/2),n*Math.sin(t)]}uy.prototype={areaStart:function(){this._curve.areaStart()},areaEnd:function(){this._curve.areaEnd()},lineStart:function(){this._curve.lineStart()},lineEnd:function(){this._curve.lineEnd()},point:function(t,n){this._curve.point(n*Math.sin(t),n*-Math.cos(t))}};var dy=Array.prototype.slice;function py(t){return t.source}function vy(t){return t.target}function gy(t){var n=py,e=vy,r=ty,i=ny,o=null;function a(){var a,u=dy.call(arguments),f=n.apply(this,u),c=e.apply(this,u);if(o||(o=a=Gi()),t(o,+r.apply(this,(u[0]=f,u)),+i.apply(this,u),+r.apply(this,(u[0]=c,u)),+i.apply(this,u)),a)return o=null,a+""||null}return a.source=function(t){return arguments.length?(n=t,a):n},a.target=function(t){return arguments.length?(e=t,a):e},a.x=function(t){return arguments.length?(r="function"==typeof t?t:Rg(+t),a):r},a.y=function(t){return arguments.length?(i="function"==typeof t?t:Rg(+t),a):i},a.context=function(t){return arguments.length?(o=null==t?null:t,a):o},a}function yy(t,n,e,r,i){t.moveTo(n,e),t.bezierCurveTo(n=(n+r)/2,e,n,i,r,i)}function _y(t,n,e,r,i){t.moveTo(n,e),t.bezierCurveTo(n,e=(e+i)/2,r,e,r,i)}function by(t,n,e,r,i){var o=hy(n,e),a=hy(n,e=(e+i)/2),u=hy(r,e),f=hy(r,i);t.moveTo(o[0],o[1]),t.bezierCurveTo(a[0],a[1],u[0],u[1],f[0],f[1])}var my={draw:function(t,n){var e=Math.sqrt(n/Ig);t.moveTo(e,0),t.arc(0,0,e,0,jg)}},xy={draw:function(t,n){var e=Math.sqrt(n/5)/2;t.moveTo(-3*e,-e),t.lineTo(-e,-e),t.lineTo(-e,-3*e),t.lineTo(e,-3*e),t.lineTo(e,-e),t.lineTo(3*e,-e),t.lineTo(3*e,e),t.lineTo(e,e),t.lineTo(e,3*e),t.lineTo(-e,3*e),t.lineTo(-e,e),t.lineTo(-3*e,e),t.closePath()}},wy=Math.sqrt(1/3),My=2*wy,Ay={draw:function(t,n){var e=Math.sqrt(n/My),r=e*wy;t.moveTo(0,-e),t.lineTo(r,0),t.lineTo(0,e),t.lineTo(-r,0),t.closePath()}},Ty=Math.sin(Ig/10)/Math.sin(7*Ig/10),Ny=Math.sin(jg/10)*Ty,Sy=-Math.cos(jg/10)*Ty,Ey={draw:function(t,n){var e=Math.sqrt(.8908130915292852*n),r=Ny*e,i=Sy*e;t.moveTo(0,-e),t.lineTo(r,i);for(var o=1;o<5;++o){var a=jg*o/5,u=Math.cos(a),f=Math.sin(a);t.lineTo(f*e,-u*e),t.lineTo(u*r-f*i,f*r+u*i)}t.closePath()}},ky={draw:function(t,n){var e=Math.sqrt(n),r=-e/2;t.rect(r,r,e,e)}},Cy=Math.sqrt(3),Py={draw:function(t,n){var e=-Math.sqrt(n/(3*Cy));t.moveTo(0,2*e),t.lineTo(-Cy*e,-e),t.lineTo(Cy*e,-e),t.closePath()}},zy=Math.sqrt(3)/2,Ry=1/Math.sqrt(12),Ly=3*(Ry/2+1),Dy={draw:function(t,n){var e=Math.sqrt(n/Ly),r=e/2,i=e*Ry,o=r,a=e*Ry+e,u=-o,f=a;t.moveTo(r,i),t.lineTo(o,a),t.lineTo(u,f),t.lineTo(-.5*r-zy*i,zy*r+-.5*i),t.lineTo(-.5*o-zy*a,zy*o+-.5*a),t.lineTo(-.5*u-zy*f,zy*u+-.5*f),t.lineTo(-.5*r+zy*i,-.5*i-zy*r),t.lineTo(-.5*o+zy*a,-.5*a-zy*o),t.lineTo(-.5*u+zy*f,-.5*f-zy*u),t.closePath()}},Uy=[my,xy,Ay,ky,Ey,Py,Dy];function qy(){}function Oy(t,n,e){t._context.bezierCurveTo((2*t._x0+t._x1)/3,(2*t._y0+t._y1)/3,(t._x0+2*t._x1)/3,(t._y0+2*t._y1)/3,(t._x0+4*t._x1+n)/6,(t._y0+4*t._y1+e)/6)}function Yy(t){this._context=t}function By(t){this._context=t}function Fy(t){this._context=t}function Iy(t,n){this._basis=new Yy(t),this._beta=n}Yy.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){switch(this._point){case 3:Oy(this,this._x1,this._y1);case 2:this._context.lineTo(this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3,this._context.lineTo((5*this._x0+this._x1)/6,(5*this._y0+this._y1)/6);default:Oy(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}},By.prototype={areaStart:qy,areaEnd:qy,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._y0=this._y1=this._y2=this._y3=this._y4=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x2,this._y2),this._context.closePath();break;case 2:this._context.moveTo((this._x2+2*this._x3)/3,(this._y2+2*this._y3)/3),this._context.lineTo((this._x3+2*this._x2)/3,(this._y3+2*this._y2)/3),this._context.closePath();break;case 3:this.point(this._x2,this._y2),this.point(this._x3,this._y3),this.point(this._x4,this._y4)}},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._x2=t,this._y2=n;break;case 1:this._point=2,this._x3=t,this._y3=n;break;case 2:this._point=3,this._x4=t,this._y4=n,this._context.moveTo((this._x0+4*this._x1+t)/6,(this._y0+4*this._y1+n)/6);break;default:Oy(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}},Fy.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3;var e=(this._x0+4*this._x1+t)/6,r=(this._y0+4*this._y1+n)/6;this._line?this._context.lineTo(e,r):this._context.moveTo(e,r);break;case 3:this._point=4;default:Oy(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}},Iy.prototype={lineStart:function(){this._x=[],this._y=[],this._basis.lineStart()},lineEnd:function(){var t=this._x,n=this._y,e=t.length-1;if(e>0)for(var r,i=t[0],o=n[0],a=t[e]-i,u=n[e]-o,f=-1;++f<=e;)r=f/e,this._basis.point(this._beta*t[f]+(1-this._beta)*(i+r*a),this._beta*n[f]+(1-this._beta)*(o+r*u));this._x=this._y=null,this._basis.lineEnd()},point:function(t,n){this._x.push(+t),this._y.push(+n)}};var Hy=function t(n){function e(t){return 1===n?new Yy(t):new Iy(t,n)}return e.beta=function(n){return t(+n)},e}(.85);function jy(t,n,e){t._context.bezierCurveTo(t._x1+t._k*(t._x2-t._x0),t._y1+t._k*(t._y2-t._y0),t._x2+t._k*(t._x1-n),t._y2+t._k*(t._y1-e),t._x2,t._y2)}function Xy(t,n){this._context=t,this._k=(1-n)/6}Xy.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:jy(this,this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2,this._x1=t,this._y1=n;break;case 2:this._point=3;default:jy(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Gy=function t(n){function e(t){return new Xy(t,n)}return e.tension=function(n){return t(+n)},e}(0);function Vy(t,n){this._context=t,this._k=(1-n)/6}Vy.prototype={areaStart:qy,areaEnd:qy,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._x3=t,this._y3=n;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=n);break;case 2:this._point=3,this._x5=t,this._y5=n;break;default:jy(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var $y=function t(n){function e(t){return new Vy(t,n)}return e.tension=function(n){return t(+n)},e}(0);function Wy(t,n){this._context=t,this._k=(1-n)/6}Wy.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:jy(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Zy=function t(n){function e(t){return new Wy(t,n)}return e.tension=function(n){return t(+n)},e}(0);function Qy(t,n,e){var r=t._x1,i=t._y1,o=t._x2,a=t._y2;if(t._l01_a>Fg){var u=2*t._l01_2a+3*t._l01_a*t._l12_a+t._l12_2a,f=3*t._l01_a*(t._l01_a+t._l12_a);r=(r*u-t._x0*t._l12_2a+t._x2*t._l01_2a)/f,i=(i*u-t._y0*t._l12_2a+t._y2*t._l01_2a)/f}if(t._l23_a>Fg){var c=2*t._l23_2a+3*t._l23_a*t._l12_a+t._l12_2a,s=3*t._l23_a*(t._l23_a+t._l12_a);o=(o*c+t._x1*t._l23_2a-n*t._l12_2a)/s,a=(a*c+t._y1*t._l23_2a-e*t._l12_2a)/s}t._context.bezierCurveTo(r,i,o,a,t._x2,t._y2)}function Jy(t,n){this._context=t,this._alpha=n}Jy.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:this.point(this._x2,this._y2)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3;default:Qy(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Ky=function t(n){function e(t){return n?new Jy(t,n):new Xy(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);function t_(t,n){this._context=t,this._alpha=n}t_.prototype={areaStart:qy,areaEnd:qy,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._x3=t,this._y3=n;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=n);break;case 2:this._point=3,this._x5=t,this._y5=n;break;default:Qy(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var n_=function t(n){function e(t){return n?new t_(t,n):new Vy(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);function e_(t,n){this._context=t,this._alpha=n}e_.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:Qy(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var r_=function t(n){function e(t){return n?new e_(t,n):new Wy(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);function i_(t){this._context=t}function o_(t){return t<0?-1:1}function a_(t,n,e){var r=t._x1-t._x0,i=n-t._x1,o=(t._y1-t._y0)/(r||i<0&&-0),a=(e-t._y1)/(i||r<0&&-0),u=(o*i+a*r)/(r+i);return(o_(o)+o_(a))*Math.min(Math.abs(o),Math.abs(a),.5*Math.abs(u))||0}function u_(t,n){var e=t._x1-t._x0;return e?(3*(t._y1-t._y0)/e-n)/2:n}function f_(t,n,e){var r=t._x0,i=t._y0,o=t._x1,a=t._y1,u=(o-r)/3;t._context.bezierCurveTo(r+u,i+u*n,o-u,a-u*e,o,a)}function c_(t){this._context=t}function s_(t){this._context=new l_(t)}function l_(t){this._context=t}function h_(t){this._context=t}function d_(t){var n,e,r=t.length-1,i=new Array(r),o=new Array(r),a=new Array(r);for(i[0]=0,o[0]=2,a[0]=t[0]+2*t[1],n=1;n<r-1;++n)i[n]=1,o[n]=4,a[n]=4*t[n]+2*t[n+1];for(i[r-1]=2,o[r-1]=7,a[r-1]=8*t[r-1]+t[r],n=1;n<r;++n)e=i[n]/o[n-1],o[n]-=e,a[n]-=e*a[n-1];for(i[r-1]=a[r-1]/o[r-1],n=r-2;n>=0;--n)i[n]=(a[n]-i[n+1])/o[n];for(o[r-1]=(t[r]+i[r-1])/2,n=0;n<r-1;++n)o[n]=2*t[n+1]-i[n+1];return[i,o]}function p_(t,n){this._context=t,this._t=n}function v_(t,n){if((i=t.length)>1)for(var e,r,i,o=1,a=t[n[0]],u=a.length;o<i;++o)for(r=a,a=t[n[o]],e=0;e<u;++e)a[e][1]+=a[e][0]=isNaN(r[e][1])?r[e][0]:r[e][1]}function g_(t){for(var n=t.length,e=new Array(n);--n>=0;)e[n]=n;return e}function y_(t,n){return t[n]}function __(t){var n=t.map(b_);return g_(t).sort(function(t,e){return n[t]-n[e]})}function b_(t){for(var n,e=0,r=-1,i=t.length;++r<i;)(n=+t[r][1])&&(e+=n);return e}function m_(t){return function(){return t}}function x_(t){return t[0]}function w_(t){return t[1]}function M_(){this._=null}function A_(t){t.U=t.C=t.L=t.R=t.P=t.N=null}function T_(t,n){var e=n,r=n.R,i=e.U;i?i.L===e?i.L=r:i.R=r:t._=r,r.U=i,e.U=r,e.R=r.L,e.R&&(e.R.U=e),r.L=e}function N_(t,n){var e=n,r=n.L,i=e.U;i?i.L===e?i.L=r:i.R=r:t._=r,r.U=i,e.U=r,e.L=r.R,e.L&&(e.L.U=e),r.R=e}function S_(t){for(;t.L;)t=t.L;return t}function E_(t,n,e,r){var i=[null,null],o=J_.push(i)-1;return i.left=t,i.right=n,e&&C_(i,t,n,e),r&&C_(i,n,t,r),Z_[t.index].halfedges.push(o),Z_[n.index].halfedges.push(o),i}function k_(t,n,e){var r=[n,e];return r.left=t,r}function C_(t,n,e,r){t[0]||t[1]?t.left===e?t[1]=r:t[0]=r:(t[0]=r,t.left=n,t.right=e)}function P_(t,n,e,r,i){var o,a=t[0],u=t[1],f=a[0],c=a[1],s=0,l=1,h=u[0]-f,d=u[1]-c;if(o=n-f,h||!(o>0)){if(o/=h,h<0){if(o<s)return;o<l&&(l=o)}else if(h>0){if(o>l)return;o>s&&(s=o)}if(o=r-f,h||!(o<0)){if(o/=h,h<0){if(o>l)return;o>s&&(s=o)}else if(h>0){if(o<s)return;o<l&&(l=o)}if(o=e-c,d||!(o>0)){if(o/=d,d<0){if(o<s)return;o<l&&(l=o)}else if(d>0){if(o>l)return;o>s&&(s=o)}if(o=i-c,d||!(o<0)){if(o/=d,d<0){if(o>l)return;o>s&&(s=o)}else if(d>0){if(o<s)return;o<l&&(l=o)}return!(s>0||l<1)||(s>0&&(t[0]=[f+s*h,c+s*d]),l<1&&(t[1]=[f+l*h,c+l*d]),!0)}}}}}function z_(t,n,e,r,i){var o=t[1];if(o)return!0;var a,u,f=t[0],c=t.left,s=t.right,l=c[0],h=c[1],d=s[0],p=s[1],v=(l+d)/2,g=(h+p)/2;if(p===h){if(v<n||v>=r)return;if(l>d){if(f){if(f[1]>=i)return}else f=[v,e];o=[v,i]}else{if(f){if(f[1]<e)return}else f=[v,i];o=[v,e]}}else if(u=g-(a=(l-d)/(p-h))*v,a<-1||a>1)if(l>d){if(f){if(f[1]>=i)return}else f=[(e-u)/a,e];o=[(i-u)/a,i]}else{if(f){if(f[1]<e)return}else f=[(i-u)/a,i];o=[(e-u)/a,e]}else if(h<p){if(f){if(f[0]>=r)return}else f=[n,a*n+u];o=[r,a*r+u]}else{if(f){if(f[0]<n)return}else f=[r,a*r+u];o=[n,a*n+u]}return t[0]=f,t[1]=o,!0}function R_(t,n){var e=t.site,r=n.left,i=n.right;return e===i&&(i=r,r=e),i?Math.atan2(i[1]-r[1],i[0]-r[0]):(e===r?(r=n[1],i=n[0]):(r=n[0],i=n[1]),Math.atan2(r[0]-i[0],i[1]-r[1]))}function L_(t,n){return n[+(n.left!==t.site)]}function D_(t,n){return n[+(n.left===t.site)]}i_.prototype={areaStart:qy,areaEnd:qy,lineStart:function(){this._point=0},lineEnd:function(){this._point&&this._context.closePath()},point:function(t,n){t=+t,n=+n,this._point?this._context.lineTo(t,n):(this._point=1,this._context.moveTo(t,n))}},c_.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=this._t0=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x1,this._y1);break;case 3:f_(this,this._t0,u_(this,this._t0))}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){var e=NaN;if(n=+n,(t=+t)!==this._x1||n!==this._y1){switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3,f_(this,u_(this,e=a_(this,t,n)),e);break;default:f_(this,this._t0,e=a_(this,t,n))}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n,this._t0=e}}},(s_.prototype=Object.create(c_.prototype)).point=function(t,n){c_.prototype.point.call(this,n,t)},l_.prototype={moveTo:function(t,n){this._context.moveTo(n,t)},closePath:function(){this._context.closePath()},lineTo:function(t,n){this._context.lineTo(n,t)},bezierCurveTo:function(t,n,e,r,i,o){this._context.bezierCurveTo(n,t,r,e,o,i)}},h_.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x=[],this._y=[]},lineEnd:function(){var t=this._x,n=this._y,e=t.length;if(e)if(this._line?this._context.lineTo(t[0],n[0]):this._context.moveTo(t[0],n[0]),2===e)this._context.lineTo(t[1],n[1]);else for(var r=d_(t),i=d_(n),o=0,a=1;a<e;++o,++a)this._context.bezierCurveTo(r[0][o],i[0][o],r[1][o],i[1][o],t[a],n[a]);(this._line||0!==this._line&&1===e)&&this._context.closePath(),this._line=1-this._line,this._x=this._y=null},point:function(t,n){this._x.push(+t),this._y.push(+n)}},p_.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x=this._y=NaN,this._point=0},lineEnd:function(){0<this._t&&this._t<1&&2===this._point&&this._context.lineTo(this._x,this._y),(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line>=0&&(this._t=1-this._t,this._line=1-this._line)},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:if(this._t<=0)this._context.lineTo(this._x,n),this._context.lineTo(t,n);else{var e=this._x*(1-this._t)+t*this._t;this._context.lineTo(e,this._y),this._context.lineTo(e,n)}}this._x=t,this._y=n}},M_.prototype={constructor:M_,insert:function(t,n){var e,r,i;if(t){if(n.P=t,n.N=t.N,t.N&&(t.N.P=n),t.N=n,t.R){for(t=t.R;t.L;)t=t.L;t.L=n}else t.R=n;e=t}else this._?(t=S_(this._),n.P=null,n.N=t,t.P=t.L=n,e=t):(n.P=n.N=null,this._=n,e=null);for(n.L=n.R=null,n.U=e,n.C=!0,t=n;e&&e.C;)e===(r=e.U).L?(i=r.R)&&i.C?(e.C=i.C=!1,r.C=!0,t=r):(t===e.R&&(T_(this,e),e=(t=e).U),e.C=!1,r.C=!0,N_(this,r)):(i=r.L)&&i.C?(e.C=i.C=!1,r.C=!0,t=r):(t===e.L&&(N_(this,e),e=(t=e).U),e.C=!1,r.C=!0,T_(this,r)),e=t.U;this._.C=!1},remove:function(t){t.N&&(t.N.P=t.P),t.P&&(t.P.N=t.N),t.N=t.P=null;var n,e,r,i=t.U,o=t.L,a=t.R;if(e=o?a?S_(a):o:a,i?i.L===t?i.L=e:i.R=e:this._=e,o&&a?(r=e.C,e.C=t.C,e.L=o,o.U=e,e!==a?(i=e.U,e.U=t.U,t=e.R,i.L=t,e.R=a,a.U=e):(e.U=i,i=e,t=e.R)):(r=t.C,t=e),t&&(t.U=i),!r)if(t&&t.C)t.C=!1;else{do{if(t===this._)break;if(t===i.L){if((n=i.R).C&&(n.C=!1,i.C=!0,T_(this,i),n=i.R),n.L&&n.L.C||n.R&&n.R.C){n.R&&n.R.C||(n.L.C=!1,n.C=!0,N_(this,n),n=i.R),n.C=i.C,i.C=n.R.C=!1,T_(this,i),t=this._;break}}else if((n=i.L).C&&(n.C=!1,i.C=!0,N_(this,i),n=i.L),n.L&&n.L.C||n.R&&n.R.C){n.L&&n.L.C||(n.R.C=!1,n.C=!0,T_(this,n),n=i.L),n.C=i.C,i.C=n.L.C=!1,N_(this,i),t=this._;break}n.C=!0,t=i,i=i.U}while(!t.C);t&&(t.C=!1)}}};var U_,q_=[];function O_(){A_(this),this.x=this.y=this.arc=this.site=this.cy=null}function Y_(t){var n=t.P,e=t.N;if(n&&e){var r=n.site,i=t.site,o=e.site;if(r!==o){var a=i[0],u=i[1],f=r[0]-a,c=r[1]-u,s=o[0]-a,l=o[1]-u,h=2*(f*l-c*s);if(!(h>=-tb)){var d=f*f+c*c,p=s*s+l*l,v=(l*d-c*p)/h,g=(f*p-s*d)/h,y=q_.pop()||new O_;y.arc=t,y.site=i,y.x=v+a,y.y=(y.cy=g+u)+Math.sqrt(v*v+g*g),t.circle=y;for(var _=null,b=Q_._;b;)if(y.y<b.y||y.y===b.y&&y.x<=b.x){if(!b.L){_=b.P;break}b=b.L}else{if(!b.R){_=b;break}b=b.R}Q_.insert(_,y),_||(U_=y)}}}}function B_(t){var n=t.circle;n&&(n.P||(U_=n.N),Q_.remove(n),q_.push(n),A_(n),t.circle=null)}var F_=[];function I_(){A_(this),this.edge=this.site=this.circle=null}function H_(t){var n=F_.pop()||new I_;return n.site=t,n}function j_(t){B_(t),W_.remove(t),F_.push(t),A_(t)}function X_(t){var n=t.circle,e=n.x,r=n.cy,i=[e,r],o=t.P,a=t.N,u=[t];j_(t);for(var f=o;f.circle&&Math.abs(e-f.circle.x)<K_&&Math.abs(r-f.circle.cy)<K_;)o=f.P,u.unshift(f),j_(f),f=o;u.unshift(f),B_(f);for(var c=a;c.circle&&Math.abs(e-c.circle.x)<K_&&Math.abs(r-c.circle.cy)<K_;)a=c.N,u.push(c),j_(c),c=a;u.push(c),B_(c);var s,l=u.length;for(s=1;s<l;++s)c=u[s],f=u[s-1],C_(c.edge,f.site,c.site,i);f=u[0],(c=u[l-1]).edge=E_(f.site,c.site,null,i),Y_(f),Y_(c)}function G_(t){for(var n,e,r,i,o=t[0],a=t[1],u=W_._;u;)if((r=V_(u,a)-o)>K_)u=u.L;else{if(!((i=o-$_(u,a))>K_)){r>-K_?(n=u.P,e=u):i>-K_?(n=u,e=u.N):n=e=u;break}if(!u.R){n=u;break}u=u.R}!function(t){Z_[t.index]={site:t,halfedges:[]}}(t);var f=H_(t);if(W_.insert(n,f),n||e){if(n===e)return B_(n),e=H_(n.site),W_.insert(f,e),f.edge=e.edge=E_(n.site,f.site),Y_(n),void Y_(e);if(e){B_(n),B_(e);var c=n.site,s=c[0],l=c[1],h=t[0]-s,d=t[1]-l,p=e.site,v=p[0]-s,g=p[1]-l,y=2*(h*g-d*v),_=h*h+d*d,b=v*v+g*g,m=[(g*_-d*b)/y+s,(h*b-v*_)/y+l];C_(e.edge,c,p,m),f.edge=E_(c,t,null,m),e.edge=E_(t,p,null,m),Y_(n),Y_(e)}else f.edge=E_(n.site,f.site)}}function V_(t,n){var e=t.site,r=e[0],i=e[1],o=i-n;if(!o)return r;var a=t.P;if(!a)return-1/0;var u=(e=a.site)[0],f=e[1],c=f-n;if(!c)return u;var s=u-r,l=1/o-1/c,h=s/c;return l?(-h+Math.sqrt(h*h-2*l*(s*s/(-2*c)-f+c/2+i-o/2)))/l+r:(r+u)/2}function $_(t,n){var e=t.N;if(e)return V_(e,n);var r=t.site;return r[1]===n?r[0]:1/0}var W_,Z_,Q_,J_,K_=1e-6,tb=1e-12;function nb(t,n){return n[1]-t[1]||n[0]-t[0]}function eb(t,n){var e,r,i,o=t.sort(nb).pop();for(J_=[],Z_=new Array(t.length),W_=new M_,Q_=new M_;;)if(i=U_,o&&(!i||o[1]<i.y||o[1]===i.y&&o[0]<i.x))o[0]===e&&o[1]===r||(G_(o),e=o[0],r=o[1]),o=t.pop();else{if(!i)break;X_(i.arc)}if(function(){for(var t,n,e,r,i=0,o=Z_.length;i<o;++i)if((t=Z_[i])&&(r=(n=t.halfedges).length)){var a=new Array(r),u=new Array(r);for(e=0;e<r;++e)a[e]=e,u[e]=R_(t,J_[n[e]]);for(a.sort(function(t,n){return u[n]-u[t]}),e=0;e<r;++e)u[e]=n[a[e]];for(e=0;e<r;++e)n[e]=u[e]}}(),n){var a=+n[0][0],u=+n[0][1],f=+n[1][0],c=+n[1][1];!function(t,n,e,r){for(var i,o=J_.length;o--;)z_(i=J_[o],t,n,e,r)&&P_(i,t,n,e,r)&&(Math.abs(i[0][0]-i[1][0])>K_||Math.abs(i[0][1]-i[1][1])>K_)||delete J_[o]}(a,u,f,c),function(t,n,e,r){var i,o,a,u,f,c,s,l,h,d,p,v,g=Z_.length,y=!0;for(i=0;i<g;++i)if(o=Z_[i]){for(a=o.site,u=(f=o.halfedges).length;u--;)J_[f[u]]||f.splice(u,1);for(u=0,c=f.length;u<c;)p=(d=D_(o,J_[f[u]]))[0],v=d[1],l=(s=L_(o,J_[f[++u%c]]))[0],h=s[1],(Math.abs(p-l)>K_||Math.abs(v-h)>K_)&&(f.splice(u,0,J_.push(k_(a,d,Math.abs(p-t)<K_&&r-v>K_?[t,Math.abs(l-t)<K_?h:r]:Math.abs(v-r)<K_&&e-p>K_?[Math.abs(h-r)<K_?l:e,r]:Math.abs(p-e)<K_&&v-n>K_?[e,Math.abs(l-e)<K_?h:n]:Math.abs(v-n)<K_&&p-t>K_?[Math.abs(h-n)<K_?l:t,n]:null))-1),++c);c&&(y=!1)}if(y){var _,b,m,x=1/0;for(i=0,y=null;i<g;++i)(o=Z_[i])&&(m=(_=(a=o.site)[0]-t)*_+(b=a[1]-n)*b)<x&&(x=m,y=o);if(y){var w=[t,n],M=[t,r],A=[e,r],T=[e,n];y.halfedges.push(J_.push(k_(a=y.site,w,M))-1,J_.push(k_(a,M,A))-1,J_.push(k_(a,A,T))-1,J_.push(k_(a,T,w))-1)}}for(i=0;i<g;++i)(o=Z_[i])&&(o.halfedges.length||delete Z_[i])}(a,u,f,c)}this.edges=J_,this.cells=Z_,W_=Q_=J_=Z_=null}function rb(t){return function(){return t}}function ib(t,n,e){this.target=t,this.type=n,this.transform=e}function ob(t,n,e){this.k=t,this.x=n,this.y=e}eb.prototype={constructor:eb,polygons:function(){var t=this.edges;return this.cells.map(function(n){var e=n.halfedges.map(function(e){return L_(n,t[e])});return e.data=n.site.data,e})},triangles:function(){var t=[],n=this.edges;return this.cells.forEach(function(e,r){if(o=(i=e.halfedges).length)for(var i,o,a,u,f,c,s=e.site,l=-1,h=n[i[o-1]],d=h.left===s?h.right:h.left;++l<o;)a=d,d=(h=n[i[l]]).left===s?h.right:h.left,a&&d&&r<a.index&&r<d.index&&(f=a,c=d,((u=s)[0]-c[0])*(f[1]-u[1])-(u[0]-f[0])*(c[1]-u[1])<0)&&t.push([s.data,a.data,d.data])}),t},links:function(){return this.edges.filter(function(t){return t.right}).map(function(t){return{source:t.left.data,target:t.right.data}})},find:function(t,n,e){for(var r,i,o=this,a=o._found||0,u=o.cells.length;!(i=o.cells[a]);)if(++a>=u)return null;var f=t-i.site[0],c=n-i.site[1],s=f*f+c*c;do{i=o.cells[r=a],a=null,i.halfedges.forEach(function(e){var r=o.edges[e],u=r.left;if(u!==i.site&&u||(u=r.right)){var f=t-u[0],c=n-u[1],l=f*f+c*c;l<s&&(s=l,a=u.index)}})}while(null!==a);return o._found=r,null==e||s<=e*e?i.site:null}},ob.prototype={constructor:ob,scale:function(t){return 1===t?this:new ob(this.k*t,this.x,this.y)},translate:function(t,n){return 0===t&0===n?this:new ob(this.k,this.x+this.k*t,this.y+this.k*n)},apply:function(t){return[t[0]*this.k+this.x,t[1]*this.k+this.y]},applyX:function(t){return t*this.k+this.x},applyY:function(t){return t*this.k+this.y},invert:function(t){return[(t[0]-this.x)/this.k,(t[1]-this.y)/this.k]},invertX:function(t){return(t-this.x)/this.k},invertY:function(t){return(t-this.y)/this.k},rescaleX:function(t){return t.copy().domain(t.range().map(this.invertX,this).map(t.invert,t))},rescaleY:function(t){return t.copy().domain(t.range().map(this.invertY,this).map(t.invert,t))},toString:function(){return"translate("+this.x+","+this.y+") scale("+this.k+")"}};var ab=new ob(1,0,0);function ub(t){return t.__zoom||ab}function fb(){t.event.stopImmediatePropagation()}function cb(){t.event.preventDefault(),t.event.stopImmediatePropagation()}function sb(){return!t.event.button}function lb(){var t,n,e=this;return e instanceof SVGElement?(t=(e=e.ownerSVGElement||e).width.baseVal.value,n=e.height.baseVal.value):(t=e.clientWidth,n=e.clientHeight),[[0,0],[t,n]]}function hb(){return this.__zoom||ab}function db(){return-t.event.deltaY*(t.event.deltaMode?120:1)/500}function pb(){return"ontouchstart"in this}function vb(t,n,e){var r=t.invertX(n[0][0])-e[0][0],i=t.invertX(n[1][0])-e[1][0],o=t.invertY(n[0][1])-e[0][1],a=t.invertY(n[1][1])-e[1][1];return t.translate(i>r?(r+i)/2:Math.min(0,r)||Math.max(0,i),a>o?(o+a)/2:Math.min(0,o)||Math.max(0,a))}ub.prototype=ob.prototype,t.version="5.7.0",t.bisect=i,t.bisectRight=i,t.bisectLeft=o,t.ascending=n,t.bisector=e,t.cross=function(t,n,e){var r,i,o,u,f=t.length,c=n.length,s=new Array(f*c);for(null==e&&(e=a),r=o=0;r<f;++r)for(u=t[r],i=0;i<c;++i,++o)s[o]=e(u,n[i]);return s},t.descending=function(t,n){return n<t?-1:n>t?1:n>=t?0:NaN},t.deviation=c,t.extent=s,t.histogram=function(){var t=v,n=s,e=M;function r(r){var o,a,u=r.length,f=new Array(u);for(o=0;o<u;++o)f[o]=t(r[o],o,r);var c=n(f),s=c[0],l=c[1],h=e(f,s,l);Array.isArray(h)||(h=w(s,l,h),h=g(Math.ceil(s/h)*h,l,h));for(var d=h.length;h[0]<=s;)h.shift(),--d;for(;h[d-1]>l;)h.pop(),--d;var p,v=new Array(d+1);for(o=0;o<=d;++o)(p=v[o]=[]).x0=o>0?h[o-1]:s,p.x1=o<d?h[o]:l;for(o=0;o<u;++o)s<=(a=f[o])&&a<=l&&v[i(h,a,0,d)].push(r[o]);return v}return r.value=function(n){return arguments.length?(t="function"==typeof n?n:p(n),r):t},r.domain=function(t){return arguments.length?(n="function"==typeof t?t:p([t[0],t[1]]),r):n},r.thresholds=function(t){return arguments.length?(e="function"==typeof t?t:Array.isArray(t)?p(h.call(t)):p(t),r):e},r},t.thresholdFreedmanDiaconis=function(t,e,r){return t=d.call(t,u).sort(n),Math.ceil((r-e)/(2*(A(t,.75)-A(t,.25))*Math.pow(t.length,-1/3)))},t.thresholdScott=function(t,n,e){return Math.ceil((e-n)/(3.5*c(t)*Math.pow(t.length,-1/3)))},t.thresholdSturges=M,t.max=T,t.mean=function(t,n){var e,r=t.length,i=r,o=-1,a=0;if(null==n)for(;++o<r;)isNaN(e=u(t[o]))?--i:a+=e;else for(;++o<r;)isNaN(e=u(n(t[o],o,t)))?--i:a+=e;if(i)return a/i},t.median=function(t,e){var r,i=t.length,o=-1,a=[];if(null==e)for(;++o<i;)isNaN(r=u(t[o]))||a.push(r);else for(;++o<i;)isNaN(r=u(e(t[o],o,t)))||a.push(r);return A(a.sort(n),.5)},t.merge=N,t.min=S,t.pairs=function(t,n){null==n&&(n=a);for(var e=0,r=t.length-1,i=t[0],o=new Array(r<0?0:r);e<r;)o[e]=n(i,i=t[++e]);return o},t.permute=function(t,n){for(var e=n.length,r=new Array(e);e--;)r[e]=t[n[e]];return r},t.quantile=A,t.range=g,t.scan=function(t,e){if(r=t.length){var r,i,o=0,a=0,u=t[a];for(null==e&&(e=n);++o<r;)(e(i=t[o],u)<0||0!==e(u,u))&&(u=i,a=o);return 0===e(u,u)?a:void 0}},t.shuffle=function(t,n,e){for(var r,i,o=(null==e?t.length:e)-(n=null==n?0:+n);o;)i=Math.random()*o--|0,r=t[o+n],t[o+n]=t[i+n],t[i+n]=r;return t},t.sum=function(t,n){var e,r=t.length,i=-1,o=0;if(null==n)for(;++i<r;)(e=+t[i])&&(o+=e);else for(;++i<r;)(e=+n(t[i],i,t))&&(o+=e);return o},t.ticks=m,t.tickIncrement=x,t.tickStep=w,t.transpose=E,t.variance=f,t.zip=function(){return E(arguments)},t.axisTop=function(t){return B(z,t)},t.axisRight=function(t){return B(R,t)},t.axisBottom=function(t){return B(L,t)},t.axisLeft=function(t){return B(D,t)},t.brush=function(){return Ri(wi)},t.brushX=function(){return Ri(mi)},t.brushY=function(){return Ri(xi)},t.brushSelection=function(t){var n=t.__brush;return n?n.dim.output(n.selection):null},t.chord=function(){var t=0,n=null,e=null,r=null;function i(i){var o,a,u,f,c,s,l=i.length,h=[],d=g(l),p=[],v=[],y=v.groups=new Array(l),_=new Array(l*l);for(o=0,c=-1;++c<l;){for(a=0,s=-1;++s<l;)a+=i[c][s];h.push(a),p.push(g(l)),o+=a}for(n&&d.sort(function(t,e){return n(h[t],h[e])}),e&&p.forEach(function(t,n){t.sort(function(t,r){return e(i[n][t],i[n][r])})}),f=(o=Yi(0,Oi-t*l)/o)?t:Oi/l,a=0,c=-1;++c<l;){for(u=a,s=-1;++s<l;){var b=d[c],m=p[b][s],x=i[b][m],w=a,M=a+=x*o;_[m*l+b]={index:b,subindex:m,startAngle:w,endAngle:M,value:x}}y[b]={index:b,startAngle:u,endAngle:a,value:h[b]},a+=f}for(c=-1;++c<l;)for(s=c-1;++s<l;){var A=_[s*l+c],T=_[c*l+s];(A.value||T.value)&&v.push(A.value<T.value?{source:T,target:A}:{source:A,target:T})}return r?v.sort(r):v}return i.padAngle=function(n){return arguments.length?(t=Yi(0,n),i):t},i.sortGroups=function(t){return arguments.length?(n=t,i):n},i.sortSubgroups=function(t){return arguments.length?(e=t,i):e},i.sortChords=function(t){return arguments.length?(null==t?r=null:(n=t,r=function(t,e){return n(t.source.value+t.target.value,e.source.value+e.target.value)})._=t,i):r&&r._;var n},i},t.ribbon=function(){var t=Vi,n=$i,e=Wi,r=Zi,i=Qi,o=null;function a(){var a,u=Bi.call(arguments),f=t.apply(this,u),c=n.apply(this,u),s=+e.apply(this,(u[0]=f,u)),l=r.apply(this,u)-qi,h=i.apply(this,u)-qi,d=s*Li(l),p=s*Di(l),v=+e.apply(this,(u[0]=c,u)),g=r.apply(this,u)-qi,y=i.apply(this,u)-qi;if(o||(o=a=Gi()),o.moveTo(d,p),o.arc(0,0,s,l,h),l===g&&h===y||(o.quadraticCurveTo(0,0,v*Li(g),v*Di(g)),o.arc(0,0,v,g,y)),o.quadraticCurveTo(0,0,d,p),o.closePath(),a)return o=null,a+""||null}return a.radius=function(t){return arguments.length?(e="function"==typeof t?t:Fi(+t),a):e},a.startAngle=function(t){return arguments.length?(r="function"==typeof t?t:Fi(+t),a):r},a.endAngle=function(t){return arguments.length?(i="function"==typeof t?t:Fi(+t),a):i},a.source=function(n){return arguments.length?(t=n,a):t},a.target=function(t){return arguments.length?(n=t,a):n},a.context=function(t){return arguments.length?(o=null==t?null:t,a):o},a},t.nest=function(){var t,n,e,r=[],i=[];function o(e,i,a,u){if(i>=r.length)return null!=t&&e.sort(t),null!=n?n(e):e;for(var f,c,s,l=-1,h=e.length,d=r[i++],p=Ki(),v=a();++l<h;)(s=p.get(f=d(c=e[l])+""))?s.push(c):p.set(f,[c]);return p.each(function(t,n){u(v,n,o(t,i,a,u))}),v}return e={object:function(t){return o(t,0,to,no)},map:function(t){return o(t,0,eo,ro)},entries:function(t){return function t(e,o){if(++o>r.length)return e;var a,u=i[o-1];return null!=n&&o>=r.length?a=e.entries():(a=[],e.each(function(n,e){a.push({key:e,values:t(n,o)})})),null!=u?a.sort(function(t,n){return u(t.key,n.key)}):a}(o(t,0,eo,ro),0)},key:function(t){return r.push(t),e},sortKeys:function(t){return i[r.length-1]=t,e},sortValues:function(n){return t=n,e},rollup:function(t){return n=t,e}}},t.set=ao,t.map=Ki,t.keys=function(t){var n=[];for(var e in t)n.push(e);return n},t.values=function(t){var n=[];for(var e in t)n.push(t[e]);return n},t.entries=function(t){var n=[];for(var e in t)n.push({key:e,value:t[e]});return n},t.color=vn,t.rgb=bn,t.hsl=Mn,t.lab=Un,t.hcl=Hn,t.lch=function(t,n,e,r){return 1===arguments.length?In(t):new jn(e,n,t,null==r?1:r)},t.gray=function(t,n){return new qn(t,0,0,null==n?1:n)},t.cubehelix=Kn,t.contours=go,t.contourDensity=function(){var t=bo,n=mo,e=xo,r=960,i=500,o=20,a=2,u=3*o,f=r+2*u>>a,c=i+2*u>>a,s=co(20);function l(r){var i=new Float32Array(f*c),l=new Float32Array(f*c);r.forEach(function(r,o,s){var l=+t(r,o,s)+u>>a,h=+n(r,o,s)+u>>a,d=+e(r,o,s);l>=0&&l<f&&h>=0&&h<c&&(i[l+h*f]+=d)}),yo({width:f,height:c,data:i},{width:f,height:c,data:l},o>>a),_o({width:f,height:c,data:l},{width:f,height:c,data:i},o>>a),yo({width:f,height:c,data:i},{width:f,height:c,data:l},o>>a),_o({width:f,height:c,data:l},{width:f,height:c,data:i},o>>a),yo({width:f,height:c,data:i},{width:f,height:c,data:l},o>>a),_o({width:f,height:c,data:l},{width:f,height:c,data:i},o>>a);var d=s(i);if(!Array.isArray(d)){var p=T(i);d=w(0,p,d),(d=g(0,Math.floor(p/d)*d,d)).shift()}return go().thresholds(d).size([f,c])(i).map(h)}function h(t){return t.value*=Math.pow(2,-2*a),t.coordinates.forEach(d),t}function d(t){t.forEach(p)}function p(t){t.forEach(v)}function v(t){t[0]=t[0]*Math.pow(2,a)-u,t[1]=t[1]*Math.pow(2,a)-u}function y(){return f=r+2*(u=3*o)>>a,c=i+2*u>>a,l}return l.x=function(n){return arguments.length?(t="function"==typeof n?n:co(+n),l):t},l.y=function(t){return arguments.length?(n="function"==typeof t?t:co(+t),l):n},l.weight=function(t){return arguments.length?(e="function"==typeof t?t:co(+t),l):e},l.size=function(t){if(!arguments.length)return[r,i];var n=Math.ceil(t[0]),e=Math.ceil(t[1]);if(!(n>=0||n>=0))throw new Error("invalid size");return r=n,i=e,y()},l.cellSize=function(t){if(!arguments.length)return 1<<a;if(!((t=+t)>=1))throw new Error("invalid cell size");return a=Math.floor(Math.log(t)/Math.LN2),y()},l.thresholds=function(t){return arguments.length?(s="function"==typeof t?t:Array.isArray(t)?co(uo.call(t)):co(t),l):s},l.bandwidth=function(t){if(!arguments.length)return Math.sqrt(o*(o+1));if(!((t=+t)>=0))throw new Error("invalid bandwidth");return o=Math.round((Math.sqrt(4*t*t+1)-1)/2),y()},l},t.dispatch=I,t.drag=function(){var n,e,r,i,o=Wt,a=Zt,u=Qt,f=Jt,c={},s=I("start","drag","end"),l=0,h=0;function d(t){t.on("mousedown.drag",p).filter(f).on("touchstart.drag",y).on("touchmove.drag",_).on("touchend.drag touchcancel.drag",b).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function p(){if(!i&&o.apply(this,arguments)){var u=m("mouse",a.apply(this,arguments),Ft,this,arguments);u&&(Dt(t.event.view).on("mousemove.drag",v,!0).on("mouseup.drag",g,!0),Xt(t.event.view),Ht(),r=!1,n=t.event.clientX,e=t.event.clientY,u("start"))}}function v(){if(jt(),!r){var i=t.event.clientX-n,o=t.event.clientY-e;r=i*i+o*o>h}c.mouse("drag")}function g(){Dt(t.event.view).on("mousemove.drag mouseup.drag",null),Gt(t.event.view,r),jt(),c.mouse("end")}function y(){if(o.apply(this,arguments)){var n,e,r=t.event.changedTouches,i=a.apply(this,arguments),u=r.length;for(n=0;n<u;++n)(e=m(r[n].identifier,i,It,this,arguments))&&(Ht(),e("start"))}}function _(){var n,e,r=t.event.changedTouches,i=r.length;for(n=0;n<i;++n)(e=c[r[n].identifier])&&(jt(),e("drag"))}function b(){var n,e,r=t.event.changedTouches,o=r.length;for(i&&clearTimeout(i),i=setTimeout(function(){i=null},500),n=0;n<o;++n)(e=c[r[n].identifier])&&(Ht(),e("end"))}function m(n,e,r,i,o){var a,f,h,p=r(e,n),v=s.copy();if(Ct(new $t(d,"beforestart",a,n,l,p[0],p[1],0,0,v),function(){return null!=(t.event.subject=a=u.apply(i,o))&&(f=a.x-p[0]||0,h=a.y-p[1]||0,!0)}))return function t(u){var s,g=p;switch(u){case"start":c[n]=t,s=l++;break;case"end":delete c[n],--l;case"drag":p=r(e,n),s=l}Ct(new $t(d,u,a,n,s,p[0]+f,p[1]+h,p[0]-g[0],p[1]-g[1],v),v.apply,v,[u,i,o])}}return d.filter=function(t){return arguments.length?(o="function"==typeof t?t:Vt(!!t),d):o},d.container=function(t){return arguments.length?(a="function"==typeof t?t:Vt(t),d):a},d.subject=function(t){return arguments.length?(u="function"==typeof t?t:Vt(t),d):u},d.touchable=function(t){return arguments.length?(f="function"==typeof t?t:Vt(!!t),d):f},d.on=function(){var t=s.on.apply(s,arguments);return t===s?d:t},d.clickDistance=function(t){return arguments.length?(h=(t=+t)*t,d):Math.sqrt(h)},d},t.dragDisable=Xt,t.dragEnable=Gt,t.dsvFormat=Eo,t.csvParse=Co,t.csvParseRows=Po,t.csvFormat=zo,t.csvFormatRows=Ro,t.tsvParse=Do,t.tsvParseRows=Uo,t.tsvFormat=qo,t.tsvFormatRows=Oo,t.easeLinear=function(t){return+t},t.easeQuad=Dr,t.easeQuadIn=function(t){return t*t},t.easeQuadOut=function(t){return t*(2-t)},t.easeQuadInOut=Dr,t.easeCubic=Ur,t.easeCubicIn=function(t){return t*t*t},t.easeCubicOut=function(t){return--t*t*t+1},t.easeCubicInOut=Ur,t.easePoly=Yr,t.easePolyIn=qr,t.easePolyOut=Or,t.easePolyInOut=Yr,t.easeSin=Ir,t.easeSinIn=function(t){return 1-Math.cos(t*Fr)},t.easeSinOut=function(t){return Math.sin(t*Fr)},t.easeSinInOut=Ir,t.easeExp=Hr,t.easeExpIn=function(t){return Math.pow(2,10*t-10)},t.easeExpOut=function(t){return 1-Math.pow(2,-10*t)},t.easeExpInOut=Hr,t.easeCircle=jr,t.easeCircleIn=function(t){return 1-Math.sqrt(1-t*t)},t.easeCircleOut=function(t){return Math.sqrt(1- --t*t)},t.easeCircleInOut=jr,t.easeBounce=ni,t.easeBounceIn=function(t){return 1-ni(1-t)},t.easeBounceOut=ni,t.easeBounceInOut=function(t){return((t*=2)<=1?1-ni(1-t):ni(t-1)+1)/2},t.easeBack=ii,t.easeBackIn=ei,t.easeBackOut=ri,t.easeBackInOut=ii,t.easeElastic=ui,t.easeElasticIn=ai,t.easeElasticOut=ui,t.easeElasticInOut=fi,t.blob=function(t,n){return fetch(t,n).then(Yo)},t.buffer=function(t,n){return fetch(t,n).then(Bo)},t.dsv=function(t,n,e,r){3===arguments.length&&"function"==typeof e&&(r=e,e=void 0);var i=Eo(t);return Io(n,e).then(function(t){return i.parse(t,r)})},t.csv=jo,t.tsv=Xo,t.image=function(t,n){return new Promise(function(e,r){var i=new Image;for(var o in n)i[o]=n[o];i.onerror=r,i.onload=function(){e(i)},i.src=t})},t.json=function(t,n){return fetch(t,n).then(Go)},t.text=Io,t.xml=$o,t.html=Wo,t.svg=Zo,t.forceCenter=function(t,n){var e;function r(){var r,i,o=e.length,a=0,u=0;for(r=0;r<o;++r)a+=(i=e[r]).x,u+=i.y;for(a=a/o-t,u=u/o-n,r=0;r<o;++r)(i=e[r]).x-=a,i.y-=u}return null==t&&(t=0),null==n&&(n=0),r.initialize=function(t){e=t},r.x=function(n){return arguments.length?(t=+n,r):t},r.y=function(t){return arguments.length?(n=+t,r):n},r},t.forceCollide=function(t){var n,e,r=1,i=1;function o(){for(var t,o,u,f,c,s,l,h=n.length,d=0;d<i;++d)for(o=ra(n,ua,fa).visitAfter(a),t=0;t<h;++t)u=n[t],s=e[u.index],l=s*s,f=u.x+u.vx,c=u.y+u.vy,o.visit(p);function p(t,n,e,i,o){var a=t.data,h=t.r,d=s+h;if(!a)return n>f+d||i<f-d||e>c+d||o<c-d;if(a.index>u.index){var p=f-a.x-a.vx,v=c-a.y-a.vy,g=p*p+v*v;g<d*d&&(0===p&&(g+=(p=Jo())*p),0===v&&(g+=(v=Jo())*v),g=(d-(g=Math.sqrt(g)))/g*r,u.vx+=(p*=g)*(d=(h*=h)/(l+h)),u.vy+=(v*=g)*d,a.vx-=p*(d=1-d),a.vy-=v*d)}}}function a(t){if(t.data)return t.r=e[t.data.index];for(var n=t.r=0;n<4;++n)t[n]&&t[n].r>t.r&&(t.r=t[n].r)}function u(){if(n){var r,i,o=n.length;for(e=new Array(o),r=0;r<o;++r)i=n[r],e[i.index]=+t(i,r,n)}}return"function"!=typeof t&&(t=Qo(null==t?1:+t)),o.initialize=function(t){n=t,u()},o.iterations=function(t){return arguments.length?(i=+t,o):i},o.strength=function(t){return arguments.length?(r=+t,o):r},o.radius=function(n){return arguments.length?(t="function"==typeof n?n:Qo(+n),u(),o):t},o},t.forceLink=function(t){var n,e,r,i,o,a=ca,u=function(t){return 1/Math.min(i[t.source.index],i[t.target.index])},f=Qo(30),c=1;function s(r){for(var i=0,a=t.length;i<c;++i)for(var u,f,s,l,h,d,p,v=0;v<a;++v)f=(u=t[v]).source,l=(s=u.target).x+s.vx-f.x-f.vx||Jo(),h=s.y+s.vy-f.y-f.vy||Jo(),l*=d=((d=Math.sqrt(l*l+h*h))-e[v])/d*r*n[v],h*=d,s.vx-=l*(p=o[v]),s.vy-=h*p,f.vx+=l*(p=1-p),f.vy+=h*p}function l(){if(r){var u,f,c=r.length,s=t.length,l=Ki(r,a);for(u=0,i=new Array(c);u<s;++u)(f=t[u]).index=u,"object"!=typeof f.source&&(f.source=sa(l,f.source)),"object"!=typeof f.target&&(f.target=sa(l,f.target)),i[f.source.index]=(i[f.source.index]||0)+1,i[f.target.index]=(i[f.target.index]||0)+1;for(u=0,o=new Array(s);u<s;++u)f=t[u],o[u]=i[f.source.index]/(i[f.source.index]+i[f.target.index]);n=new Array(s),h(),e=new Array(s),d()}}function h(){if(r)for(var e=0,i=t.length;e<i;++e)n[e]=+u(t[e],e,t)}function d(){if(r)for(var n=0,i=t.length;n<i;++n)e[n]=+f(t[n],n,t)}return null==t&&(t=[]),s.initialize=function(t){r=t,l()},s.links=function(n){return arguments.length?(t=n,l(),s):t},s.id=function(t){return arguments.length?(a=t,s):a},s.iterations=function(t){return arguments.length?(c=+t,s):c},s.strength=function(t){return arguments.length?(u="function"==typeof t?t:Qo(+t),h(),s):u},s.distance=function(t){return arguments.length?(f="function"==typeof t?t:Qo(+t),d(),s):f},s},t.forceManyBody=function(){var t,n,e,r,i=Qo(-30),o=1,a=1/0,u=.81;function f(r){var i,o=t.length,a=ra(t,la,ha).visitAfter(s);for(e=r,i=0;i<o;++i)n=t[i],a.visit(l)}function c(){if(t){var n,e,o=t.length;for(r=new Array(o),n=0;n<o;++n)e=t[n],r[e.index]=+i(e,n,t)}}function s(t){var n,e,i,o,a,u=0,f=0;if(t.length){for(i=o=a=0;a<4;++a)(n=t[a])&&(e=Math.abs(n.value))&&(u+=n.value,f+=e,i+=e*n.x,o+=e*n.y);t.x=i/f,t.y=o/f}else{(n=t).x=n.data.x,n.y=n.data.y;do{u+=r[n.data.index]}while(n=n.next)}t.value=u}function l(t,i,f,c){if(!t.value)return!0;var s=t.x-n.x,l=t.y-n.y,h=c-i,d=s*s+l*l;if(h*h/u<d)return d<a&&(0===s&&(d+=(s=Jo())*s),0===l&&(d+=(l=Jo())*l),d<o&&(d=Math.sqrt(o*d)),n.vx+=s*t.value*e/d,n.vy+=l*t.value*e/d),!0;if(!(t.length||d>=a)){(t.data!==n||t.next)&&(0===s&&(d+=(s=Jo())*s),0===l&&(d+=(l=Jo())*l),d<o&&(d=Math.sqrt(o*d)));do{t.data!==n&&(h=r[t.data.index]*e/d,n.vx+=s*h,n.vy+=l*h)}while(t=t.next)}}return f.initialize=function(n){t=n,c()},f.strength=function(t){return arguments.length?(i="function"==typeof t?t:Qo(+t),c(),f):i},f.distanceMin=function(t){return arguments.length?(o=t*t,f):Math.sqrt(o)},f.distanceMax=function(t){return arguments.length?(a=t*t,f):Math.sqrt(a)},f.theta=function(t){return arguments.length?(u=t*t,f):Math.sqrt(u)},f},t.forceRadial=function(t,n,e){var r,i,o,a=Qo(.1);function u(t){for(var a=0,u=r.length;a<u;++a){var f=r[a],c=f.x-n||1e-6,s=f.y-e||1e-6,l=Math.sqrt(c*c+s*s),h=(o[a]-l)*i[a]*t/l;f.vx+=c*h,f.vy+=s*h}}function f(){if(r){var n,e=r.length;for(i=new Array(e),o=new Array(e),n=0;n<e;++n)o[n]=+t(r[n],n,r),i[n]=isNaN(o[n])?0:+a(r[n],n,r)}}return"function"!=typeof t&&(t=Qo(+t)),null==n&&(n=0),null==e&&(e=0),u.initialize=function(t){r=t,f()},u.strength=function(t){return arguments.length?(a="function"==typeof t?t:Qo(+t),f(),u):a},u.radius=function(n){return arguments.length?(t="function"==typeof n?n:Qo(+n),f(),u):t},u.x=function(t){return arguments.length?(n=+t,u):n},u.y=function(t){return arguments.length?(e=+t,u):e},u},t.forceSimulation=function(t){var n,e=1,r=.001,i=1-Math.pow(r,1/300),o=0,a=.6,u=Ki(),f=ur(s),c=I("tick","end");function s(){l(),c.call("tick",n),e<r&&(f.stop(),c.call("end",n))}function l(){var n,r,f=t.length;for(e+=(o-e)*i,u.each(function(t){t(e)}),n=0;n<f;++n)null==(r=t[n]).fx?r.x+=r.vx*=a:(r.x=r.fx,r.vx=0),null==r.fy?r.y+=r.vy*=a:(r.y=r.fy,r.vy=0)}function h(){for(var n,e=0,r=t.length;e<r;++e){if((n=t[e]).index=e,isNaN(n.x)||isNaN(n.y)){var i=da*Math.sqrt(e),o=e*pa;n.x=i*Math.cos(o),n.y=i*Math.sin(o)}(isNaN(n.vx)||isNaN(n.vy))&&(n.vx=n.vy=0)}}function d(n){return n.initialize&&n.initialize(t),n}return null==t&&(t=[]),h(),n={tick:l,restart:function(){return f.restart(s),n},stop:function(){return f.stop(),n},nodes:function(e){return arguments.length?(t=e,h(),u.each(d),n):t},alpha:function(t){return arguments.length?(e=+t,n):e},alphaMin:function(t){return arguments.length?(r=+t,n):r},alphaDecay:function(t){return arguments.length?(i=+t,n):+i},alphaTarget:function(t){return arguments.length?(o=+t,n):o},velocityDecay:function(t){return arguments.length?(a=1-t,n):1-a},force:function(t,e){return arguments.length>1?(null==e?u.remove(t):u.set(t,d(e)),n):u.get(t)},find:function(n,e,r){var i,o,a,u,f,c=0,s=t.length;for(null==r?r=1/0:r*=r,c=0;c<s;++c)(a=(i=n-(u=t[c]).x)*i+(o=e-u.y)*o)<r&&(f=u,r=a);return f},on:function(t,e){return arguments.length>1?(c.on(t,e),n):c.on(t)}}},t.forceX=function(t){var n,e,r,i=Qo(.1);function o(t){for(var i,o=0,a=n.length;o<a;++o)(i=n[o]).vx+=(r[o]-i.x)*e[o]*t}function a(){if(n){var o,a=n.length;for(e=new Array(a),r=new Array(a),o=0;o<a;++o)e[o]=isNaN(r[o]=+t(n[o],o,n))?0:+i(n[o],o,n)}}return"function"!=typeof t&&(t=Qo(null==t?0:+t)),o.initialize=function(t){n=t,a()},o.strength=function(t){return arguments.length?(i="function"==typeof t?t:Qo(+t),a(),o):i},o.x=function(n){return arguments.length?(t="function"==typeof n?n:Qo(+n),a(),o):t},o},t.forceY=function(t){var n,e,r,i=Qo(.1);function o(t){for(var i,o=0,a=n.length;o<a;++o)(i=n[o]).vy+=(r[o]-i.y)*e[o]*t}function a(){if(n){var o,a=n.length;for(e=new Array(a),r=new Array(a),o=0;o<a;++o)e[o]=isNaN(r[o]=+t(n[o],o,n))?0:+i(n[o],o,n)}}return"function"!=typeof t&&(t=Qo(null==t?0:+t)),o.initialize=function(t){n=t,a()},o.strength=function(t){return arguments.length?(i="function"==typeof t?t:Qo(+t),a(),o):i},o.y=function(n){return arguments.length?(t="function"==typeof n?n:Qo(+n),a(),o):t},o},t.formatDefaultLocale=Sa,t.formatLocale=Na,t.formatSpecifier=ba,t.precisionFixed=Ea,t.precisionPrefix=ka,t.precisionRound=Ca,t.geoArea=function(t){return yu.reset(),su(t,_u),2*yu},t.geoBounds=function(t){var n,e,r,i,o,a,u;if(Ru=zu=-(Cu=Pu=1/0),Ou=[],su(t,rf),e=Ou.length){for(Ou.sort(df),n=1,o=[r=Ou[0]];n<e;++n)pf(r,(i=Ou[n])[0])||pf(r,i[1])?(hf(r[0],i[1])>hf(r[0],r[1])&&(r[1]=i[1]),hf(i[0],r[1])>hf(r[0],r[1])&&(r[0]=i[0])):o.push(r=i);for(a=-1/0,n=0,r=o[e=o.length-1];n<=e;r=i,++n)i=o[n],(u=hf(r[1],i[0]))>a&&(a=u,Cu=i[0],zu=r[1])}return Ou=Yu=null,Cu===1/0||Pu===1/0?[[NaN,NaN],[NaN,NaN]]:[[Cu,Pu],[zu,Ru]]},t.geoCentroid=function(t){Bu=Fu=Iu=Hu=ju=Xu=Gu=Vu=$u=Wu=Zu=0,su(t,vf);var n=$u,e=Wu,r=Zu,i=n*n+e*e+r*r;return i<Ua&&(n=Xu,e=Gu,r=Vu,Fu<Da&&(n=Iu,e=Hu,r=ju),(i=n*n+e*e+r*r)<Ua)?[NaN,NaN]:[Xa(e,n)*Fa,eu(r/Ka(i))*Fa]},t.geoCircle=function(){var t,n,e=Nf([0,0]),r=Nf(90),i=Nf(6),o={point:function(e,r){t.push(e=n(e,r)),e[0]*=Fa,e[1]*=Fa}};function a(){var a=e.apply(this,arguments),u=r.apply(this,arguments)*Ia,f=i.apply(this,arguments)*Ia;return t=[],n=kf(-a[0]*Ia,-a[1]*Ia,0).invert,Lf(o,u,f,1),a={type:"Polygon",coordinates:[t]},t=n=null,a}return a.center=function(t){return arguments.length?(e="function"==typeof t?t:Nf([+t[0],+t[1]]),a):e},a.radius=function(t){return arguments.length?(r="function"==typeof t?t:Nf(+t),a):r},a.precision=function(t){return arguments.length?(i="function"==typeof t?t:Nf(+t),a):i},a},t.geoClipAntimeridian=Gf,t.geoClipCircle=Vf,t.geoClipExtent=function(){var t,n,e,r=0,i=0,o=960,a=500;return e={stream:function(e){return t&&n===e?t:t=Zf(r,i,o,a)(n=e)},extent:function(u){return arguments.length?(r=+u[0][0],i=+u[0][1],o=+u[1][0],a=+u[1][1],t=n=null,e):[[r,i],[o,a]]}}},t.geoClipRectangle=Zf,t.geoContains=function(t,n){return(t&&cc.hasOwnProperty(t.type)?cc[t.type]:lc)(t,n)},t.geoDistance=fc,t.geoGraticule=bc,t.geoGraticule10=function(){return bc()()},t.geoInterpolate=function(t,n){var e=t[0]*Ia,r=t[1]*Ia,i=n[0]*Ia,o=n[1]*Ia,a=Ga(r),u=Qa(r),f=Ga(o),c=Qa(o),s=a*Ga(e),l=a*Qa(e),h=f*Ga(i),d=f*Qa(i),p=2*eu(Ka(ru(o-r)+a*f*ru(i-e))),v=Qa(p),g=p?function(t){var n=Qa(t*=p)/v,e=Qa(p-t)/v,r=e*s+n*h,i=e*l+n*d,o=e*u+n*c;return[Xa(i,r)*Fa,Xa(o,Ka(r*r+i*i))*Fa]}:function(){return[e*Fa,r*Fa]};return g.distance=p,g},t.geoLength=oc,t.geoPath=function(t,n){var e,r,i=4.5;function o(t){return t&&("function"==typeof i&&r.pointRadius(+i.apply(this,arguments)),su(t,e(r))),r.result()}return o.area=function(t){return su(t,e(Sc)),Sc.result()},o.measure=function(t){return su(t,e(ds)),ds.result()},o.bounds=function(t){return su(t,e(Uc)),Uc.result()},o.centroid=function(t){return su(t,e(Zc)),Zc.result()},o.projection=function(n){return arguments.length?(e=null==n?(t=null,mc):(t=n).stream,o):t},o.context=function(t){return arguments.length?(r=null==t?(n=null,new gs):new as(n=t),"function"!=typeof i&&r.pointRadius(i),o):n},o.pointRadius=function(t){return arguments.length?(i="function"==typeof t?t:(r.pointRadius(+t),+t),o):i},o.projection(t).context(n)},t.geoAlbers=Ds,t.geoAlbersUsa=function(){var t,n,e,r,i,o,a=Ds(),u=Ls().rotate([154,0]).center([-2,58.5]).parallels([55,65]),f=Ls().rotate([157,0]).center([-3,19.9]).parallels([8,18]),c={point:function(t,n){o=[t,n]}};function s(t){var n=t[0],a=t[1];return o=null,e.point(n,a),o||(r.point(n,a),o)||(i.point(n,a),o)}function l(){return t=n=null,s}return s.invert=function(t){var n=a.scale(),e=a.translate(),r=(t[0]-e[0])/n,i=(t[1]-e[1])/n;return(i>=.12&&i<.234&&r>=-.425&&r<-.214?u:i>=.166&&i<.234&&r>=-.214&&r<-.115?f:a).invert(t)},s.stream=function(e){return t&&n===e?t:(r=[a.stream(n=e),u.stream(e),f.stream(e)],i=r.length,t={point:function(t,n){for(var e=-1;++e<i;)r[e].point(t,n)},sphere:function(){for(var t=-1;++t<i;)r[t].sphere()},lineStart:function(){for(var t=-1;++t<i;)r[t].lineStart()},lineEnd:function(){for(var t=-1;++t<i;)r[t].lineEnd()},polygonStart:function(){for(var t=-1;++t<i;)r[t].polygonStart()},polygonEnd:function(){for(var t=-1;++t<i;)r[t].polygonEnd()}});var r,i},s.precision=function(t){return arguments.length?(a.precision(t),u.precision(t),f.precision(t),l()):a.precision()},s.scale=function(t){return arguments.length?(a.scale(t),u.scale(.35*t),f.scale(t),s.translate(a.translate())):a.scale()},s.translate=function(t){if(!arguments.length)return a.translate();var n=a.scale(),o=+t[0],s=+t[1];return e=a.translate(t).clipExtent([[o-.455*n,s-.238*n],[o+.455*n,s+.238*n]]).stream(c),r=u.translate([o-.307*n,s+.201*n]).clipExtent([[o-.425*n+Da,s+.12*n+Da],[o-.214*n-Da,s+.234*n-Da]]).stream(c),i=f.translate([o-.205*n,s+.212*n]).clipExtent([[o-.214*n+Da,s+.166*n+Da],[o-.115*n-Da,s+.234*n-Da]]).stream(c),l()},s.fitExtent=function(t,n){return xs(s,t,n)},s.fitSize=function(t,n){return ws(s,t,n)},s.fitWidth=function(t,n){return Ms(s,t,n)},s.fitHeight=function(t,n){return As(s,t,n)},s.scale(1070)},t.geoAzimuthalEqualArea=function(){return Cs(Os).scale(124.75).clipAngle(179.999)},t.geoAzimuthalEqualAreaRaw=Os,t.geoAzimuthalEquidistant=function(){return Cs(Ys).scale(79.4188).clipAngle(179.999)},t.geoAzimuthalEquidistantRaw=Ys,t.geoConicConformal=function(){return zs(Hs).scale(109.5).parallels([30,30])},t.geoConicConformalRaw=Hs,t.geoConicEqualArea=Ls,t.geoConicEqualAreaRaw=Rs,t.geoConicEquidistant=function(){return zs(Xs).scale(131.154).center([0,13.9389])},t.geoConicEquidistantRaw=Xs,t.geoEqualEarth=function(){return Cs(Qs).scale(177.158)},t.geoEqualEarthRaw=Qs,t.geoEquirectangular=function(){return Cs(js).scale(152.63)},t.geoEquirectangularRaw=js,t.geoGnomonic=function(){return Cs(Js).scale(144.049).clipAngle(60)},t.geoGnomonicRaw=Js,t.geoIdentity=function(){var t,n,e,r,i,o,a=1,u=0,f=0,c=1,s=1,l=mc,h=null,d=mc;function p(){return r=i=null,o}return o={stream:function(t){return r&&i===t?r:r=l(d(i=t))},postclip:function(r){return arguments.length?(d=r,h=t=n=e=null,p()):d},clipExtent:function(r){return arguments.length?(d=null==r?(h=t=n=e=null,mc):Zf(h=+r[0][0],t=+r[0][1],n=+r[1][0],e=+r[1][1]),p()):null==h?null:[[h,t],[n,e]]},scale:function(t){return arguments.length?(l=Ks((a=+t)*c,a*s,u,f),p()):a},translate:function(t){return arguments.length?(l=Ks(a*c,a*s,u=+t[0],f=+t[1]),p()):[u,f]},reflectX:function(t){return arguments.length?(l=Ks(a*(c=t?-1:1),a*s,u,f),p()):c<0},reflectY:function(t){return arguments.length?(l=Ks(a*c,a*(s=t?-1:1),u,f),p()):s<0},fitExtent:function(t,n){return xs(o,t,n)},fitSize:function(t,n){return ws(o,t,n)},fitWidth:function(t,n){return Ms(o,t,n)},fitHeight:function(t,n){return As(o,t,n)}}},t.geoProjection=Cs,t.geoProjectionMutator=Ps,t.geoMercator=function(){return Fs(Bs).scale(961/Ba)},t.geoMercatorRaw=Bs,t.geoNaturalEarth1=function(){return Cs(tl).scale(175.295)},t.geoNaturalEarth1Raw=tl,t.geoOrthographic=function(){return Cs(nl).scale(249.5).clipAngle(90+Da)},t.geoOrthographicRaw=nl,t.geoStereographic=function(){return Cs(el).scale(250).clipAngle(142)},t.geoStereographicRaw=el,t.geoTransverseMercator=function(){var t=Fs(rl),n=t.center,e=t.rotate;return t.center=function(t){return arguments.length?n([-t[1],t[0]]):[(t=n())[1],-t[0]]},t.rotate=function(t){return arguments.length?e([t[0],t[1],t.length>2?t[2]+90:90]):[(t=e())[0],t[1],t[2]-90]},e([0,0,90]).scale(159.155)},t.geoTransverseMercatorRaw=rl,t.geoRotation=Rf,t.geoStream=su,t.geoTransform=function(t){return{stream:_s(t)}},t.cluster=function(){var t=il,n=1,e=1,r=!1;function i(i){var o,a=0;i.eachAfter(function(n){var e=n.children;e?(n.x=function(t){return t.reduce(ol,0)/t.length}(e),n.y=function(t){return 1+t.reduce(al,0)}(e)):(n.x=o?a+=t(n,o):0,n.y=0,o=n)});var u=function(t){for(var n;n=t.children;)t=n[0];return t}(i),f=function(t){for(var n;n=t.children;)t=n[n.length-1];return t}(i),c=u.x-t(u,f)/2,s=f.x+t(f,u)/2;return i.eachAfter(r?function(t){t.x=(t.x-i.x)*n,t.y=(i.y-t.y)*e}:function(t){t.x=(t.x-c)/(s-c)*n,t.y=(1-(i.y?t.y/i.y:1))*e})}return i.separation=function(n){return arguments.length?(t=n,i):t},i.size=function(t){return arguments.length?(r=!1,n=+t[0],e=+t[1],i):r?null:[n,e]},i.nodeSize=function(t){return arguments.length?(r=!0,n=+t[0],e=+t[1],i):r?[n,e]:null},i},t.hierarchy=fl,t.pack=function(){var t=null,n=1,e=1,r=El;function i(i){return i.x=n/2,i.y=e/2,t?i.eachBefore(Pl(t)).eachAfter(zl(r,.5)).eachBefore(Rl(1)):i.eachBefore(Pl(Cl)).eachAfter(zl(El,1)).eachAfter(zl(r,i.r/Math.min(n,e))).eachBefore(Rl(Math.min(n,e)/(2*i.r))),i}return i.radius=function(n){return arguments.length?(t=null==(e=n)?null:Sl(e),i):t;var e},i.size=function(t){return arguments.length?(n=+t[0],e=+t[1],i):[n,e]},i.padding=function(t){return arguments.length?(r="function"==typeof t?t:kl(+t),i):r},i},t.packSiblings=function(t){return Nl(t),t},t.packEnclose=pl,t.partition=function(){var t=1,n=1,e=0,r=!1;function i(i){var o=i.height+1;return i.x0=i.y0=e,i.x1=t,i.y1=n/o,i.eachBefore(function(t,n){return function(r){r.children&&Dl(r,r.x0,t*(r.depth+1)/n,r.x1,t*(r.depth+2)/n);var i=r.x0,o=r.y0,a=r.x1-e,u=r.y1-e;a<i&&(i=a=(i+a)/2),u<o&&(o=u=(o+u)/2),r.x0=i,r.y0=o,r.x1=a,r.y1=u}}(n,o)),r&&i.eachBefore(Ll),i}return i.round=function(t){return arguments.length?(r=!!t,i):r},i.size=function(e){return arguments.length?(t=+e[0],n=+e[1],i):[t,n]},i.padding=function(t){return arguments.length?(e=+t,i):e},i},t.stratify=function(){var t=Yl,n=Bl;function e(e){var r,i,o,a,u,f,c,s=e.length,l=new Array(s),h={};for(i=0;i<s;++i)r=e[i],u=l[i]=new hl(r),null!=(f=t(r,i,e))&&(f+="")&&(h[c=Ul+(u.id=f)]=c in h?Ol:u);for(i=0;i<s;++i)if(u=l[i],null!=(f=n(e[i],i,e))&&(f+="")){if(!(a=h[Ul+f]))throw new Error("missing: "+f);if(a===Ol)throw new Error("ambiguous: "+f);a.children?a.children.push(u):a.children=[u],u.parent=a}else{if(o)throw new Error("multiple roots");o=u}if(!o)throw new Error("no root");if(o.parent=ql,o.eachBefore(function(t){t.depth=t.parent.depth+1,--s}).eachBefore(ll),o.parent=null,s>0)throw new Error("cycle");return o}return e.id=function(n){return arguments.length?(t=Sl(n),e):t},e.parentId=function(t){return arguments.length?(n=Sl(t),e):n},e},t.tree=function(){var t=Fl,n=1,e=1,r=null;function i(i){var f=function(t){for(var n,e,r,i,o,a=new Gl(t,0),u=[a];n=u.pop();)if(r=n._.children)for(n.children=new Array(o=r.length),i=o-1;i>=0;--i)u.push(e=n.children[i]=new Gl(r[i],i)),e.parent=n;return(a.parent=new Gl(null,0)).children=[a],a}(i);if(f.eachAfter(o),f.parent.m=-f.z,f.eachBefore(a),r)i.eachBefore(u);else{var c=i,s=i,l=i;i.eachBefore(function(t){t.x<c.x&&(c=t),t.x>s.x&&(s=t),t.depth>l.depth&&(l=t)});var h=c===s?1:t(c,s)/2,d=h-c.x,p=n/(s.x+h+d),v=e/(l.depth||1);i.eachBefore(function(t){t.x=(t.x+d)*p,t.y=t.depth*v})}return i}function o(n){var e=n.children,r=n.parent.children,i=n.i?r[n.i-1]:null;if(e){!function(t){for(var n,e=0,r=0,i=t.children,o=i.length;--o>=0;)(n=i[o]).z+=e,n.m+=e,e+=n.s+(r+=n.c)}(n);var o=(e[0].z+e[e.length-1].z)/2;i?(n.z=i.z+t(n._,i._),n.m=n.z-o):n.z=o}else i&&(n.z=i.z+t(n._,i._));n.parent.A=function(n,e,r){if(e){for(var i,o=n,a=n,u=e,f=o.parent.children[0],c=o.m,s=a.m,l=u.m,h=f.m;u=Hl(u),o=Il(o),u&&o;)f=Il(f),(a=Hl(a)).a=n,(i=u.z+l-o.z-c+t(u._,o._))>0&&(jl(Xl(u,n,r),n,i),c+=i,s+=i),l+=u.m,c+=o.m,h+=f.m,s+=a.m;u&&!Hl(a)&&(a.t=u,a.m+=l-s),o&&!Il(f)&&(f.t=o,f.m+=c-h,r=n)}return r}(n,i,n.parent.A||r[0])}function a(t){t._.x=t.z+t.parent.m,t.m+=t.parent.m}function u(t){t.x*=n,t.y=t.depth*e}return i.separation=function(n){return arguments.length?(t=n,i):t},i.size=function(t){return arguments.length?(r=!1,n=+t[0],e=+t[1],i):r?null:[n,e]},i.nodeSize=function(t){return arguments.length?(r=!0,n=+t[0],e=+t[1],i):r?[n,e]:null},i},t.treemap=function(){var t=Zl,n=!1,e=1,r=1,i=[0],o=El,a=El,u=El,f=El,c=El;function s(t){return t.x0=t.y0=0,t.x1=e,t.y1=r,t.eachBefore(l),i=[0],n&&t.eachBefore(Ll),t}function l(n){var e=i[n.depth],r=n.x0+e,s=n.y0+e,l=n.x1-e,h=n.y1-e;l<r&&(r=l=(r+l)/2),h<s&&(s=h=(s+h)/2),n.x0=r,n.y0=s,n.x1=l,n.y1=h,n.children&&(e=i[n.depth+1]=o(n)/2,r+=c(n)-e,s+=a(n)-e,(l-=u(n)-e)<r&&(r=l=(r+l)/2),(h-=f(n)-e)<s&&(s=h=(s+h)/2),t(n,r,s,l,h))}return s.round=function(t){return arguments.length?(n=!!t,s):n},s.size=function(t){return arguments.length?(e=+t[0],r=+t[1],s):[e,r]},s.tile=function(n){return arguments.length?(t=Sl(n),s):t},s.padding=function(t){return arguments.length?s.paddingInner(t).paddingOuter(t):s.paddingInner()},s.paddingInner=function(t){return arguments.length?(o="function"==typeof t?t:kl(+t),s):o},s.paddingOuter=function(t){return arguments.length?s.paddingTop(t).paddingRight(t).paddingBottom(t).paddingLeft(t):s.paddingTop()},s.paddingTop=function(t){return arguments.length?(a="function"==typeof t?t:kl(+t),s):a},s.paddingRight=function(t){return arguments.length?(u="function"==typeof t?t:kl(+t),s):u},s.paddingBottom=function(t){return arguments.length?(f="function"==typeof t?t:kl(+t),s):f},s.paddingLeft=function(t){return arguments.length?(c="function"==typeof t?t:kl(+t),s):c},s},t.treemapBinary=function(t,n,e,r,i){var o,a,u=t.children,f=u.length,c=new Array(f+1);for(c[0]=a=o=0;o<f;++o)c[o+1]=a+=u[o].value;!function t(n,e,r,i,o,a,f){if(n>=e-1){var s=u[n];return s.x0=i,s.y0=o,s.x1=a,void(s.y1=f)}for(var l=c[n],h=r/2+l,d=n+1,p=e-1;d<p;){var v=d+p>>>1;c[v]<h?d=v+1:p=v}h-c[d-1]<c[d]-h&&n+1<d&&--d;var g=c[d]-l,y=r-g;if(a-i>f-o){var _=(i*y+a*g)/r;t(n,d,g,i,o,_,f),t(d,e,y,_,o,a,f)}else{var b=(o*y+f*g)/r;t(n,d,g,i,o,a,b),t(d,e,y,i,b,a,f)}}(0,f,t.value,n,e,r,i)},t.treemapDice=Dl,t.treemapSlice=Vl,t.treemapSliceDice=function(t,n,e,r,i){(1&t.depth?Vl:Dl)(t,n,e,r,i)},t.treemapSquarify=Zl,t.treemapResquarify=Ql,t.interpolate=me,t.interpolateArray=de,t.interpolateBasis=ee,t.interpolateBasisClosed=re,t.interpolateDate=pe,t.interpolateDiscrete=function(t){var n=t.length;return function(e){return t[Math.max(0,Math.min(n-1,Math.floor(e*n)))]}},t.interpolateHue=function(t,n){var e=ae(+t,+n);return function(t){var n=e(t);return n-360*Math.floor(n/360)}},t.interpolateNumber=ve,t.interpolateObject=ge,t.interpolateRound=xe,t.interpolateString=be,t.interpolateTransformCss=Ce,t.interpolateTransformSvg=Pe,t.interpolateZoom=qe,t.interpolateRgb=ce,t.interpolateRgbBasis=le,t.interpolateRgbBasisClosed=he,t.interpolateHsl=Ye,t.interpolateHslLong=Be,t.interpolateLab=function(t,n){var e=fe((t=Un(t)).l,(n=Un(n)).l),r=fe(t.a,n.a),i=fe(t.b,n.b),o=fe(t.opacity,n.opacity);return function(n){return t.l=e(n),t.a=r(n),t.b=i(n),t.opacity=o(n),t+""}},t.interpolateHcl=Ie,t.interpolateHclLong=He,t.interpolateCubehelix=Xe,t.interpolateCubehelixLong=Ge,t.piecewise=function(t,n){for(var e=0,r=n.length-1,i=n[0],o=new Array(r<0?0:r);e<r;)o[e]=t(i,i=n[++e]);return function(t){var n=Math.max(0,Math.min(r-1,Math.floor(t*=r)));return o[n](t-n)}},t.quantize=function(t,n){for(var e=new Array(n),r=0;r<n;++r)e[r]=t(r/(n-1));return e},t.path=Gi,t.polygonArea=function(t){for(var n,e=-1,r=t.length,i=t[r-1],o=0;++e<r;)n=i,i=t[e],o+=n[1]*i[0]-n[0]*i[1];return o/2},t.polygonCentroid=function(t){for(var n,e,r=-1,i=t.length,o=0,a=0,u=t[i-1],f=0;++r<i;)n=u,u=t[r],f+=e=n[0]*u[1]-u[0]*n[1],o+=(n[0]+u[0])*e,a+=(n[1]+u[1])*e;return[o/(f*=3),a/f]},t.polygonHull=function(t){if((e=t.length)<3)return null;var n,e,r=new Array(e),i=new Array(e);for(n=0;n<e;++n)r[n]=[+t[n][0],+t[n][1],n];for(r.sort(Jl),n=0;n<e;++n)i[n]=[r[n][0],-r[n][1]];var o=Kl(r),a=Kl(i),u=a[0]===o[0],f=a[a.length-1]===o[o.length-1],c=[];for(n=o.length-1;n>=0;--n)c.push(t[r[o[n]][2]]);for(n=+u;n<a.length-f;++n)c.push(t[r[a[n]][2]]);return c},t.polygonContains=function(t,n){for(var e,r,i=t.length,o=t[i-1],a=n[0],u=n[1],f=o[0],c=o[1],s=!1,l=0;l<i;++l)e=(o=t[l])[0],(r=o[1])>u!=c>u&&a<(f-e)*(u-r)/(c-r)+e&&(s=!s),f=e,c=r;return s},t.polygonLength=function(t){for(var n,e,r=-1,i=t.length,o=t[i-1],a=o[0],u=o[1],f=0;++r<i;)n=a,e=u,n-=a=(o=t[r])[0],e-=u=o[1],f+=Math.sqrt(n*n+e*e);return f},t.quadtree=ra,t.randomUniform=nh,t.randomNormal=eh,t.randomLogNormal=rh,t.randomBates=oh,t.randomIrwinHall=ih,t.randomExponential=ah,t.scaleBand=hh,t.scalePoint=function(){return function t(n){var e=n.copy;return n.padding=n.paddingOuter,delete n.paddingInner,delete n.paddingOuter,n.copy=function(){return t(e())},n}(hh().paddingInner(1))},t.scaleIdentity=function t(){var n=[0,1];function e(t){return+t}return e.invert=e,e.domain=e.range=function(t){return arguments.length?(n=fh.call(t,ph),e):n.slice()},e.copy=function(){return t().domain(n)},xh(e)},t.scaleLinear=function t(){var n=mh(gh,ve);return n.copy=function(){return bh(n,t())},xh(n)},t.scaleLog=function n(){var e=mh(Mh,Ah).domain([1,10]),r=e.domain,i=10,o=Sh(10),a=Nh(10);function u(){return o=Sh(i),a=Nh(i),r()[0]<0&&(o=Eh(o),a=Eh(a)),e}return e.base=function(t){return arguments.length?(i=+t,u()):i},e.domain=function(t){return arguments.length?(r(t),u()):r()},e.ticks=function(t){var n,e=r(),u=e[0],f=e[e.length-1];(n=f<u)&&(h=u,u=f,f=h);var c,s,l,h=o(u),d=o(f),p=null==t?10:+t,v=[];if(!(i%1)&&d-h<p){if(h=Math.round(h)-1,d=Math.round(d)+1,u>0){for(;h<d;++h)for(s=1,c=a(h);s<i;++s)if(!((l=c*s)<u)){if(l>f)break;v.push(l)}}else for(;h<d;++h)for(s=i-1,c=a(h);s>=1;--s)if(!((l=c*s)<u)){if(l>f)break;v.push(l)}}else v=m(h,d,Math.min(d-h,p)).map(a);return n?v.reverse():v},e.tickFormat=function(n,r){if(null==r&&(r=10===i?".0e":","),"function"!=typeof r&&(r=t.format(r)),n===1/0)return r;null==n&&(n=10);var u=Math.max(1,i*n/e.ticks().length);return function(t){var n=t/a(Math.round(o(t)));return n*i<i-.5&&(n*=i),n<=u?r(t):""}},e.nice=function(){return r(wh(r(),{floor:function(t){return a(Math.floor(o(t)))},ceil:function(t){return a(Math.ceil(o(t)))}}))},e.copy=function(){return bh(e,n().base(i))},e},t.scaleOrdinal=lh,t.scaleImplicit=sh,t.scalePow=Ch,t.scaleSqrt=function(){return Ch().exponent(.5)},t.scaleQuantile=function t(){var e=[],r=[],o=[];function a(){var t=0,n=Math.max(1,r.length);for(o=new Array(n-1);++t<n;)o[t-1]=A(e,t/n);return u}function u(t){if(!isNaN(t=+t))return r[i(o,t)]}return u.invertExtent=function(t){var n=r.indexOf(t);return n<0?[NaN,NaN]:[n>0?o[n-1]:e[0],n<o.length?o[n]:e[e.length-1]]},u.domain=function(t){if(!arguments.length)return e.slice();e=[];for(var r,i=0,o=t.length;i<o;++i)null==(r=t[i])||isNaN(r=+r)||e.push(r);return e.sort(n),a()},u.range=function(t){return arguments.length?(r=ch.call(t),a()):r.slice()},u.quantiles=function(){return o.slice()},u.copy=function(){return t().domain(e).range(r)},u},t.scaleQuantize=function t(){var n=0,e=1,r=1,o=[.5],a=[0,1];function u(t){if(t<=t)return a[i(o,t,0,r)]}function f(){var t=-1;for(o=new Array(r);++t<r;)o[t]=((t+1)*e-(t-r)*n)/(r+1);return u}return u.domain=function(t){return arguments.length?(n=+t[0],e=+t[1],f()):[n,e]},u.range=function(t){return arguments.length?(r=(a=ch.call(t)).length-1,f()):a.slice()},u.invertExtent=function(t){var i=a.indexOf(t);return i<0?[NaN,NaN]:i<1?[n,o[0]]:i>=r?[o[r-1],e]:[o[i-1],o[i]]},u.copy=function(){return t().domain([n,e]).range(a)},xh(u)},t.scaleThreshold=function t(){var n=[.5],e=[0,1],r=1;function o(t){if(t<=t)return e[i(n,t,0,r)]}return o.domain=function(t){return arguments.length?(n=ch.call(t),r=Math.min(n.length,e.length-1),o):n.slice()},o.range=function(t){return arguments.length?(e=ch.call(t),r=Math.min(n.length,e.length-1),o):e.slice()},o.invertExtent=function(t){var r=e.indexOf(t);return[n[r-1],n[r]]},o.copy=function(){return t().domain(n).range(e)},o},t.scaleTime=function(){return cv(cd,ud,Vh,jh,Ih,Bh,Oh,Lh,t.timeFormat).domain([new Date(2e3,0,1),new Date(2e3,0,2)])},t.scaleUtc=function(){return cv(Ld,zd,_d,vd,dd,ld,Oh,Lh,t.utcFormat).domain([Date.UTC(2e3,0,1),Date.UTC(2e3,0,2)])},t.scaleSequential=function t(n){var e=0,r=1,i=1,o=!1;function a(t){var r=(t-e)*i;return n(o?Math.max(0,Math.min(1,r)):r)}return a.domain=function(t){return arguments.length?(e=+t[0],r=+t[1],i=e===r?0:1/(r-e),a):[e,r]},a.clamp=function(t){return arguments.length?(o=!!t,a):o},a.interpolator=function(t){return arguments.length?(n=t,a):n},a.copy=function(){return t(n).domain([e,r]).clamp(o)},xh(a)},t.scaleDiverging=function t(n){var e=0,r=.5,i=1,o=1,a=1,u=!1;function f(t){var e=.5+((t=+t)-r)*(t<r?o:a);return n(u?Math.max(0,Math.min(1,e)):e)}return f.domain=function(t){return arguments.length?(e=+t[0],r=+t[1],i=+t[2],o=e===r?0:.5/(r-e),a=r===i?0:.5/(i-r),f):[e,r,i]},f.clamp=function(t){return arguments.length?(u=!!t,f):u},f.interpolator=function(t){return arguments.length?(n=t,f):n},f.copy=function(){return t(n).domain([e,r,i]).clamp(u)},xh(f)},t.schemeCategory10=lv,t.schemeAccent=hv,t.schemeDark2=dv,t.schemePaired=pv,t.schemePastel1=vv,t.schemePastel2=gv,t.schemeSet1=yv,t.schemeSet2=_v,t.schemeSet3=bv,t.interpolateBrBG=wv,t.schemeBrBG=xv,t.interpolatePRGn=Av,t.schemePRGn=Mv,t.interpolatePiYG=Nv,t.schemePiYG=Tv,t.interpolatePuOr=Ev,t.schemePuOr=Sv,t.interpolateRdBu=Cv,t.schemeRdBu=kv,t.interpolateRdGy=zv,t.schemeRdGy=Pv,t.interpolateRdYlBu=Lv,t.schemeRdYlBu=Rv,t.interpolateRdYlGn=Uv,t.schemeRdYlGn=Dv,t.interpolateSpectral=Ov,t.schemeSpectral=qv,t.interpolateBuGn=Bv,t.schemeBuGn=Yv,t.interpolateBuPu=Iv,t.schemeBuPu=Fv,t.interpolateGnBu=jv,t.schemeGnBu=Hv,t.interpolateOrRd=Gv,t.schemeOrRd=Xv,t.interpolatePuBuGn=$v,t.schemePuBuGn=Vv,t.interpolatePuBu=Zv,t.schemePuBu=Wv,t.interpolatePuRd=Jv,t.schemePuRd=Qv,t.interpolateRdPu=tg,t.schemeRdPu=Kv,t.interpolateYlGnBu=eg,t.schemeYlGnBu=ng,t.interpolateYlGn=ig,t.schemeYlGn=rg,t.interpolateYlOrBr=ag,t.schemeYlOrBr=og,t.interpolateYlOrRd=fg,t.schemeYlOrRd=ug,t.interpolateBlues=sg,t.schemeBlues=cg,t.interpolateGreens=hg,t.schemeGreens=lg,t.interpolateGreys=pg,t.schemeGreys=dg,t.interpolatePurples=gg,t.schemePurples=vg,t.interpolateReds=_g,t.schemeReds=yg,t.interpolateOranges=mg,t.schemeOranges=bg,t.interpolateCubehelixDefault=xg,t.interpolateRainbow=function(t){(t<0||t>1)&&(t-=Math.floor(t));var n=Math.abs(t-.5);return Ag.h=360*t-100,Ag.s=1.5-1.5*n,Ag.l=.8-.9*n,Ag+""},t.interpolateWarm=wg,t.interpolateCool=Mg,t.interpolateSinebow=function(t){var n;return t=(.5-t)*Math.PI,Tg.r=255*(n=Math.sin(t))*n,Tg.g=255*(n=Math.sin(t+Ng))*n,Tg.b=255*(n=Math.sin(t+Sg))*n,Tg+""},t.interpolateViridis=kg,t.interpolateMagma=Cg,t.interpolateInferno=Pg,t.interpolatePlasma=zg,t.create=function(t){return Dt(W(t).call(document.documentElement))},t.creator=W,t.local=qt,t.matcher=rt,t.mouse=Ft,t.namespace=$,t.namespaces=V,t.clientPoint=Bt,t.select=Dt,t.selectAll=function(t){return"string"==typeof t?new Rt([document.querySelectorAll(t)],[document.documentElement]):new Rt([null==t?[]:t],zt)},t.selection=Lt,t.selector=Q,t.selectorAll=K,t.style=lt,t.touch=It,t.touches=function(t,n){null==n&&(n=Yt().touches);for(var e=0,r=n?n.length:0,i=new Array(r);e<r;++e)i[e]=Bt(t,n[e]);return i},t.window=st,t.customEvent=Ct,t.arc=function(){var t=Gg,n=Vg,e=Rg(0),r=null,i=$g,o=Wg,a=Zg,u=null;function f(){var f,c,s,l=+t.apply(this,arguments),h=+n.apply(this,arguments),d=i.apply(this,arguments)-Hg,p=o.apply(this,arguments)-Hg,v=Lg(p-d),g=p>d;if(u||(u=f=Gi()),h<l&&(c=h,h=l,l=c),h>Fg)if(v>jg-Fg)u.moveTo(h*Ug(d),h*Yg(d)),u.arc(0,0,h,d,p,!g),l>Fg&&(u.moveTo(l*Ug(p),l*Yg(p)),u.arc(0,0,l,p,d,g));else{var y,_,b=d,m=p,x=d,w=p,M=v,A=v,T=a.apply(this,arguments)/2,N=T>Fg&&(r?+r.apply(this,arguments):Bg(l*l+h*h)),S=Og(Lg(h-l)/2,+e.apply(this,arguments)),E=S,k=S;if(N>Fg){var C=Xg(N/l*Yg(T)),P=Xg(N/h*Yg(T));(M-=2*C)>Fg?(x+=C*=g?1:-1,w-=C):(M=0,x=w=(d+p)/2),(A-=2*P)>Fg?(b+=P*=g?1:-1,m-=P):(A=0,b=m=(d+p)/2)}var z=h*Ug(b),R=h*Yg(b),L=l*Ug(w),D=l*Yg(w);if(S>Fg){var U=h*Ug(m),q=h*Yg(m),O=l*Ug(x),Y=l*Yg(x);if(v<Ig){var B=M>Fg?function(t,n,e,r,i,o,a,u){var f=e-t,c=r-n,s=a-i,l=u-o,h=(s*(n-o)-l*(t-i))/(l*f-s*c);return[t+h*f,n+h*c]}(z,R,O,Y,U,q,L,D):[L,D],F=z-B[0],I=R-B[1],H=U-B[0],j=q-B[1],X=1/Yg(((s=(F*H+I*j)/(Bg(F*F+I*I)*Bg(H*H+j*j)))>1?0:s<-1?Ig:Math.acos(s))/2),G=Bg(B[0]*B[0]+B[1]*B[1]);E=Og(S,(l-G)/(X-1)),k=Og(S,(h-G)/(X+1))}}A>Fg?k>Fg?(y=Qg(O,Y,z,R,h,k,g),_=Qg(U,q,L,D,h,k,g),u.moveTo(y.cx+y.x01,y.cy+y.y01),k<S?u.arc(y.cx,y.cy,k,Dg(y.y01,y.x01),Dg(_.y01,_.x01),!g):(u.arc(y.cx,y.cy,k,Dg(y.y01,y.x01),Dg(y.y11,y.x11),!g),u.arc(0,0,h,Dg(y.cy+y.y11,y.cx+y.x11),Dg(_.cy+_.y11,_.cx+_.x11),!g),u.arc(_.cx,_.cy,k,Dg(_.y11,_.x11),Dg(_.y01,_.x01),!g))):(u.moveTo(z,R),u.arc(0,0,h,b,m,!g)):u.moveTo(z,R),l>Fg&&M>Fg?E>Fg?(y=Qg(L,D,U,q,l,-E,g),_=Qg(z,R,O,Y,l,-E,g),u.lineTo(y.cx+y.x01,y.cy+y.y01),E<S?u.arc(y.cx,y.cy,E,Dg(y.y01,y.x01),Dg(_.y01,_.x01),!g):(u.arc(y.cx,y.cy,E,Dg(y.y01,y.x01),Dg(y.y11,y.x11),!g),u.arc(0,0,l,Dg(y.cy+y.y11,y.cx+y.x11),Dg(_.cy+_.y11,_.cx+_.x11),g),u.arc(_.cx,_.cy,E,Dg(_.y11,_.x11),Dg(_.y01,_.x01),!g))):u.arc(0,0,l,w,x,g):u.lineTo(L,D)}else u.moveTo(0,0);if(u.closePath(),f)return u=null,f+""||null}return f.centroid=function(){var e=(+t.apply(this,arguments)+ +n.apply(this,arguments))/2,r=(+i.apply(this,arguments)+ +o.apply(this,arguments))/2-Ig/2;return[Ug(r)*e,Yg(r)*e]},f.innerRadius=function(n){return arguments.length?(t="function"==typeof n?n:Rg(+n),f):t},f.outerRadius=function(t){return arguments.length?(n="function"==typeof t?t:Rg(+t),f):n},f.cornerRadius=function(t){return arguments.length?(e="function"==typeof t?t:Rg(+t),f):e},f.padRadius=function(t){return arguments.length?(r=null==t?null:"function"==typeof t?t:Rg(+t),f):r},f.startAngle=function(t){return arguments.length?(i="function"==typeof t?t:Rg(+t),f):i},f.endAngle=function(t){return arguments.length?(o="function"==typeof t?t:Rg(+t),f):o},f.padAngle=function(t){return arguments.length?(a="function"==typeof t?t:Rg(+t),f):a},f.context=function(t){return arguments.length?(u=null==t?null:t,f):u},f},t.area=ry,t.line=ey,t.pie=function(){var t=oy,n=iy,e=null,r=Rg(0),i=Rg(jg),o=Rg(0);function a(a){var u,f,c,s,l,h=a.length,d=0,p=new Array(h),v=new Array(h),g=+r.apply(this,arguments),y=Math.min(jg,Math.max(-jg,i.apply(this,arguments)-g)),_=Math.min(Math.abs(y)/h,o.apply(this,arguments)),b=_*(y<0?-1:1);for(u=0;u<h;++u)(l=v[p[u]=u]=+t(a[u],u,a))>0&&(d+=l);for(null!=n?p.sort(function(t,e){return n(v[t],v[e])}):null!=e&&p.sort(function(t,n){return e(a[t],a[n])}),u=0,c=d?(y-h*b)/d:0;u<h;++u,g=s)f=p[u],s=g+((l=v[f])>0?l*c:0)+b,v[f]={data:a[f],index:u,value:l,startAngle:g,endAngle:s,padAngle:_};return v}return a.value=function(n){return arguments.length?(t="function"==typeof n?n:Rg(+n),a):t},a.sortValues=function(t){return arguments.length?(n=t,e=null,a):n},a.sort=function(t){return arguments.length?(e=t,n=null,a):e},a.startAngle=function(t){return arguments.length?(r="function"==typeof t?t:Rg(+t),a):r},a.endAngle=function(t){return arguments.length?(i="function"==typeof t?t:Rg(+t),a):i},a.padAngle=function(t){return arguments.length?(o="function"==typeof t?t:Rg(+t),a):o},a},t.areaRadial=ly,t.radialArea=ly,t.lineRadial=sy,t.radialLine=sy,t.pointRadial=hy,t.linkHorizontal=function(){return gy(yy)},t.linkVertical=function(){return gy(_y)},t.linkRadial=function(){var t=gy(by);return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t},t.symbol=function(){var t=Rg(my),n=Rg(64),e=null;function r(){var r;if(e||(e=r=Gi()),t.apply(this,arguments).draw(e,+n.apply(this,arguments)),r)return e=null,r+""||null}return r.type=function(n){return arguments.length?(t="function"==typeof n?n:Rg(n),r):t},r.size=function(t){return arguments.length?(n="function"==typeof t?t:Rg(+t),r):n},r.context=function(t){return arguments.length?(e=null==t?null:t,r):e},r},t.symbols=Uy,t.symbolCircle=my,t.symbolCross=xy,t.symbolDiamond=Ay,t.symbolSquare=ky,t.symbolStar=Ey,t.symbolTriangle=Py,t.symbolWye=Dy,t.curveBasisClosed=function(t){return new By(t)},t.curveBasisOpen=function(t){return new Fy(t)},t.curveBasis=function(t){return new Yy(t)},t.curveBundle=Hy,t.curveCardinalClosed=$y,t.curveCardinalOpen=Zy,t.curveCardinal=Gy,t.curveCatmullRomClosed=n_,t.curveCatmullRomOpen=r_,t.curveCatmullRom=Ky,t.curveLinearClosed=function(t){return new i_(t)},t.curveLinear=Kg,t.curveMonotoneX=function(t){return new c_(t)},t.curveMonotoneY=function(t){return new s_(t)},t.curveNatural=function(t){return new h_(t)},t.curveStep=function(t){return new p_(t,.5)},t.curveStepAfter=function(t){return new p_(t,1)},t.curveStepBefore=function(t){return new p_(t,0)},t.stack=function(){var t=Rg([]),n=g_,e=v_,r=y_;function i(i){var o,a,u=t.apply(this,arguments),f=i.length,c=u.length,s=new Array(c);for(o=0;o<c;++o){for(var l,h=u[o],d=s[o]=new Array(f),p=0;p<f;++p)d[p]=l=[0,+r(i[p],h,p,i)],l.data=i[p];d.key=h}for(o=0,a=n(s);o<c;++o)s[a[o]].index=o;return e(s,a),s}return i.keys=function(n){return arguments.length?(t="function"==typeof n?n:Rg(dy.call(n)),i):t},i.value=function(t){return arguments.length?(r="function"==typeof t?t:Rg(+t),i):r},i.order=function(t){return arguments.length?(n=null==t?g_:"function"==typeof t?t:Rg(dy.call(t)),i):n},i.offset=function(t){return arguments.length?(e=null==t?v_:t,i):e},i},t.stackOffsetExpand=function(t,n){if((r=t.length)>0){for(var e,r,i,o=0,a=t[0].length;o<a;++o){for(i=e=0;e<r;++e)i+=t[e][o][1]||0;if(i)for(e=0;e<r;++e)t[e][o][1]/=i}v_(t,n)}},t.stackOffsetDiverging=function(t,n){if((u=t.length)>1)for(var e,r,i,o,a,u,f=0,c=t[n[0]].length;f<c;++f)for(o=a=0,e=0;e<u;++e)(i=(r=t[n[e]][f])[1]-r[0])>=0?(r[0]=o,r[1]=o+=i):i<0?(r[1]=a,r[0]=a+=i):r[0]=o},t.stackOffsetNone=v_,t.stackOffsetSilhouette=function(t,n){if((e=t.length)>0){for(var e,r=0,i=t[n[0]],o=i.length;r<o;++r){for(var a=0,u=0;a<e;++a)u+=t[a][r][1]||0;i[r][1]+=i[r][0]=-u/2}v_(t,n)}},t.stackOffsetWiggle=function(t,n){if((i=t.length)>0&&(r=(e=t[n[0]]).length)>0){for(var e,r,i,o=0,a=1;a<r;++a){for(var u=0,f=0,c=0;u<i;++u){for(var s=t[n[u]],l=s[a][1]||0,h=(l-(s[a-1][1]||0))/2,d=0;d<u;++d){var p=t[n[d]];h+=(p[a][1]||0)-(p[a-1][1]||0)}f+=l,c+=h*l}e[a-1][1]+=e[a-1][0]=o,f&&(o-=c/f)}e[a-1][1]+=e[a-1][0]=o,v_(t,n)}},t.stackOrderAscending=__,t.stackOrderDescending=function(t){return __(t).reverse()},t.stackOrderInsideOut=function(t){var n,e,r=t.length,i=t.map(b_),o=g_(t).sort(function(t,n){return i[n]-i[t]}),a=0,u=0,f=[],c=[];for(n=0;n<r;++n)e=o[n],a<u?(a+=i[e],f.push(e)):(u+=i[e],c.push(e));return c.reverse().concat(f)},t.stackOrderNone=g_,t.stackOrderReverse=function(t){return g_(t).reverse()},t.timeInterval=Rh,t.timeMillisecond=Lh,t.timeMilliseconds=Dh,t.utcMillisecond=Lh,t.utcMilliseconds=Dh,t.timeSecond=Oh,t.timeSeconds=Yh,t.utcSecond=Oh,t.utcSeconds=Yh,t.timeMinute=Bh,t.timeMinutes=Fh,t.timeHour=Ih,t.timeHours=Hh,t.timeDay=jh,t.timeDays=Xh,t.timeWeek=Vh,t.timeWeeks=td,t.timeSunday=Vh,t.timeSundays=td,t.timeMonday=$h,t.timeMondays=nd,t.timeTuesday=Wh,t.timeTuesdays=ed,t.timeWednesday=Zh,t.timeWednesdays=rd,t.timeThursday=Qh,t.timeThursdays=id,t.timeFriday=Jh,t.timeFridays=od,t.timeSaturday=Kh,t.timeSaturdays=ad,t.timeMonth=ud,t.timeMonths=fd,t.timeYear=cd,t.timeYears=sd,t.utcMinute=ld,t.utcMinutes=hd,t.utcHour=dd,t.utcHours=pd,t.utcDay=vd,t.utcDays=gd,t.utcWeek=_d,t.utcWeeks=Td,t.utcSunday=_d,t.utcSundays=Td,t.utcMonday=bd,t.utcMondays=Nd,t.utcTuesday=md,t.utcTuesdays=Sd,t.utcWednesday=xd,t.utcWednesdays=Ed,t.utcThursday=wd,t.utcThursdays=kd,t.utcFriday=Md,t.utcFridays=Cd,t.utcSaturday=Ad,t.utcSaturdays=Pd,t.utcMonth=zd,t.utcMonths=Rd,t.utcYear=Ld,t.utcYears=Dd,t.timeFormatDefaultLocale=Qp,t.timeFormatLocale=Yd,t.isoFormat=Jp,t.isoParse=Kp,t.now=ir,t.timer=ur,t.timerFlush=fr,t.timeout=hr,t.interval=function(t,n,e){var r=new ar,i=n;return null==n?(r.restart(t,n,e),r):(n=+n,e=null==e?ir():+e,r.restart(function o(a){a+=i,r.restart(o,i+=n,e),t(a)},n,e),r)},t.transition=zr,t.active=function(t,n){var e,r,i=t.__transition;if(i)for(r in n=null==n?null:n+"",i)if((e=i[r]).state>gr&&e.name===n)return new Pr([[t]],li,n,+r);return null},t.interrupt=Nr,t.voronoi=function(){var t=x_,n=w_,e=null;function r(r){return new eb(r.map(function(e,i){var o=[Math.round(t(e,i,r)/K_)*K_,Math.round(n(e,i,r)/K_)*K_];return o.index=i,o.data=e,o}),e)}return r.polygons=function(t){return r(t).polygons()},r.links=function(t){return r(t).links()},r.triangles=function(t){return r(t).triangles()},r.x=function(n){return arguments.length?(t="function"==typeof n?n:m_(+n),r):t},r.y=function(t){return arguments.length?(n="function"==typeof t?t:m_(+t),r):n},r.extent=function(t){return arguments.length?(e=null==t?null:[[+t[0][0],+t[0][1]],[+t[1][0],+t[1][1]]],r):e&&[[e[0][0],e[0][1]],[e[1][0],e[1][1]]]},r.size=function(t){return arguments.length?(e=null==t?null:[[0,0],[+t[0],+t[1]]],r):e&&[e[1][0]-e[0][0],e[1][1]-e[0][1]]},r},t.zoom=function(){var n,e,r=sb,i=lb,o=vb,a=db,u=pb,f=[0,1/0],c=[[-1/0,-1/0],[1/0,1/0]],s=250,l=qe,h=[],d=I("start","zoom","end"),p=500,v=150,g=0;function y(t){t.property("__zoom",hb).on("wheel.zoom",A).on("mousedown.zoom",T).on("dblclick.zoom",N).filter(u).on("touchstart.zoom",S).on("touchmove.zoom",E).on("touchend.zoom touchcancel.zoom",k).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function _(t,n){return(n=Math.max(f[0],Math.min(f[1],n)))===t.k?t:new ob(n,t.x,t.y)}function b(t,n,e){var r=n[0]-e[0]*t.k,i=n[1]-e[1]*t.k;return r===t.x&&i===t.y?t:new ob(t.k,r,i)}function m(t){return[(+t[0][0]+ +t[1][0])/2,(+t[0][1]+ +t[1][1])/2]}function x(t,n,e){t.on("start.zoom",function(){w(this,arguments).start()}).on("interrupt.zoom end.zoom",function(){w(this,arguments).end()}).tween("zoom",function(){var t=arguments,r=w(this,t),o=i.apply(this,t),a=e||m(o),u=Math.max(o[1][0]-o[0][0],o[1][1]-o[0][1]),f=this.__zoom,c="function"==typeof n?n.apply(this,t):n,s=l(f.invert(a).concat(u/f.k),c.invert(a).concat(u/c.k));return function(t){if(1===t)t=c;else{var n=s(t),e=u/n[2];t=new ob(e,a[0]-n[0]*e,a[1]-n[1]*e)}r.zoom(null,t)}})}function w(t,n){for(var e,r=0,i=h.length;r<i;++r)if((e=h[r]).that===t)return e;return new M(t,n)}function M(t,n){this.that=t,this.args=n,this.index=-1,this.active=0,this.extent=i.apply(t,n)}function A(){if(r.apply(this,arguments)){var t=w(this,arguments),n=this.__zoom,e=Math.max(f[0],Math.min(f[1],n.k*Math.pow(2,a.apply(this,arguments)))),i=Ft(this);if(t.wheel)t.mouse[0][0]===i[0]&&t.mouse[0][1]===i[1]||(t.mouse[1]=n.invert(t.mouse[0]=i)),clearTimeout(t.wheel);else{if(n.k===e)return;t.mouse=[i,n.invert(i)],Nr(this),t.start()}cb(),t.wheel=setTimeout(function(){t.wheel=null,t.end()},v),t.zoom("mouse",o(b(_(n,e),t.mouse[0],t.mouse[1]),t.extent,c))}}function T(){if(!e&&r.apply(this,arguments)){var n=w(this,arguments),i=Dt(t.event.view).on("mousemove.zoom",function(){if(cb(),!n.moved){var e=t.event.clientX-u,r=t.event.clientY-f;n.moved=e*e+r*r>g}n.zoom("mouse",o(b(n.that.__zoom,n.mouse[0]=Ft(n.that),n.mouse[1]),n.extent,c))},!0).on("mouseup.zoom",function(){i.on("mousemove.zoom mouseup.zoom",null),Gt(t.event.view,n.moved),cb(),n.end()},!0),a=Ft(this),u=t.event.clientX,f=t.event.clientY;Xt(t.event.view),fb(),n.mouse=[a,this.__zoom.invert(a)],Nr(this),n.start()}}function N(){if(r.apply(this,arguments)){var n=this.__zoom,e=Ft(this),a=n.invert(e),u=n.k*(t.event.shiftKey?.5:2),f=o(b(_(n,u),e,a),i.apply(this,arguments),c);cb(),s>0?Dt(this).transition().duration(s).call(x,f,e):Dt(this).call(y.transform,f)}}function S(){if(r.apply(this,arguments)){var e,i,o,a,u=w(this,arguments),f=t.event.changedTouches,c=f.length;for(fb(),i=0;i<c;++i)a=[a=It(this,f,(o=f[i]).identifier),this.__zoom.invert(a),o.identifier],u.touch0?u.touch1||(u.touch1=a):(u.touch0=a,e=!0);if(n&&(n=clearTimeout(n),!u.touch1))return u.end(),void((a=Dt(this).on("dblclick.zoom"))&&a.apply(this,arguments));e&&(n=setTimeout(function(){n=null},p),Nr(this),u.start())}}function E(){var e,r,i,a,u=w(this,arguments),f=t.event.changedTouches,s=f.length;for(cb(),n&&(n=clearTimeout(n)),e=0;e<s;++e)i=It(this,f,(r=f[e]).identifier),u.touch0&&u.touch0[2]===r.identifier?u.touch0[0]=i:u.touch1&&u.touch1[2]===r.identifier&&(u.touch1[0]=i);if(r=u.that.__zoom,u.touch1){var l=u.touch0[0],h=u.touch0[1],d=u.touch1[0],p=u.touch1[1],v=(v=d[0]-l[0])*v+(v=d[1]-l[1])*v,g=(g=p[0]-h[0])*g+(g=p[1]-h[1])*g;r=_(r,Math.sqrt(v/g)),i=[(l[0]+d[0])/2,(l[1]+d[1])/2],a=[(h[0]+p[0])/2,(h[1]+p[1])/2]}else{if(!u.touch0)return;i=u.touch0[0],a=u.touch0[1]}u.zoom("touch",o(b(r,i,a),u.extent,c))}function k(){var n,r,i=w(this,arguments),o=t.event.changedTouches,a=o.length;for(fb(),e&&clearTimeout(e),e=setTimeout(function(){e=null},p),n=0;n<a;++n)r=o[n],i.touch0&&i.touch0[2]===r.identifier?delete i.touch0:i.touch1&&i.touch1[2]===r.identifier&&delete i.touch1;i.touch1&&!i.touch0&&(i.touch0=i.touch1,delete i.touch1),i.touch0?i.touch0[1]=this.__zoom.invert(i.touch0[0]):i.end()}return y.transform=function(t,n){var e=t.selection?t.selection():t;e.property("__zoom",hb),t!==e?x(t,n):e.interrupt().each(function(){w(this,arguments).start().zoom(null,"function"==typeof n?n.apply(this,arguments):n).end()})},y.scaleBy=function(t,n){y.scaleTo(t,function(){return this.__zoom.k*("function"==typeof n?n.apply(this,arguments):n)})},y.scaleTo=function(t,n){y.transform(t,function(){var t=i.apply(this,arguments),e=this.__zoom,r=m(t),a=e.invert(r),u="function"==typeof n?n.apply(this,arguments):n;return o(b(_(e,u),r,a),t,c)})},y.translateBy=function(t,n,e){y.transform(t,function(){return o(this.__zoom.translate("function"==typeof n?n.apply(this,arguments):n,"function"==typeof e?e.apply(this,arguments):e),i.apply(this,arguments),c)})},y.translateTo=function(t,n,e){y.transform(t,function(){var t=i.apply(this,arguments),r=this.__zoom,a=m(t);return o(ab.translate(a[0],a[1]).scale(r.k).translate("function"==typeof n?-n.apply(this,arguments):-n,"function"==typeof e?-e.apply(this,arguments):-e),t,c)})},M.prototype={start:function(){return 1==++this.active&&(this.index=h.push(this)-1,this.emit("start")),this},zoom:function(t,n){return this.mouse&&"mouse"!==t&&(this.mouse[1]=n.invert(this.mouse[0])),this.touch0&&"touch"!==t&&(this.touch0[1]=n.invert(this.touch0[0])),this.touch1&&"touch"!==t&&(this.touch1[1]=n.invert(this.touch1[0])),this.that.__zoom=n,this.emit("zoom"),this},end:function(){return 0==--this.active&&(h.splice(this.index,1),this.index=-1,this.emit("end")),this},emit:function(t){Ct(new ib(y,t,this.that.__zoom),d.apply,d,[t,this.that,this.args])}},y.wheelDelta=function(t){return arguments.length?(a="function"==typeof t?t:rb(+t),y):a},y.filter=function(t){return arguments.length?(r="function"==typeof t?t:rb(!!t),y):r},y.touchable=function(t){return arguments.length?(u="function"==typeof t?t:rb(!!t),y):u},y.extent=function(t){return arguments.length?(i="function"==typeof t?t:rb([[+t[0][0],+t[0][1]],[+t[1][0],+t[1][1]]]),y):i},y.scaleExtent=function(t){return arguments.length?(f[0]=+t[0],f[1]=+t[1],y):[f[0],f[1]]},y.translateExtent=function(t){return arguments.length?(c[0][0]=+t[0][0],c[1][0]=+t[1][0],c[0][1]=+t[0][1],c[1][1]=+t[1][1],y):[[c[0][0],c[0][1]],[c[1][0],c[1][1]]]},y.constrain=function(t){return arguments.length?(o=t,y):o},y.duration=function(t){return arguments.length?(s=+t,y):s},y.interpolate=function(t){return arguments.length?(l=t,y):l},y.on=function(){var t=d.on.apply(d,arguments);return t===d?y:t},y.clickDistance=function(t){return arguments.length?(g=(t=+t)*t,y):Math.sqrt(g)},y},t.zoomTransform=ub,t.zoomIdentity=ab,Object.defineProperty(t,"__esModule",{value:!0})}); diff --git a/js/scripts/dat.gui.min.js b/js/scripts/dat.gui.min.js new file mode 100644 index 00000000000..b360ac9fb79 --- /dev/null +++ b/js/scripts/dat.gui.min.js @@ -0,0 +1,2 @@ +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.dat=t():e.dat=t()}(this,function(){return function(e){function t(o){if(n[o])return n[o].exports;var i=n[o]={exports:{},id:o,loaded:!1};return e[o].call(i.exports,i,i.exports,t),i.loaded=!0,i.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}var i=n(1),r=o(i);e.exports=r["default"]},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}t.__esModule=!0;var i=n(2),r=o(i),a=n(6),l=o(a),s=n(3),u=o(s),d=n(7),c=o(d),f=n(8),_=o(f),p=n(10),h=o(p),m=n(11),b=o(m),g=n(12),v=o(g),y=n(13),w=o(y),x=n(14),E=o(x),C=n(15),A=o(C),S=n(16),k=o(S),O=n(9),T=o(O),R=n(17),L=o(R);t["default"]={color:{Color:r["default"],math:l["default"],interpret:u["default"]},controllers:{Controller:c["default"],BooleanController:_["default"],OptionController:h["default"],StringController:b["default"],NumberController:v["default"],NumberControllerBox:w["default"],NumberControllerSlider:E["default"],FunctionController:A["default"],ColorController:k["default"]},dom:{dom:T["default"]},gui:{GUI:L["default"]},GUI:L["default"]}},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t,n){Object.defineProperty(e,t,{get:function(){return"RGB"===this.__state.space?this.__state[t]:(h.recalculateRGB(this,t,n),this.__state[t])},set:function(e){"RGB"!==this.__state.space&&(h.recalculateRGB(this,t,n),this.__state.space="RGB"),this.__state[t]=e}})}function a(e,t){Object.defineProperty(e,t,{get:function(){return"HSV"===this.__state.space?this.__state[t]:(h.recalculateHSV(this),this.__state[t])},set:function(e){"HSV"!==this.__state.space&&(h.recalculateHSV(this),this.__state.space="HSV"),this.__state[t]=e}})}t.__esModule=!0;var l=n(3),s=o(l),u=n(6),d=o(u),c=n(4),f=o(c),_=n(5),p=o(_),h=function(){function e(){if(i(this,e),this.__state=s["default"].apply(this,arguments),this.__state===!1)throw new Error("Failed to interpret color arguments");this.__state.a=this.__state.a||1}return e.prototype.toString=function(){return(0,f["default"])(this)},e.prototype.toHexString=function(){return(0,f["default"])(this,!0)},e.prototype.toOriginal=function(){return this.__state.conversion.write(this)},e}();h.recalculateRGB=function(e,t,n){if("HEX"===e.__state.space)e.__state[t]=d["default"].component_from_hex(e.__state.hex,n);else{if("HSV"!==e.__state.space)throw new Error("Corrupted color state");p["default"].extend(e.__state,d["default"].hsv_to_rgb(e.__state.h,e.__state.s,e.__state.v))}},h.recalculateHSV=function(e){var t=d["default"].rgb_to_hsv(e.r,e.g,e.b);p["default"].extend(e.__state,{s:t.s,v:t.v}),p["default"].isNaN(t.h)?p["default"].isUndefined(e.__state.h)&&(e.__state.h=0):e.__state.h=t.h},h.COMPONENTS=["r","g","b","h","s","v","hex","a"],r(h.prototype,"r",2),r(h.prototype,"g",1),r(h.prototype,"b",0),a(h.prototype,"h"),a(h.prototype,"s"),a(h.prototype,"v"),Object.defineProperty(h.prototype,"a",{get:function(){return this.__state.a},set:function(e){this.__state.a=e}}),Object.defineProperty(h.prototype,"hex",{get:function(){return"HEX"!==!this.__state.space&&(this.__state.hex=d["default"].rgb_to_hex(this.r,this.g,this.b)),this.__state.hex},set:function(e){this.__state.space="HEX",this.__state.hex=e}}),t["default"]=h},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}t.__esModule=!0;var i=n(4),r=o(i),a=n(5),l=o(a),s=[{litmus:l["default"].isString,conversions:{THREE_CHAR_HEX:{read:function(e){var t=e.match(/^#([A-F0-9])([A-F0-9])([A-F0-9])$/i);return null!==t&&{space:"HEX",hex:parseInt("0x"+t[1].toString()+t[1].toString()+t[2].toString()+t[2].toString()+t[3].toString()+t[3].toString(),0)}},write:r["default"]},SIX_CHAR_HEX:{read:function(e){var t=e.match(/^#([A-F0-9]{6})$/i);return null!==t&&{space:"HEX",hex:parseInt("0x"+t[1].toString(),0)}},write:r["default"]},CSS_RGB:{read:function(e){var t=e.match(/^rgb\(\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*\)/);return null!==t&&{space:"RGB",r:parseFloat(t[1]),g:parseFloat(t[2]),b:parseFloat(t[3])}},write:r["default"]},CSS_RGBA:{read:function(e){var t=e.match(/^rgba\(\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*\)/);return null!==t&&{space:"RGB",r:parseFloat(t[1]),g:parseFloat(t[2]),b:parseFloat(t[3]),a:parseFloat(t[4])}},write:r["default"]}}},{litmus:l["default"].isNumber,conversions:{HEX:{read:function(e){return{space:"HEX",hex:e,conversionName:"HEX"}},write:function(e){return e.hex}}}},{litmus:l["default"].isArray,conversions:{RGB_ARRAY:{read:function(e){return 3===e.length&&{space:"RGB",r:e[0],g:e[1],b:e[2]}},write:function(e){return[e.r,e.g,e.b]}},RGBA_ARRAY:{read:function(e){return 4===e.length&&{space:"RGB",r:e[0],g:e[1],b:e[2],a:e[3]}},write:function(e){return[e.r,e.g,e.b,e.a]}}}},{litmus:l["default"].isObject,conversions:{RGBA_OBJ:{read:function(e){return!!(l["default"].isNumber(e.r)&&l["default"].isNumber(e.g)&&l["default"].isNumber(e.b)&&l["default"].isNumber(e.a))&&{space:"RGB",r:e.r,g:e.g,b:e.b,a:e.a}},write:function(e){return{r:e.r,g:e.g,b:e.b,a:e.a}}},RGB_OBJ:{read:function(e){return!!(l["default"].isNumber(e.r)&&l["default"].isNumber(e.g)&&l["default"].isNumber(e.b))&&{space:"RGB",r:e.r,g:e.g,b:e.b}},write:function(e){return{r:e.r,g:e.g,b:e.b}}},HSVA_OBJ:{read:function(e){return!!(l["default"].isNumber(e.h)&&l["default"].isNumber(e.s)&&l["default"].isNumber(e.v)&&l["default"].isNumber(e.a))&&{space:"HSV",h:e.h,s:e.s,v:e.v,a:e.a}},write:function(e){return{h:e.h,s:e.s,v:e.v,a:e.a}}},HSV_OBJ:{read:function(e){return!!(l["default"].isNumber(e.h)&&l["default"].isNumber(e.s)&&l["default"].isNumber(e.v))&&{space:"HSV",h:e.h,s:e.s,v:e.v}},write:function(e){return{h:e.h,s:e.s,v:e.v}}}}}],u=void 0,d=void 0,c=function(){d=!1;var e=arguments.length>1?l["default"].toArray(arguments):arguments[0];return l["default"].each(s,function(t){if(t.litmus(e))return l["default"].each(t.conversions,function(t,n){if(u=t.read(e),d===!1&&u!==!1)return d=u,u.conversionName=n,u.conversion=t,l["default"].BREAK}),l["default"].BREAK}),d};t["default"]=c},function(e,t){"use strict";t.__esModule=!0,t["default"]=function(e,t){var n=e.__state.conversionName.toString(),o=Math.round(e.r),i=Math.round(e.g),r=Math.round(e.b),a=e.a,l=Math.round(e.h),s=e.s.toFixed(1),u=e.v.toFixed(1);if(t||"THREE_CHAR_HEX"===n||"SIX_CHAR_HEX"===n){for(var d=e.hex.toString(16);d.length<6;)d="0"+d;return"#"+d}return"CSS_RGB"===n?"rgb("+o+","+i+","+r+")":"CSS_RGBA"===n?"rgba("+o+","+i+","+r+","+a+")":"HEX"===n?"0x"+e.hex.toString(16):"RGB_ARRAY"===n?"["+o+","+i+","+r+"]":"RGBA_ARRAY"===n?"["+o+","+i+","+r+","+a+"]":"RGB_OBJ"===n?"{r:"+o+",g:"+i+",b:"+r+"}":"RGBA_OBJ"===n?"{r:"+o+",g:"+i+",b:"+r+",a:"+a+"}":"HSV_OBJ"===n?"{h:"+l+",s:"+s+",v:"+u+"}":"HSVA_OBJ"===n?"{h:"+l+",s:"+s+",v:"+u+",a:"+a+"}":"unknown format"}},function(e,t){"use strict";t.__esModule=!0;var n=Array.prototype.forEach,o=Array.prototype.slice,i={BREAK:{},extend:function(e){return this.each(o.call(arguments,1),function(t){var n=this.isObject(t)?Object.keys(t):[];n.forEach(function(n){this.isUndefined(t[n])||(e[n]=t[n])}.bind(this))},this),e},defaults:function(e){return this.each(o.call(arguments,1),function(t){var n=this.isObject(t)?Object.keys(t):[];n.forEach(function(n){this.isUndefined(e[n])&&(e[n]=t[n])}.bind(this))},this),e},compose:function(){var e=o.call(arguments);return function(){for(var t=o.call(arguments),n=e.length-1;n>=0;n--)t=[e[n].apply(this,t)];return t[0]}},each:function(e,t,o){if(e)if(n&&e.forEach&&e.forEach===n)e.forEach(t,o);else if(e.length===e.length+0){var i=void 0,r=void 0;for(i=0,r=e.length;i<r;i++)if(i in e&&t.call(o,e[i],i)===this.BREAK)return}else for(var a in e)if(t.call(o,e[a],a)===this.BREAK)return},defer:function(e){setTimeout(e,0)},debounce:function(e,t){var n=void 0;return function(){function o(){n=null}var i=this,r=arguments,a=!n;clearTimeout(n),n=setTimeout(o,t),a&&e.apply(i,r)}},toArray:function(e){return e.toArray?e.toArray():o.call(e)},isUndefined:function(e){return void 0===e},isNull:function(e){return null===e},isNaN:function(e){function t(t){return e.apply(this,arguments)}return t.toString=function(){return e.toString()},t}(function(e){return isNaN(e)}),isArray:Array.isArray||function(e){return e.constructor===Array},isObject:function(e){return e===Object(e)},isNumber:function(e){return e===e+0},isString:function(e){return e===e+""},isBoolean:function(e){return e===!1||e===!0},isFunction:function(e){return"[object Function]"===Object.prototype.toString.call(e)}};t["default"]=i},function(e,t){"use strict";t.__esModule=!0;var n=void 0,o={hsv_to_rgb:function(e,t,n){var o=Math.floor(e/60)%6,i=e/60-Math.floor(e/60),r=n*(1-t),a=n*(1-i*t),l=n*(1-(1-i)*t),s=[[n,l,r],[a,n,r],[r,n,l],[r,a,n],[l,r,n],[n,r,a]][o];return{r:255*s[0],g:255*s[1],b:255*s[2]}},rgb_to_hsv:function(e,t,n){var o=Math.min(e,t,n),i=Math.max(e,t,n),r=i-o,a=void 0,l=void 0;return 0===i?{h:NaN,s:0,v:0}:(l=r/i,a=e===i?(t-n)/r:t===i?2+(n-e)/r:4+(e-t)/r,a/=6,a<0&&(a+=1),{h:360*a,s:l,v:i/255})},rgb_to_hex:function(e,t,n){var o=this.hex_with_component(0,2,e);return o=this.hex_with_component(o,1,t),o=this.hex_with_component(o,0,n)},component_from_hex:function(e,t){return e>>8*t&255},hex_with_component:function(e,t,o){return o<<(n=8*t)|e&~(255<<n)}};t["default"]=o},function(e,t){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}t.__esModule=!0;var o=function(){function e(t,o){n(this,e),this.initialValue=t[o],this.domElement=document.createElement("div"),this.object=t,this.property=o,this.__onChange=void 0,this.__onFinishChange=void 0}return e.prototype.onChange=function(e){return this.__onChange=e,this},e.prototype.onFinishChange=function(e){return this.__onFinishChange=e,this},e.prototype.setValue=function(e){return this.object[this.property]=e,this.__onChange&&this.__onChange.call(this,e),this.updateDisplay(),this},e.prototype.getValue=function(){return this.object[this.property]},e.prototype.updateDisplay=function(){return this},e.prototype.isModified=function(){return this.initialValue!==this.getValue()},e}();t["default"]=o},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}t.__esModule=!0;var l=n(7),s=o(l),u=n(9),d=o(u),c=function(e){function t(n,o){function a(){s.setValue(!s.__prev)}i(this,t);var l=r(this,e.call(this,n,o)),s=l;return l.__prev=l.getValue(),l.__checkbox=document.createElement("input"),l.__checkbox.setAttribute("type","checkbox"),d["default"].bind(l.__checkbox,"change",a,!1),l.domElement.appendChild(l.__checkbox),l.updateDisplay(),l}return a(t,e),t.prototype.setValue=function(t){var n=e.prototype.setValue.call(this,t);return this.__onFinishChange&&this.__onFinishChange.call(this,this.getValue()),this.__prev=this.getValue(),n},t.prototype.updateDisplay=function(){return this.getValue()===!0?(this.__checkbox.setAttribute("checked","checked"),this.__checkbox.checked=!0):this.__checkbox.checked=!1,e.prototype.updateDisplay.call(this)},t}(s["default"]);t["default"]=c},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function i(e){if("0"===e||a["default"].isUndefined(e))return 0;var t=e.match(u);return a["default"].isNull(t)?0:parseFloat(t[1])}t.__esModule=!0;var r=n(5),a=o(r),l={HTMLEvents:["change"],MouseEvents:["click","mousemove","mousedown","mouseup","mouseover"],KeyboardEvents:["keydown"]},s={};a["default"].each(l,function(e,t){a["default"].each(e,function(e){s[e]=t})});var u=/(\d+(\.\d+)?)px/,d={makeSelectable:function(e,t){void 0!==e&&void 0!==e.style&&(e.onselectstart=t?function(){return!1}:function(){},e.style.MozUserSelect=t?"auto":"none",e.style.KhtmlUserSelect=t?"auto":"none",e.unselectable=t?"on":"off")},makeFullscreen:function(e,t,n){var o=n,i=t;a["default"].isUndefined(i)&&(i=!0),a["default"].isUndefined(o)&&(o=!0),e.style.position="absolute",i&&(e.style.left=0,e.style.right=0),o&&(e.style.top=0,e.style.bottom=0)},fakeEvent:function(e,t,n,o){var i=n||{},r=s[t];if(!r)throw new Error("Event type "+t+" not supported.");var l=document.createEvent(r);switch(r){case"MouseEvents":var u=i.x||i.clientX||0,d=i.y||i.clientY||0;l.initMouseEvent(t,i.bubbles||!1,i.cancelable||!0,window,i.clickCount||1,0,0,u,d,!1,!1,!1,!1,0,null);break;case"KeyboardEvents":var c=l.initKeyboardEvent||l.initKeyEvent;a["default"].defaults(i,{cancelable:!0,ctrlKey:!1,altKey:!1,shiftKey:!1,metaKey:!1,keyCode:void 0,charCode:void 0}),c(t,i.bubbles||!1,i.cancelable,window,i.ctrlKey,i.altKey,i.shiftKey,i.metaKey,i.keyCode,i.charCode);break;default:l.initEvent(t,i.bubbles||!1,i.cancelable||!0)}a["default"].defaults(l,o),e.dispatchEvent(l)},bind:function(e,t,n,o){var i=o||!1;return e.addEventListener?e.addEventListener(t,n,i):e.attachEvent&&e.attachEvent("on"+t,n),d},unbind:function(e,t,n,o){var i=o||!1;return e.removeEventListener?e.removeEventListener(t,n,i):e.detachEvent&&e.detachEvent("on"+t,n),d},addClass:function(e,t){if(void 0===e.className)e.className=t;else if(e.className!==t){var n=e.className.split(/ +/);n.indexOf(t)===-1&&(n.push(t),e.className=n.join(" ").replace(/^\s+/,"").replace(/\s+$/,""))}return d},removeClass:function(e,t){if(t)if(e.className===t)e.removeAttribute("class");else{var n=e.className.split(/ +/),o=n.indexOf(t);o!==-1&&(n.splice(o,1),e.className=n.join(" "))}else e.className=void 0;return d},hasClass:function(e,t){return new RegExp("(?:^|\\s+)"+t+"(?:\\s+|$)").test(e.className)||!1},getWidth:function(e){var t=getComputedStyle(e);return i(t["border-left-width"])+i(t["border-right-width"])+i(t["padding-left"])+i(t["padding-right"])+i(t.width)},getHeight:function(e){var t=getComputedStyle(e);return i(t["border-top-width"])+i(t["border-bottom-width"])+i(t["padding-top"])+i(t["padding-bottom"])+i(t.height)},getOffset:function(e){var t=e,n={left:0,top:0};if(t.offsetParent)do n.left+=t.offsetLeft,n.top+=t.offsetTop,t=t.offsetParent;while(t);return n},isActive:function(e){return e===document.activeElement&&(e.type||e.href)}};t["default"]=d},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}t.__esModule=!0;var l=n(7),s=o(l),u=n(9),d=o(u),c=n(5),f=o(c),_=function(e){function t(n,o,a){i(this,t);var l=r(this,e.call(this,n,o)),s=a,u=l;return l.__select=document.createElement("select"),f["default"].isArray(s)&&!function(){var e={};f["default"].each(s,function(t){e[t]=t}),s=e}(),f["default"].each(s,function(e,t){var n=document.createElement("option");n.innerHTML=t,n.setAttribute("value",e),u.__select.appendChild(n)}),l.updateDisplay(),d["default"].bind(l.__select,"change",function(){var e=this.options[this.selectedIndex].value;u.setValue(e)}),l.domElement.appendChild(l.__select),l}return a(t,e),t.prototype.setValue=function(t){var n=e.prototype.setValue.call(this,t);return this.__onFinishChange&&this.__onFinishChange.call(this,this.getValue()),n},t.prototype.updateDisplay=function(){return d["default"].isActive(this.__select)?this:(this.__select.value=this.getValue(),e.prototype.updateDisplay.call(this))},t}(s["default"]);t["default"]=_},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}t.__esModule=!0;var l=n(7),s=o(l),u=n(9),d=o(u),c=function(e){function t(n,o){function a(){u.setValue(u.__input.value)}function l(){u.__onFinishChange&&u.__onFinishChange.call(u,u.getValue())}i(this,t);var s=r(this,e.call(this,n,o)),u=s;return s.__input=document.createElement("input"),s.__input.setAttribute("type","text"),d["default"].bind(s.__input,"keyup",a),d["default"].bind(s.__input,"change",a),d["default"].bind(s.__input,"blur",l),d["default"].bind(s.__input,"keydown",function(e){13===e.keyCode&&this.blur()}),s.updateDisplay(),s.domElement.appendChild(s.__input),s}return a(t,e),t.prototype.updateDisplay=function(){return d["default"].isActive(this.__input)||(this.__input.value=this.getValue()),e.prototype.updateDisplay.call(this)},t}(s["default"]);t["default"]=c},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function l(e){var t=e.toString();return t.indexOf(".")>-1?t.length-t.indexOf(".")-1:0}t.__esModule=!0;var s=n(7),u=o(s),d=n(5),c=o(d),f=function(e){function t(n,o,a){i(this,t);var s=r(this,e.call(this,n,o)),u=a||{};return s.__min=u.min,s.__max=u.max,s.__step=u.step,c["default"].isUndefined(s.__step)?0===s.initialValue?s.__impliedStep=1:s.__impliedStep=Math.pow(10,Math.floor(Math.log(Math.abs(s.initialValue))/Math.LN10))/10:s.__impliedStep=s.__step,s.__precision=l(s.__impliedStep),s}return a(t,e),t.prototype.setValue=function(t){var n=t;return void 0!==this.__min&&n<this.__min?n=this.__min:void 0!==this.__max&&n>this.__max&&(n=this.__max),void 0!==this.__step&&n%this.__step!==0&&(n=Math.round(n/this.__step)*this.__step),e.prototype.setValue.call(this,n)},t.prototype.min=function(e){return this.__min=e,this},t.prototype.max=function(e){return this.__max=e,this},t.prototype.step=function(e){return this.__step=e,this.__impliedStep=e,this.__precision=l(e),this},t}(u["default"]);t["default"]=f},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function l(e,t){var n=Math.pow(10,t);return Math.round(e*n)/n}t.__esModule=!0;var s=n(12),u=o(s),d=n(9),c=o(d),f=n(5),_=o(f),p=function(e){function t(n,o,a){function l(){var e=parseFloat(m.__input.value);_["default"].isNaN(e)||m.setValue(e)}function s(){m.__onFinishChange&&m.__onFinishChange.call(m,m.getValue())}function u(){s()}function d(e){var t=b-e.clientY;m.setValue(m.getValue()+t*m.__impliedStep),b=e.clientY}function f(){c["default"].unbind(window,"mousemove",d),c["default"].unbind(window,"mouseup",f),s()}function p(e){c["default"].bind(window,"mousemove",d),c["default"].bind(window,"mouseup",f),b=e.clientY}i(this,t);var h=r(this,e.call(this,n,o,a));h.__truncationSuspended=!1;var m=h,b=void 0;return h.__input=document.createElement("input"),h.__input.setAttribute("type","text"),c["default"].bind(h.__input,"change",l),c["default"].bind(h.__input,"blur",u),c["default"].bind(h.__input,"mousedown",p),c["default"].bind(h.__input,"keydown",function(e){13===e.keyCode&&(m.__truncationSuspended=!0,this.blur(),m.__truncationSuspended=!1,s())}),h.updateDisplay(),h.domElement.appendChild(h.__input),h}return a(t,e),t.prototype.updateDisplay=function(){return this.__input.value=this.__truncationSuspended?this.getValue():l(this.getValue(),this.__precision),e.prototype.updateDisplay.call(this)},t}(u["default"]);t["default"]=p},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function l(e,t,n,o,i){return o+(i-o)*((e-t)/(n-t))}t.__esModule=!0;var s=n(12),u=o(s),d=n(9),c=o(d),f=function(e){function t(n,o,a,s,u){function d(e){document.activeElement.blur(),c["default"].bind(window,"mousemove",f),c["default"].bind(window,"mouseup",_),f(e)}function f(e){e.preventDefault();var t=h.__background.getBoundingClientRect();return h.setValue(l(e.clientX,t.left,t.right,h.__min,h.__max)),!1}function _(){c["default"].unbind(window,"mousemove",f),c["default"].unbind(window,"mouseup",_),h.__onFinishChange&&h.__onFinishChange.call(h,h.getValue())}i(this,t);var p=r(this,e.call(this,n,o,{min:a,max:s,step:u})),h=p;return p.__background=document.createElement("div"),p.__foreground=document.createElement("div"),c["default"].bind(p.__background,"mousedown",d),c["default"].addClass(p.__background,"slider"),c["default"].addClass(p.__foreground,"slider-fg"),p.updateDisplay(),p.__background.appendChild(p.__foreground),p.domElement.appendChild(p.__background),p}return a(t,e),t.prototype.updateDisplay=function(){var t=(this.getValue()-this.__min)/(this.__max-this.__min);return this.__foreground.style.width=100*t+"%",e.prototype.updateDisplay.call(this)},t}(u["default"]);t["default"]=f},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}t.__esModule=!0;var l=n(7),s=o(l),u=n(9),d=o(u),c=function(e){function t(n,o,a){i(this,t);var l=r(this,e.call(this,n,o)),s=l;return l.__button=document.createElement("div"),l.__button.innerHTML=void 0===a?"Fire":a,d["default"].bind(l.__button,"click",function(e){return e.preventDefault(),s.fire(),!1}),d["default"].addClass(l.__button,"button"),l.domElement.appendChild(l.__button),l}return a(t,e),t.prototype.fire=function(){this.__onChange&&this.__onChange.call(this),this.getValue().call(this.object),this.__onFinishChange&&this.__onFinishChange.call(this,this.getValue())},t}(s["default"]);t["default"]=c},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function l(e,t,n,o){e.style.background="",g["default"].each(y,function(i){e.style.cssText+="background: "+i+"linear-gradient("+t+", "+n+" 0%, "+o+" 100%); "})}function s(e){e.style.background="",e.style.cssText+="background: -moz-linear-gradient(top, #ff0000 0%, #ff00ff 17%, #0000ff 34%, #00ffff 50%, #00ff00 67%, #ffff00 84%, #ff0000 100%);",e.style.cssText+="background: -webkit-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);",e.style.cssText+="background: -o-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);",e.style.cssText+="background: -ms-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);",e.style.cssText+="background: linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);"}t.__esModule=!0;var u=n(7),d=o(u),c=n(9),f=o(c),_=n(2),p=o(_),h=n(3),m=o(h),b=n(5),g=o(b),v=function(e){function t(n,o){function a(e){h(e),f["default"].bind(window,"mousemove",h),f["default"].bind(window,"mouseup",u)}function u(){f["default"].unbind(window,"mousemove",h),f["default"].unbind(window,"mouseup",u),_()}function d(){var e=(0,m["default"])(this.value);e!==!1?(y.__color.__state=e,y.setValue(y.__color.toOriginal())):this.value=y.__color.toString()}function c(){f["default"].unbind(window,"mousemove",b),f["default"].unbind(window,"mouseup",c),_()}function _(){y.__onFinishChange&&y.__onFinishChange.call(y,y.__color.toOriginal())}function h(e){e.preventDefault();var t=y.__saturation_field.getBoundingClientRect(),n=(e.clientX-t.left)/(t.right-t.left),o=1-(e.clientY-t.top)/(t.bottom-t.top);return o>1?o=1:o<0&&(o=0),n>1?n=1:n<0&&(n=0),y.__color.v=o,y.__color.s=n,y.setValue(y.__color.toOriginal()),!1}function b(e){e.preventDefault();var t=y.__hue_field.getBoundingClientRect(),n=1-(e.clientY-t.top)/(t.bottom-t.top);return n>1?n=1:n<0&&(n=0),y.__color.h=360*n,y.setValue(y.__color.toOriginal()),!1}i(this,t);var v=r(this,e.call(this,n,o));v.__color=new p["default"](v.getValue()),v.__temp=new p["default"](0);var y=v;v.domElement=document.createElement("div"),f["default"].makeSelectable(v.domElement,!1),v.__selector=document.createElement("div"),v.__selector.className="selector",v.__saturation_field=document.createElement("div"),v.__saturation_field.className="saturation-field",v.__field_knob=document.createElement("div"),v.__field_knob.className="field-knob",v.__field_knob_border="2px solid ",v.__hue_knob=document.createElement("div"),v.__hue_knob.className="hue-knob",v.__hue_field=document.createElement("div"),v.__hue_field.className="hue-field",v.__input=document.createElement("input"),v.__input.type="text",v.__input_textShadow="0 1px 1px ",f["default"].bind(v.__input,"keydown",function(e){13===e.keyCode&&d.call(this)}),f["default"].bind(v.__input,"blur",d),f["default"].bind(v.__selector,"mousedown",function(){f["default"].addClass(this,"drag").bind(window,"mouseup",function(){f["default"].removeClass(y.__selector,"drag")})});var w=document.createElement("div");return g["default"].extend(v.__selector.style,{width:"122px",height:"102px",padding:"3px",backgroundColor:"#222",boxShadow:"0px 1px 3px rgba(0,0,0,0.3)"}),g["default"].extend(v.__field_knob.style,{position:"absolute",width:"12px",height:"12px",border:v.__field_knob_border+(v.__color.v<.5?"#fff":"#000"),boxShadow:"0px 1px 3px rgba(0,0,0,0.5)",borderRadius:"12px",zIndex:1}),g["default"].extend(v.__hue_knob.style,{position:"absolute",width:"15px",height:"2px",borderRight:"4px solid #fff",zIndex:1}),g["default"].extend(v.__saturation_field.style,{width:"100px",height:"100px",border:"1px solid #555",marginRight:"3px",display:"inline-block",cursor:"pointer"}),g["default"].extend(w.style,{width:"100%",height:"100%",background:"none"}),l(w,"top","rgba(0,0,0,0)","#000"),g["default"].extend(v.__hue_field.style,{width:"15px",height:"100px",border:"1px solid #555",cursor:"ns-resize",position:"absolute",top:"3px",right:"3px"}),s(v.__hue_field),g["default"].extend(v.__input.style,{outline:"none",textAlign:"center",color:"#fff",border:0,fontWeight:"bold",textShadow:v.__input_textShadow+"rgba(0,0,0,0.7)"}),f["default"].bind(v.__saturation_field,"mousedown",a),f["default"].bind(v.__field_knob,"mousedown",a),f["default"].bind(v.__hue_field,"mousedown",function(e){b(e),f["default"].bind(window,"mousemove",b),f["default"].bind(window,"mouseup",c)}),v.__saturation_field.appendChild(w),v.__selector.appendChild(v.__field_knob),v.__selector.appendChild(v.__saturation_field),v.__selector.appendChild(v.__hue_field),v.__hue_field.appendChild(v.__hue_knob),v.domElement.appendChild(v.__input),v.domElement.appendChild(v.__selector),v.updateDisplay(),v}return a(t,e),t.prototype.updateDisplay=function(){var e=(0,m["default"])(this.getValue());if(e!==!1){var t=!1;g["default"].each(p["default"].COMPONENTS,function(n){if(!g["default"].isUndefined(e[n])&&!g["default"].isUndefined(this.__color.__state[n])&&e[n]!==this.__color.__state[n])return t=!0,{}},this),t&&g["default"].extend(this.__color.__state,e)}g["default"].extend(this.__temp.__state,this.__color.__state),this.__temp.a=1;var n=this.__color.v<.5||this.__color.s>.5?255:0,o=255-n;g["default"].extend(this.__field_knob.style,{marginLeft:100*this.__color.s-7+"px",marginTop:100*(1-this.__color.v)-7+"px",backgroundColor:this.__temp.toHexString(),border:this.__field_knob_border+"rgb("+n+","+n+","+n+")"}),this.__hue_knob.style.marginTop=100*(1-this.__color.h/360)+"px",this.__temp.s=1,this.__temp.v=1,l(this.__saturation_field,"left","#fff",this.__temp.toHexString()),this.__input.value=this.__color.toString(),g["default"].extend(this.__input.style,{backgroundColor:this.__color.toHexString(),color:"rgb("+n+","+n+","+n+")",textShadow:this.__input_textShadow+"rgba("+o+","+o+","+o+",.7)"})},t}(d["default"]),y=["-moz-","-o-","-webkit-","-ms-",""];t["default"]=v},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function i(e,t,n){var o=document.createElement("li");return t&&o.appendChild(t),n?e.__ul.insertBefore(o,n):e.__ul.appendChild(o),e.onResize(),o}function r(e,t){var n=e.__preset_select[e.__preset_select.selectedIndex];t?n.innerHTML=n.value+"*":n.innerHTML=n.value}function a(e,t,n){if(n.__li=t,n.__gui=e,U["default"].extend(n,{options:function(t){if(arguments.length>1){var o=n.__li.nextElementSibling;return n.remove(),s(e,n.object,n.property,{before:o,factoryArgs:[U["default"].toArray(arguments)]})}if(U["default"].isArray(t)||U["default"].isObject(t)){var i=n.__li.nextElementSibling;return n.remove(),s(e,n.object,n.property,{before:i,factoryArgs:[t]})}},name:function(e){return n.__li.firstElementChild.firstElementChild.innerHTML=e,n},listen:function(){return n.__gui.listen(n),n},remove:function(){ +return n.__gui.remove(n),n}}),n instanceof B["default"])!function(){var e=new N["default"](n.object,n.property,{min:n.__min,max:n.__max,step:n.__step});U["default"].each(["updateDisplay","onChange","onFinishChange","step"],function(t){var o=n[t],i=e[t];n[t]=e[t]=function(){var t=Array.prototype.slice.call(arguments);return i.apply(e,t),o.apply(n,t)}}),z["default"].addClass(t,"has-slider"),n.domElement.insertBefore(e.domElement,n.domElement.firstElementChild)}();else if(n instanceof N["default"]){var o=function(t){if(U["default"].isNumber(n.__min)&&U["default"].isNumber(n.__max)){var o=n.__li.firstElementChild.firstElementChild.innerHTML,i=n.__gui.__listening.indexOf(n)>-1;n.remove();var r=s(e,n.object,n.property,{before:n.__li.nextElementSibling,factoryArgs:[n.__min,n.__max,n.__step]});return r.name(o),i&&r.listen(),r}return t};n.min=U["default"].compose(o,n.min),n.max=U["default"].compose(o,n.max)}else n instanceof O["default"]?(z["default"].bind(t,"click",function(){z["default"].fakeEvent(n.__checkbox,"click")}),z["default"].bind(n.__checkbox,"click",function(e){e.stopPropagation()})):n instanceof R["default"]?(z["default"].bind(t,"click",function(){z["default"].fakeEvent(n.__button,"click")}),z["default"].bind(t,"mouseover",function(){z["default"].addClass(n.__button,"hover")}),z["default"].bind(t,"mouseout",function(){z["default"].removeClass(n.__button,"hover")})):n instanceof j["default"]&&(z["default"].addClass(t,"color"),n.updateDisplay=U["default"].compose(function(e){return t.style.borderLeftColor=n.__color.toString(),e},n.updateDisplay),n.updateDisplay());n.setValue=U["default"].compose(function(t){return e.getRoot().__preset_select&&n.isModified()&&r(e.getRoot(),!0),t},n.setValue)}function l(e,t){var n=e.getRoot(),o=n.__rememberedObjects.indexOf(t.object);if(o!==-1){var i=n.__rememberedObjectIndecesToControllers[o];if(void 0===i&&(i={},n.__rememberedObjectIndecesToControllers[o]=i),i[t.property]=t,n.load&&n.load.remembered){var r=n.load.remembered,a=void 0;if(r[e.preset])a=r[e.preset];else{if(!r[Q])return;a=r[Q]}if(a[o]&&void 0!==a[o][t.property]){var l=a[o][t.property];t.initialValue=l,t.setValue(l)}}}}function s(e,t,n,o){if(void 0===t[n])throw new Error('Object "'+t+'" has no property "'+n+'"');var r=void 0;if(o.color)r=new j["default"](t,n);else{var s=[t,n].concat(o.factoryArgs);r=C["default"].apply(e,s)}o.before instanceof S["default"]&&(o.before=o.before.__li),l(e,r),z["default"].addClass(r.domElement,"c");var u=document.createElement("span");z["default"].addClass(u,"property-name"),u.innerHTML=r.property;var d=document.createElement("div");d.appendChild(u),d.appendChild(r.domElement);var c=i(e,d,o.before);return z["default"].addClass(c,oe.CLASS_CONTROLLER_ROW),r instanceof j["default"]?z["default"].addClass(c,"color"):z["default"].addClass(c,g(r.getValue())),a(e,c,r),e.__controllers.push(r),r}function u(e,t){return document.location.href+"."+t}function d(e,t,n){var o=document.createElement("option");o.innerHTML=t,o.value=t,e.__preset_select.appendChild(o),n&&(e.__preset_select.selectedIndex=e.__preset_select.length-1)}function c(e,t){t.style.display=e.useLocalStorage?"block":"none"}function f(e){var t=e.__save_row=document.createElement("li");z["default"].addClass(e.domElement,"has-save"),e.__ul.insertBefore(t,e.__ul.firstChild),z["default"].addClass(t,"save-row");var n=document.createElement("span");n.innerHTML=" ",z["default"].addClass(n,"button gears");var o=document.createElement("span");o.innerHTML="Save",z["default"].addClass(o,"button"),z["default"].addClass(o,"save");var i=document.createElement("span");i.innerHTML="New",z["default"].addClass(i,"button"),z["default"].addClass(i,"save-as");var r=document.createElement("span");r.innerHTML="Revert",z["default"].addClass(r,"button"),z["default"].addClass(r,"revert");var a=e.__preset_select=document.createElement("select");e.load&&e.load.remembered?U["default"].each(e.load.remembered,function(t,n){d(e,n,n===e.preset)}):d(e,Q,!1),z["default"].bind(a,"change",function(){for(var t=0;t<e.__preset_select.length;t++)e.__preset_select[t].innerHTML=e.__preset_select[t].value;e.preset=this.value}),t.appendChild(a),t.appendChild(n),t.appendChild(o),t.appendChild(i),t.appendChild(r),q&&!function(){var t=document.getElementById("dg-local-explain"),n=document.getElementById("dg-local-storage"),o=document.getElementById("dg-save-locally");o.style.display="block","true"===localStorage.getItem(u(e,"isLocal"))&&n.setAttribute("checked","checked"),c(e,t),z["default"].bind(n,"change",function(){e.useLocalStorage=!e.useLocalStorage,c(e,t)})}();var l=document.getElementById("dg-new-constructor");z["default"].bind(l,"keydown",function(e){!e.metaKey||67!==e.which&&67!==e.keyCode||Z.hide()}),z["default"].bind(n,"click",function(){l.innerHTML=JSON.stringify(e.getSaveObject(),void 0,2),Z.show(),l.focus(),l.select()}),z["default"].bind(o,"click",function(){e.save()}),z["default"].bind(i,"click",function(){var t=prompt("Enter a new preset name.");t&&e.saveAs(t)}),z["default"].bind(r,"click",function(){e.revert()})}function _(e){function t(t){return t.preventDefault(),e.width+=i-t.clientX,e.onResize(),i=t.clientX,!1}function n(){z["default"].removeClass(e.__closeButton,oe.CLASS_DRAG),z["default"].unbind(window,"mousemove",t),z["default"].unbind(window,"mouseup",n)}function o(o){return o.preventDefault(),i=o.clientX,z["default"].addClass(e.__closeButton,oe.CLASS_DRAG),z["default"].bind(window,"mousemove",t),z["default"].bind(window,"mouseup",n),!1}var i=void 0;e.__resize_handle=document.createElement("div"),U["default"].extend(e.__resize_handle.style,{width:"6px",marginLeft:"-3px",height:"200px",cursor:"ew-resize",position:"absolute"}),z["default"].bind(e.__resize_handle,"mousedown",o),z["default"].bind(e.__closeButton,"mousedown",o),e.domElement.insertBefore(e.__resize_handle,e.domElement.firstElementChild)}function p(e,t){e.domElement.style.width=t+"px",e.__save_row&&e.autoPlace&&(e.__save_row.style.width=t+"px"),e.__closeButton&&(e.__closeButton.style.width=t+"px")}function h(e,t){var n={};return U["default"].each(e.__rememberedObjects,function(o,i){var r={},a=e.__rememberedObjectIndecesToControllers[i];U["default"].each(a,function(e,n){r[n]=t?e.initialValue:e.getValue()}),n[i]=r}),n}function m(e){for(var t=0;t<e.__preset_select.length;t++)e.__preset_select[t].value===e.preset&&(e.__preset_select.selectedIndex=t)}function b(e){0!==e.length&&D["default"].call(window,function(){b(e)}),U["default"].each(e,function(e){e.updateDisplay()})}var g="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol?"symbol":typeof e},v=n(18),y=o(v),w=n(19),x=o(w),E=n(20),C=o(E),A=n(7),S=o(A),k=n(8),O=o(k),T=n(15),R=o(T),L=n(13),N=o(L),M=n(14),B=o(M),H=n(16),j=o(H),P=n(21),D=o(P),V=n(22),F=o(V),I=n(9),z=o(I),G=n(5),U=o(G),X=n(23),K=o(X);y["default"].inject(K["default"]);var Y="dg",J=72,W=20,Q="Default",q=function(){try{return"localStorage"in window&&null!==window.localStorage}catch(e){return!1}}(),Z=void 0,$=!0,ee=void 0,te=!1,ne=[],oe=function ie(e){function t(){var e=n.getRoot();e.width+=1,U["default"].defer(function(){e.width-=1})}var n=this,o=e||{};this.domElement=document.createElement("div"),this.__ul=document.createElement("ul"),this.domElement.appendChild(this.__ul),z["default"].addClass(this.domElement,Y),this.__folders={},this.__controllers=[],this.__rememberedObjects=[],this.__rememberedObjectIndecesToControllers=[],this.__listening=[],o=U["default"].defaults(o,{autoPlace:!0,width:ie.DEFAULT_WIDTH}),o=U["default"].defaults(o,{resizable:o.autoPlace,hideable:o.autoPlace}),U["default"].isUndefined(o.load)?o.load={preset:Q}:o.preset&&(o.load.preset=o.preset),U["default"].isUndefined(o.parent)&&o.hideable&&ne.push(this),o.resizable=U["default"].isUndefined(o.parent)&&o.resizable,o.autoPlace&&U["default"].isUndefined(o.scrollable)&&(o.scrollable=!0);var r=q&&"true"===localStorage.getItem(u(this,"isLocal")),a=void 0;if(Object.defineProperties(this,{parent:{get:function(){return o.parent}},scrollable:{get:function(){return o.scrollable}},autoPlace:{get:function(){return o.autoPlace}},preset:{get:function(){return n.parent?n.getRoot().preset:o.load.preset},set:function(e){n.parent?n.getRoot().preset=e:o.load.preset=e,m(this),n.revert()}},width:{get:function(){return o.width},set:function(e){o.width=e,p(n,e)}},name:{get:function(){return o.name},set:function(e){o.name=e,titleRowName&&(titleRowName.innerHTML=o.name)}},closed:{get:function(){return o.closed},set:function(e){o.closed=e,o.closed?z["default"].addClass(n.__ul,ie.CLASS_CLOSED):z["default"].removeClass(n.__ul,ie.CLASS_CLOSED),this.onResize(),n.__closeButton&&(n.__closeButton.innerHTML=e?ie.TEXT_OPEN:ie.TEXT_CLOSED)}},load:{get:function(){return o.load}},useLocalStorage:{get:function(){return r},set:function(e){q&&(r=e,e?z["default"].bind(window,"unload",a):z["default"].unbind(window,"unload",a),localStorage.setItem(u(n,"isLocal"),e))}}}),U["default"].isUndefined(o.parent)){if(o.closed=!1,z["default"].addClass(this.domElement,ie.CLASS_MAIN),z["default"].makeSelectable(this.domElement,!1),q&&r){n.useLocalStorage=!0;var l=localStorage.getItem(u(this,"gui"));l&&(o.load=JSON.parse(l))}this.__closeButton=document.createElement("div"),this.__closeButton.innerHTML=ie.TEXT_CLOSED,z["default"].addClass(this.__closeButton,ie.CLASS_CLOSE_BUTTON),this.domElement.appendChild(this.__closeButton),z["default"].bind(this.__closeButton,"click",function(){n.closed=!n.closed})}else{void 0===o.closed&&(o.closed=!0);var s=document.createTextNode(o.name);z["default"].addClass(s,"controller-name");var d=i(n,s),c=function(e){return e.preventDefault(),n.closed=!n.closed,!1};z["default"].addClass(this.__ul,ie.CLASS_CLOSED),z["default"].addClass(d,"title"),z["default"].bind(d,"click",c),o.closed||(this.closed=!1)}o.autoPlace&&(U["default"].isUndefined(o.parent)&&($&&(ee=document.createElement("div"),z["default"].addClass(ee,Y),z["default"].addClass(ee,ie.CLASS_AUTO_PLACE_CONTAINER),document.body.appendChild(ee),$=!1),ee.appendChild(this.domElement),z["default"].addClass(this.domElement,ie.CLASS_AUTO_PLACE)),this.parent||p(n,o.width)),this.__resizeHandler=function(){n.onResizeDebounced()},z["default"].bind(window,"resize",this.__resizeHandler),z["default"].bind(this.__ul,"webkitTransitionEnd",this.__resizeHandler),z["default"].bind(this.__ul,"transitionend",this.__resizeHandler),z["default"].bind(this.__ul,"oTransitionEnd",this.__resizeHandler),this.onResize(),o.resizable&&_(this),a=function(){q&&"true"===localStorage.getItem(u(n,"isLocal"))&&localStorage.setItem(u(n,"gui"),JSON.stringify(n.getSaveObject()))},this.saveToLocalStorageIfPossible=a,o.parent||t()};oe.toggleHide=function(){te=!te,U["default"].each(ne,function(e){e.domElement.style.display=te?"none":""})},oe.CLASS_AUTO_PLACE="a",oe.CLASS_AUTO_PLACE_CONTAINER="ac",oe.CLASS_MAIN="main",oe.CLASS_CONTROLLER_ROW="cr",oe.CLASS_TOO_TALL="taller-than-window",oe.CLASS_CLOSED="closed",oe.CLASS_CLOSE_BUTTON="close-button",oe.CLASS_DRAG="drag",oe.DEFAULT_WIDTH=245,oe.TEXT_CLOSED="Close Controls",oe.TEXT_OPEN="Open Controls",oe._keydownHandler=function(e){"text"===document.activeElement.type||e.which!==J&&e.keyCode!==J||oe.toggleHide()},z["default"].bind(window,"keydown",oe._keydownHandler,!1),U["default"].extend(oe.prototype,{add:function(e,t){return s(this,e,t,{factoryArgs:Array.prototype.slice.call(arguments,2)})},addColor:function(e,t){return s(this,e,t,{color:!0})},remove:function(e){this.__ul.removeChild(e.__li),this.__controllers.splice(this.__controllers.indexOf(e),1);var t=this;U["default"].defer(function(){t.onResize()})},destroy:function(){this.autoPlace&&ee.removeChild(this.domElement),z["default"].unbind(window,"keydown",oe._keydownHandler,!1),z["default"].unbind(window,"resize",this.__resizeHandler),this.saveToLocalStorageIfPossible&&z["default"].unbind(window,"unload",this.saveToLocalStorageIfPossible)},addFolder:function(e){if(void 0!==this.__folders[e])throw new Error('You already have a folder in this GUI by the name "'+e+'"');var t={name:e,parent:this};t.autoPlace=this.autoPlace,this.load&&this.load.folders&&this.load.folders[e]&&(t.closed=this.load.folders[e].closed,t.load=this.load.folders[e]);var n=new oe(t);this.__folders[e]=n;var o=i(this,n.domElement);return z["default"].addClass(o,"folder"),n},open:function(){this.closed=!1},close:function(){this.closed=!0},onResize:function(){var e=this.getRoot();if(e.scrollable){var t=z["default"].getOffset(e.__ul).top,n=0;U["default"].each(e.__ul.childNodes,function(t){e.autoPlace&&t===e.__save_row||(n+=z["default"].getHeight(t))}),window.innerHeight-t-W<n?(z["default"].addClass(e.domElement,oe.CLASS_TOO_TALL),e.__ul.style.height=window.innerHeight-t-W+"px"):(z["default"].removeClass(e.domElement,oe.CLASS_TOO_TALL),e.__ul.style.height="auto")}e.__resize_handle&&U["default"].defer(function(){e.__resize_handle.style.height=e.__ul.offsetHeight+"px"}),e.__closeButton&&(e.__closeButton.style.width=e.width+"px")},onResizeDebounced:U["default"].debounce(function(){this.onResize()},200),remember:function(){if(U["default"].isUndefined(Z)&&(Z=new F["default"],Z.domElement.innerHTML=x["default"]),this.parent)throw new Error("You can only call remember on a top level GUI.");var e=this;U["default"].each(Array.prototype.slice.call(arguments),function(t){0===e.__rememberedObjects.length&&f(e),e.__rememberedObjects.indexOf(t)===-1&&e.__rememberedObjects.push(t)}),this.autoPlace&&p(this,this.width)},getRoot:function(){for(var e=this;e.parent;)e=e.parent;return e},getSaveObject:function(){var e=this.load;return e.closed=this.closed,this.__rememberedObjects.length>0&&(e.preset=this.preset,e.remembered||(e.remembered={}),e.remembered[this.preset]=h(this)),e.folders={},U["default"].each(this.__folders,function(t,n){e.folders[n]=t.getSaveObject()}),e},save:function(){this.load.remembered||(this.load.remembered={}),this.load.remembered[this.preset]=h(this),r(this,!1),this.saveToLocalStorageIfPossible()},saveAs:function(e){this.load.remembered||(this.load.remembered={},this.load.remembered[Q]=h(this,!0)),this.load.remembered[e]=h(this),this.preset=e,d(this,e,!0),this.saveToLocalStorageIfPossible()},revert:function(e){U["default"].each(this.__controllers,function(t){this.getRoot().load.remembered?l(e||this.getRoot(),t):t.setValue(t.initialValue),t.__onFinishChange&&t.__onFinishChange.call(t,t.getValue())},this),U["default"].each(this.__folders,function(e){e.revert(e)}),e||r(this.getRoot(),!1)},listen:function(e){var t=0===this.__listening.length;this.__listening.push(e),t&&b(this.__listening)},updateDisplay:function(){U["default"].each(this.__controllers,function(e){e.updateDisplay()}),U["default"].each(this.__folders,function(e){e.updateDisplay()})}}),e.exports=oe},function(e,t){"use strict";e.exports={load:function(e,t){var n=t||document,o=n.createElement("link");o.type="text/css",o.rel="stylesheet",o.href=e,n.getElementsByTagName("head")[0].appendChild(o)},inject:function(e,t){var n=t||document,o=document.createElement("style");o.type="text/css",o.innerHTML=e;var i=n.getElementsByTagName("head")[0];try{i.appendChild(o)}catch(r){}}}},function(e,t){e.exports="<div id=dg-save class=\"dg dialogue\"> Here's the new load parameter for your <code>GUI</code>'s constructor: <textarea id=dg-new-constructor></textarea> <div id=dg-save-locally> <input id=dg-local-storage type=checkbox /> Automatically save values to <code>localStorage</code> on exit. <div id=dg-local-explain>The values saved to <code>localStorage</code> will override those passed to <code>dat.GUI</code>'s constructor. This makes it easier to work incrementally, but <code>localStorage</code> is fragile, and your friends may not see the same values you do. </div> </div> </div>"},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}t.__esModule=!0;var i=n(10),r=o(i),a=n(13),l=o(a),s=n(14),u=o(s),d=n(11),c=o(d),f=n(15),_=o(f),p=n(8),h=o(p),m=n(5),b=o(m),g=function(e,t){var n=e[t];return b["default"].isArray(arguments[2])||b["default"].isObject(arguments[2])?new r["default"](e,t,arguments[2]):b["default"].isNumber(n)?b["default"].isNumber(arguments[2])&&b["default"].isNumber(arguments[3])?b["default"].isNumber(arguments[4])?new u["default"](e,t,arguments[2],arguments[3],arguments[4]):new u["default"](e,t,arguments[2],arguments[3]):b["default"].isNumber(arguments[4])?new l["default"](e,t,{min:arguments[2],max:arguments[3],step:arguments[4]}):new l["default"](e,t,{min:arguments[2],max:arguments[3]}):b["default"].isString(n)?new c["default"](e,t):b["default"].isFunction(n)?new _["default"](e,t,""):b["default"].isBoolean(n)?new h["default"](e,t):null};t["default"]=g},function(e,t){"use strict";function n(e){setTimeout(e,1e3/60)}t.__esModule=!0,t["default"]=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||n},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}t.__esModule=!0;var r=n(9),a=o(r),l=n(5),s=o(l),u=function(){function e(){i(this,e),this.backgroundElement=document.createElement("div"),s["default"].extend(this.backgroundElement.style,{backgroundColor:"rgba(0,0,0,0.8)",top:0,left:0,display:"none",zIndex:"1000",opacity:0,WebkitTransition:"opacity 0.2s linear",transition:"opacity 0.2s linear"}),a["default"].makeFullscreen(this.backgroundElement),this.backgroundElement.style.position="fixed",this.domElement=document.createElement("div"),s["default"].extend(this.domElement.style,{position:"fixed",display:"none",zIndex:"1001",opacity:0,WebkitTransition:"-webkit-transform 0.2s ease-out, opacity 0.2s linear",transition:"transform 0.2s ease-out, opacity 0.2s linear"}),document.body.appendChild(this.backgroundElement),document.body.appendChild(this.domElement);var t=this;a["default"].bind(this.backgroundElement,"click",function(){t.hide()})}return e.prototype.show=function(){var e=this;this.backgroundElement.style.display="block",this.domElement.style.display="block",this.domElement.style.opacity=0,this.domElement.style.webkitTransform="scale(1.1)",this.layout(),s["default"].defer(function(){e.backgroundElement.style.opacity=1,e.domElement.style.opacity=1,e.domElement.style.webkitTransform="scale(1)"})},e.prototype.hide=function t(){var e=this,t=function n(){e.domElement.style.display="none",e.backgroundElement.style.display="none",a["default"].unbind(e.domElement,"webkitTransitionEnd",n),a["default"].unbind(e.domElement,"transitionend",n),a["default"].unbind(e.domElement,"oTransitionEnd",n)};a["default"].bind(this.domElement,"webkitTransitionEnd",t),a["default"].bind(this.domElement,"transitionend",t),a["default"].bind(this.domElement,"oTransitionEnd",t),this.backgroundElement.style.opacity=0,this.domElement.style.opacity=0,this.domElement.style.webkitTransform="scale(1.1)"},e.prototype.layout=function(){this.domElement.style.left=window.innerWidth/2-a["default"].getWidth(this.domElement)/2+"px",this.domElement.style.top=window.innerHeight/2-a["default"].getHeight(this.domElement)/2+"px"},e}();t["default"]=u},function(e,t,n){t=e.exports=n(24)(),t.push([e.id,".dg ul{list-style:none;margin:0;padding:0;width:100%;clear:both}.dg.ac{position:fixed;top:0;left:0;right:0;height:0;z-index:0}.dg:not(.ac) .main{overflow:hidden}.dg.main{-webkit-transition:opacity .1s linear;transition:opacity .1s linear}.dg.main.taller-than-window{overflow-y:auto}.dg.main.taller-than-window .close-button{opacity:1;margin-top:-1px;border-top:1px solid #2c2c2c}.dg.main ul.closed .close-button{opacity:1!important}.dg.main .close-button.drag,.dg.main:hover .close-button{opacity:1}.dg.main .close-button{-webkit-transition:opacity .1s linear;transition:opacity .1s linear;border:0;position:absolute;line-height:19px;height:20px;cursor:pointer;text-align:center;background-color:#000}.dg.main .close-button:hover{background-color:#111}.dg.a{float:right;margin-right:15px;overflow-x:hidden}.dg.a.has-save>ul{margin-top:27px}.dg.a.has-save>ul.closed{margin-top:0}.dg.a .save-row{position:fixed;top:0;z-index:1002}.dg li{-webkit-transition:height .1s ease-out;transition:height .1s ease-out}.dg li:not(.folder){cursor:auto;height:27px;line-height:27px;overflow:hidden;padding:0 4px 0 5px}.dg li.folder{padding:0;border-left:4px solid transparent}.dg li.title{cursor:pointer;margin-left:-4px}.dg .closed li:not(.title),.dg .closed ul li,.dg .closed ul li>*{height:0;overflow:hidden;border:0}.dg .cr{clear:both;padding-left:3px;height:27px}.dg .property-name{cursor:default;float:left;clear:left;width:40%;overflow:hidden;text-overflow:ellipsis}.dg .c{float:left;width:60%}.dg .c input[type=text]{border:0;margin-top:4px;padding:3px;width:100%;float:right}.dg .has-slider input[type=text]{width:30%;margin-left:0}.dg .slider{float:left;width:66%;margin-left:-5px;margin-right:0;height:19px;margin-top:4px}.dg .slider-fg{height:100%}.dg .c input[type=checkbox]{margin-top:9px}.dg .c select{margin-top:5px}.dg .cr.boolean,.dg .cr.boolean *,.dg .cr.function,.dg .cr.function *,.dg .cr.function .property-name{cursor:pointer}.dg .selector{display:none;position:absolute;margin-left:-9px;margin-top:23px;z-index:10}.dg .c:hover .selector,.dg .selector.drag{display:block}.dg li.save-row{padding:0}.dg li.save-row .button{display:inline-block;padding:0 6px}.dg.dialogue{background-color:#222;width:460px;padding:15px;font-size:13px;line-height:15px}#dg-new-constructor{padding:10px;color:#222;font-family:Monaco,monospace;font-size:10px;border:0;resize:none;box-shadow:inset 1px 1px 1px #888;word-wrap:break-word;margin:12px 0;display:block;width:440px;overflow-y:scroll;height:100px;position:relative}#dg-local-explain{display:none;font-size:11px;line-height:17px;border-radius:3px;background-color:#333;padding:8px;margin-top:10px}#dg-local-explain code{font-size:10px}#dat-gui-save-locally{display:none}.dg{color:#eee;font:11px Lucida Grande,sans-serif;text-shadow:0 -1px 0 #111}.dg.main::-webkit-scrollbar{width:5px;background:#1a1a1a}.dg.main::-webkit-scrollbar-corner{height:0;display:none}.dg.main::-webkit-scrollbar-thumb{border-radius:5px;background:#676767}.dg li:not(.folder){background:#1a1a1a;border-bottom:1px solid #2c2c2c}.dg li.save-row{line-height:25px;background:#dad5cb;border:0}.dg li.save-row select{margin-left:5px;width:108px}.dg li.save-row .button{margin-left:5px;margin-top:1px;border-radius:2px;font-size:9px;line-height:7px;padding:4px 4px 5px;background:#c5bdad;color:#fff;text-shadow:0 1px 0 #b0a58f;box-shadow:0 -1px 0 #b0a58f;cursor:pointer}.dg li.save-row .button.gears{background:#c5bdad url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAANCAYAAAB/9ZQ7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQJJREFUeNpiYKAU/P//PwGIC/ApCABiBSAW+I8AClAcgKxQ4T9hoMAEUrxx2QSGN6+egDX+/vWT4e7N82AMYoPAx/evwWoYoSYbACX2s7KxCxzcsezDh3evFoDEBYTEEqycggWAzA9AuUSQQgeYPa9fPv6/YWm/Acx5IPb7ty/fw+QZblw67vDs8R0YHyQhgObx+yAJkBqmG5dPPDh1aPOGR/eugW0G4vlIoTIfyFcA+QekhhHJhPdQxbiAIguMBTQZrPD7108M6roWYDFQiIAAv6Aow/1bFwXgis+f2LUAynwoIaNcz8XNx3Dl7MEJUDGQpx9gtQ8YCueB+D26OECAAQDadt7e46D42QAAAABJRU5ErkJggg==) 2px 1px no-repeat;height:7px;width:8px}.dg li.save-row .button:hover{background-color:#bab19e;box-shadow:0 -1px 0 #b0a58f}.dg li.folder{border-bottom:0}.dg li.title{padding-left:16px;background:#000 url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlI+hKgFxoCgAOw==) 6px 10px no-repeat;cursor:pointer;border-bottom:1px solid hsla(0,0%,100%,.2)}.dg .closed li.title{background-image:url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlGIWqMCbWAEAOw==)}.dg .cr.boolean{border-left:3px solid #806787}.dg .cr.color{border-left:3px solid}.dg .cr.function{border-left:3px solid #e61d5f}.dg .cr.number{border-left:3px solid #2fa1d6}.dg .cr.number input[type=text]{color:#2fa1d6}.dg .cr.string{border-left:3px solid #1ed36f}.dg .cr.string input[type=text]{color:#1ed36f}.dg .cr.boolean:hover,.dg .cr.function:hover{background:#111}.dg .c input[type=text]{background:#303030;outline:none}.dg .c input[type=text]:hover{background:#3c3c3c}.dg .c input[type=text]:focus{background:#494949;color:#fff}.dg .c .slider{background:#303030;cursor:ew-resize}.dg .c .slider-fg{background:#2fa1d6;max-width:100%}.dg .c .slider:hover{background:#3c3c3c}.dg .c .slider:hover .slider-fg{background:#44abda}",""])},function(e,t){e.exports=function(){var e=[];return e.toString=function(){for(var e=[],t=0;t<this.length;t++){var n=this[t];n[2]?e.push("@media "+n[2]+"{"+n[1]+"}"):e.push(n[1])}return e.join("")},e.i=function(t,n){"string"==typeof t&&(t=[[null,t,""]]);for(var o={},i=0;i<this.length;i++){var r=this[i][0];"number"==typeof r&&(o[r]=!0)}for(i=0;i<t.length;i++){var a=t[i];"number"==typeof a[0]&&o[a[0]]||(n&&!a[2]?a[2]=n:n&&(a[2]="("+a[2]+") and ("+n+")"),e.push(a))}},e}}])}); \ No newline at end of file diff --git a/js/scripts/jquery-ui.min.js b/js/scripts/jquery-ui.min.js new file mode 100644 index 00000000000..25398a16741 --- /dev/null +++ b/js/scripts/jquery-ui.min.js @@ -0,0 +1,13 @@ +/*! jQuery UI - v1.12.1 - 2016-09-14 +* http://jqueryui.com +* Includes: widget.js, position.js, data.js, disable-selection.js, effect.js, effects/effect-blind.js, effects/effect-bounce.js, effects/effect-clip.js, effects/effect-drop.js, effects/effect-explode.js, effects/effect-fade.js, effects/effect-fold.js, effects/effect-highlight.js, effects/effect-puff.js, effects/effect-pulsate.js, effects/effect-scale.js, effects/effect-shake.js, effects/effect-size.js, effects/effect-slide.js, effects/effect-transfer.js, focusable.js, form-reset-mixin.js, jquery-1-7.js, keycode.js, labels.js, scroll-parent.js, tabbable.js, unique-id.js, widgets/accordion.js, widgets/autocomplete.js, widgets/button.js, widgets/checkboxradio.js, widgets/controlgroup.js, widgets/datepicker.js, widgets/dialog.js, widgets/draggable.js, widgets/droppable.js, widgets/menu.js, widgets/mouse.js, widgets/progressbar.js, widgets/resizable.js, widgets/selectable.js, widgets/selectmenu.js, widgets/slider.js, widgets/sortable.js, widgets/spinner.js, widgets/tabs.js, widgets/tooltip.js +* Copyright jQuery Foundation and other contributors; Licensed MIT */ + +(function(t){"function"==typeof define&&define.amd?define(["jquery"],t):t(jQuery)})(function(t){function e(t){for(var e=t.css("visibility");"inherit"===e;)t=t.parent(),e=t.css("visibility");return"hidden"!==e}function i(t){for(var e,i;t.length&&t[0]!==document;){if(e=t.css("position"),("absolute"===e||"relative"===e||"fixed"===e)&&(i=parseInt(t.css("zIndex"),10),!isNaN(i)&&0!==i))return i;t=t.parent()}return 0}function s(){this._curInst=null,this._keyEvent=!1,this._disabledInputs=[],this._datepickerShowing=!1,this._inDialog=!1,this._mainDivId="ui-datepicker-div",this._inlineClass="ui-datepicker-inline",this._appendClass="ui-datepicker-append",this._triggerClass="ui-datepicker-trigger",this._dialogClass="ui-datepicker-dialog",this._disableClass="ui-datepicker-disabled",this._unselectableClass="ui-datepicker-unselectable",this._currentClass="ui-datepicker-current-day",this._dayOverClass="ui-datepicker-days-cell-over",this.regional=[],this.regional[""]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su","Mo","Tu","We","Th","Fr","Sa"],weekHeader:"Wk",dateFormat:"mm/dd/yy",firstDay:0,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},this._defaults={showOn:"focus",showAnim:"fadeIn",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:!1,hideIfNoPrevNext:!1,navigationAsDateFormat:!1,gotoCurrent:!1,changeMonth:!1,changeYear:!1,yearRange:"c-10:c+10",showOtherMonths:!1,selectOtherMonths:!1,showWeek:!1,calculateWeek:this.iso8601Week,shortYearCutoff:"+10",minDate:null,maxDate:null,duration:"fast",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:!0,showButtonPanel:!1,autoSize:!1,disabled:!1},t.extend(this._defaults,this.regional[""]),this.regional.en=t.extend(!0,{},this.regional[""]),this.regional["en-US"]=t.extend(!0,{},this.regional.en),this.dpDiv=n(t("<div id='"+this._mainDivId+"' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>"))}function n(e){var i="button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";return e.on("mouseout",i,function(){t(this).removeClass("ui-state-hover"),-1!==this.className.indexOf("ui-datepicker-prev")&&t(this).removeClass("ui-datepicker-prev-hover"),-1!==this.className.indexOf("ui-datepicker-next")&&t(this).removeClass("ui-datepicker-next-hover")}).on("mouseover",i,o)}function o(){t.datepicker._isDisabledDatepicker(m.inline?m.dpDiv.parent()[0]:m.input[0])||(t(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"),t(this).addClass("ui-state-hover"),-1!==this.className.indexOf("ui-datepicker-prev")&&t(this).addClass("ui-datepicker-prev-hover"),-1!==this.className.indexOf("ui-datepicker-next")&&t(this).addClass("ui-datepicker-next-hover"))}function a(e,i){t.extend(e,i);for(var s in i)null==i[s]&&(e[s]=i[s]);return e}function r(t){return function(){var e=this.element.val();t.apply(this,arguments),this._refresh(),e!==this.element.val()&&this._trigger("change")}}t.ui=t.ui||{},t.ui.version="1.12.1";var h=0,l=Array.prototype.slice;t.cleanData=function(e){return function(i){var s,n,o;for(o=0;null!=(n=i[o]);o++)try{s=t._data(n,"events"),s&&s.remove&&t(n).triggerHandler("remove")}catch(a){}e(i)}}(t.cleanData),t.widget=function(e,i,s){var n,o,a,r={},h=e.split(".")[0];e=e.split(".")[1];var l=h+"-"+e;return s||(s=i,i=t.Widget),t.isArray(s)&&(s=t.extend.apply(null,[{}].concat(s))),t.expr[":"][l.toLowerCase()]=function(e){return!!t.data(e,l)},t[h]=t[h]||{},n=t[h][e],o=t[h][e]=function(t,e){return this._createWidget?(arguments.length&&this._createWidget(t,e),void 0):new o(t,e)},t.extend(o,n,{version:s.version,_proto:t.extend({},s),_childConstructors:[]}),a=new i,a.options=t.widget.extend({},a.options),t.each(s,function(e,s){return t.isFunction(s)?(r[e]=function(){function t(){return i.prototype[e].apply(this,arguments)}function n(t){return i.prototype[e].apply(this,t)}return function(){var e,i=this._super,o=this._superApply;return this._super=t,this._superApply=n,e=s.apply(this,arguments),this._super=i,this._superApply=o,e}}(),void 0):(r[e]=s,void 0)}),o.prototype=t.widget.extend(a,{widgetEventPrefix:n?a.widgetEventPrefix||e:e},r,{constructor:o,namespace:h,widgetName:e,widgetFullName:l}),n?(t.each(n._childConstructors,function(e,i){var s=i.prototype;t.widget(s.namespace+"."+s.widgetName,o,i._proto)}),delete n._childConstructors):i._childConstructors.push(o),t.widget.bridge(e,o),o},t.widget.extend=function(e){for(var i,s,n=l.call(arguments,1),o=0,a=n.length;a>o;o++)for(i in n[o])s=n[o][i],n[o].hasOwnProperty(i)&&void 0!==s&&(e[i]=t.isPlainObject(s)?t.isPlainObject(e[i])?t.widget.extend({},e[i],s):t.widget.extend({},s):s);return e},t.widget.bridge=function(e,i){var s=i.prototype.widgetFullName||e;t.fn[e]=function(n){var o="string"==typeof n,a=l.call(arguments,1),r=this;return o?this.length||"instance"!==n?this.each(function(){var i,o=t.data(this,s);return"instance"===n?(r=o,!1):o?t.isFunction(o[n])&&"_"!==n.charAt(0)?(i=o[n].apply(o,a),i!==o&&void 0!==i?(r=i&&i.jquery?r.pushStack(i.get()):i,!1):void 0):t.error("no such method '"+n+"' for "+e+" widget instance"):t.error("cannot call methods on "+e+" prior to initialization; "+"attempted to call method '"+n+"'")}):r=void 0:(a.length&&(n=t.widget.extend.apply(null,[n].concat(a))),this.each(function(){var e=t.data(this,s);e?(e.option(n||{}),e._init&&e._init()):t.data(this,s,new i(n,this))})),r}},t.Widget=function(){},t.Widget._childConstructors=[],t.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"<div>",options:{classes:{},disabled:!1,create:null},_createWidget:function(e,i){i=t(i||this.defaultElement||this)[0],this.element=t(i),this.uuid=h++,this.eventNamespace="."+this.widgetName+this.uuid,this.bindings=t(),this.hoverable=t(),this.focusable=t(),this.classesElementLookup={},i!==this&&(t.data(i,this.widgetFullName,this),this._on(!0,this.element,{remove:function(t){t.target===i&&this.destroy()}}),this.document=t(i.style?i.ownerDocument:i.document||i),this.window=t(this.document[0].defaultView||this.document[0].parentWindow)),this.options=t.widget.extend({},this.options,this._getCreateOptions(),e),this._create(),this.options.disabled&&this._setOptionDisabled(this.options.disabled),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:function(){return{}},_getCreateEventData:t.noop,_create:t.noop,_init:t.noop,destroy:function(){var e=this;this._destroy(),t.each(this.classesElementLookup,function(t,i){e._removeClass(i,t)}),this.element.off(this.eventNamespace).removeData(this.widgetFullName),this.widget().off(this.eventNamespace).removeAttr("aria-disabled"),this.bindings.off(this.eventNamespace)},_destroy:t.noop,widget:function(){return this.element},option:function(e,i){var s,n,o,a=e;if(0===arguments.length)return t.widget.extend({},this.options);if("string"==typeof e)if(a={},s=e.split("."),e=s.shift(),s.length){for(n=a[e]=t.widget.extend({},this.options[e]),o=0;s.length-1>o;o++)n[s[o]]=n[s[o]]||{},n=n[s[o]];if(e=s.pop(),1===arguments.length)return void 0===n[e]?null:n[e];n[e]=i}else{if(1===arguments.length)return void 0===this.options[e]?null:this.options[e];a[e]=i}return this._setOptions(a),this},_setOptions:function(t){var e;for(e in t)this._setOption(e,t[e]);return this},_setOption:function(t,e){return"classes"===t&&this._setOptionClasses(e),this.options[t]=e,"disabled"===t&&this._setOptionDisabled(e),this},_setOptionClasses:function(e){var i,s,n;for(i in e)n=this.classesElementLookup[i],e[i]!==this.options.classes[i]&&n&&n.length&&(s=t(n.get()),this._removeClass(n,i),s.addClass(this._classes({element:s,keys:i,classes:e,add:!0})))},_setOptionDisabled:function(t){this._toggleClass(this.widget(),this.widgetFullName+"-disabled",null,!!t),t&&(this._removeClass(this.hoverable,null,"ui-state-hover"),this._removeClass(this.focusable,null,"ui-state-focus"))},enable:function(){return this._setOptions({disabled:!1})},disable:function(){return this._setOptions({disabled:!0})},_classes:function(e){function i(i,o){var a,r;for(r=0;i.length>r;r++)a=n.classesElementLookup[i[r]]||t(),a=e.add?t(t.unique(a.get().concat(e.element.get()))):t(a.not(e.element).get()),n.classesElementLookup[i[r]]=a,s.push(i[r]),o&&e.classes[i[r]]&&s.push(e.classes[i[r]])}var s=[],n=this;return e=t.extend({element:this.element,classes:this.options.classes||{}},e),this._on(e.element,{remove:"_untrackClassesElement"}),e.keys&&i(e.keys.match(/\S+/g)||[],!0),e.extra&&i(e.extra.match(/\S+/g)||[]),s.join(" ")},_untrackClassesElement:function(e){var i=this;t.each(i.classesElementLookup,function(s,n){-1!==t.inArray(e.target,n)&&(i.classesElementLookup[s]=t(n.not(e.target).get()))})},_removeClass:function(t,e,i){return this._toggleClass(t,e,i,!1)},_addClass:function(t,e,i){return this._toggleClass(t,e,i,!0)},_toggleClass:function(t,e,i,s){s="boolean"==typeof s?s:i;var n="string"==typeof t||null===t,o={extra:n?e:i,keys:n?t:e,element:n?this.element:t,add:s};return o.element.toggleClass(this._classes(o),s),this},_on:function(e,i,s){var n,o=this;"boolean"!=typeof e&&(s=i,i=e,e=!1),s?(i=n=t(i),this.bindings=this.bindings.add(i)):(s=i,i=this.element,n=this.widget()),t.each(s,function(s,a){function r(){return e||o.options.disabled!==!0&&!t(this).hasClass("ui-state-disabled")?("string"==typeof a?o[a]:a).apply(o,arguments):void 0}"string"!=typeof a&&(r.guid=a.guid=a.guid||r.guid||t.guid++);var h=s.match(/^([\w:-]*)\s*(.*)$/),l=h[1]+o.eventNamespace,c=h[2];c?n.on(l,c,r):i.on(l,r)})},_off:function(e,i){i=(i||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,e.off(i).off(i),this.bindings=t(this.bindings.not(e).get()),this.focusable=t(this.focusable.not(e).get()),this.hoverable=t(this.hoverable.not(e).get())},_delay:function(t,e){function i(){return("string"==typeof t?s[t]:t).apply(s,arguments)}var s=this;return setTimeout(i,e||0)},_hoverable:function(e){this.hoverable=this.hoverable.add(e),this._on(e,{mouseenter:function(e){this._addClass(t(e.currentTarget),null,"ui-state-hover")},mouseleave:function(e){this._removeClass(t(e.currentTarget),null,"ui-state-hover")}})},_focusable:function(e){this.focusable=this.focusable.add(e),this._on(e,{focusin:function(e){this._addClass(t(e.currentTarget),null,"ui-state-focus")},focusout:function(e){this._removeClass(t(e.currentTarget),null,"ui-state-focus")}})},_trigger:function(e,i,s){var n,o,a=this.options[e];if(s=s||{},i=t.Event(i),i.type=(e===this.widgetEventPrefix?e:this.widgetEventPrefix+e).toLowerCase(),i.target=this.element[0],o=i.originalEvent)for(n in o)n in i||(i[n]=o[n]);return this.element.trigger(i,s),!(t.isFunction(a)&&a.apply(this.element[0],[i].concat(s))===!1||i.isDefaultPrevented())}},t.each({show:"fadeIn",hide:"fadeOut"},function(e,i){t.Widget.prototype["_"+e]=function(s,n,o){"string"==typeof n&&(n={effect:n});var a,r=n?n===!0||"number"==typeof n?i:n.effect||i:e;n=n||{},"number"==typeof n&&(n={duration:n}),a=!t.isEmptyObject(n),n.complete=o,n.delay&&s.delay(n.delay),a&&t.effects&&t.effects.effect[r]?s[e](n):r!==e&&s[r]?s[r](n.duration,n.easing,o):s.queue(function(i){t(this)[e](),o&&o.call(s[0]),i()})}}),t.widget,function(){function e(t,e,i){return[parseFloat(t[0])*(u.test(t[0])?e/100:1),parseFloat(t[1])*(u.test(t[1])?i/100:1)]}function i(e,i){return parseInt(t.css(e,i),10)||0}function s(e){var i=e[0];return 9===i.nodeType?{width:e.width(),height:e.height(),offset:{top:0,left:0}}:t.isWindow(i)?{width:e.width(),height:e.height(),offset:{top:e.scrollTop(),left:e.scrollLeft()}}:i.preventDefault?{width:0,height:0,offset:{top:i.pageY,left:i.pageX}}:{width:e.outerWidth(),height:e.outerHeight(),offset:e.offset()}}var n,o=Math.max,a=Math.abs,r=/left|center|right/,h=/top|center|bottom/,l=/[\+\-]\d+(\.[\d]+)?%?/,c=/^\w+/,u=/%$/,d=t.fn.position;t.position={scrollbarWidth:function(){if(void 0!==n)return n;var e,i,s=t("<div style='display:block;position:absolute;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>"),o=s.children()[0];return t("body").append(s),e=o.offsetWidth,s.css("overflow","scroll"),i=o.offsetWidth,e===i&&(i=s[0].clientWidth),s.remove(),n=e-i},getScrollInfo:function(e){var i=e.isWindow||e.isDocument?"":e.element.css("overflow-x"),s=e.isWindow||e.isDocument?"":e.element.css("overflow-y"),n="scroll"===i||"auto"===i&&e.width<e.element[0].scrollWidth,o="scroll"===s||"auto"===s&&e.height<e.element[0].scrollHeight;return{width:o?t.position.scrollbarWidth():0,height:n?t.position.scrollbarWidth():0}},getWithinInfo:function(e){var i=t(e||window),s=t.isWindow(i[0]),n=!!i[0]&&9===i[0].nodeType,o=!s&&!n;return{element:i,isWindow:s,isDocument:n,offset:o?t(e).offset():{left:0,top:0},scrollLeft:i.scrollLeft(),scrollTop:i.scrollTop(),width:i.outerWidth(),height:i.outerHeight()}}},t.fn.position=function(n){if(!n||!n.of)return d.apply(this,arguments);n=t.extend({},n);var u,p,f,g,m,_,v=t(n.of),b=t.position.getWithinInfo(n.within),y=t.position.getScrollInfo(b),w=(n.collision||"flip").split(" "),k={};return _=s(v),v[0].preventDefault&&(n.at="left top"),p=_.width,f=_.height,g=_.offset,m=t.extend({},g),t.each(["my","at"],function(){var t,e,i=(n[this]||"").split(" ");1===i.length&&(i=r.test(i[0])?i.concat(["center"]):h.test(i[0])?["center"].concat(i):["center","center"]),i[0]=r.test(i[0])?i[0]:"center",i[1]=h.test(i[1])?i[1]:"center",t=l.exec(i[0]),e=l.exec(i[1]),k[this]=[t?t[0]:0,e?e[0]:0],n[this]=[c.exec(i[0])[0],c.exec(i[1])[0]]}),1===w.length&&(w[1]=w[0]),"right"===n.at[0]?m.left+=p:"center"===n.at[0]&&(m.left+=p/2),"bottom"===n.at[1]?m.top+=f:"center"===n.at[1]&&(m.top+=f/2),u=e(k.at,p,f),m.left+=u[0],m.top+=u[1],this.each(function(){var s,r,h=t(this),l=h.outerWidth(),c=h.outerHeight(),d=i(this,"marginLeft"),_=i(this,"marginTop"),x=l+d+i(this,"marginRight")+y.width,C=c+_+i(this,"marginBottom")+y.height,D=t.extend({},m),I=e(k.my,h.outerWidth(),h.outerHeight());"right"===n.my[0]?D.left-=l:"center"===n.my[0]&&(D.left-=l/2),"bottom"===n.my[1]?D.top-=c:"center"===n.my[1]&&(D.top-=c/2),D.left+=I[0],D.top+=I[1],s={marginLeft:d,marginTop:_},t.each(["left","top"],function(e,i){t.ui.position[w[e]]&&t.ui.position[w[e]][i](D,{targetWidth:p,targetHeight:f,elemWidth:l,elemHeight:c,collisionPosition:s,collisionWidth:x,collisionHeight:C,offset:[u[0]+I[0],u[1]+I[1]],my:n.my,at:n.at,within:b,elem:h})}),n.using&&(r=function(t){var e=g.left-D.left,i=e+p-l,s=g.top-D.top,r=s+f-c,u={target:{element:v,left:g.left,top:g.top,width:p,height:f},element:{element:h,left:D.left,top:D.top,width:l,height:c},horizontal:0>i?"left":e>0?"right":"center",vertical:0>r?"top":s>0?"bottom":"middle"};l>p&&p>a(e+i)&&(u.horizontal="center"),c>f&&f>a(s+r)&&(u.vertical="middle"),u.important=o(a(e),a(i))>o(a(s),a(r))?"horizontal":"vertical",n.using.call(this,t,u)}),h.offset(t.extend(D,{using:r}))})},t.ui.position={fit:{left:function(t,e){var i,s=e.within,n=s.isWindow?s.scrollLeft:s.offset.left,a=s.width,r=t.left-e.collisionPosition.marginLeft,h=n-r,l=r+e.collisionWidth-a-n;e.collisionWidth>a?h>0&&0>=l?(i=t.left+h+e.collisionWidth-a-n,t.left+=h-i):t.left=l>0&&0>=h?n:h>l?n+a-e.collisionWidth:n:h>0?t.left+=h:l>0?t.left-=l:t.left=o(t.left-r,t.left)},top:function(t,e){var i,s=e.within,n=s.isWindow?s.scrollTop:s.offset.top,a=e.within.height,r=t.top-e.collisionPosition.marginTop,h=n-r,l=r+e.collisionHeight-a-n;e.collisionHeight>a?h>0&&0>=l?(i=t.top+h+e.collisionHeight-a-n,t.top+=h-i):t.top=l>0&&0>=h?n:h>l?n+a-e.collisionHeight:n:h>0?t.top+=h:l>0?t.top-=l:t.top=o(t.top-r,t.top)}},flip:{left:function(t,e){var i,s,n=e.within,o=n.offset.left+n.scrollLeft,r=n.width,h=n.isWindow?n.scrollLeft:n.offset.left,l=t.left-e.collisionPosition.marginLeft,c=l-h,u=l+e.collisionWidth-r-h,d="left"===e.my[0]?-e.elemWidth:"right"===e.my[0]?e.elemWidth:0,p="left"===e.at[0]?e.targetWidth:"right"===e.at[0]?-e.targetWidth:0,f=-2*e.offset[0];0>c?(i=t.left+d+p+f+e.collisionWidth-r-o,(0>i||a(c)>i)&&(t.left+=d+p+f)):u>0&&(s=t.left-e.collisionPosition.marginLeft+d+p+f-h,(s>0||u>a(s))&&(t.left+=d+p+f))},top:function(t,e){var i,s,n=e.within,o=n.offset.top+n.scrollTop,r=n.height,h=n.isWindow?n.scrollTop:n.offset.top,l=t.top-e.collisionPosition.marginTop,c=l-h,u=l+e.collisionHeight-r-h,d="top"===e.my[1],p=d?-e.elemHeight:"bottom"===e.my[1]?e.elemHeight:0,f="top"===e.at[1]?e.targetHeight:"bottom"===e.at[1]?-e.targetHeight:0,g=-2*e.offset[1];0>c?(s=t.top+p+f+g+e.collisionHeight-r-o,(0>s||a(c)>s)&&(t.top+=p+f+g)):u>0&&(i=t.top-e.collisionPosition.marginTop+p+f+g-h,(i>0||u>a(i))&&(t.top+=p+f+g))}},flipfit:{left:function(){t.ui.position.flip.left.apply(this,arguments),t.ui.position.fit.left.apply(this,arguments)},top:function(){t.ui.position.flip.top.apply(this,arguments),t.ui.position.fit.top.apply(this,arguments)}}}}(),t.ui.position,t.extend(t.expr[":"],{data:t.expr.createPseudo?t.expr.createPseudo(function(e){return function(i){return!!t.data(i,e)}}):function(e,i,s){return!!t.data(e,s[3])}}),t.fn.extend({disableSelection:function(){var t="onselectstart"in document.createElement("div")?"selectstart":"mousedown";return function(){return this.on(t+".ui-disableSelection",function(t){t.preventDefault()})}}(),enableSelection:function(){return this.off(".ui-disableSelection")}});var c="ui-effects-",u="ui-effects-style",d="ui-effects-animated",p=t;t.effects={effect:{}},function(t,e){function i(t,e,i){var s=u[e.type]||{};return null==t?i||!e.def?null:e.def:(t=s.floor?~~t:parseFloat(t),isNaN(t)?e.def:s.mod?(t+s.mod)%s.mod:0>t?0:t>s.max?s.max:t)}function s(i){var s=l(),n=s._rgba=[];return i=i.toLowerCase(),f(h,function(t,o){var a,r=o.re.exec(i),h=r&&o.parse(r),l=o.space||"rgba";return h?(a=s[l](h),s[c[l].cache]=a[c[l].cache],n=s._rgba=a._rgba,!1):e}),n.length?("0,0,0,0"===n.join()&&t.extend(n,o.transparent),s):o[i]}function n(t,e,i){return i=(i+1)%1,1>6*i?t+6*(e-t)*i:1>2*i?e:2>3*i?t+6*(e-t)*(2/3-i):t}var o,a="backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",r=/^([\-+])=\s*(\d+\.?\d*)/,h=[{re:/rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,parse:function(t){return[t[1],t[2],t[3],t[4]]}},{re:/rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,parse:function(t){return[2.55*t[1],2.55*t[2],2.55*t[3],t[4]]}},{re:/#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,parse:function(t){return[parseInt(t[1],16),parseInt(t[2],16),parseInt(t[3],16)]}},{re:/#([a-f0-9])([a-f0-9])([a-f0-9])/,parse:function(t){return[parseInt(t[1]+t[1],16),parseInt(t[2]+t[2],16),parseInt(t[3]+t[3],16)]}},{re:/hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,space:"hsla",parse:function(t){return[t[1],t[2]/100,t[3]/100,t[4]]}}],l=t.Color=function(e,i,s,n){return new t.Color.fn.parse(e,i,s,n)},c={rgba:{props:{red:{idx:0,type:"byte"},green:{idx:1,type:"byte"},blue:{idx:2,type:"byte"}}},hsla:{props:{hue:{idx:0,type:"degrees"},saturation:{idx:1,type:"percent"},lightness:{idx:2,type:"percent"}}}},u={"byte":{floor:!0,max:255},percent:{max:1},degrees:{mod:360,floor:!0}},d=l.support={},p=t("<p>")[0],f=t.each;p.style.cssText="background-color:rgba(1,1,1,.5)",d.rgba=p.style.backgroundColor.indexOf("rgba")>-1,f(c,function(t,e){e.cache="_"+t,e.props.alpha={idx:3,type:"percent",def:1}}),l.fn=t.extend(l.prototype,{parse:function(n,a,r,h){if(n===e)return this._rgba=[null,null,null,null],this;(n.jquery||n.nodeType)&&(n=t(n).css(a),a=e);var u=this,d=t.type(n),p=this._rgba=[];return a!==e&&(n=[n,a,r,h],d="array"),"string"===d?this.parse(s(n)||o._default):"array"===d?(f(c.rgba.props,function(t,e){p[e.idx]=i(n[e.idx],e)}),this):"object"===d?(n instanceof l?f(c,function(t,e){n[e.cache]&&(u[e.cache]=n[e.cache].slice())}):f(c,function(e,s){var o=s.cache;f(s.props,function(t,e){if(!u[o]&&s.to){if("alpha"===t||null==n[t])return;u[o]=s.to(u._rgba)}u[o][e.idx]=i(n[t],e,!0)}),u[o]&&0>t.inArray(null,u[o].slice(0,3))&&(u[o][3]=1,s.from&&(u._rgba=s.from(u[o])))}),this):e},is:function(t){var i=l(t),s=!0,n=this;return f(c,function(t,o){var a,r=i[o.cache];return r&&(a=n[o.cache]||o.to&&o.to(n._rgba)||[],f(o.props,function(t,i){return null!=r[i.idx]?s=r[i.idx]===a[i.idx]:e})),s}),s},_space:function(){var t=[],e=this;return f(c,function(i,s){e[s.cache]&&t.push(i)}),t.pop()},transition:function(t,e){var s=l(t),n=s._space(),o=c[n],a=0===this.alpha()?l("transparent"):this,r=a[o.cache]||o.to(a._rgba),h=r.slice();return s=s[o.cache],f(o.props,function(t,n){var o=n.idx,a=r[o],l=s[o],c=u[n.type]||{};null!==l&&(null===a?h[o]=l:(c.mod&&(l-a>c.mod/2?a+=c.mod:a-l>c.mod/2&&(a-=c.mod)),h[o]=i((l-a)*e+a,n)))}),this[n](h)},blend:function(e){if(1===this._rgba[3])return this;var i=this._rgba.slice(),s=i.pop(),n=l(e)._rgba;return l(t.map(i,function(t,e){return(1-s)*n[e]+s*t}))},toRgbaString:function(){var e="rgba(",i=t.map(this._rgba,function(t,e){return null==t?e>2?1:0:t});return 1===i[3]&&(i.pop(),e="rgb("),e+i.join()+")"},toHslaString:function(){var e="hsla(",i=t.map(this.hsla(),function(t,e){return null==t&&(t=e>2?1:0),e&&3>e&&(t=Math.round(100*t)+"%"),t});return 1===i[3]&&(i.pop(),e="hsl("),e+i.join()+")"},toHexString:function(e){var i=this._rgba.slice(),s=i.pop();return e&&i.push(~~(255*s)),"#"+t.map(i,function(t){return t=(t||0).toString(16),1===t.length?"0"+t:t}).join("")},toString:function(){return 0===this._rgba[3]?"transparent":this.toRgbaString()}}),l.fn.parse.prototype=l.fn,c.hsla.to=function(t){if(null==t[0]||null==t[1]||null==t[2])return[null,null,null,t[3]];var e,i,s=t[0]/255,n=t[1]/255,o=t[2]/255,a=t[3],r=Math.max(s,n,o),h=Math.min(s,n,o),l=r-h,c=r+h,u=.5*c;return e=h===r?0:s===r?60*(n-o)/l+360:n===r?60*(o-s)/l+120:60*(s-n)/l+240,i=0===l?0:.5>=u?l/c:l/(2-c),[Math.round(e)%360,i,u,null==a?1:a]},c.hsla.from=function(t){if(null==t[0]||null==t[1]||null==t[2])return[null,null,null,t[3]];var e=t[0]/360,i=t[1],s=t[2],o=t[3],a=.5>=s?s*(1+i):s+i-s*i,r=2*s-a;return[Math.round(255*n(r,a,e+1/3)),Math.round(255*n(r,a,e)),Math.round(255*n(r,a,e-1/3)),o]},f(c,function(s,n){var o=n.props,a=n.cache,h=n.to,c=n.from;l.fn[s]=function(s){if(h&&!this[a]&&(this[a]=h(this._rgba)),s===e)return this[a].slice();var n,r=t.type(s),u="array"===r||"object"===r?s:arguments,d=this[a].slice();return f(o,function(t,e){var s=u["object"===r?t:e.idx];null==s&&(s=d[e.idx]),d[e.idx]=i(s,e)}),c?(n=l(c(d)),n[a]=d,n):l(d)},f(o,function(e,i){l.fn[e]||(l.fn[e]=function(n){var o,a=t.type(n),h="alpha"===e?this._hsla?"hsla":"rgba":s,l=this[h](),c=l[i.idx];return"undefined"===a?c:("function"===a&&(n=n.call(this,c),a=t.type(n)),null==n&&i.empty?this:("string"===a&&(o=r.exec(n),o&&(n=c+parseFloat(o[2])*("+"===o[1]?1:-1))),l[i.idx]=n,this[h](l)))})})}),l.hook=function(e){var i=e.split(" ");f(i,function(e,i){t.cssHooks[i]={set:function(e,n){var o,a,r="";if("transparent"!==n&&("string"!==t.type(n)||(o=s(n)))){if(n=l(o||n),!d.rgba&&1!==n._rgba[3]){for(a="backgroundColor"===i?e.parentNode:e;(""===r||"transparent"===r)&&a&&a.style;)try{r=t.css(a,"backgroundColor"),a=a.parentNode}catch(h){}n=n.blend(r&&"transparent"!==r?r:"_default")}n=n.toRgbaString()}try{e.style[i]=n}catch(h){}}},t.fx.step[i]=function(e){e.colorInit||(e.start=l(e.elem,i),e.end=l(e.end),e.colorInit=!0),t.cssHooks[i].set(e.elem,e.start.transition(e.end,e.pos))}})},l.hook(a),t.cssHooks.borderColor={expand:function(t){var e={};return f(["Top","Right","Bottom","Left"],function(i,s){e["border"+s+"Color"]=t}),e}},o=t.Color.names={aqua:"#00ffff",black:"#000000",blue:"#0000ff",fuchsia:"#ff00ff",gray:"#808080",green:"#008000",lime:"#00ff00",maroon:"#800000",navy:"#000080",olive:"#808000",purple:"#800080",red:"#ff0000",silver:"#c0c0c0",teal:"#008080",white:"#ffffff",yellow:"#ffff00",transparent:[null,null,null,0],_default:"#ffffff"}}(p),function(){function e(e){var i,s,n=e.ownerDocument.defaultView?e.ownerDocument.defaultView.getComputedStyle(e,null):e.currentStyle,o={};if(n&&n.length&&n[0]&&n[n[0]])for(s=n.length;s--;)i=n[s],"string"==typeof n[i]&&(o[t.camelCase(i)]=n[i]);else for(i in n)"string"==typeof n[i]&&(o[i]=n[i]);return o}function i(e,i){var s,o,a={};for(s in i)o=i[s],e[s]!==o&&(n[s]||(t.fx.step[s]||!isNaN(parseFloat(o)))&&(a[s]=o));return a}var s=["add","remove","toggle"],n={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};t.each(["borderLeftStyle","borderRightStyle","borderBottomStyle","borderTopStyle"],function(e,i){t.fx.step[i]=function(t){("none"!==t.end&&!t.setAttr||1===t.pos&&!t.setAttr)&&(p.style(t.elem,i,t.end),t.setAttr=!0)}}),t.fn.addBack||(t.fn.addBack=function(t){return this.add(null==t?this.prevObject:this.prevObject.filter(t))}),t.effects.animateClass=function(n,o,a,r){var h=t.speed(o,a,r);return this.queue(function(){var o,a=t(this),r=a.attr("class")||"",l=h.children?a.find("*").addBack():a;l=l.map(function(){var i=t(this);return{el:i,start:e(this)}}),o=function(){t.each(s,function(t,e){n[e]&&a[e+"Class"](n[e])})},o(),l=l.map(function(){return this.end=e(this.el[0]),this.diff=i(this.start,this.end),this}),a.attr("class",r),l=l.map(function(){var e=this,i=t.Deferred(),s=t.extend({},h,{queue:!1,complete:function(){i.resolve(e)}});return this.el.animate(this.diff,s),i.promise()}),t.when.apply(t,l.get()).done(function(){o(),t.each(arguments,function(){var e=this.el;t.each(this.diff,function(t){e.css(t,"")})}),h.complete.call(a[0])})})},t.fn.extend({addClass:function(e){return function(i,s,n,o){return s?t.effects.animateClass.call(this,{add:i},s,n,o):e.apply(this,arguments)}}(t.fn.addClass),removeClass:function(e){return function(i,s,n,o){return arguments.length>1?t.effects.animateClass.call(this,{remove:i},s,n,o):e.apply(this,arguments)}}(t.fn.removeClass),toggleClass:function(e){return function(i,s,n,o,a){return"boolean"==typeof s||void 0===s?n?t.effects.animateClass.call(this,s?{add:i}:{remove:i},n,o,a):e.apply(this,arguments):t.effects.animateClass.call(this,{toggle:i},s,n,o)}}(t.fn.toggleClass),switchClass:function(e,i,s,n,o){return t.effects.animateClass.call(this,{add:i,remove:e},s,n,o)}})}(),function(){function e(e,i,s,n){return t.isPlainObject(e)&&(i=e,e=e.effect),e={effect:e},null==i&&(i={}),t.isFunction(i)&&(n=i,s=null,i={}),("number"==typeof i||t.fx.speeds[i])&&(n=s,s=i,i={}),t.isFunction(s)&&(n=s,s=null),i&&t.extend(e,i),s=s||i.duration,e.duration=t.fx.off?0:"number"==typeof s?s:s in t.fx.speeds?t.fx.speeds[s]:t.fx.speeds._default,e.complete=n||i.complete,e}function i(e){return!e||"number"==typeof e||t.fx.speeds[e]?!0:"string"!=typeof e||t.effects.effect[e]?t.isFunction(e)?!0:"object"!=typeof e||e.effect?!1:!0:!0}function s(t,e){var i=e.outerWidth(),s=e.outerHeight(),n=/^rect\((-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto)\)$/,o=n.exec(t)||["",0,i,s,0];return{top:parseFloat(o[1])||0,right:"auto"===o[2]?i:parseFloat(o[2]),bottom:"auto"===o[3]?s:parseFloat(o[3]),left:parseFloat(o[4])||0}}t.expr&&t.expr.filters&&t.expr.filters.animated&&(t.expr.filters.animated=function(e){return function(i){return!!t(i).data(d)||e(i)}}(t.expr.filters.animated)),t.uiBackCompat!==!1&&t.extend(t.effects,{save:function(t,e){for(var i=0,s=e.length;s>i;i++)null!==e[i]&&t.data(c+e[i],t[0].style[e[i]])},restore:function(t,e){for(var i,s=0,n=e.length;n>s;s++)null!==e[s]&&(i=t.data(c+e[s]),t.css(e[s],i))},setMode:function(t,e){return"toggle"===e&&(e=t.is(":hidden")?"show":"hide"),e},createWrapper:function(e){if(e.parent().is(".ui-effects-wrapper"))return e.parent();var i={width:e.outerWidth(!0),height:e.outerHeight(!0),"float":e.css("float")},s=t("<div></div>").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}),n={width:e.width(),height:e.height()},o=document.activeElement;try{o.id}catch(a){o=document.body}return e.wrap(s),(e[0]===o||t.contains(e[0],o))&&t(o).trigger("focus"),s=e.parent(),"static"===e.css("position")?(s.css({position:"relative"}),e.css({position:"relative"})):(t.extend(i,{position:e.css("position"),zIndex:e.css("z-index")}),t.each(["top","left","bottom","right"],function(t,s){i[s]=e.css(s),isNaN(parseInt(i[s],10))&&(i[s]="auto")}),e.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})),e.css(n),s.css(i).show()},removeWrapper:function(e){var i=document.activeElement;return e.parent().is(".ui-effects-wrapper")&&(e.parent().replaceWith(e),(e[0]===i||t.contains(e[0],i))&&t(i).trigger("focus")),e}}),t.extend(t.effects,{version:"1.12.1",define:function(e,i,s){return s||(s=i,i="effect"),t.effects.effect[e]=s,t.effects.effect[e].mode=i,s},scaledDimensions:function(t,e,i){if(0===e)return{height:0,width:0,outerHeight:0,outerWidth:0};var s="horizontal"!==i?(e||100)/100:1,n="vertical"!==i?(e||100)/100:1;return{height:t.height()*n,width:t.width()*s,outerHeight:t.outerHeight()*n,outerWidth:t.outerWidth()*s}},clipToBox:function(t){return{width:t.clip.right-t.clip.left,height:t.clip.bottom-t.clip.top,left:t.clip.left,top:t.clip.top}},unshift:function(t,e,i){var s=t.queue();e>1&&s.splice.apply(s,[1,0].concat(s.splice(e,i))),t.dequeue()},saveStyle:function(t){t.data(u,t[0].style.cssText)},restoreStyle:function(t){t[0].style.cssText=t.data(u)||"",t.removeData(u)},mode:function(t,e){var i=t.is(":hidden");return"toggle"===e&&(e=i?"show":"hide"),(i?"hide"===e:"show"===e)&&(e="none"),e},getBaseline:function(t,e){var i,s;switch(t[0]){case"top":i=0;break;case"middle":i=.5;break;case"bottom":i=1;break;default:i=t[0]/e.height}switch(t[1]){case"left":s=0;break;case"center":s=.5;break;case"right":s=1;break;default:s=t[1]/e.width}return{x:s,y:i}},createPlaceholder:function(e){var i,s=e.css("position"),n=e.position();return e.css({marginTop:e.css("marginTop"),marginBottom:e.css("marginBottom"),marginLeft:e.css("marginLeft"),marginRight:e.css("marginRight")}).outerWidth(e.outerWidth()).outerHeight(e.outerHeight()),/^(static|relative)/.test(s)&&(s="absolute",i=t("<"+e[0].nodeName+">").insertAfter(e).css({display:/^(inline|ruby)/.test(e.css("display"))?"inline-block":"block",visibility:"hidden",marginTop:e.css("marginTop"),marginBottom:e.css("marginBottom"),marginLeft:e.css("marginLeft"),marginRight:e.css("marginRight"),"float":e.css("float")}).outerWidth(e.outerWidth()).outerHeight(e.outerHeight()).addClass("ui-effects-placeholder"),e.data(c+"placeholder",i)),e.css({position:s,left:n.left,top:n.top}),i},removePlaceholder:function(t){var e=c+"placeholder",i=t.data(e);i&&(i.remove(),t.removeData(e))},cleanUp:function(e){t.effects.restoreStyle(e),t.effects.removePlaceholder(e)},setTransition:function(e,i,s,n){return n=n||{},t.each(i,function(t,i){var o=e.cssUnit(i);o[0]>0&&(n[i]=o[0]*s+o[1])}),n}}),t.fn.extend({effect:function(){function i(e){function i(){r.removeData(d),t.effects.cleanUp(r),"hide"===s.mode&&r.hide(),a()}function a(){t.isFunction(h)&&h.call(r[0]),t.isFunction(e)&&e()}var r=t(this);s.mode=c.shift(),t.uiBackCompat===!1||o?"none"===s.mode?(r[l](),a()):n.call(r[0],s,i):(r.is(":hidden")?"hide"===l:"show"===l)?(r[l](),a()):n.call(r[0],s,a)}var s=e.apply(this,arguments),n=t.effects.effect[s.effect],o=n.mode,a=s.queue,r=a||"fx",h=s.complete,l=s.mode,c=[],u=function(e){var i=t(this),s=t.effects.mode(i,l)||o;i.data(d,!0),c.push(s),o&&("show"===s||s===o&&"hide"===s)&&i.show(),o&&"none"===s||t.effects.saveStyle(i),t.isFunction(e)&&e()};return t.fx.off||!n?l?this[l](s.duration,h):this.each(function(){h&&h.call(this)}):a===!1?this.each(u).each(i):this.queue(r,u).queue(r,i)},show:function(t){return function(s){if(i(s))return t.apply(this,arguments);var n=e.apply(this,arguments);return n.mode="show",this.effect.call(this,n) +}}(t.fn.show),hide:function(t){return function(s){if(i(s))return t.apply(this,arguments);var n=e.apply(this,arguments);return n.mode="hide",this.effect.call(this,n)}}(t.fn.hide),toggle:function(t){return function(s){if(i(s)||"boolean"==typeof s)return t.apply(this,arguments);var n=e.apply(this,arguments);return n.mode="toggle",this.effect.call(this,n)}}(t.fn.toggle),cssUnit:function(e){var i=this.css(e),s=[];return t.each(["em","px","%","pt"],function(t,e){i.indexOf(e)>0&&(s=[parseFloat(i),e])}),s},cssClip:function(t){return t?this.css("clip","rect("+t.top+"px "+t.right+"px "+t.bottom+"px "+t.left+"px)"):s(this.css("clip"),this)},transfer:function(e,i){var s=t(this),n=t(e.to),o="fixed"===n.css("position"),a=t("body"),r=o?a.scrollTop():0,h=o?a.scrollLeft():0,l=n.offset(),c={top:l.top-r,left:l.left-h,height:n.innerHeight(),width:n.innerWidth()},u=s.offset(),d=t("<div class='ui-effects-transfer'></div>").appendTo("body").addClass(e.className).css({top:u.top-r,left:u.left-h,height:s.innerHeight(),width:s.innerWidth(),position:o?"fixed":"absolute"}).animate(c,e.duration,e.easing,function(){d.remove(),t.isFunction(i)&&i()})}}),t.fx.step.clip=function(e){e.clipInit||(e.start=t(e.elem).cssClip(),"string"==typeof e.end&&(e.end=s(e.end,e.elem)),e.clipInit=!0),t(e.elem).cssClip({top:e.pos*(e.end.top-e.start.top)+e.start.top,right:e.pos*(e.end.right-e.start.right)+e.start.right,bottom:e.pos*(e.end.bottom-e.start.bottom)+e.start.bottom,left:e.pos*(e.end.left-e.start.left)+e.start.left})}}(),function(){var e={};t.each(["Quad","Cubic","Quart","Quint","Expo"],function(t,i){e[i]=function(e){return Math.pow(e,t+2)}}),t.extend(e,{Sine:function(t){return 1-Math.cos(t*Math.PI/2)},Circ:function(t){return 1-Math.sqrt(1-t*t)},Elastic:function(t){return 0===t||1===t?t:-Math.pow(2,8*(t-1))*Math.sin((80*(t-1)-7.5)*Math.PI/15)},Back:function(t){return t*t*(3*t-2)},Bounce:function(t){for(var e,i=4;((e=Math.pow(2,--i))-1)/11>t;);return 1/Math.pow(4,3-i)-7.5625*Math.pow((3*e-2)/22-t,2)}}),t.each(e,function(e,i){t.easing["easeIn"+e]=i,t.easing["easeOut"+e]=function(t){return 1-i(1-t)},t.easing["easeInOut"+e]=function(t){return.5>t?i(2*t)/2:1-i(-2*t+2)/2}})}();var f=t.effects;t.effects.define("blind","hide",function(e,i){var s={up:["bottom","top"],vertical:["bottom","top"],down:["top","bottom"],left:["right","left"],horizontal:["right","left"],right:["left","right"]},n=t(this),o=e.direction||"up",a=n.cssClip(),r={clip:t.extend({},a)},h=t.effects.createPlaceholder(n);r.clip[s[o][0]]=r.clip[s[o][1]],"show"===e.mode&&(n.cssClip(r.clip),h&&h.css(t.effects.clipToBox(r)),r.clip=a),h&&h.animate(t.effects.clipToBox(r),e.duration,e.easing),n.animate(r,{queue:!1,duration:e.duration,easing:e.easing,complete:i})}),t.effects.define("bounce",function(e,i){var s,n,o,a=t(this),r=e.mode,h="hide"===r,l="show"===r,c=e.direction||"up",u=e.distance,d=e.times||5,p=2*d+(l||h?1:0),f=e.duration/p,g=e.easing,m="up"===c||"down"===c?"top":"left",_="up"===c||"left"===c,v=0,b=a.queue().length;for(t.effects.createPlaceholder(a),o=a.css(m),u||(u=a["top"===m?"outerHeight":"outerWidth"]()/3),l&&(n={opacity:1},n[m]=o,a.css("opacity",0).css(m,_?2*-u:2*u).animate(n,f,g)),h&&(u/=Math.pow(2,d-1)),n={},n[m]=o;d>v;v++)s={},s[m]=(_?"-=":"+=")+u,a.animate(s,f,g).animate(n,f,g),u=h?2*u:u/2;h&&(s={opacity:0},s[m]=(_?"-=":"+=")+u,a.animate(s,f,g)),a.queue(i),t.effects.unshift(a,b,p+1)}),t.effects.define("clip","hide",function(e,i){var s,n={},o=t(this),a=e.direction||"vertical",r="both"===a,h=r||"horizontal"===a,l=r||"vertical"===a;s=o.cssClip(),n.clip={top:l?(s.bottom-s.top)/2:s.top,right:h?(s.right-s.left)/2:s.right,bottom:l?(s.bottom-s.top)/2:s.bottom,left:h?(s.right-s.left)/2:s.left},t.effects.createPlaceholder(o),"show"===e.mode&&(o.cssClip(n.clip),n.clip=s),o.animate(n,{queue:!1,duration:e.duration,easing:e.easing,complete:i})}),t.effects.define("drop","hide",function(e,i){var s,n=t(this),o=e.mode,a="show"===o,r=e.direction||"left",h="up"===r||"down"===r?"top":"left",l="up"===r||"left"===r?"-=":"+=",c="+="===l?"-=":"+=",u={opacity:0};t.effects.createPlaceholder(n),s=e.distance||n["top"===h?"outerHeight":"outerWidth"](!0)/2,u[h]=l+s,a&&(n.css(u),u[h]=c+s,u.opacity=1),n.animate(u,{queue:!1,duration:e.duration,easing:e.easing,complete:i})}),t.effects.define("explode","hide",function(e,i){function s(){b.push(this),b.length===u*d&&n()}function n(){p.css({visibility:"visible"}),t(b).remove(),i()}var o,a,r,h,l,c,u=e.pieces?Math.round(Math.sqrt(e.pieces)):3,d=u,p=t(this),f=e.mode,g="show"===f,m=p.show().css("visibility","hidden").offset(),_=Math.ceil(p.outerWidth()/d),v=Math.ceil(p.outerHeight()/u),b=[];for(o=0;u>o;o++)for(h=m.top+o*v,c=o-(u-1)/2,a=0;d>a;a++)r=m.left+a*_,l=a-(d-1)/2,p.clone().appendTo("body").wrap("<div></div>").css({position:"absolute",visibility:"visible",left:-a*_,top:-o*v}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:_,height:v,left:r+(g?l*_:0),top:h+(g?c*v:0),opacity:g?0:1}).animate({left:r+(g?0:l*_),top:h+(g?0:c*v),opacity:g?1:0},e.duration||500,e.easing,s)}),t.effects.define("fade","toggle",function(e,i){var s="show"===e.mode;t(this).css("opacity",s?0:1).animate({opacity:s?1:0},{queue:!1,duration:e.duration,easing:e.easing,complete:i})}),t.effects.define("fold","hide",function(e,i){var s=t(this),n=e.mode,o="show"===n,a="hide"===n,r=e.size||15,h=/([0-9]+)%/.exec(r),l=!!e.horizFirst,c=l?["right","bottom"]:["bottom","right"],u=e.duration/2,d=t.effects.createPlaceholder(s),p=s.cssClip(),f={clip:t.extend({},p)},g={clip:t.extend({},p)},m=[p[c[0]],p[c[1]]],_=s.queue().length;h&&(r=parseInt(h[1],10)/100*m[a?0:1]),f.clip[c[0]]=r,g.clip[c[0]]=r,g.clip[c[1]]=0,o&&(s.cssClip(g.clip),d&&d.css(t.effects.clipToBox(g)),g.clip=p),s.queue(function(i){d&&d.animate(t.effects.clipToBox(f),u,e.easing).animate(t.effects.clipToBox(g),u,e.easing),i()}).animate(f,u,e.easing).animate(g,u,e.easing).queue(i),t.effects.unshift(s,_,4)}),t.effects.define("highlight","show",function(e,i){var s=t(this),n={backgroundColor:s.css("backgroundColor")};"hide"===e.mode&&(n.opacity=0),t.effects.saveStyle(s),s.css({backgroundImage:"none",backgroundColor:e.color||"#ffff99"}).animate(n,{queue:!1,duration:e.duration,easing:e.easing,complete:i})}),t.effects.define("size",function(e,i){var s,n,o,a=t(this),r=["fontSize"],h=["borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"],l=["borderLeftWidth","borderRightWidth","paddingLeft","paddingRight"],c=e.mode,u="effect"!==c,d=e.scale||"both",p=e.origin||["middle","center"],f=a.css("position"),g=a.position(),m=t.effects.scaledDimensions(a),_=e.from||m,v=e.to||t.effects.scaledDimensions(a,0);t.effects.createPlaceholder(a),"show"===c&&(o=_,_=v,v=o),n={from:{y:_.height/m.height,x:_.width/m.width},to:{y:v.height/m.height,x:v.width/m.width}},("box"===d||"both"===d)&&(n.from.y!==n.to.y&&(_=t.effects.setTransition(a,h,n.from.y,_),v=t.effects.setTransition(a,h,n.to.y,v)),n.from.x!==n.to.x&&(_=t.effects.setTransition(a,l,n.from.x,_),v=t.effects.setTransition(a,l,n.to.x,v))),("content"===d||"both"===d)&&n.from.y!==n.to.y&&(_=t.effects.setTransition(a,r,n.from.y,_),v=t.effects.setTransition(a,r,n.to.y,v)),p&&(s=t.effects.getBaseline(p,m),_.top=(m.outerHeight-_.outerHeight)*s.y+g.top,_.left=(m.outerWidth-_.outerWidth)*s.x+g.left,v.top=(m.outerHeight-v.outerHeight)*s.y+g.top,v.left=(m.outerWidth-v.outerWidth)*s.x+g.left),a.css(_),("content"===d||"both"===d)&&(h=h.concat(["marginTop","marginBottom"]).concat(r),l=l.concat(["marginLeft","marginRight"]),a.find("*[width]").each(function(){var i=t(this),s=t.effects.scaledDimensions(i),o={height:s.height*n.from.y,width:s.width*n.from.x,outerHeight:s.outerHeight*n.from.y,outerWidth:s.outerWidth*n.from.x},a={height:s.height*n.to.y,width:s.width*n.to.x,outerHeight:s.height*n.to.y,outerWidth:s.width*n.to.x};n.from.y!==n.to.y&&(o=t.effects.setTransition(i,h,n.from.y,o),a=t.effects.setTransition(i,h,n.to.y,a)),n.from.x!==n.to.x&&(o=t.effects.setTransition(i,l,n.from.x,o),a=t.effects.setTransition(i,l,n.to.x,a)),u&&t.effects.saveStyle(i),i.css(o),i.animate(a,e.duration,e.easing,function(){u&&t.effects.restoreStyle(i)})})),a.animate(v,{queue:!1,duration:e.duration,easing:e.easing,complete:function(){var e=a.offset();0===v.opacity&&a.css("opacity",_.opacity),u||(a.css("position","static"===f?"relative":f).offset(e),t.effects.saveStyle(a)),i()}})}),t.effects.define("scale",function(e,i){var s=t(this),n=e.mode,o=parseInt(e.percent,10)||(0===parseInt(e.percent,10)?0:"effect"!==n?0:100),a=t.extend(!0,{from:t.effects.scaledDimensions(s),to:t.effects.scaledDimensions(s,o,e.direction||"both"),origin:e.origin||["middle","center"]},e);e.fade&&(a.from.opacity=1,a.to.opacity=0),t.effects.effect.size.call(this,a,i)}),t.effects.define("puff","hide",function(e,i){var s=t.extend(!0,{},e,{fade:!0,percent:parseInt(e.percent,10)||150});t.effects.effect.scale.call(this,s,i)}),t.effects.define("pulsate","show",function(e,i){var s=t(this),n=e.mode,o="show"===n,a="hide"===n,r=o||a,h=2*(e.times||5)+(r?1:0),l=e.duration/h,c=0,u=1,d=s.queue().length;for((o||!s.is(":visible"))&&(s.css("opacity",0).show(),c=1);h>u;u++)s.animate({opacity:c},l,e.easing),c=1-c;s.animate({opacity:c},l,e.easing),s.queue(i),t.effects.unshift(s,d,h+1)}),t.effects.define("shake",function(e,i){var s=1,n=t(this),o=e.direction||"left",a=e.distance||20,r=e.times||3,h=2*r+1,l=Math.round(e.duration/h),c="up"===o||"down"===o?"top":"left",u="up"===o||"left"===o,d={},p={},f={},g=n.queue().length;for(t.effects.createPlaceholder(n),d[c]=(u?"-=":"+=")+a,p[c]=(u?"+=":"-=")+2*a,f[c]=(u?"-=":"+=")+2*a,n.animate(d,l,e.easing);r>s;s++)n.animate(p,l,e.easing).animate(f,l,e.easing);n.animate(p,l,e.easing).animate(d,l/2,e.easing).queue(i),t.effects.unshift(n,g,h+1)}),t.effects.define("slide","show",function(e,i){var s,n,o=t(this),a={up:["bottom","top"],down:["top","bottom"],left:["right","left"],right:["left","right"]},r=e.mode,h=e.direction||"left",l="up"===h||"down"===h?"top":"left",c="up"===h||"left"===h,u=e.distance||o["top"===l?"outerHeight":"outerWidth"](!0),d={};t.effects.createPlaceholder(o),s=o.cssClip(),n=o.position()[l],d[l]=(c?-1:1)*u+n,d.clip=o.cssClip(),d.clip[a[h][1]]=d.clip[a[h][0]],"show"===r&&(o.cssClip(d.clip),o.css(l,d[l]),d.clip=s,d[l]=n),o.animate(d,{queue:!1,duration:e.duration,easing:e.easing,complete:i})});var f;t.uiBackCompat!==!1&&(f=t.effects.define("transfer",function(e,i){t(this).transfer(e,i)})),t.ui.focusable=function(i,s){var n,o,a,r,h,l=i.nodeName.toLowerCase();return"area"===l?(n=i.parentNode,o=n.name,i.href&&o&&"map"===n.nodeName.toLowerCase()?(a=t("img[usemap='#"+o+"']"),a.length>0&&a.is(":visible")):!1):(/^(input|select|textarea|button|object)$/.test(l)?(r=!i.disabled,r&&(h=t(i).closest("fieldset")[0],h&&(r=!h.disabled))):r="a"===l?i.href||s:s,r&&t(i).is(":visible")&&e(t(i)))},t.extend(t.expr[":"],{focusable:function(e){return t.ui.focusable(e,null!=t.attr(e,"tabindex"))}}),t.ui.focusable,t.fn.form=function(){return"string"==typeof this[0].form?this.closest("form"):t(this[0].form)},t.ui.formResetMixin={_formResetHandler:function(){var e=t(this);setTimeout(function(){var i=e.data("ui-form-reset-instances");t.each(i,function(){this.refresh()})})},_bindFormResetHandler:function(){if(this.form=this.element.form(),this.form.length){var t=this.form.data("ui-form-reset-instances")||[];t.length||this.form.on("reset.ui-form-reset",this._formResetHandler),t.push(this),this.form.data("ui-form-reset-instances",t)}},_unbindFormResetHandler:function(){if(this.form.length){var e=this.form.data("ui-form-reset-instances");e.splice(t.inArray(this,e),1),e.length?this.form.data("ui-form-reset-instances",e):this.form.removeData("ui-form-reset-instances").off("reset.ui-form-reset")}}},"1.7"===t.fn.jquery.substring(0,3)&&(t.each(["Width","Height"],function(e,i){function s(e,i,s,o){return t.each(n,function(){i-=parseFloat(t.css(e,"padding"+this))||0,s&&(i-=parseFloat(t.css(e,"border"+this+"Width"))||0),o&&(i-=parseFloat(t.css(e,"margin"+this))||0)}),i}var n="Width"===i?["Left","Right"]:["Top","Bottom"],o=i.toLowerCase(),a={innerWidth:t.fn.innerWidth,innerHeight:t.fn.innerHeight,outerWidth:t.fn.outerWidth,outerHeight:t.fn.outerHeight};t.fn["inner"+i]=function(e){return void 0===e?a["inner"+i].call(this):this.each(function(){t(this).css(o,s(this,e)+"px")})},t.fn["outer"+i]=function(e,n){return"number"!=typeof e?a["outer"+i].call(this,e):this.each(function(){t(this).css(o,s(this,e,!0,n)+"px")})}}),t.fn.addBack=function(t){return this.add(null==t?this.prevObject:this.prevObject.filter(t))}),t.ui.keyCode={BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38},t.ui.escapeSelector=function(){var t=/([!"#$%&'()*+,.\/:;<=>?@[\]^`{|}~])/g;return function(e){return e.replace(t,"\\$1")}}(),t.fn.labels=function(){var e,i,s,n,o;return this[0].labels&&this[0].labels.length?this.pushStack(this[0].labels):(n=this.eq(0).parents("label"),s=this.attr("id"),s&&(e=this.eq(0).parents().last(),o=e.add(e.length?e.siblings():this.siblings()),i="label[for='"+t.ui.escapeSelector(s)+"']",n=n.add(o.find(i).addBack(i))),this.pushStack(n))},t.fn.scrollParent=function(e){var i=this.css("position"),s="absolute"===i,n=e?/(auto|scroll|hidden)/:/(auto|scroll)/,o=this.parents().filter(function(){var e=t(this);return s&&"static"===e.css("position")?!1:n.test(e.css("overflow")+e.css("overflow-y")+e.css("overflow-x"))}).eq(0);return"fixed"!==i&&o.length?o:t(this[0].ownerDocument||document)},t.extend(t.expr[":"],{tabbable:function(e){var i=t.attr(e,"tabindex"),s=null!=i;return(!s||i>=0)&&t.ui.focusable(e,s)}}),t.fn.extend({uniqueId:function(){var t=0;return function(){return this.each(function(){this.id||(this.id="ui-id-"+ ++t)})}}(),removeUniqueId:function(){return this.each(function(){/^ui-id-\d+$/.test(this.id)&&t(this).removeAttr("id")})}}),t.widget("ui.accordion",{version:"1.12.1",options:{active:0,animate:{},classes:{"ui-accordion-header":"ui-corner-top","ui-accordion-header-collapsed":"ui-corner-all","ui-accordion-content":"ui-corner-bottom"},collapsible:!1,event:"click",header:"> li > :first-child, > :not(li):even",heightStyle:"auto",icons:{activeHeader:"ui-icon-triangle-1-s",header:"ui-icon-triangle-1-e"},activate:null,beforeActivate:null},hideProps:{borderTopWidth:"hide",borderBottomWidth:"hide",paddingTop:"hide",paddingBottom:"hide",height:"hide"},showProps:{borderTopWidth:"show",borderBottomWidth:"show",paddingTop:"show",paddingBottom:"show",height:"show"},_create:function(){var e=this.options;this.prevShow=this.prevHide=t(),this._addClass("ui-accordion","ui-widget ui-helper-reset"),this.element.attr("role","tablist"),e.collapsible||e.active!==!1&&null!=e.active||(e.active=0),this._processPanels(),0>e.active&&(e.active+=this.headers.length),this._refresh()},_getCreateEventData:function(){return{header:this.active,panel:this.active.length?this.active.next():t()}},_createIcons:function(){var e,i,s=this.options.icons;s&&(e=t("<span>"),this._addClass(e,"ui-accordion-header-icon","ui-icon "+s.header),e.prependTo(this.headers),i=this.active.children(".ui-accordion-header-icon"),this._removeClass(i,s.header)._addClass(i,null,s.activeHeader)._addClass(this.headers,"ui-accordion-icons"))},_destroyIcons:function(){this._removeClass(this.headers,"ui-accordion-icons"),this.headers.children(".ui-accordion-header-icon").remove()},_destroy:function(){var t;this.element.removeAttr("role"),this.headers.removeAttr("role aria-expanded aria-selected aria-controls tabIndex").removeUniqueId(),this._destroyIcons(),t=this.headers.next().css("display","").removeAttr("role aria-hidden aria-labelledby").removeUniqueId(),"content"!==this.options.heightStyle&&t.css("height","")},_setOption:function(t,e){return"active"===t?(this._activate(e),void 0):("event"===t&&(this.options.event&&this._off(this.headers,this.options.event),this._setupEvents(e)),this._super(t,e),"collapsible"!==t||e||this.options.active!==!1||this._activate(0),"icons"===t&&(this._destroyIcons(),e&&this._createIcons()),void 0)},_setOptionDisabled:function(t){this._super(t),this.element.attr("aria-disabled",t),this._toggleClass(null,"ui-state-disabled",!!t),this._toggleClass(this.headers.add(this.headers.next()),null,"ui-state-disabled",!!t)},_keydown:function(e){if(!e.altKey&&!e.ctrlKey){var i=t.ui.keyCode,s=this.headers.length,n=this.headers.index(e.target),o=!1;switch(e.keyCode){case i.RIGHT:case i.DOWN:o=this.headers[(n+1)%s];break;case i.LEFT:case i.UP:o=this.headers[(n-1+s)%s];break;case i.SPACE:case i.ENTER:this._eventHandler(e);break;case i.HOME:o=this.headers[0];break;case i.END:o=this.headers[s-1]}o&&(t(e.target).attr("tabIndex",-1),t(o).attr("tabIndex",0),t(o).trigger("focus"),e.preventDefault())}},_panelKeyDown:function(e){e.keyCode===t.ui.keyCode.UP&&e.ctrlKey&&t(e.currentTarget).prev().trigger("focus")},refresh:function(){var e=this.options;this._processPanels(),e.active===!1&&e.collapsible===!0||!this.headers.length?(e.active=!1,this.active=t()):e.active===!1?this._activate(0):this.active.length&&!t.contains(this.element[0],this.active[0])?this.headers.length===this.headers.find(".ui-state-disabled").length?(e.active=!1,this.active=t()):this._activate(Math.max(0,e.active-1)):e.active=this.headers.index(this.active),this._destroyIcons(),this._refresh()},_processPanels:function(){var t=this.headers,e=this.panels;this.headers=this.element.find(this.options.header),this._addClass(this.headers,"ui-accordion-header ui-accordion-header-collapsed","ui-state-default"),this.panels=this.headers.next().filter(":not(.ui-accordion-content-active)").hide(),this._addClass(this.panels,"ui-accordion-content","ui-helper-reset ui-widget-content"),e&&(this._off(t.not(this.headers)),this._off(e.not(this.panels)))},_refresh:function(){var e,i=this.options,s=i.heightStyle,n=this.element.parent();this.active=this._findActive(i.active),this._addClass(this.active,"ui-accordion-header-active","ui-state-active")._removeClass(this.active,"ui-accordion-header-collapsed"),this._addClass(this.active.next(),"ui-accordion-content-active"),this.active.next().show(),this.headers.attr("role","tab").each(function(){var e=t(this),i=e.uniqueId().attr("id"),s=e.next(),n=s.uniqueId().attr("id");e.attr("aria-controls",n),s.attr("aria-labelledby",i)}).next().attr("role","tabpanel"),this.headers.not(this.active).attr({"aria-selected":"false","aria-expanded":"false",tabIndex:-1}).next().attr({"aria-hidden":"true"}).hide(),this.active.length?this.active.attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0}).next().attr({"aria-hidden":"false"}):this.headers.eq(0).attr("tabIndex",0),this._createIcons(),this._setupEvents(i.event),"fill"===s?(e=n.height(),this.element.siblings(":visible").each(function(){var i=t(this),s=i.css("position");"absolute"!==s&&"fixed"!==s&&(e-=i.outerHeight(!0))}),this.headers.each(function(){e-=t(this).outerHeight(!0)}),this.headers.next().each(function(){t(this).height(Math.max(0,e-t(this).innerHeight()+t(this).height()))}).css("overflow","auto")):"auto"===s&&(e=0,this.headers.next().each(function(){var i=t(this).is(":visible");i||t(this).show(),e=Math.max(e,t(this).css("height","").height()),i||t(this).hide()}).height(e))},_activate:function(e){var i=this._findActive(e)[0];i!==this.active[0]&&(i=i||this.active[0],this._eventHandler({target:i,currentTarget:i,preventDefault:t.noop}))},_findActive:function(e){return"number"==typeof e?this.headers.eq(e):t()},_setupEvents:function(e){var i={keydown:"_keydown"};e&&t.each(e.split(" "),function(t,e){i[e]="_eventHandler"}),this._off(this.headers.add(this.headers.next())),this._on(this.headers,i),this._on(this.headers.next(),{keydown:"_panelKeyDown"}),this._hoverable(this.headers),this._focusable(this.headers)},_eventHandler:function(e){var i,s,n=this.options,o=this.active,a=t(e.currentTarget),r=a[0]===o[0],h=r&&n.collapsible,l=h?t():a.next(),c=o.next(),u={oldHeader:o,oldPanel:c,newHeader:h?t():a,newPanel:l};e.preventDefault(),r&&!n.collapsible||this._trigger("beforeActivate",e,u)===!1||(n.active=h?!1:this.headers.index(a),this.active=r?t():a,this._toggle(u),this._removeClass(o,"ui-accordion-header-active","ui-state-active"),n.icons&&(i=o.children(".ui-accordion-header-icon"),this._removeClass(i,null,n.icons.activeHeader)._addClass(i,null,n.icons.header)),r||(this._removeClass(a,"ui-accordion-header-collapsed")._addClass(a,"ui-accordion-header-active","ui-state-active"),n.icons&&(s=a.children(".ui-accordion-header-icon"),this._removeClass(s,null,n.icons.header)._addClass(s,null,n.icons.activeHeader)),this._addClass(a.next(),"ui-accordion-content-active")))},_toggle:function(e){var i=e.newPanel,s=this.prevShow.length?this.prevShow:e.oldPanel;this.prevShow.add(this.prevHide).stop(!0,!0),this.prevShow=i,this.prevHide=s,this.options.animate?this._animate(i,s,e):(s.hide(),i.show(),this._toggleComplete(e)),s.attr({"aria-hidden":"true"}),s.prev().attr({"aria-selected":"false","aria-expanded":"false"}),i.length&&s.length?s.prev().attr({tabIndex:-1,"aria-expanded":"false"}):i.length&&this.headers.filter(function(){return 0===parseInt(t(this).attr("tabIndex"),10)}).attr("tabIndex",-1),i.attr("aria-hidden","false").prev().attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0})},_animate:function(t,e,i){var s,n,o,a=this,r=0,h=t.css("box-sizing"),l=t.length&&(!e.length||t.index()<e.index()),c=this.options.animate||{},u=l&&c.down||c,d=function(){a._toggleComplete(i)};return"number"==typeof u&&(o=u),"string"==typeof u&&(n=u),n=n||u.easing||c.easing,o=o||u.duration||c.duration,e.length?t.length?(s=t.show().outerHeight(),e.animate(this.hideProps,{duration:o,easing:n,step:function(t,e){e.now=Math.round(t)}}),t.hide().animate(this.showProps,{duration:o,easing:n,complete:d,step:function(t,i){i.now=Math.round(t),"height"!==i.prop?"content-box"===h&&(r+=i.now):"content"!==a.options.heightStyle&&(i.now=Math.round(s-e.outerHeight()-r),r=0)}}),void 0):e.animate(this.hideProps,o,n,d):t.animate(this.showProps,o,n,d)},_toggleComplete:function(t){var e=t.oldPanel,i=e.prev();this._removeClass(e,"ui-accordion-content-active"),this._removeClass(i,"ui-accordion-header-active")._addClass(i,"ui-accordion-header-collapsed"),e.length&&(e.parent()[0].className=e.parent()[0].className),this._trigger("activate",null,t)}}),t.ui.safeActiveElement=function(t){var e;try{e=t.activeElement}catch(i){e=t.body}return e||(e=t.body),e.nodeName||(e=t.body),e},t.widget("ui.menu",{version:"1.12.1",defaultElement:"<ul>",delay:300,options:{icons:{submenu:"ui-icon-caret-1-e"},items:"> *",menus:"ul",position:{my:"left top",at:"right top"},role:"menu",blur:null,focus:null,select:null},_create:function(){this.activeMenu=this.element,this.mouseHandled=!1,this.element.uniqueId().attr({role:this.options.role,tabIndex:0}),this._addClass("ui-menu","ui-widget ui-widget-content"),this._on({"mousedown .ui-menu-item":function(t){t.preventDefault()},"click .ui-menu-item":function(e){var i=t(e.target),s=t(t.ui.safeActiveElement(this.document[0]));!this.mouseHandled&&i.not(".ui-state-disabled").length&&(this.select(e),e.isPropagationStopped()||(this.mouseHandled=!0),i.has(".ui-menu").length?this.expand(e):!this.element.is(":focus")&&s.closest(".ui-menu").length&&(this.element.trigger("focus",[!0]),this.active&&1===this.active.parents(".ui-menu").length&&clearTimeout(this.timer)))},"mouseenter .ui-menu-item":function(e){if(!this.previousFilter){var i=t(e.target).closest(".ui-menu-item"),s=t(e.currentTarget);i[0]===s[0]&&(this._removeClass(s.siblings().children(".ui-state-active"),null,"ui-state-active"),this.focus(e,s))}},mouseleave:"collapseAll","mouseleave .ui-menu":"collapseAll",focus:function(t,e){var i=this.active||this.element.find(this.options.items).eq(0);e||this.focus(t,i)},blur:function(e){this._delay(function(){var i=!t.contains(this.element[0],t.ui.safeActiveElement(this.document[0]));i&&this.collapseAll(e)})},keydown:"_keydown"}),this.refresh(),this._on(this.document,{click:function(t){this._closeOnDocumentClick(t)&&this.collapseAll(t),this.mouseHandled=!1}})},_destroy:function(){var e=this.element.find(".ui-menu-item").removeAttr("role aria-disabled"),i=e.children(".ui-menu-item-wrapper").removeUniqueId().removeAttr("tabIndex role aria-haspopup");this.element.removeAttr("aria-activedescendant").find(".ui-menu").addBack().removeAttr("role aria-labelledby aria-expanded aria-hidden aria-disabled tabIndex").removeUniqueId().show(),i.children().each(function(){var e=t(this);e.data("ui-menu-submenu-caret")&&e.remove()})},_keydown:function(e){var i,s,n,o,a=!0;switch(e.keyCode){case t.ui.keyCode.PAGE_UP:this.previousPage(e);break;case t.ui.keyCode.PAGE_DOWN:this.nextPage(e);break;case t.ui.keyCode.HOME:this._move("first","first",e);break;case t.ui.keyCode.END:this._move("last","last",e);break;case t.ui.keyCode.UP:this.previous(e);break;case t.ui.keyCode.DOWN:this.next(e);break;case t.ui.keyCode.LEFT:this.collapse(e);break;case t.ui.keyCode.RIGHT:this.active&&!this.active.is(".ui-state-disabled")&&this.expand(e);break;case t.ui.keyCode.ENTER:case t.ui.keyCode.SPACE:this._activate(e);break;case t.ui.keyCode.ESCAPE:this.collapse(e);break;default:a=!1,s=this.previousFilter||"",o=!1,n=e.keyCode>=96&&105>=e.keyCode?""+(e.keyCode-96):String.fromCharCode(e.keyCode),clearTimeout(this.filterTimer),n===s?o=!0:n=s+n,i=this._filterMenuItems(n),i=o&&-1!==i.index(this.active.next())?this.active.nextAll(".ui-menu-item"):i,i.length||(n=String.fromCharCode(e.keyCode),i=this._filterMenuItems(n)),i.length?(this.focus(e,i),this.previousFilter=n,this.filterTimer=this._delay(function(){delete this.previousFilter},1e3)):delete this.previousFilter}a&&e.preventDefault()},_activate:function(t){this.active&&!this.active.is(".ui-state-disabled")&&(this.active.children("[aria-haspopup='true']").length?this.expand(t):this.select(t))},refresh:function(){var e,i,s,n,o,a=this,r=this.options.icons.submenu,h=this.element.find(this.options.menus);this._toggleClass("ui-menu-icons",null,!!this.element.find(".ui-icon").length),s=h.filter(":not(.ui-menu)").hide().attr({role:this.options.role,"aria-hidden":"true","aria-expanded":"false"}).each(function(){var e=t(this),i=e.prev(),s=t("<span>").data("ui-menu-submenu-caret",!0);a._addClass(s,"ui-menu-icon","ui-icon "+r),i.attr("aria-haspopup","true").prepend(s),e.attr("aria-labelledby",i.attr("id"))}),this._addClass(s,"ui-menu","ui-widget ui-widget-content ui-front"),e=h.add(this.element),i=e.find(this.options.items),i.not(".ui-menu-item").each(function(){var e=t(this);a._isDivider(e)&&a._addClass(e,"ui-menu-divider","ui-widget-content")}),n=i.not(".ui-menu-item, .ui-menu-divider"),o=n.children().not(".ui-menu").uniqueId().attr({tabIndex:-1,role:this._itemRole()}),this._addClass(n,"ui-menu-item")._addClass(o,"ui-menu-item-wrapper"),i.filter(".ui-state-disabled").attr("aria-disabled","true"),this.active&&!t.contains(this.element[0],this.active[0])&&this.blur()},_itemRole:function(){return{menu:"menuitem",listbox:"option"}[this.options.role]},_setOption:function(t,e){if("icons"===t){var i=this.element.find(".ui-menu-icon");this._removeClass(i,null,this.options.icons.submenu)._addClass(i,null,e.submenu)}this._super(t,e)},_setOptionDisabled:function(t){this._super(t),this.element.attr("aria-disabled",t+""),this._toggleClass(null,"ui-state-disabled",!!t)},focus:function(t,e){var i,s,n;this.blur(t,t&&"focus"===t.type),this._scrollIntoView(e),this.active=e.first(),s=this.active.children(".ui-menu-item-wrapper"),this._addClass(s,null,"ui-state-active"),this.options.role&&this.element.attr("aria-activedescendant",s.attr("id")),n=this.active.parent().closest(".ui-menu-item").children(".ui-menu-item-wrapper"),this._addClass(n,null,"ui-state-active"),t&&"keydown"===t.type?this._close():this.timer=this._delay(function(){this._close()},this.delay),i=e.children(".ui-menu"),i.length&&t&&/^mouse/.test(t.type)&&this._startOpening(i),this.activeMenu=e.parent(),this._trigger("focus",t,{item:e})},_scrollIntoView:function(e){var i,s,n,o,a,r;this._hasScroll()&&(i=parseFloat(t.css(this.activeMenu[0],"borderTopWidth"))||0,s=parseFloat(t.css(this.activeMenu[0],"paddingTop"))||0,n=e.offset().top-this.activeMenu.offset().top-i-s,o=this.activeMenu.scrollTop(),a=this.activeMenu.height(),r=e.outerHeight(),0>n?this.activeMenu.scrollTop(o+n):n+r>a&&this.activeMenu.scrollTop(o+n-a+r))},blur:function(t,e){e||clearTimeout(this.timer),this.active&&(this._removeClass(this.active.children(".ui-menu-item-wrapper"),null,"ui-state-active"),this._trigger("blur",t,{item:this.active}),this.active=null)},_startOpening:function(t){clearTimeout(this.timer),"true"===t.attr("aria-hidden")&&(this.timer=this._delay(function(){this._close(),this._open(t)},this.delay))},_open:function(e){var i=t.extend({of:this.active},this.options.position);clearTimeout(this.timer),this.element.find(".ui-menu").not(e.parents(".ui-menu")).hide().attr("aria-hidden","true"),e.show().removeAttr("aria-hidden").attr("aria-expanded","true").position(i)},collapseAll:function(e,i){clearTimeout(this.timer),this.timer=this._delay(function(){var s=i?this.element:t(e&&e.target).closest(this.element.find(".ui-menu"));s.length||(s=this.element),this._close(s),this.blur(e),this._removeClass(s.find(".ui-state-active"),null,"ui-state-active"),this.activeMenu=s},this.delay)},_close:function(t){t||(t=this.active?this.active.parent():this.element),t.find(".ui-menu").hide().attr("aria-hidden","true").attr("aria-expanded","false")},_closeOnDocumentClick:function(e){return!t(e.target).closest(".ui-menu").length},_isDivider:function(t){return!/[^\-\u2014\u2013\s]/.test(t.text())},collapse:function(t){var e=this.active&&this.active.parent().closest(".ui-menu-item",this.element);e&&e.length&&(this._close(),this.focus(t,e))},expand:function(t){var e=this.active&&this.active.children(".ui-menu ").find(this.options.items).first();e&&e.length&&(this._open(e.parent()),this._delay(function(){this.focus(t,e)}))},next:function(t){this._move("next","first",t)},previous:function(t){this._move("prev","last",t)},isFirstItem:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},isLastItem:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},_move:function(t,e,i){var s;this.active&&(s="first"===t||"last"===t?this.active["first"===t?"prevAll":"nextAll"](".ui-menu-item").eq(-1):this.active[t+"All"](".ui-menu-item").eq(0)),s&&s.length&&this.active||(s=this.activeMenu.find(this.options.items)[e]()),this.focus(i,s)},nextPage:function(e){var i,s,n;return this.active?(this.isLastItem()||(this._hasScroll()?(s=this.active.offset().top,n=this.element.height(),this.active.nextAll(".ui-menu-item").each(function(){return i=t(this),0>i.offset().top-s-n}),this.focus(e,i)):this.focus(e,this.activeMenu.find(this.options.items)[this.active?"last":"first"]())),void 0):(this.next(e),void 0)},previousPage:function(e){var i,s,n;return this.active?(this.isFirstItem()||(this._hasScroll()?(s=this.active.offset().top,n=this.element.height(),this.active.prevAll(".ui-menu-item").each(function(){return i=t(this),i.offset().top-s+n>0}),this.focus(e,i)):this.focus(e,this.activeMenu.find(this.options.items).first())),void 0):(this.next(e),void 0)},_hasScroll:function(){return this.element.outerHeight()<this.element.prop("scrollHeight")},select:function(e){this.active=this.active||t(e.target).closest(".ui-menu-item");var i={item:this.active};this.active.has(".ui-menu").length||this.collapseAll(e,!0),this._trigger("select",e,i)},_filterMenuItems:function(e){var i=e.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&"),s=RegExp("^"+i,"i");return this.activeMenu.find(this.options.items).filter(".ui-menu-item").filter(function(){return s.test(t.trim(t(this).children(".ui-menu-item-wrapper").text()))})}}),t.widget("ui.autocomplete",{version:"1.12.1",defaultElement:"<input>",options:{appendTo:null,autoFocus:!1,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null,change:null,close:null,focus:null,open:null,response:null,search:null,select:null},requestIndex:0,pending:0,_create:function(){var e,i,s,n=this.element[0].nodeName.toLowerCase(),o="textarea"===n,a="input"===n; +this.isMultiLine=o||!a&&this._isContentEditable(this.element),this.valueMethod=this.element[o||a?"val":"text"],this.isNewMenu=!0,this._addClass("ui-autocomplete-input"),this.element.attr("autocomplete","off"),this._on(this.element,{keydown:function(n){if(this.element.prop("readOnly"))return e=!0,s=!0,i=!0,void 0;e=!1,s=!1,i=!1;var o=t.ui.keyCode;switch(n.keyCode){case o.PAGE_UP:e=!0,this._move("previousPage",n);break;case o.PAGE_DOWN:e=!0,this._move("nextPage",n);break;case o.UP:e=!0,this._keyEvent("previous",n);break;case o.DOWN:e=!0,this._keyEvent("next",n);break;case o.ENTER:this.menu.active&&(e=!0,n.preventDefault(),this.menu.select(n));break;case o.TAB:this.menu.active&&this.menu.select(n);break;case o.ESCAPE:this.menu.element.is(":visible")&&(this.isMultiLine||this._value(this.term),this.close(n),n.preventDefault());break;default:i=!0,this._searchTimeout(n)}},keypress:function(s){if(e)return e=!1,(!this.isMultiLine||this.menu.element.is(":visible"))&&s.preventDefault(),void 0;if(!i){var n=t.ui.keyCode;switch(s.keyCode){case n.PAGE_UP:this._move("previousPage",s);break;case n.PAGE_DOWN:this._move("nextPage",s);break;case n.UP:this._keyEvent("previous",s);break;case n.DOWN:this._keyEvent("next",s)}}},input:function(t){return s?(s=!1,t.preventDefault(),void 0):(this._searchTimeout(t),void 0)},focus:function(){this.selectedItem=null,this.previous=this._value()},blur:function(t){return this.cancelBlur?(delete this.cancelBlur,void 0):(clearTimeout(this.searching),this.close(t),this._change(t),void 0)}}),this._initSource(),this.menu=t("<ul>").appendTo(this._appendTo()).menu({role:null}).hide().menu("instance"),this._addClass(this.menu.element,"ui-autocomplete","ui-front"),this._on(this.menu.element,{mousedown:function(e){e.preventDefault(),this.cancelBlur=!0,this._delay(function(){delete this.cancelBlur,this.element[0]!==t.ui.safeActiveElement(this.document[0])&&this.element.trigger("focus")})},menufocus:function(e,i){var s,n;return this.isNewMenu&&(this.isNewMenu=!1,e.originalEvent&&/^mouse/.test(e.originalEvent.type))?(this.menu.blur(),this.document.one("mousemove",function(){t(e.target).trigger(e.originalEvent)}),void 0):(n=i.item.data("ui-autocomplete-item"),!1!==this._trigger("focus",e,{item:n})&&e.originalEvent&&/^key/.test(e.originalEvent.type)&&this._value(n.value),s=i.item.attr("aria-label")||n.value,s&&t.trim(s).length&&(this.liveRegion.children().hide(),t("<div>").text(s).appendTo(this.liveRegion)),void 0)},menuselect:function(e,i){var s=i.item.data("ui-autocomplete-item"),n=this.previous;this.element[0]!==t.ui.safeActiveElement(this.document[0])&&(this.element.trigger("focus"),this.previous=n,this._delay(function(){this.previous=n,this.selectedItem=s})),!1!==this._trigger("select",e,{item:s})&&this._value(s.value),this.term=this._value(),this.close(e),this.selectedItem=s}}),this.liveRegion=t("<div>",{role:"status","aria-live":"assertive","aria-relevant":"additions"}).appendTo(this.document[0].body),this._addClass(this.liveRegion,null,"ui-helper-hidden-accessible"),this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete")}})},_destroy:function(){clearTimeout(this.searching),this.element.removeAttr("autocomplete"),this.menu.element.remove(),this.liveRegion.remove()},_setOption:function(t,e){this._super(t,e),"source"===t&&this._initSource(),"appendTo"===t&&this.menu.element.appendTo(this._appendTo()),"disabled"===t&&e&&this.xhr&&this.xhr.abort()},_isEventTargetInWidget:function(e){var i=this.menu.element[0];return e.target===this.element[0]||e.target===i||t.contains(i,e.target)},_closeOnClickOutside:function(t){this._isEventTargetInWidget(t)||this.close()},_appendTo:function(){var e=this.options.appendTo;return e&&(e=e.jquery||e.nodeType?t(e):this.document.find(e).eq(0)),e&&e[0]||(e=this.element.closest(".ui-front, dialog")),e.length||(e=this.document[0].body),e},_initSource:function(){var e,i,s=this;t.isArray(this.options.source)?(e=this.options.source,this.source=function(i,s){s(t.ui.autocomplete.filter(e,i.term))}):"string"==typeof this.options.source?(i=this.options.source,this.source=function(e,n){s.xhr&&s.xhr.abort(),s.xhr=t.ajax({url:i,data:e,dataType:"json",success:function(t){n(t)},error:function(){n([])}})}):this.source=this.options.source},_searchTimeout:function(t){clearTimeout(this.searching),this.searching=this._delay(function(){var e=this.term===this._value(),i=this.menu.element.is(":visible"),s=t.altKey||t.ctrlKey||t.metaKey||t.shiftKey;(!e||e&&!i&&!s)&&(this.selectedItem=null,this.search(null,t))},this.options.delay)},search:function(t,e){return t=null!=t?t:this._value(),this.term=this._value(),t.length<this.options.minLength?this.close(e):this._trigger("search",e)!==!1?this._search(t):void 0},_search:function(t){this.pending++,this._addClass("ui-autocomplete-loading"),this.cancelSearch=!1,this.source({term:t},this._response())},_response:function(){var e=++this.requestIndex;return t.proxy(function(t){e===this.requestIndex&&this.__response(t),this.pending--,this.pending||this._removeClass("ui-autocomplete-loading")},this)},__response:function(t){t&&(t=this._normalize(t)),this._trigger("response",null,{content:t}),!this.options.disabled&&t&&t.length&&!this.cancelSearch?(this._suggest(t),this._trigger("open")):this._close()},close:function(t){this.cancelSearch=!0,this._close(t)},_close:function(t){this._off(this.document,"mousedown"),this.menu.element.is(":visible")&&(this.menu.element.hide(),this.menu.blur(),this.isNewMenu=!0,this._trigger("close",t))},_change:function(t){this.previous!==this._value()&&this._trigger("change",t,{item:this.selectedItem})},_normalize:function(e){return e.length&&e[0].label&&e[0].value?e:t.map(e,function(e){return"string"==typeof e?{label:e,value:e}:t.extend({},e,{label:e.label||e.value,value:e.value||e.label})})},_suggest:function(e){var i=this.menu.element.empty();this._renderMenu(i,e),this.isNewMenu=!0,this.menu.refresh(),i.show(),this._resizeMenu(),i.position(t.extend({of:this.element},this.options.position)),this.options.autoFocus&&this.menu.next(),this._on(this.document,{mousedown:"_closeOnClickOutside"})},_resizeMenu:function(){var t=this.menu.element;t.outerWidth(Math.max(t.width("").outerWidth()+1,this.element.outerWidth()))},_renderMenu:function(e,i){var s=this;t.each(i,function(t,i){s._renderItemData(e,i)})},_renderItemData:function(t,e){return this._renderItem(t,e).data("ui-autocomplete-item",e)},_renderItem:function(e,i){return t("<li>").append(t("<div>").text(i.label)).appendTo(e)},_move:function(t,e){return this.menu.element.is(":visible")?this.menu.isFirstItem()&&/^previous/.test(t)||this.menu.isLastItem()&&/^next/.test(t)?(this.isMultiLine||this._value(this.term),this.menu.blur(),void 0):(this.menu[t](e),void 0):(this.search(null,e),void 0)},widget:function(){return this.menu.element},_value:function(){return this.valueMethod.apply(this.element,arguments)},_keyEvent:function(t,e){(!this.isMultiLine||this.menu.element.is(":visible"))&&(this._move(t,e),e.preventDefault())},_isContentEditable:function(t){if(!t.length)return!1;var e=t.prop("contentEditable");return"inherit"===e?this._isContentEditable(t.parent()):"true"===e}}),t.extend(t.ui.autocomplete,{escapeRegex:function(t){return t.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")},filter:function(e,i){var s=RegExp(t.ui.autocomplete.escapeRegex(i),"i");return t.grep(e,function(t){return s.test(t.label||t.value||t)})}}),t.widget("ui.autocomplete",t.ui.autocomplete,{options:{messages:{noResults:"No search results.",results:function(t){return t+(t>1?" results are":" result is")+" available, use up and down arrow keys to navigate."}}},__response:function(e){var i;this._superApply(arguments),this.options.disabled||this.cancelSearch||(i=e&&e.length?this.options.messages.results(e.length):this.options.messages.noResults,this.liveRegion.children().hide(),t("<div>").text(i).appendTo(this.liveRegion))}}),t.ui.autocomplete;var g=/ui-corner-([a-z]){2,6}/g;t.widget("ui.controlgroup",{version:"1.12.1",defaultElement:"<div>",options:{direction:"horizontal",disabled:null,onlyVisible:!0,items:{button:"input[type=button], input[type=submit], input[type=reset], button, a",controlgroupLabel:".ui-controlgroup-label",checkboxradio:"input[type='checkbox'], input[type='radio']",selectmenu:"select",spinner:".ui-spinner-input"}},_create:function(){this._enhance()},_enhance:function(){this.element.attr("role","toolbar"),this.refresh()},_destroy:function(){this._callChildMethod("destroy"),this.childWidgets.removeData("ui-controlgroup-data"),this.element.removeAttr("role"),this.options.items.controlgroupLabel&&this.element.find(this.options.items.controlgroupLabel).find(".ui-controlgroup-label-contents").contents().unwrap()},_initWidgets:function(){var e=this,i=[];t.each(this.options.items,function(s,n){var o,a={};return n?"controlgroupLabel"===s?(o=e.element.find(n),o.each(function(){var e=t(this);e.children(".ui-controlgroup-label-contents").length||e.contents().wrapAll("<span class='ui-controlgroup-label-contents'></span>")}),e._addClass(o,null,"ui-widget ui-widget-content ui-state-default"),i=i.concat(o.get()),void 0):(t.fn[s]&&(a=e["_"+s+"Options"]?e["_"+s+"Options"]("middle"):{classes:{}},e.element.find(n).each(function(){var n=t(this),o=n[s]("instance"),r=t.widget.extend({},a);if("button"!==s||!n.parent(".ui-spinner").length){o||(o=n[s]()[s]("instance")),o&&(r.classes=e._resolveClassesValues(r.classes,o)),n[s](r);var h=n[s]("widget");t.data(h[0],"ui-controlgroup-data",o?o:n[s]("instance")),i.push(h[0])}})),void 0):void 0}),this.childWidgets=t(t.unique(i)),this._addClass(this.childWidgets,"ui-controlgroup-item")},_callChildMethod:function(e){this.childWidgets.each(function(){var i=t(this),s=i.data("ui-controlgroup-data");s&&s[e]&&s[e]()})},_updateCornerClass:function(t,e){var i="ui-corner-top ui-corner-bottom ui-corner-left ui-corner-right ui-corner-all",s=this._buildSimpleOptions(e,"label").classes.label;this._removeClass(t,null,i),this._addClass(t,null,s)},_buildSimpleOptions:function(t,e){var i="vertical"===this.options.direction,s={classes:{}};return s.classes[e]={middle:"",first:"ui-corner-"+(i?"top":"left"),last:"ui-corner-"+(i?"bottom":"right"),only:"ui-corner-all"}[t],s},_spinnerOptions:function(t){var e=this._buildSimpleOptions(t,"ui-spinner");return e.classes["ui-spinner-up"]="",e.classes["ui-spinner-down"]="",e},_buttonOptions:function(t){return this._buildSimpleOptions(t,"ui-button")},_checkboxradioOptions:function(t){return this._buildSimpleOptions(t,"ui-checkboxradio-label")},_selectmenuOptions:function(t){var e="vertical"===this.options.direction;return{width:e?"auto":!1,classes:{middle:{"ui-selectmenu-button-open":"","ui-selectmenu-button-closed":""},first:{"ui-selectmenu-button-open":"ui-corner-"+(e?"top":"tl"),"ui-selectmenu-button-closed":"ui-corner-"+(e?"top":"left")},last:{"ui-selectmenu-button-open":e?"":"ui-corner-tr","ui-selectmenu-button-closed":"ui-corner-"+(e?"bottom":"right")},only:{"ui-selectmenu-button-open":"ui-corner-top","ui-selectmenu-button-closed":"ui-corner-all"}}[t]}},_resolveClassesValues:function(e,i){var s={};return t.each(e,function(n){var o=i.options.classes[n]||"";o=t.trim(o.replace(g,"")),s[n]=(o+" "+e[n]).replace(/\s+/g," ")}),s},_setOption:function(t,e){return"direction"===t&&this._removeClass("ui-controlgroup-"+this.options.direction),this._super(t,e),"disabled"===t?(this._callChildMethod(e?"disable":"enable"),void 0):(this.refresh(),void 0)},refresh:function(){var e,i=this;this._addClass("ui-controlgroup ui-controlgroup-"+this.options.direction),"horizontal"===this.options.direction&&this._addClass(null,"ui-helper-clearfix"),this._initWidgets(),e=this.childWidgets,this.options.onlyVisible&&(e=e.filter(":visible")),e.length&&(t.each(["first","last"],function(t,s){var n=e[s]().data("ui-controlgroup-data");if(n&&i["_"+n.widgetName+"Options"]){var o=i["_"+n.widgetName+"Options"](1===e.length?"only":s);o.classes=i._resolveClassesValues(o.classes,n),n.element[n.widgetName](o)}else i._updateCornerClass(e[s](),s)}),this._callChildMethod("refresh"))}}),t.widget("ui.checkboxradio",[t.ui.formResetMixin,{version:"1.12.1",options:{disabled:null,label:null,icon:!0,classes:{"ui-checkboxradio-label":"ui-corner-all","ui-checkboxradio-icon":"ui-corner-all"}},_getCreateOptions:function(){var e,i,s=this,n=this._super()||{};return this._readType(),i=this.element.labels(),this.label=t(i[i.length-1]),this.label.length||t.error("No label found for checkboxradio widget"),this.originalLabel="",this.label.contents().not(this.element[0]).each(function(){s.originalLabel+=3===this.nodeType?t(this).text():this.outerHTML}),this.originalLabel&&(n.label=this.originalLabel),e=this.element[0].disabled,null!=e&&(n.disabled=e),n},_create:function(){var t=this.element[0].checked;this._bindFormResetHandler(),null==this.options.disabled&&(this.options.disabled=this.element[0].disabled),this._setOption("disabled",this.options.disabled),this._addClass("ui-checkboxradio","ui-helper-hidden-accessible"),this._addClass(this.label,"ui-checkboxradio-label","ui-button ui-widget"),"radio"===this.type&&this._addClass(this.label,"ui-checkboxradio-radio-label"),this.options.label&&this.options.label!==this.originalLabel?this._updateLabel():this.originalLabel&&(this.options.label=this.originalLabel),this._enhance(),t&&(this._addClass(this.label,"ui-checkboxradio-checked","ui-state-active"),this.icon&&this._addClass(this.icon,null,"ui-state-hover")),this._on({change:"_toggleClasses",focus:function(){this._addClass(this.label,null,"ui-state-focus ui-visual-focus")},blur:function(){this._removeClass(this.label,null,"ui-state-focus ui-visual-focus")}})},_readType:function(){var e=this.element[0].nodeName.toLowerCase();this.type=this.element[0].type,"input"===e&&/radio|checkbox/.test(this.type)||t.error("Can't create checkboxradio on element.nodeName="+e+" and element.type="+this.type)},_enhance:function(){this._updateIcon(this.element[0].checked)},widget:function(){return this.label},_getRadioGroup:function(){var e,i=this.element[0].name,s="input[name='"+t.ui.escapeSelector(i)+"']";return i?(e=this.form.length?t(this.form[0].elements).filter(s):t(s).filter(function(){return 0===t(this).form().length}),e.not(this.element)):t([])},_toggleClasses:function(){var e=this.element[0].checked;this._toggleClass(this.label,"ui-checkboxradio-checked","ui-state-active",e),this.options.icon&&"checkbox"===this.type&&this._toggleClass(this.icon,null,"ui-icon-check ui-state-checked",e)._toggleClass(this.icon,null,"ui-icon-blank",!e),"radio"===this.type&&this._getRadioGroup().each(function(){var e=t(this).checkboxradio("instance");e&&e._removeClass(e.label,"ui-checkboxradio-checked","ui-state-active")})},_destroy:function(){this._unbindFormResetHandler(),this.icon&&(this.icon.remove(),this.iconSpace.remove())},_setOption:function(t,e){return"label"!==t||e?(this._super(t,e),"disabled"===t?(this._toggleClass(this.label,null,"ui-state-disabled",e),this.element[0].disabled=e,void 0):(this.refresh(),void 0)):void 0},_updateIcon:function(e){var i="ui-icon ui-icon-background ";this.options.icon?(this.icon||(this.icon=t("<span>"),this.iconSpace=t("<span> </span>"),this._addClass(this.iconSpace,"ui-checkboxradio-icon-space")),"checkbox"===this.type?(i+=e?"ui-icon-check ui-state-checked":"ui-icon-blank",this._removeClass(this.icon,null,e?"ui-icon-blank":"ui-icon-check")):i+="ui-icon-blank",this._addClass(this.icon,"ui-checkboxradio-icon",i),e||this._removeClass(this.icon,null,"ui-icon-check ui-state-checked"),this.icon.prependTo(this.label).after(this.iconSpace)):void 0!==this.icon&&(this.icon.remove(),this.iconSpace.remove(),delete this.icon)},_updateLabel:function(){var t=this.label.contents().not(this.element[0]);this.icon&&(t=t.not(this.icon[0])),this.iconSpace&&(t=t.not(this.iconSpace[0])),t.remove(),this.label.append(this.options.label)},refresh:function(){var t=this.element[0].checked,e=this.element[0].disabled;this._updateIcon(t),this._toggleClass(this.label,"ui-checkboxradio-checked","ui-state-active",t),null!==this.options.label&&this._updateLabel(),e!==this.options.disabled&&this._setOptions({disabled:e})}}]),t.ui.checkboxradio,t.widget("ui.button",{version:"1.12.1",defaultElement:"<button>",options:{classes:{"ui-button":"ui-corner-all"},disabled:null,icon:null,iconPosition:"beginning",label:null,showLabel:!0},_getCreateOptions:function(){var t,e=this._super()||{};return this.isInput=this.element.is("input"),t=this.element[0].disabled,null!=t&&(e.disabled=t),this.originalLabel=this.isInput?this.element.val():this.element.html(),this.originalLabel&&(e.label=this.originalLabel),e},_create:function(){!this.option.showLabel&!this.options.icon&&(this.options.showLabel=!0),null==this.options.disabled&&(this.options.disabled=this.element[0].disabled||!1),this.hasTitle=!!this.element.attr("title"),this.options.label&&this.options.label!==this.originalLabel&&(this.isInput?this.element.val(this.options.label):this.element.html(this.options.label)),this._addClass("ui-button","ui-widget"),this._setOption("disabled",this.options.disabled),this._enhance(),this.element.is("a")&&this._on({keyup:function(e){e.keyCode===t.ui.keyCode.SPACE&&(e.preventDefault(),this.element[0].click?this.element[0].click():this.element.trigger("click"))}})},_enhance:function(){this.element.is("button")||this.element.attr("role","button"),this.options.icon&&(this._updateIcon("icon",this.options.icon),this._updateTooltip())},_updateTooltip:function(){this.title=this.element.attr("title"),this.options.showLabel||this.title||this.element.attr("title",this.options.label)},_updateIcon:function(e,i){var s="iconPosition"!==e,n=s?this.options.iconPosition:i,o="top"===n||"bottom"===n;this.icon?s&&this._removeClass(this.icon,null,this.options.icon):(this.icon=t("<span>"),this._addClass(this.icon,"ui-button-icon","ui-icon"),this.options.showLabel||this._addClass("ui-button-icon-only")),s&&this._addClass(this.icon,null,i),this._attachIcon(n),o?(this._addClass(this.icon,null,"ui-widget-icon-block"),this.iconSpace&&this.iconSpace.remove()):(this.iconSpace||(this.iconSpace=t("<span> </span>"),this._addClass(this.iconSpace,"ui-button-icon-space")),this._removeClass(this.icon,null,"ui-wiget-icon-block"),this._attachIconSpace(n))},_destroy:function(){this.element.removeAttr("role"),this.icon&&this.icon.remove(),this.iconSpace&&this.iconSpace.remove(),this.hasTitle||this.element.removeAttr("title")},_attachIconSpace:function(t){this.icon[/^(?:end|bottom)/.test(t)?"before":"after"](this.iconSpace)},_attachIcon:function(t){this.element[/^(?:end|bottom)/.test(t)?"append":"prepend"](this.icon)},_setOptions:function(t){var e=void 0===t.showLabel?this.options.showLabel:t.showLabel,i=void 0===t.icon?this.options.icon:t.icon;e||i||(t.showLabel=!0),this._super(t)},_setOption:function(t,e){"icon"===t&&(e?this._updateIcon(t,e):this.icon&&(this.icon.remove(),this.iconSpace&&this.iconSpace.remove())),"iconPosition"===t&&this._updateIcon(t,e),"showLabel"===t&&(this._toggleClass("ui-button-icon-only",null,!e),this._updateTooltip()),"label"===t&&(this.isInput?this.element.val(e):(this.element.html(e),this.icon&&(this._attachIcon(this.options.iconPosition),this._attachIconSpace(this.options.iconPosition)))),this._super(t,e),"disabled"===t&&(this._toggleClass(null,"ui-state-disabled",e),this.element[0].disabled=e,e&&this.element.blur())},refresh:function(){var t=this.element.is("input, button")?this.element[0].disabled:this.element.hasClass("ui-button-disabled");t!==this.options.disabled&&this._setOptions({disabled:t}),this._updateTooltip()}}),t.uiBackCompat!==!1&&(t.widget("ui.button",t.ui.button,{options:{text:!0,icons:{primary:null,secondary:null}},_create:function(){this.options.showLabel&&!this.options.text&&(this.options.showLabel=this.options.text),!this.options.showLabel&&this.options.text&&(this.options.text=this.options.showLabel),this.options.icon||!this.options.icons.primary&&!this.options.icons.secondary?this.options.icon&&(this.options.icons.primary=this.options.icon):this.options.icons.primary?this.options.icon=this.options.icons.primary:(this.options.icon=this.options.icons.secondary,this.options.iconPosition="end"),this._super()},_setOption:function(t,e){return"text"===t?(this._super("showLabel",e),void 0):("showLabel"===t&&(this.options.text=e),"icon"===t&&(this.options.icons.primary=e),"icons"===t&&(e.primary?(this._super("icon",e.primary),this._super("iconPosition","beginning")):e.secondary&&(this._super("icon",e.secondary),this._super("iconPosition","end"))),this._superApply(arguments),void 0)}}),t.fn.button=function(e){return function(){return!this.length||this.length&&"INPUT"!==this[0].tagName||this.length&&"INPUT"===this[0].tagName&&"checkbox"!==this.attr("type")&&"radio"!==this.attr("type")?e.apply(this,arguments):(t.ui.checkboxradio||t.error("Checkboxradio widget missing"),0===arguments.length?this.checkboxradio({icon:!1}):this.checkboxradio.apply(this,arguments))}}(t.fn.button),t.fn.buttonset=function(){return t.ui.controlgroup||t.error("Controlgroup widget missing"),"option"===arguments[0]&&"items"===arguments[1]&&arguments[2]?this.controlgroup.apply(this,[arguments[0],"items.button",arguments[2]]):"option"===arguments[0]&&"items"===arguments[1]?this.controlgroup.apply(this,[arguments[0],"items.button"]):("object"==typeof arguments[0]&&arguments[0].items&&(arguments[0].items={button:arguments[0].items}),this.controlgroup.apply(this,arguments))}),t.ui.button,t.extend(t.ui,{datepicker:{version:"1.12.1"}});var m;t.extend(s.prototype,{markerClassName:"hasDatepicker",maxRows:4,_widgetDatepicker:function(){return this.dpDiv},setDefaults:function(t){return a(this._defaults,t||{}),this},_attachDatepicker:function(e,i){var s,n,o;s=e.nodeName.toLowerCase(),n="div"===s||"span"===s,e.id||(this.uuid+=1,e.id="dp"+this.uuid),o=this._newInst(t(e),n),o.settings=t.extend({},i||{}),"input"===s?this._connectDatepicker(e,o):n&&this._inlineDatepicker(e,o)},_newInst:function(e,i){var s=e[0].id.replace(/([^A-Za-z0-9_\-])/g,"\\\\$1");return{id:s,input:e,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:i,dpDiv:i?n(t("<div class='"+this._inlineClass+" ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")):this.dpDiv}},_connectDatepicker:function(e,i){var s=t(e);i.append=t([]),i.trigger=t([]),s.hasClass(this.markerClassName)||(this._attachments(s,i),s.addClass(this.markerClassName).on("keydown",this._doKeyDown).on("keypress",this._doKeyPress).on("keyup",this._doKeyUp),this._autoSize(i),t.data(e,"datepicker",i),i.settings.disabled&&this._disableDatepicker(e))},_attachments:function(e,i){var s,n,o,a=this._get(i,"appendText"),r=this._get(i,"isRTL");i.append&&i.append.remove(),a&&(i.append=t("<span class='"+this._appendClass+"'>"+a+"</span>"),e[r?"before":"after"](i.append)),e.off("focus",this._showDatepicker),i.trigger&&i.trigger.remove(),s=this._get(i,"showOn"),("focus"===s||"both"===s)&&e.on("focus",this._showDatepicker),("button"===s||"both"===s)&&(n=this._get(i,"buttonText"),o=this._get(i,"buttonImage"),i.trigger=t(this._get(i,"buttonImageOnly")?t("<img/>").addClass(this._triggerClass).attr({src:o,alt:n,title:n}):t("<button type='button'></button>").addClass(this._triggerClass).html(o?t("<img/>").attr({src:o,alt:n,title:n}):n)),e[r?"before":"after"](i.trigger),i.trigger.on("click",function(){return t.datepicker._datepickerShowing&&t.datepicker._lastInput===e[0]?t.datepicker._hideDatepicker():t.datepicker._datepickerShowing&&t.datepicker._lastInput!==e[0]?(t.datepicker._hideDatepicker(),t.datepicker._showDatepicker(e[0])):t.datepicker._showDatepicker(e[0]),!1}))},_autoSize:function(t){if(this._get(t,"autoSize")&&!t.inline){var e,i,s,n,o=new Date(2009,11,20),a=this._get(t,"dateFormat");a.match(/[DM]/)&&(e=function(t){for(i=0,s=0,n=0;t.length>n;n++)t[n].length>i&&(i=t[n].length,s=n);return s},o.setMonth(e(this._get(t,a.match(/MM/)?"monthNames":"monthNamesShort"))),o.setDate(e(this._get(t,a.match(/DD/)?"dayNames":"dayNamesShort"))+20-o.getDay())),t.input.attr("size",this._formatDate(t,o).length)}},_inlineDatepicker:function(e,i){var s=t(e);s.hasClass(this.markerClassName)||(s.addClass(this.markerClassName).append(i.dpDiv),t.data(e,"datepicker",i),this._setDate(i,this._getDefaultDate(i),!0),this._updateDatepicker(i),this._updateAlternate(i),i.settings.disabled&&this._disableDatepicker(e),i.dpDiv.css("display","block"))},_dialogDatepicker:function(e,i,s,n,o){var r,h,l,c,u,d=this._dialogInst;return d||(this.uuid+=1,r="dp"+this.uuid,this._dialogInput=t("<input type='text' id='"+r+"' style='position: absolute; top: -100px; width: 0px;'/>"),this._dialogInput.on("keydown",this._doKeyDown),t("body").append(this._dialogInput),d=this._dialogInst=this._newInst(this._dialogInput,!1),d.settings={},t.data(this._dialogInput[0],"datepicker",d)),a(d.settings,n||{}),i=i&&i.constructor===Date?this._formatDate(d,i):i,this._dialogInput.val(i),this._pos=o?o.length?o:[o.pageX,o.pageY]:null,this._pos||(h=document.documentElement.clientWidth,l=document.documentElement.clientHeight,c=document.documentElement.scrollLeft||document.body.scrollLeft,u=document.documentElement.scrollTop||document.body.scrollTop,this._pos=[h/2-100+c,l/2-150+u]),this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px"),d.settings.onSelect=s,this._inDialog=!0,this.dpDiv.addClass(this._dialogClass),this._showDatepicker(this._dialogInput[0]),t.blockUI&&t.blockUI(this.dpDiv),t.data(this._dialogInput[0],"datepicker",d),this},_destroyDatepicker:function(e){var i,s=t(e),n=t.data(e,"datepicker");s.hasClass(this.markerClassName)&&(i=e.nodeName.toLowerCase(),t.removeData(e,"datepicker"),"input"===i?(n.append.remove(),n.trigger.remove(),s.removeClass(this.markerClassName).off("focus",this._showDatepicker).off("keydown",this._doKeyDown).off("keypress",this._doKeyPress).off("keyup",this._doKeyUp)):("div"===i||"span"===i)&&s.removeClass(this.markerClassName).empty(),m===n&&(m=null))},_enableDatepicker:function(e){var i,s,n=t(e),o=t.data(e,"datepicker");n.hasClass(this.markerClassName)&&(i=e.nodeName.toLowerCase(),"input"===i?(e.disabled=!1,o.trigger.filter("button").each(function(){this.disabled=!1}).end().filter("img").css({opacity:"1.0",cursor:""})):("div"===i||"span"===i)&&(s=n.children("."+this._inlineClass),s.children().removeClass("ui-state-disabled"),s.find("select.ui-datepicker-month, select.ui-datepicker-year").prop("disabled",!1)),this._disabledInputs=t.map(this._disabledInputs,function(t){return t===e?null:t}))},_disableDatepicker:function(e){var i,s,n=t(e),o=t.data(e,"datepicker");n.hasClass(this.markerClassName)&&(i=e.nodeName.toLowerCase(),"input"===i?(e.disabled=!0,o.trigger.filter("button").each(function(){this.disabled=!0}).end().filter("img").css({opacity:"0.5",cursor:"default"})):("div"===i||"span"===i)&&(s=n.children("."+this._inlineClass),s.children().addClass("ui-state-disabled"),s.find("select.ui-datepicker-month, select.ui-datepicker-year").prop("disabled",!0)),this._disabledInputs=t.map(this._disabledInputs,function(t){return t===e?null:t}),this._disabledInputs[this._disabledInputs.length]=e)},_isDisabledDatepicker:function(t){if(!t)return!1;for(var e=0;this._disabledInputs.length>e;e++)if(this._disabledInputs[e]===t)return!0;return!1},_getInst:function(e){try{return t.data(e,"datepicker")}catch(i){throw"Missing instance data for this datepicker"}},_optionDatepicker:function(e,i,s){var n,o,r,h,l=this._getInst(e);return 2===arguments.length&&"string"==typeof i?"defaults"===i?t.extend({},t.datepicker._defaults):l?"all"===i?t.extend({},l.settings):this._get(l,i):null:(n=i||{},"string"==typeof i&&(n={},n[i]=s),l&&(this._curInst===l&&this._hideDatepicker(),o=this._getDateDatepicker(e,!0),r=this._getMinMaxDate(l,"min"),h=this._getMinMaxDate(l,"max"),a(l.settings,n),null!==r&&void 0!==n.dateFormat&&void 0===n.minDate&&(l.settings.minDate=this._formatDate(l,r)),null!==h&&void 0!==n.dateFormat&&void 0===n.maxDate&&(l.settings.maxDate=this._formatDate(l,h)),"disabled"in n&&(n.disabled?this._disableDatepicker(e):this._enableDatepicker(e)),this._attachments(t(e),l),this._autoSize(l),this._setDate(l,o),this._updateAlternate(l),this._updateDatepicker(l)),void 0)},_changeDatepicker:function(t,e,i){this._optionDatepicker(t,e,i)},_refreshDatepicker:function(t){var e=this._getInst(t);e&&this._updateDatepicker(e)},_setDateDatepicker:function(t,e){var i=this._getInst(t);i&&(this._setDate(i,e),this._updateDatepicker(i),this._updateAlternate(i))},_getDateDatepicker:function(t,e){var i=this._getInst(t);return i&&!i.inline&&this._setDateFromField(i,e),i?this._getDate(i):null},_doKeyDown:function(e){var i,s,n,o=t.datepicker._getInst(e.target),a=!0,r=o.dpDiv.is(".ui-datepicker-rtl");if(o._keyEvent=!0,t.datepicker._datepickerShowing)switch(e.keyCode){case 9:t.datepicker._hideDatepicker(),a=!1;break;case 13:return n=t("td."+t.datepicker._dayOverClass+":not(."+t.datepicker._currentClass+")",o.dpDiv),n[0]&&t.datepicker._selectDay(e.target,o.selectedMonth,o.selectedYear,n[0]),i=t.datepicker._get(o,"onSelect"),i?(s=t.datepicker._formatDate(o),i.apply(o.input?o.input[0]:null,[s,o])):t.datepicker._hideDatepicker(),!1;case 27:t.datepicker._hideDatepicker();break;case 33:t.datepicker._adjustDate(e.target,e.ctrlKey?-t.datepicker._get(o,"stepBigMonths"):-t.datepicker._get(o,"stepMonths"),"M");break;case 34:t.datepicker._adjustDate(e.target,e.ctrlKey?+t.datepicker._get(o,"stepBigMonths"):+t.datepicker._get(o,"stepMonths"),"M");break;case 35:(e.ctrlKey||e.metaKey)&&t.datepicker._clearDate(e.target),a=e.ctrlKey||e.metaKey;break;case 36:(e.ctrlKey||e.metaKey)&&t.datepicker._gotoToday(e.target),a=e.ctrlKey||e.metaKey;break;case 37:(e.ctrlKey||e.metaKey)&&t.datepicker._adjustDate(e.target,r?1:-1,"D"),a=e.ctrlKey||e.metaKey,e.originalEvent.altKey&&t.datepicker._adjustDate(e.target,e.ctrlKey?-t.datepicker._get(o,"stepBigMonths"):-t.datepicker._get(o,"stepMonths"),"M");break;case 38:(e.ctrlKey||e.metaKey)&&t.datepicker._adjustDate(e.target,-7,"D"),a=e.ctrlKey||e.metaKey;break;case 39:(e.ctrlKey||e.metaKey)&&t.datepicker._adjustDate(e.target,r?-1:1,"D"),a=e.ctrlKey||e.metaKey,e.originalEvent.altKey&&t.datepicker._adjustDate(e.target,e.ctrlKey?+t.datepicker._get(o,"stepBigMonths"):+t.datepicker._get(o,"stepMonths"),"M");break;case 40:(e.ctrlKey||e.metaKey)&&t.datepicker._adjustDate(e.target,7,"D"),a=e.ctrlKey||e.metaKey;break;default:a=!1}else 36===e.keyCode&&e.ctrlKey?t.datepicker._showDatepicker(this):a=!1;a&&(e.preventDefault(),e.stopPropagation())},_doKeyPress:function(e){var i,s,n=t.datepicker._getInst(e.target);return t.datepicker._get(n,"constrainInput")?(i=t.datepicker._possibleChars(t.datepicker._get(n,"dateFormat")),s=String.fromCharCode(null==e.charCode?e.keyCode:e.charCode),e.ctrlKey||e.metaKey||" ">s||!i||i.indexOf(s)>-1):void 0},_doKeyUp:function(e){var i,s=t.datepicker._getInst(e.target);if(s.input.val()!==s.lastVal)try{i=t.datepicker.parseDate(t.datepicker._get(s,"dateFormat"),s.input?s.input.val():null,t.datepicker._getFormatConfig(s)),i&&(t.datepicker._setDateFromField(s),t.datepicker._updateAlternate(s),t.datepicker._updateDatepicker(s))}catch(n){}return!0},_showDatepicker:function(e){if(e=e.target||e,"input"!==e.nodeName.toLowerCase()&&(e=t("input",e.parentNode)[0]),!t.datepicker._isDisabledDatepicker(e)&&t.datepicker._lastInput!==e){var s,n,o,r,h,l,c;s=t.datepicker._getInst(e),t.datepicker._curInst&&t.datepicker._curInst!==s&&(t.datepicker._curInst.dpDiv.stop(!0,!0),s&&t.datepicker._datepickerShowing&&t.datepicker._hideDatepicker(t.datepicker._curInst.input[0])),n=t.datepicker._get(s,"beforeShow"),o=n?n.apply(e,[e,s]):{},o!==!1&&(a(s.settings,o),s.lastVal=null,t.datepicker._lastInput=e,t.datepicker._setDateFromField(s),t.datepicker._inDialog&&(e.value=""),t.datepicker._pos||(t.datepicker._pos=t.datepicker._findPos(e),t.datepicker._pos[1]+=e.offsetHeight),r=!1,t(e).parents().each(function(){return r|="fixed"===t(this).css("position"),!r}),h={left:t.datepicker._pos[0],top:t.datepicker._pos[1]},t.datepicker._pos=null,s.dpDiv.empty(),s.dpDiv.css({position:"absolute",display:"block",top:"-1000px"}),t.datepicker._updateDatepicker(s),h=t.datepicker._checkOffset(s,h,r),s.dpDiv.css({position:t.datepicker._inDialog&&t.blockUI?"static":r?"fixed":"absolute",display:"none",left:h.left+"px",top:h.top+"px"}),s.inline||(l=t.datepicker._get(s,"showAnim"),c=t.datepicker._get(s,"duration"),s.dpDiv.css("z-index",i(t(e))+1),t.datepicker._datepickerShowing=!0,t.effects&&t.effects.effect[l]?s.dpDiv.show(l,t.datepicker._get(s,"showOptions"),c):s.dpDiv[l||"show"](l?c:null),t.datepicker._shouldFocusInput(s)&&s.input.trigger("focus"),t.datepicker._curInst=s)) +}},_updateDatepicker:function(e){this.maxRows=4,m=e,e.dpDiv.empty().append(this._generateHTML(e)),this._attachHandlers(e);var i,s=this._getNumberOfMonths(e),n=s[1],a=17,r=e.dpDiv.find("."+this._dayOverClass+" a");r.length>0&&o.apply(r.get(0)),e.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width(""),n>1&&e.dpDiv.addClass("ui-datepicker-multi-"+n).css("width",a*n+"em"),e.dpDiv[(1!==s[0]||1!==s[1]?"add":"remove")+"Class"]("ui-datepicker-multi"),e.dpDiv[(this._get(e,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl"),e===t.datepicker._curInst&&t.datepicker._datepickerShowing&&t.datepicker._shouldFocusInput(e)&&e.input.trigger("focus"),e.yearshtml&&(i=e.yearshtml,setTimeout(function(){i===e.yearshtml&&e.yearshtml&&e.dpDiv.find("select.ui-datepicker-year:first").replaceWith(e.yearshtml),i=e.yearshtml=null},0))},_shouldFocusInput:function(t){return t.input&&t.input.is(":visible")&&!t.input.is(":disabled")&&!t.input.is(":focus")},_checkOffset:function(e,i,s){var n=e.dpDiv.outerWidth(),o=e.dpDiv.outerHeight(),a=e.input?e.input.outerWidth():0,r=e.input?e.input.outerHeight():0,h=document.documentElement.clientWidth+(s?0:t(document).scrollLeft()),l=document.documentElement.clientHeight+(s?0:t(document).scrollTop());return i.left-=this._get(e,"isRTL")?n-a:0,i.left-=s&&i.left===e.input.offset().left?t(document).scrollLeft():0,i.top-=s&&i.top===e.input.offset().top+r?t(document).scrollTop():0,i.left-=Math.min(i.left,i.left+n>h&&h>n?Math.abs(i.left+n-h):0),i.top-=Math.min(i.top,i.top+o>l&&l>o?Math.abs(o+r):0),i},_findPos:function(e){for(var i,s=this._getInst(e),n=this._get(s,"isRTL");e&&("hidden"===e.type||1!==e.nodeType||t.expr.filters.hidden(e));)e=e[n?"previousSibling":"nextSibling"];return i=t(e).offset(),[i.left,i.top]},_hideDatepicker:function(e){var i,s,n,o,a=this._curInst;!a||e&&a!==t.data(e,"datepicker")||this._datepickerShowing&&(i=this._get(a,"showAnim"),s=this._get(a,"duration"),n=function(){t.datepicker._tidyDialog(a)},t.effects&&(t.effects.effect[i]||t.effects[i])?a.dpDiv.hide(i,t.datepicker._get(a,"showOptions"),s,n):a.dpDiv["slideDown"===i?"slideUp":"fadeIn"===i?"fadeOut":"hide"](i?s:null,n),i||n(),this._datepickerShowing=!1,o=this._get(a,"onClose"),o&&o.apply(a.input?a.input[0]:null,[a.input?a.input.val():"",a]),this._lastInput=null,this._inDialog&&(this._dialogInput.css({position:"absolute",left:"0",top:"-100px"}),t.blockUI&&(t.unblockUI(),t("body").append(this.dpDiv))),this._inDialog=!1)},_tidyDialog:function(t){t.dpDiv.removeClass(this._dialogClass).off(".ui-datepicker-calendar")},_checkExternalClick:function(e){if(t.datepicker._curInst){var i=t(e.target),s=t.datepicker._getInst(i[0]);(i[0].id!==t.datepicker._mainDivId&&0===i.parents("#"+t.datepicker._mainDivId).length&&!i.hasClass(t.datepicker.markerClassName)&&!i.closest("."+t.datepicker._triggerClass).length&&t.datepicker._datepickerShowing&&(!t.datepicker._inDialog||!t.blockUI)||i.hasClass(t.datepicker.markerClassName)&&t.datepicker._curInst!==s)&&t.datepicker._hideDatepicker()}},_adjustDate:function(e,i,s){var n=t(e),o=this._getInst(n[0]);this._isDisabledDatepicker(n[0])||(this._adjustInstDate(o,i+("M"===s?this._get(o,"showCurrentAtPos"):0),s),this._updateDatepicker(o))},_gotoToday:function(e){var i,s=t(e),n=this._getInst(s[0]);this._get(n,"gotoCurrent")&&n.currentDay?(n.selectedDay=n.currentDay,n.drawMonth=n.selectedMonth=n.currentMonth,n.drawYear=n.selectedYear=n.currentYear):(i=new Date,n.selectedDay=i.getDate(),n.drawMonth=n.selectedMonth=i.getMonth(),n.drawYear=n.selectedYear=i.getFullYear()),this._notifyChange(n),this._adjustDate(s)},_selectMonthYear:function(e,i,s){var n=t(e),o=this._getInst(n[0]);o["selected"+("M"===s?"Month":"Year")]=o["draw"+("M"===s?"Month":"Year")]=parseInt(i.options[i.selectedIndex].value,10),this._notifyChange(o),this._adjustDate(n)},_selectDay:function(e,i,s,n){var o,a=t(e);t(n).hasClass(this._unselectableClass)||this._isDisabledDatepicker(a[0])||(o=this._getInst(a[0]),o.selectedDay=o.currentDay=t("a",n).html(),o.selectedMonth=o.currentMonth=i,o.selectedYear=o.currentYear=s,this._selectDate(e,this._formatDate(o,o.currentDay,o.currentMonth,o.currentYear)))},_clearDate:function(e){var i=t(e);this._selectDate(i,"")},_selectDate:function(e,i){var s,n=t(e),o=this._getInst(n[0]);i=null!=i?i:this._formatDate(o),o.input&&o.input.val(i),this._updateAlternate(o),s=this._get(o,"onSelect"),s?s.apply(o.input?o.input[0]:null,[i,o]):o.input&&o.input.trigger("change"),o.inline?this._updateDatepicker(o):(this._hideDatepicker(),this._lastInput=o.input[0],"object"!=typeof o.input[0]&&o.input.trigger("focus"),this._lastInput=null)},_updateAlternate:function(e){var i,s,n,o=this._get(e,"altField");o&&(i=this._get(e,"altFormat")||this._get(e,"dateFormat"),s=this._getDate(e),n=this.formatDate(i,s,this._getFormatConfig(e)),t(o).val(n))},noWeekends:function(t){var e=t.getDay();return[e>0&&6>e,""]},iso8601Week:function(t){var e,i=new Date(t.getTime());return i.setDate(i.getDate()+4-(i.getDay()||7)),e=i.getTime(),i.setMonth(0),i.setDate(1),Math.floor(Math.round((e-i)/864e5)/7)+1},parseDate:function(e,i,s){if(null==e||null==i)throw"Invalid arguments";if(i="object"==typeof i?""+i:i+"",""===i)return null;var n,o,a,r,h=0,l=(s?s.shortYearCutoff:null)||this._defaults.shortYearCutoff,c="string"!=typeof l?l:(new Date).getFullYear()%100+parseInt(l,10),u=(s?s.dayNamesShort:null)||this._defaults.dayNamesShort,d=(s?s.dayNames:null)||this._defaults.dayNames,p=(s?s.monthNamesShort:null)||this._defaults.monthNamesShort,f=(s?s.monthNames:null)||this._defaults.monthNames,g=-1,m=-1,_=-1,v=-1,b=!1,y=function(t){var i=e.length>n+1&&e.charAt(n+1)===t;return i&&n++,i},w=function(t){var e=y(t),s="@"===t?14:"!"===t?20:"y"===t&&e?4:"o"===t?3:2,n="y"===t?s:1,o=RegExp("^\\d{"+n+","+s+"}"),a=i.substring(h).match(o);if(!a)throw"Missing number at position "+h;return h+=a[0].length,parseInt(a[0],10)},k=function(e,s,n){var o=-1,a=t.map(y(e)?n:s,function(t,e){return[[e,t]]}).sort(function(t,e){return-(t[1].length-e[1].length)});if(t.each(a,function(t,e){var s=e[1];return i.substr(h,s.length).toLowerCase()===s.toLowerCase()?(o=e[0],h+=s.length,!1):void 0}),-1!==o)return o+1;throw"Unknown name at position "+h},x=function(){if(i.charAt(h)!==e.charAt(n))throw"Unexpected literal at position "+h;h++};for(n=0;e.length>n;n++)if(b)"'"!==e.charAt(n)||y("'")?x():b=!1;else switch(e.charAt(n)){case"d":_=w("d");break;case"D":k("D",u,d);break;case"o":v=w("o");break;case"m":m=w("m");break;case"M":m=k("M",p,f);break;case"y":g=w("y");break;case"@":r=new Date(w("@")),g=r.getFullYear(),m=r.getMonth()+1,_=r.getDate();break;case"!":r=new Date((w("!")-this._ticksTo1970)/1e4),g=r.getFullYear(),m=r.getMonth()+1,_=r.getDate();break;case"'":y("'")?x():b=!0;break;default:x()}if(i.length>h&&(a=i.substr(h),!/^\s+/.test(a)))throw"Extra/unparsed characters found in date: "+a;if(-1===g?g=(new Date).getFullYear():100>g&&(g+=(new Date).getFullYear()-(new Date).getFullYear()%100+(c>=g?0:-100)),v>-1)for(m=1,_=v;;){if(o=this._getDaysInMonth(g,m-1),o>=_)break;m++,_-=o}if(r=this._daylightSavingAdjust(new Date(g,m-1,_)),r.getFullYear()!==g||r.getMonth()+1!==m||r.getDate()!==_)throw"Invalid date";return r},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:1e7*60*60*24*(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925)),formatDate:function(t,e,i){if(!e)return"";var s,n=(i?i.dayNamesShort:null)||this._defaults.dayNamesShort,o=(i?i.dayNames:null)||this._defaults.dayNames,a=(i?i.monthNamesShort:null)||this._defaults.monthNamesShort,r=(i?i.monthNames:null)||this._defaults.monthNames,h=function(e){var i=t.length>s+1&&t.charAt(s+1)===e;return i&&s++,i},l=function(t,e,i){var s=""+e;if(h(t))for(;i>s.length;)s="0"+s;return s},c=function(t,e,i,s){return h(t)?s[e]:i[e]},u="",d=!1;if(e)for(s=0;t.length>s;s++)if(d)"'"!==t.charAt(s)||h("'")?u+=t.charAt(s):d=!1;else switch(t.charAt(s)){case"d":u+=l("d",e.getDate(),2);break;case"D":u+=c("D",e.getDay(),n,o);break;case"o":u+=l("o",Math.round((new Date(e.getFullYear(),e.getMonth(),e.getDate()).getTime()-new Date(e.getFullYear(),0,0).getTime())/864e5),3);break;case"m":u+=l("m",e.getMonth()+1,2);break;case"M":u+=c("M",e.getMonth(),a,r);break;case"y":u+=h("y")?e.getFullYear():(10>e.getFullYear()%100?"0":"")+e.getFullYear()%100;break;case"@":u+=e.getTime();break;case"!":u+=1e4*e.getTime()+this._ticksTo1970;break;case"'":h("'")?u+="'":d=!0;break;default:u+=t.charAt(s)}return u},_possibleChars:function(t){var e,i="",s=!1,n=function(i){var s=t.length>e+1&&t.charAt(e+1)===i;return s&&e++,s};for(e=0;t.length>e;e++)if(s)"'"!==t.charAt(e)||n("'")?i+=t.charAt(e):s=!1;else switch(t.charAt(e)){case"d":case"m":case"y":case"@":i+="0123456789";break;case"D":case"M":return null;case"'":n("'")?i+="'":s=!0;break;default:i+=t.charAt(e)}return i},_get:function(t,e){return void 0!==t.settings[e]?t.settings[e]:this._defaults[e]},_setDateFromField:function(t,e){if(t.input.val()!==t.lastVal){var i=this._get(t,"dateFormat"),s=t.lastVal=t.input?t.input.val():null,n=this._getDefaultDate(t),o=n,a=this._getFormatConfig(t);try{o=this.parseDate(i,s,a)||n}catch(r){s=e?"":s}t.selectedDay=o.getDate(),t.drawMonth=t.selectedMonth=o.getMonth(),t.drawYear=t.selectedYear=o.getFullYear(),t.currentDay=s?o.getDate():0,t.currentMonth=s?o.getMonth():0,t.currentYear=s?o.getFullYear():0,this._adjustInstDate(t)}},_getDefaultDate:function(t){return this._restrictMinMax(t,this._determineDate(t,this._get(t,"defaultDate"),new Date))},_determineDate:function(e,i,s){var n=function(t){var e=new Date;return e.setDate(e.getDate()+t),e},o=function(i){try{return t.datepicker.parseDate(t.datepicker._get(e,"dateFormat"),i,t.datepicker._getFormatConfig(e))}catch(s){}for(var n=(i.toLowerCase().match(/^c/)?t.datepicker._getDate(e):null)||new Date,o=n.getFullYear(),a=n.getMonth(),r=n.getDate(),h=/([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,l=h.exec(i);l;){switch(l[2]||"d"){case"d":case"D":r+=parseInt(l[1],10);break;case"w":case"W":r+=7*parseInt(l[1],10);break;case"m":case"M":a+=parseInt(l[1],10),r=Math.min(r,t.datepicker._getDaysInMonth(o,a));break;case"y":case"Y":o+=parseInt(l[1],10),r=Math.min(r,t.datepicker._getDaysInMonth(o,a))}l=h.exec(i)}return new Date(o,a,r)},a=null==i||""===i?s:"string"==typeof i?o(i):"number"==typeof i?isNaN(i)?s:n(i):new Date(i.getTime());return a=a&&"Invalid Date"==""+a?s:a,a&&(a.setHours(0),a.setMinutes(0),a.setSeconds(0),a.setMilliseconds(0)),this._daylightSavingAdjust(a)},_daylightSavingAdjust:function(t){return t?(t.setHours(t.getHours()>12?t.getHours()+2:0),t):null},_setDate:function(t,e,i){var s=!e,n=t.selectedMonth,o=t.selectedYear,a=this._restrictMinMax(t,this._determineDate(t,e,new Date));t.selectedDay=t.currentDay=a.getDate(),t.drawMonth=t.selectedMonth=t.currentMonth=a.getMonth(),t.drawYear=t.selectedYear=t.currentYear=a.getFullYear(),n===t.selectedMonth&&o===t.selectedYear||i||this._notifyChange(t),this._adjustInstDate(t),t.input&&t.input.val(s?"":this._formatDate(t))},_getDate:function(t){var e=!t.currentYear||t.input&&""===t.input.val()?null:this._daylightSavingAdjust(new Date(t.currentYear,t.currentMonth,t.currentDay));return e},_attachHandlers:function(e){var i=this._get(e,"stepMonths"),s="#"+e.id.replace(/\\\\/g,"\\");e.dpDiv.find("[data-handler]").map(function(){var e={prev:function(){t.datepicker._adjustDate(s,-i,"M")},next:function(){t.datepicker._adjustDate(s,+i,"M")},hide:function(){t.datepicker._hideDatepicker()},today:function(){t.datepicker._gotoToday(s)},selectDay:function(){return t.datepicker._selectDay(s,+this.getAttribute("data-month"),+this.getAttribute("data-year"),this),!1},selectMonth:function(){return t.datepicker._selectMonthYear(s,this,"M"),!1},selectYear:function(){return t.datepicker._selectMonthYear(s,this,"Y"),!1}};t(this).on(this.getAttribute("data-event"),e[this.getAttribute("data-handler")])})},_generateHTML:function(t){var e,i,s,n,o,a,r,h,l,c,u,d,p,f,g,m,_,v,b,y,w,k,x,C,D,I,T,P,M,S,H,z,O,A,N,W,E,F,L,R=new Date,B=this._daylightSavingAdjust(new Date(R.getFullYear(),R.getMonth(),R.getDate())),Y=this._get(t,"isRTL"),j=this._get(t,"showButtonPanel"),q=this._get(t,"hideIfNoPrevNext"),K=this._get(t,"navigationAsDateFormat"),U=this._getNumberOfMonths(t),V=this._get(t,"showCurrentAtPos"),$=this._get(t,"stepMonths"),X=1!==U[0]||1!==U[1],G=this._daylightSavingAdjust(t.currentDay?new Date(t.currentYear,t.currentMonth,t.currentDay):new Date(9999,9,9)),Q=this._getMinMaxDate(t,"min"),J=this._getMinMaxDate(t,"max"),Z=t.drawMonth-V,te=t.drawYear;if(0>Z&&(Z+=12,te--),J)for(e=this._daylightSavingAdjust(new Date(J.getFullYear(),J.getMonth()-U[0]*U[1]+1,J.getDate())),e=Q&&Q>e?Q:e;this._daylightSavingAdjust(new Date(te,Z,1))>e;)Z--,0>Z&&(Z=11,te--);for(t.drawMonth=Z,t.drawYear=te,i=this._get(t,"prevText"),i=K?this.formatDate(i,this._daylightSavingAdjust(new Date(te,Z-$,1)),this._getFormatConfig(t)):i,s=this._canAdjustMonth(t,-1,te,Z)?"<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click' title='"+i+"'><span class='ui-icon ui-icon-circle-triangle-"+(Y?"e":"w")+"'>"+i+"</span></a>":q?"":"<a class='ui-datepicker-prev ui-corner-all ui-state-disabled' title='"+i+"'><span class='ui-icon ui-icon-circle-triangle-"+(Y?"e":"w")+"'>"+i+"</span></a>",n=this._get(t,"nextText"),n=K?this.formatDate(n,this._daylightSavingAdjust(new Date(te,Z+$,1)),this._getFormatConfig(t)):n,o=this._canAdjustMonth(t,1,te,Z)?"<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click' title='"+n+"'><span class='ui-icon ui-icon-circle-triangle-"+(Y?"w":"e")+"'>"+n+"</span></a>":q?"":"<a class='ui-datepicker-next ui-corner-all ui-state-disabled' title='"+n+"'><span class='ui-icon ui-icon-circle-triangle-"+(Y?"w":"e")+"'>"+n+"</span></a>",a=this._get(t,"currentText"),r=this._get(t,"gotoCurrent")&&t.currentDay?G:B,a=K?this.formatDate(a,r,this._getFormatConfig(t)):a,h=t.inline?"":"<button type='button' class='ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all' data-handler='hide' data-event='click'>"+this._get(t,"closeText")+"</button>",l=j?"<div class='ui-datepicker-buttonpane ui-widget-content'>"+(Y?h:"")+(this._isInRange(t,r)?"<button type='button' class='ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all' data-handler='today' data-event='click'>"+a+"</button>":"")+(Y?"":h)+"</div>":"",c=parseInt(this._get(t,"firstDay"),10),c=isNaN(c)?0:c,u=this._get(t,"showWeek"),d=this._get(t,"dayNames"),p=this._get(t,"dayNamesMin"),f=this._get(t,"monthNames"),g=this._get(t,"monthNamesShort"),m=this._get(t,"beforeShowDay"),_=this._get(t,"showOtherMonths"),v=this._get(t,"selectOtherMonths"),b=this._getDefaultDate(t),y="",k=0;U[0]>k;k++){for(x="",this.maxRows=4,C=0;U[1]>C;C++){if(D=this._daylightSavingAdjust(new Date(te,Z,t.selectedDay)),I=" ui-corner-all",T="",X){if(T+="<div class='ui-datepicker-group",U[1]>1)switch(C){case 0:T+=" ui-datepicker-group-first",I=" ui-corner-"+(Y?"right":"left");break;case U[1]-1:T+=" ui-datepicker-group-last",I=" ui-corner-"+(Y?"left":"right");break;default:T+=" ui-datepicker-group-middle",I=""}T+="'>"}for(T+="<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix"+I+"'>"+(/all|left/.test(I)&&0===k?Y?o:s:"")+(/all|right/.test(I)&&0===k?Y?s:o:"")+this._generateMonthYearHeader(t,Z,te,Q,J,k>0||C>0,f,g)+"</div><table class='ui-datepicker-calendar'><thead>"+"<tr>",P=u?"<th class='ui-datepicker-week-col'>"+this._get(t,"weekHeader")+"</th>":"",w=0;7>w;w++)M=(w+c)%7,P+="<th scope='col'"+((w+c+6)%7>=5?" class='ui-datepicker-week-end'":"")+">"+"<span title='"+d[M]+"'>"+p[M]+"</span></th>";for(T+=P+"</tr></thead><tbody>",S=this._getDaysInMonth(te,Z),te===t.selectedYear&&Z===t.selectedMonth&&(t.selectedDay=Math.min(t.selectedDay,S)),H=(this._getFirstDayOfMonth(te,Z)-c+7)%7,z=Math.ceil((H+S)/7),O=X?this.maxRows>z?this.maxRows:z:z,this.maxRows=O,A=this._daylightSavingAdjust(new Date(te,Z,1-H)),N=0;O>N;N++){for(T+="<tr>",W=u?"<td class='ui-datepicker-week-col'>"+this._get(t,"calculateWeek")(A)+"</td>":"",w=0;7>w;w++)E=m?m.apply(t.input?t.input[0]:null,[A]):[!0,""],F=A.getMonth()!==Z,L=F&&!v||!E[0]||Q&&Q>A||J&&A>J,W+="<td class='"+((w+c+6)%7>=5?" ui-datepicker-week-end":"")+(F?" ui-datepicker-other-month":"")+(A.getTime()===D.getTime()&&Z===t.selectedMonth&&t._keyEvent||b.getTime()===A.getTime()&&b.getTime()===D.getTime()?" "+this._dayOverClass:"")+(L?" "+this._unselectableClass+" ui-state-disabled":"")+(F&&!_?"":" "+E[1]+(A.getTime()===G.getTime()?" "+this._currentClass:"")+(A.getTime()===B.getTime()?" ui-datepicker-today":""))+"'"+(F&&!_||!E[2]?"":" title='"+E[2].replace(/'/g,"'")+"'")+(L?"":" data-handler='selectDay' data-event='click' data-month='"+A.getMonth()+"' data-year='"+A.getFullYear()+"'")+">"+(F&&!_?" ":L?"<span class='ui-state-default'>"+A.getDate()+"</span>":"<a class='ui-state-default"+(A.getTime()===B.getTime()?" ui-state-highlight":"")+(A.getTime()===G.getTime()?" ui-state-active":"")+(F?" ui-priority-secondary":"")+"' href='#'>"+A.getDate()+"</a>")+"</td>",A.setDate(A.getDate()+1),A=this._daylightSavingAdjust(A);T+=W+"</tr>"}Z++,Z>11&&(Z=0,te++),T+="</tbody></table>"+(X?"</div>"+(U[0]>0&&C===U[1]-1?"<div class='ui-datepicker-row-break'></div>":""):""),x+=T}y+=x}return y+=l,t._keyEvent=!1,y},_generateMonthYearHeader:function(t,e,i,s,n,o,a,r){var h,l,c,u,d,p,f,g,m=this._get(t,"changeMonth"),_=this._get(t,"changeYear"),v=this._get(t,"showMonthAfterYear"),b="<div class='ui-datepicker-title'>",y="";if(o||!m)y+="<span class='ui-datepicker-month'>"+a[e]+"</span>";else{for(h=s&&s.getFullYear()===i,l=n&&n.getFullYear()===i,y+="<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>",c=0;12>c;c++)(!h||c>=s.getMonth())&&(!l||n.getMonth()>=c)&&(y+="<option value='"+c+"'"+(c===e?" selected='selected'":"")+">"+r[c]+"</option>");y+="</select>"}if(v||(b+=y+(!o&&m&&_?"":" ")),!t.yearshtml)if(t.yearshtml="",o||!_)b+="<span class='ui-datepicker-year'>"+i+"</span>";else{for(u=this._get(t,"yearRange").split(":"),d=(new Date).getFullYear(),p=function(t){var e=t.match(/c[+\-].*/)?i+parseInt(t.substring(1),10):t.match(/[+\-].*/)?d+parseInt(t,10):parseInt(t,10);return isNaN(e)?d:e},f=p(u[0]),g=Math.max(f,p(u[1]||"")),f=s?Math.max(f,s.getFullYear()):f,g=n?Math.min(g,n.getFullYear()):g,t.yearshtml+="<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";g>=f;f++)t.yearshtml+="<option value='"+f+"'"+(f===i?" selected='selected'":"")+">"+f+"</option>";t.yearshtml+="</select>",b+=t.yearshtml,t.yearshtml=null}return b+=this._get(t,"yearSuffix"),v&&(b+=(!o&&m&&_?"":" ")+y),b+="</div>"},_adjustInstDate:function(t,e,i){var s=t.selectedYear+("Y"===i?e:0),n=t.selectedMonth+("M"===i?e:0),o=Math.min(t.selectedDay,this._getDaysInMonth(s,n))+("D"===i?e:0),a=this._restrictMinMax(t,this._daylightSavingAdjust(new Date(s,n,o)));t.selectedDay=a.getDate(),t.drawMonth=t.selectedMonth=a.getMonth(),t.drawYear=t.selectedYear=a.getFullYear(),("M"===i||"Y"===i)&&this._notifyChange(t)},_restrictMinMax:function(t,e){var i=this._getMinMaxDate(t,"min"),s=this._getMinMaxDate(t,"max"),n=i&&i>e?i:e;return s&&n>s?s:n},_notifyChange:function(t){var e=this._get(t,"onChangeMonthYear");e&&e.apply(t.input?t.input[0]:null,[t.selectedYear,t.selectedMonth+1,t])},_getNumberOfMonths:function(t){var e=this._get(t,"numberOfMonths");return null==e?[1,1]:"number"==typeof e?[1,e]:e},_getMinMaxDate:function(t,e){return this._determineDate(t,this._get(t,e+"Date"),null)},_getDaysInMonth:function(t,e){return 32-this._daylightSavingAdjust(new Date(t,e,32)).getDate()},_getFirstDayOfMonth:function(t,e){return new Date(t,e,1).getDay()},_canAdjustMonth:function(t,e,i,s){var n=this._getNumberOfMonths(t),o=this._daylightSavingAdjust(new Date(i,s+(0>e?e:n[0]*n[1]),1));return 0>e&&o.setDate(this._getDaysInMonth(o.getFullYear(),o.getMonth())),this._isInRange(t,o)},_isInRange:function(t,e){var i,s,n=this._getMinMaxDate(t,"min"),o=this._getMinMaxDate(t,"max"),a=null,r=null,h=this._get(t,"yearRange");return h&&(i=h.split(":"),s=(new Date).getFullYear(),a=parseInt(i[0],10),r=parseInt(i[1],10),i[0].match(/[+\-].*/)&&(a+=s),i[1].match(/[+\-].*/)&&(r+=s)),(!n||e.getTime()>=n.getTime())&&(!o||e.getTime()<=o.getTime())&&(!a||e.getFullYear()>=a)&&(!r||r>=e.getFullYear())},_getFormatConfig:function(t){var e=this._get(t,"shortYearCutoff");return e="string"!=typeof e?e:(new Date).getFullYear()%100+parseInt(e,10),{shortYearCutoff:e,dayNamesShort:this._get(t,"dayNamesShort"),dayNames:this._get(t,"dayNames"),monthNamesShort:this._get(t,"monthNamesShort"),monthNames:this._get(t,"monthNames")}},_formatDate:function(t,e,i,s){e||(t.currentDay=t.selectedDay,t.currentMonth=t.selectedMonth,t.currentYear=t.selectedYear);var n=e?"object"==typeof e?e:this._daylightSavingAdjust(new Date(s,i,e)):this._daylightSavingAdjust(new Date(t.currentYear,t.currentMonth,t.currentDay));return this.formatDate(this._get(t,"dateFormat"),n,this._getFormatConfig(t))}}),t.fn.datepicker=function(e){if(!this.length)return this;t.datepicker.initialized||(t(document).on("mousedown",t.datepicker._checkExternalClick),t.datepicker.initialized=!0),0===t("#"+t.datepicker._mainDivId).length&&t("body").append(t.datepicker.dpDiv);var i=Array.prototype.slice.call(arguments,1);return"string"!=typeof e||"isDisabled"!==e&&"getDate"!==e&&"widget"!==e?"option"===e&&2===arguments.length&&"string"==typeof arguments[1]?t.datepicker["_"+e+"Datepicker"].apply(t.datepicker,[this[0]].concat(i)):this.each(function(){"string"==typeof e?t.datepicker["_"+e+"Datepicker"].apply(t.datepicker,[this].concat(i)):t.datepicker._attachDatepicker(this,e)}):t.datepicker["_"+e+"Datepicker"].apply(t.datepicker,[this[0]].concat(i))},t.datepicker=new s,t.datepicker.initialized=!1,t.datepicker.uuid=(new Date).getTime(),t.datepicker.version="1.12.1",t.datepicker,t.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase());var _=!1;t(document).on("mouseup",function(){_=!1}),t.widget("ui.mouse",{version:"1.12.1",options:{cancel:"input, textarea, button, select, option",distance:1,delay:0},_mouseInit:function(){var e=this;this.element.on("mousedown."+this.widgetName,function(t){return e._mouseDown(t)}).on("click."+this.widgetName,function(i){return!0===t.data(i.target,e.widgetName+".preventClickEvent")?(t.removeData(i.target,e.widgetName+".preventClickEvent"),i.stopImmediatePropagation(),!1):void 0}),this.started=!1},_mouseDestroy:function(){this.element.off("."+this.widgetName),this._mouseMoveDelegate&&this.document.off("mousemove."+this.widgetName,this._mouseMoveDelegate).off("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(e){if(!_){this._mouseMoved=!1,this._mouseStarted&&this._mouseUp(e),this._mouseDownEvent=e;var i=this,s=1===e.which,n="string"==typeof this.options.cancel&&e.target.nodeName?t(e.target).closest(this.options.cancel).length:!1;return s&&!n&&this._mouseCapture(e)?(this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){i.mouseDelayMet=!0},this.options.delay)),this._mouseDistanceMet(e)&&this._mouseDelayMet(e)&&(this._mouseStarted=this._mouseStart(e)!==!1,!this._mouseStarted)?(e.preventDefault(),!0):(!0===t.data(e.target,this.widgetName+".preventClickEvent")&&t.removeData(e.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(t){return i._mouseMove(t)},this._mouseUpDelegate=function(t){return i._mouseUp(t)},this.document.on("mousemove."+this.widgetName,this._mouseMoveDelegate).on("mouseup."+this.widgetName,this._mouseUpDelegate),e.preventDefault(),_=!0,!0)):!0}},_mouseMove:function(e){if(this._mouseMoved){if(t.ui.ie&&(!document.documentMode||9>document.documentMode)&&!e.button)return this._mouseUp(e);if(!e.which)if(e.originalEvent.altKey||e.originalEvent.ctrlKey||e.originalEvent.metaKey||e.originalEvent.shiftKey)this.ignoreMissingWhich=!0;else if(!this.ignoreMissingWhich)return this._mouseUp(e)}return(e.which||e.button)&&(this._mouseMoved=!0),this._mouseStarted?(this._mouseDrag(e),e.preventDefault()):(this._mouseDistanceMet(e)&&this._mouseDelayMet(e)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,e)!==!1,this._mouseStarted?this._mouseDrag(e):this._mouseUp(e)),!this._mouseStarted)},_mouseUp:function(e){this.document.off("mousemove."+this.widgetName,this._mouseMoveDelegate).off("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,e.target===this._mouseDownEvent.target&&t.data(e.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(e)),this._mouseDelayTimer&&(clearTimeout(this._mouseDelayTimer),delete this._mouseDelayTimer),this.ignoreMissingWhich=!1,_=!1,e.preventDefault()},_mouseDistanceMet:function(t){return Math.max(Math.abs(this._mouseDownEvent.pageX-t.pageX),Math.abs(this._mouseDownEvent.pageY-t.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}}),t.ui.plugin={add:function(e,i,s){var n,o=t.ui[e].prototype;for(n in s)o.plugins[n]=o.plugins[n]||[],o.plugins[n].push([i,s[n]])},call:function(t,e,i,s){var n,o=t.plugins[e];if(o&&(s||t.element[0].parentNode&&11!==t.element[0].parentNode.nodeType))for(n=0;o.length>n;n++)t.options[o[n][0]]&&o[n][1].apply(t.element,i)}},t.ui.safeBlur=function(e){e&&"body"!==e.nodeName.toLowerCase()&&t(e).trigger("blur")},t.widget("ui.draggable",t.ui.mouse,{version:"1.12.1",widgetEventPrefix:"drag",options:{addClasses:!0,appendTo:"parent",axis:!1,connectToSortable:!1,containment:!1,cursor:"auto",cursorAt:!1,grid:!1,handle:!1,helper:"original",iframeFix:!1,opacity:!1,refreshPositions:!1,revert:!1,revertDuration:500,scope:"default",scroll:!0,scrollSensitivity:20,scrollSpeed:20,snap:!1,snapMode:"both",snapTolerance:20,stack:!1,zIndex:!1,drag:null,start:null,stop:null},_create:function(){"original"===this.options.helper&&this._setPositionRelative(),this.options.addClasses&&this._addClass("ui-draggable"),this._setHandleClassName(),this._mouseInit()},_setOption:function(t,e){this._super(t,e),"handle"===t&&(this._removeHandleClassName(),this._setHandleClassName())},_destroy:function(){return(this.helper||this.element).is(".ui-draggable-dragging")?(this.destroyOnClear=!0,void 0):(this._removeHandleClassName(),this._mouseDestroy(),void 0)},_mouseCapture:function(e){var i=this.options;return this.helper||i.disabled||t(e.target).closest(".ui-resizable-handle").length>0?!1:(this.handle=this._getHandle(e),this.handle?(this._blurActiveElement(e),this._blockFrames(i.iframeFix===!0?"iframe":i.iframeFix),!0):!1)},_blockFrames:function(e){this.iframeBlocks=this.document.find(e).map(function(){var e=t(this);return t("<div>").css("position","absolute").appendTo(e.parent()).outerWidth(e.outerWidth()).outerHeight(e.outerHeight()).offset(e.offset())[0]})},_unblockFrames:function(){this.iframeBlocks&&(this.iframeBlocks.remove(),delete this.iframeBlocks)},_blurActiveElement:function(e){var i=t.ui.safeActiveElement(this.document[0]),s=t(e.target);s.closest(i).length||t.ui.safeBlur(i)},_mouseStart:function(e){var i=this.options;return this.helper=this._createHelper(e),this._addClass(this.helper,"ui-draggable-dragging"),this._cacheHelperProportions(),t.ui.ddmanager&&(t.ui.ddmanager.current=this),this._cacheMargins(),this.cssPosition=this.helper.css("position"),this.scrollParent=this.helper.scrollParent(!0),this.offsetParent=this.helper.offsetParent(),this.hasFixedAncestor=this.helper.parents().filter(function(){return"fixed"===t(this).css("position")}).length>0,this.positionAbs=this.element.offset(),this._refreshOffsets(e),this.originalPosition=this.position=this._generatePosition(e,!1),this.originalPageX=e.pageX,this.originalPageY=e.pageY,i.cursorAt&&this._adjustOffsetFromHelper(i.cursorAt),this._setContainment(),this._trigger("start",e)===!1?(this._clear(),!1):(this._cacheHelperProportions(),t.ui.ddmanager&&!i.dropBehaviour&&t.ui.ddmanager.prepareOffsets(this,e),this._mouseDrag(e,!0),t.ui.ddmanager&&t.ui.ddmanager.dragStart(this,e),!0)},_refreshOffsets:function(t){this.offset={top:this.positionAbs.top-this.margins.top,left:this.positionAbs.left-this.margins.left,scroll:!1,parent:this._getParentOffset(),relative:this._getRelativeOffset()},this.offset.click={left:t.pageX-this.offset.left,top:t.pageY-this.offset.top}},_mouseDrag:function(e,i){if(this.hasFixedAncestor&&(this.offset.parent=this._getParentOffset()),this.position=this._generatePosition(e,!0),this.positionAbs=this._convertPositionTo("absolute"),!i){var s=this._uiHash();if(this._trigger("drag",e,s)===!1)return this._mouseUp(new t.Event("mouseup",e)),!1;this.position=s.position}return this.helper[0].style.left=this.position.left+"px",this.helper[0].style.top=this.position.top+"px",t.ui.ddmanager&&t.ui.ddmanager.drag(this,e),!1},_mouseStop:function(e){var i=this,s=!1;return t.ui.ddmanager&&!this.options.dropBehaviour&&(s=t.ui.ddmanager.drop(this,e)),this.dropped&&(s=this.dropped,this.dropped=!1),"invalid"===this.options.revert&&!s||"valid"===this.options.revert&&s||this.options.revert===!0||t.isFunction(this.options.revert)&&this.options.revert.call(this.element,s)?t(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){i._trigger("stop",e)!==!1&&i._clear()}):this._trigger("stop",e)!==!1&&this._clear(),!1},_mouseUp:function(e){return this._unblockFrames(),t.ui.ddmanager&&t.ui.ddmanager.dragStop(this,e),this.handleElement.is(e.target)&&this.element.trigger("focus"),t.ui.mouse.prototype._mouseUp.call(this,e)},cancel:function(){return this.helper.is(".ui-draggable-dragging")?this._mouseUp(new t.Event("mouseup",{target:this.element[0]})):this._clear(),this},_getHandle:function(e){return this.options.handle?!!t(e.target).closest(this.element.find(this.options.handle)).length:!0},_setHandleClassName:function(){this.handleElement=this.options.handle?this.element.find(this.options.handle):this.element,this._addClass(this.handleElement,"ui-draggable-handle")},_removeHandleClassName:function(){this._removeClass(this.handleElement,"ui-draggable-handle")},_createHelper:function(e){var i=this.options,s=t.isFunction(i.helper),n=s?t(i.helper.apply(this.element[0],[e])):"clone"===i.helper?this.element.clone().removeAttr("id"):this.element;return n.parents("body").length||n.appendTo("parent"===i.appendTo?this.element[0].parentNode:i.appendTo),s&&n[0]===this.element[0]&&this._setPositionRelative(),n[0]===this.element[0]||/(fixed|absolute)/.test(n.css("position"))||n.css("position","absolute"),n},_setPositionRelative:function(){/^(?:r|a|f)/.test(this.element.css("position"))||(this.element[0].style.position="relative")},_adjustOffsetFromHelper:function(e){"string"==typeof e&&(e=e.split(" ")),t.isArray(e)&&(e={left:+e[0],top:+e[1]||0}),"left"in e&&(this.offset.click.left=e.left+this.margins.left),"right"in e&&(this.offset.click.left=this.helperProportions.width-e.right+this.margins.left),"top"in e&&(this.offset.click.top=e.top+this.margins.top),"bottom"in e&&(this.offset.click.top=this.helperProportions.height-e.bottom+this.margins.top)},_isRootNode:function(t){return/(html|body)/i.test(t.tagName)||t===this.document[0]},_getParentOffset:function(){var e=this.offsetParent.offset(),i=this.document[0];return"absolute"===this.cssPosition&&this.scrollParent[0]!==i&&t.contains(this.scrollParent[0],this.offsetParent[0])&&(e.left+=this.scrollParent.scrollLeft(),e.top+=this.scrollParent.scrollTop()),this._isRootNode(this.offsetParent[0])&&(e={top:0,left:0}),{top:e.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:e.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"!==this.cssPosition)return{top:0,left:0};var t=this.element.position(),e=this._isRootNode(this.scrollParent[0]);return{top:t.top-(parseInt(this.helper.css("top"),10)||0)+(e?0:this.scrollParent.scrollTop()),left:t.left-(parseInt(this.helper.css("left"),10)||0)+(e?0:this.scrollParent.scrollLeft())} +},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var e,i,s,n=this.options,o=this.document[0];return this.relativeContainer=null,n.containment?"window"===n.containment?(this.containment=[t(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,t(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,t(window).scrollLeft()+t(window).width()-this.helperProportions.width-this.margins.left,t(window).scrollTop()+(t(window).height()||o.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top],void 0):"document"===n.containment?(this.containment=[0,0,t(o).width()-this.helperProportions.width-this.margins.left,(t(o).height()||o.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top],void 0):n.containment.constructor===Array?(this.containment=n.containment,void 0):("parent"===n.containment&&(n.containment=this.helper[0].parentNode),i=t(n.containment),s=i[0],s&&(e=/(scroll|auto)/.test(i.css("overflow")),this.containment=[(parseInt(i.css("borderLeftWidth"),10)||0)+(parseInt(i.css("paddingLeft"),10)||0),(parseInt(i.css("borderTopWidth"),10)||0)+(parseInt(i.css("paddingTop"),10)||0),(e?Math.max(s.scrollWidth,s.offsetWidth):s.offsetWidth)-(parseInt(i.css("borderRightWidth"),10)||0)-(parseInt(i.css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(e?Math.max(s.scrollHeight,s.offsetHeight):s.offsetHeight)-(parseInt(i.css("borderBottomWidth"),10)||0)-(parseInt(i.css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom],this.relativeContainer=i),void 0):(this.containment=null,void 0)},_convertPositionTo:function(t,e){e||(e=this.position);var i="absolute"===t?1:-1,s=this._isRootNode(this.scrollParent[0]);return{top:e.top+this.offset.relative.top*i+this.offset.parent.top*i-("fixed"===this.cssPosition?-this.offset.scroll.top:s?0:this.offset.scroll.top)*i,left:e.left+this.offset.relative.left*i+this.offset.parent.left*i-("fixed"===this.cssPosition?-this.offset.scroll.left:s?0:this.offset.scroll.left)*i}},_generatePosition:function(t,e){var i,s,n,o,a=this.options,r=this._isRootNode(this.scrollParent[0]),h=t.pageX,l=t.pageY;return r&&this.offset.scroll||(this.offset.scroll={top:this.scrollParent.scrollTop(),left:this.scrollParent.scrollLeft()}),e&&(this.containment&&(this.relativeContainer?(s=this.relativeContainer.offset(),i=[this.containment[0]+s.left,this.containment[1]+s.top,this.containment[2]+s.left,this.containment[3]+s.top]):i=this.containment,t.pageX-this.offset.click.left<i[0]&&(h=i[0]+this.offset.click.left),t.pageY-this.offset.click.top<i[1]&&(l=i[1]+this.offset.click.top),t.pageX-this.offset.click.left>i[2]&&(h=i[2]+this.offset.click.left),t.pageY-this.offset.click.top>i[3]&&(l=i[3]+this.offset.click.top)),a.grid&&(n=a.grid[1]?this.originalPageY+Math.round((l-this.originalPageY)/a.grid[1])*a.grid[1]:this.originalPageY,l=i?n-this.offset.click.top>=i[1]||n-this.offset.click.top>i[3]?n:n-this.offset.click.top>=i[1]?n-a.grid[1]:n+a.grid[1]:n,o=a.grid[0]?this.originalPageX+Math.round((h-this.originalPageX)/a.grid[0])*a.grid[0]:this.originalPageX,h=i?o-this.offset.click.left>=i[0]||o-this.offset.click.left>i[2]?o:o-this.offset.click.left>=i[0]?o-a.grid[0]:o+a.grid[0]:o),"y"===a.axis&&(h=this.originalPageX),"x"===a.axis&&(l=this.originalPageY)),{top:l-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.offset.scroll.top:r?0:this.offset.scroll.top),left:h-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.offset.scroll.left:r?0:this.offset.scroll.left)}},_clear:function(){this._removeClass(this.helper,"ui-draggable-dragging"),this.helper[0]===this.element[0]||this.cancelHelperRemoval||this.helper.remove(),this.helper=null,this.cancelHelperRemoval=!1,this.destroyOnClear&&this.destroy()},_trigger:function(e,i,s){return s=s||this._uiHash(),t.ui.plugin.call(this,e,[i,s,this],!0),/^(drag|start|stop)/.test(e)&&(this.positionAbs=this._convertPositionTo("absolute"),s.offset=this.positionAbs),t.Widget.prototype._trigger.call(this,e,i,s)},plugins:{},_uiHash:function(){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}}),t.ui.plugin.add("draggable","connectToSortable",{start:function(e,i,s){var n=t.extend({},i,{item:s.element});s.sortables=[],t(s.options.connectToSortable).each(function(){var i=t(this).sortable("instance");i&&!i.options.disabled&&(s.sortables.push(i),i.refreshPositions(),i._trigger("activate",e,n))})},stop:function(e,i,s){var n=t.extend({},i,{item:s.element});s.cancelHelperRemoval=!1,t.each(s.sortables,function(){var t=this;t.isOver?(t.isOver=0,s.cancelHelperRemoval=!0,t.cancelHelperRemoval=!1,t._storedCSS={position:t.placeholder.css("position"),top:t.placeholder.css("top"),left:t.placeholder.css("left")},t._mouseStop(e),t.options.helper=t.options._helper):(t.cancelHelperRemoval=!0,t._trigger("deactivate",e,n))})},drag:function(e,i,s){t.each(s.sortables,function(){var n=!1,o=this;o.positionAbs=s.positionAbs,o.helperProportions=s.helperProportions,o.offset.click=s.offset.click,o._intersectsWith(o.containerCache)&&(n=!0,t.each(s.sortables,function(){return this.positionAbs=s.positionAbs,this.helperProportions=s.helperProportions,this.offset.click=s.offset.click,this!==o&&this._intersectsWith(this.containerCache)&&t.contains(o.element[0],this.element[0])&&(n=!1),n})),n?(o.isOver||(o.isOver=1,s._parent=i.helper.parent(),o.currentItem=i.helper.appendTo(o.element).data("ui-sortable-item",!0),o.options._helper=o.options.helper,o.options.helper=function(){return i.helper[0]},e.target=o.currentItem[0],o._mouseCapture(e,!0),o._mouseStart(e,!0,!0),o.offset.click.top=s.offset.click.top,o.offset.click.left=s.offset.click.left,o.offset.parent.left-=s.offset.parent.left-o.offset.parent.left,o.offset.parent.top-=s.offset.parent.top-o.offset.parent.top,s._trigger("toSortable",e),s.dropped=o.element,t.each(s.sortables,function(){this.refreshPositions()}),s.currentItem=s.element,o.fromOutside=s),o.currentItem&&(o._mouseDrag(e),i.position=o.position)):o.isOver&&(o.isOver=0,o.cancelHelperRemoval=!0,o.options._revert=o.options.revert,o.options.revert=!1,o._trigger("out",e,o._uiHash(o)),o._mouseStop(e,!0),o.options.revert=o.options._revert,o.options.helper=o.options._helper,o.placeholder&&o.placeholder.remove(),i.helper.appendTo(s._parent),s._refreshOffsets(e),i.position=s._generatePosition(e,!0),s._trigger("fromSortable",e),s.dropped=!1,t.each(s.sortables,function(){this.refreshPositions()}))})}}),t.ui.plugin.add("draggable","cursor",{start:function(e,i,s){var n=t("body"),o=s.options;n.css("cursor")&&(o._cursor=n.css("cursor")),n.css("cursor",o.cursor)},stop:function(e,i,s){var n=s.options;n._cursor&&t("body").css("cursor",n._cursor)}}),t.ui.plugin.add("draggable","opacity",{start:function(e,i,s){var n=t(i.helper),o=s.options;n.css("opacity")&&(o._opacity=n.css("opacity")),n.css("opacity",o.opacity)},stop:function(e,i,s){var n=s.options;n._opacity&&t(i.helper).css("opacity",n._opacity)}}),t.ui.plugin.add("draggable","scroll",{start:function(t,e,i){i.scrollParentNotHidden||(i.scrollParentNotHidden=i.helper.scrollParent(!1)),i.scrollParentNotHidden[0]!==i.document[0]&&"HTML"!==i.scrollParentNotHidden[0].tagName&&(i.overflowOffset=i.scrollParentNotHidden.offset())},drag:function(e,i,s){var n=s.options,o=!1,a=s.scrollParentNotHidden[0],r=s.document[0];a!==r&&"HTML"!==a.tagName?(n.axis&&"x"===n.axis||(s.overflowOffset.top+a.offsetHeight-e.pageY<n.scrollSensitivity?a.scrollTop=o=a.scrollTop+n.scrollSpeed:e.pageY-s.overflowOffset.top<n.scrollSensitivity&&(a.scrollTop=o=a.scrollTop-n.scrollSpeed)),n.axis&&"y"===n.axis||(s.overflowOffset.left+a.offsetWidth-e.pageX<n.scrollSensitivity?a.scrollLeft=o=a.scrollLeft+n.scrollSpeed:e.pageX-s.overflowOffset.left<n.scrollSensitivity&&(a.scrollLeft=o=a.scrollLeft-n.scrollSpeed))):(n.axis&&"x"===n.axis||(e.pageY-t(r).scrollTop()<n.scrollSensitivity?o=t(r).scrollTop(t(r).scrollTop()-n.scrollSpeed):t(window).height()-(e.pageY-t(r).scrollTop())<n.scrollSensitivity&&(o=t(r).scrollTop(t(r).scrollTop()+n.scrollSpeed))),n.axis&&"y"===n.axis||(e.pageX-t(r).scrollLeft()<n.scrollSensitivity?o=t(r).scrollLeft(t(r).scrollLeft()-n.scrollSpeed):t(window).width()-(e.pageX-t(r).scrollLeft())<n.scrollSensitivity&&(o=t(r).scrollLeft(t(r).scrollLeft()+n.scrollSpeed)))),o!==!1&&t.ui.ddmanager&&!n.dropBehaviour&&t.ui.ddmanager.prepareOffsets(s,e)}}),t.ui.plugin.add("draggable","snap",{start:function(e,i,s){var n=s.options;s.snapElements=[],t(n.snap.constructor!==String?n.snap.items||":data(ui-draggable)":n.snap).each(function(){var e=t(this),i=e.offset();this!==s.element[0]&&s.snapElements.push({item:this,width:e.outerWidth(),height:e.outerHeight(),top:i.top,left:i.left})})},drag:function(e,i,s){var n,o,a,r,h,l,c,u,d,p,f=s.options,g=f.snapTolerance,m=i.offset.left,_=m+s.helperProportions.width,v=i.offset.top,b=v+s.helperProportions.height;for(d=s.snapElements.length-1;d>=0;d--)h=s.snapElements[d].left-s.margins.left,l=h+s.snapElements[d].width,c=s.snapElements[d].top-s.margins.top,u=c+s.snapElements[d].height,h-g>_||m>l+g||c-g>b||v>u+g||!t.contains(s.snapElements[d].item.ownerDocument,s.snapElements[d].item)?(s.snapElements[d].snapping&&s.options.snap.release&&s.options.snap.release.call(s.element,e,t.extend(s._uiHash(),{snapItem:s.snapElements[d].item})),s.snapElements[d].snapping=!1):("inner"!==f.snapMode&&(n=g>=Math.abs(c-b),o=g>=Math.abs(u-v),a=g>=Math.abs(h-_),r=g>=Math.abs(l-m),n&&(i.position.top=s._convertPositionTo("relative",{top:c-s.helperProportions.height,left:0}).top),o&&(i.position.top=s._convertPositionTo("relative",{top:u,left:0}).top),a&&(i.position.left=s._convertPositionTo("relative",{top:0,left:h-s.helperProportions.width}).left),r&&(i.position.left=s._convertPositionTo("relative",{top:0,left:l}).left)),p=n||o||a||r,"outer"!==f.snapMode&&(n=g>=Math.abs(c-v),o=g>=Math.abs(u-b),a=g>=Math.abs(h-m),r=g>=Math.abs(l-_),n&&(i.position.top=s._convertPositionTo("relative",{top:c,left:0}).top),o&&(i.position.top=s._convertPositionTo("relative",{top:u-s.helperProportions.height,left:0}).top),a&&(i.position.left=s._convertPositionTo("relative",{top:0,left:h}).left),r&&(i.position.left=s._convertPositionTo("relative",{top:0,left:l-s.helperProportions.width}).left)),!s.snapElements[d].snapping&&(n||o||a||r||p)&&s.options.snap.snap&&s.options.snap.snap.call(s.element,e,t.extend(s._uiHash(),{snapItem:s.snapElements[d].item})),s.snapElements[d].snapping=n||o||a||r||p)}}),t.ui.plugin.add("draggable","stack",{start:function(e,i,s){var n,o=s.options,a=t.makeArray(t(o.stack)).sort(function(e,i){return(parseInt(t(e).css("zIndex"),10)||0)-(parseInt(t(i).css("zIndex"),10)||0)});a.length&&(n=parseInt(t(a[0]).css("zIndex"),10)||0,t(a).each(function(e){t(this).css("zIndex",n+e)}),this.css("zIndex",n+a.length))}}),t.ui.plugin.add("draggable","zIndex",{start:function(e,i,s){var n=t(i.helper),o=s.options;n.css("zIndex")&&(o._zIndex=n.css("zIndex")),n.css("zIndex",o.zIndex)},stop:function(e,i,s){var n=s.options;n._zIndex&&t(i.helper).css("zIndex",n._zIndex)}}),t.ui.draggable,t.widget("ui.resizable",t.ui.mouse,{version:"1.12.1",widgetEventPrefix:"resize",options:{alsoResize:!1,animate:!1,animateDuration:"slow",animateEasing:"swing",aspectRatio:!1,autoHide:!1,classes:{"ui-resizable-se":"ui-icon ui-icon-gripsmall-diagonal-se"},containment:!1,ghost:!1,grid:!1,handles:"e,s,se",helper:!1,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:90,resize:null,start:null,stop:null},_num:function(t){return parseFloat(t)||0},_isNumber:function(t){return!isNaN(parseFloat(t))},_hasScroll:function(e,i){if("hidden"===t(e).css("overflow"))return!1;var s=i&&"left"===i?"scrollLeft":"scrollTop",n=!1;return e[s]>0?!0:(e[s]=1,n=e[s]>0,e[s]=0,n)},_create:function(){var e,i=this.options,s=this;this._addClass("ui-resizable"),t.extend(this,{_aspectRatio:!!i.aspectRatio,aspectRatio:i.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:i.helper||i.ghost||i.animate?i.helper||"ui-resizable-helper":null}),this.element[0].nodeName.match(/^(canvas|textarea|input|select|button|img)$/i)&&(this.element.wrap(t("<div class='ui-wrapper' style='overflow: hidden;'></div>").css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("ui-resizable",this.element.resizable("instance")),this.elementIsWrapper=!0,e={marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom"),marginLeft:this.originalElement.css("marginLeft")},this.element.css(e),this.originalElement.css("margin",0),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css(e),this._proportionallyResize()),this._setupHandles(),i.autoHide&&t(this.element).on("mouseenter",function(){i.disabled||(s._removeClass("ui-resizable-autohide"),s._handles.show())}).on("mouseleave",function(){i.disabled||s.resizing||(s._addClass("ui-resizable-autohide"),s._handles.hide())}),this._mouseInit()},_destroy:function(){this._mouseDestroy();var e,i=function(e){t(e).removeData("resizable").removeData("ui-resizable").off(".resizable").find(".ui-resizable-handle").remove()};return this.elementIsWrapper&&(i(this.element),e=this.element,this.originalElement.css({position:e.css("position"),width:e.outerWidth(),height:e.outerHeight(),top:e.css("top"),left:e.css("left")}).insertAfter(e),e.remove()),this.originalElement.css("resize",this.originalResizeStyle),i(this.originalElement),this},_setOption:function(t,e){switch(this._super(t,e),t){case"handles":this._removeHandles(),this._setupHandles();break;default:}},_setupHandles:function(){var e,i,s,n,o,a=this.options,r=this;if(this.handles=a.handles||(t(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se"),this._handles=t(),this.handles.constructor===String)for("all"===this.handles&&(this.handles="n,e,s,w,se,sw,ne,nw"),s=this.handles.split(","),this.handles={},i=0;s.length>i;i++)e=t.trim(s[i]),n="ui-resizable-"+e,o=t("<div>"),this._addClass(o,"ui-resizable-handle "+n),o.css({zIndex:a.zIndex}),this.handles[e]=".ui-resizable-"+e,this.element.append(o);this._renderAxis=function(e){var i,s,n,o;e=e||this.element;for(i in this.handles)this.handles[i].constructor===String?this.handles[i]=this.element.children(this.handles[i]).first().show():(this.handles[i].jquery||this.handles[i].nodeType)&&(this.handles[i]=t(this.handles[i]),this._on(this.handles[i],{mousedown:r._mouseDown})),this.elementIsWrapper&&this.originalElement[0].nodeName.match(/^(textarea|input|select|button)$/i)&&(s=t(this.handles[i],this.element),o=/sw|ne|nw|se|n|s/.test(i)?s.outerHeight():s.outerWidth(),n=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join(""),e.css(n,o),this._proportionallyResize()),this._handles=this._handles.add(this.handles[i])},this._renderAxis(this.element),this._handles=this._handles.add(this.element.find(".ui-resizable-handle")),this._handles.disableSelection(),this._handles.on("mouseover",function(){r.resizing||(this.className&&(o=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)),r.axis=o&&o[1]?o[1]:"se")}),a.autoHide&&(this._handles.hide(),this._addClass("ui-resizable-autohide"))},_removeHandles:function(){this._handles.remove()},_mouseCapture:function(e){var i,s,n=!1;for(i in this.handles)s=t(this.handles[i])[0],(s===e.target||t.contains(s,e.target))&&(n=!0);return!this.options.disabled&&n},_mouseStart:function(e){var i,s,n,o=this.options,a=this.element;return this.resizing=!0,this._renderProxy(),i=this._num(this.helper.css("left")),s=this._num(this.helper.css("top")),o.containment&&(i+=t(o.containment).scrollLeft()||0,s+=t(o.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:i,top:s},this.size=this._helper?{width:this.helper.width(),height:this.helper.height()}:{width:a.width(),height:a.height()},this.originalSize=this._helper?{width:a.outerWidth(),height:a.outerHeight()}:{width:a.width(),height:a.height()},this.sizeDiff={width:a.outerWidth()-a.width(),height:a.outerHeight()-a.height()},this.originalPosition={left:i,top:s},this.originalMousePosition={left:e.pageX,top:e.pageY},this.aspectRatio="number"==typeof o.aspectRatio?o.aspectRatio:this.originalSize.width/this.originalSize.height||1,n=t(".ui-resizable-"+this.axis).css("cursor"),t("body").css("cursor","auto"===n?this.axis+"-resize":n),this._addClass("ui-resizable-resizing"),this._propagate("start",e),!0},_mouseDrag:function(e){var i,s,n=this.originalMousePosition,o=this.axis,a=e.pageX-n.left||0,r=e.pageY-n.top||0,h=this._change[o];return this._updatePrevProperties(),h?(i=h.apply(this,[e,a,r]),this._updateVirtualBoundaries(e.shiftKey),(this._aspectRatio||e.shiftKey)&&(i=this._updateRatio(i,e)),i=this._respectSize(i,e),this._updateCache(i),this._propagate("resize",e),s=this._applyChanges(),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),t.isEmptyObject(s)||(this._updatePrevProperties(),this._trigger("resize",e,this.ui()),this._applyChanges()),!1):!1},_mouseStop:function(e){this.resizing=!1;var i,s,n,o,a,r,h,l=this.options,c=this;return this._helper&&(i=this._proportionallyResizeElements,s=i.length&&/textarea/i.test(i[0].nodeName),n=s&&this._hasScroll(i[0],"left")?0:c.sizeDiff.height,o=s?0:c.sizeDiff.width,a={width:c.helper.width()-o,height:c.helper.height()-n},r=parseFloat(c.element.css("left"))+(c.position.left-c.originalPosition.left)||null,h=parseFloat(c.element.css("top"))+(c.position.top-c.originalPosition.top)||null,l.animate||this.element.css(t.extend(a,{top:h,left:r})),c.helper.height(c.size.height),c.helper.width(c.size.width),this._helper&&!l.animate&&this._proportionallyResize()),t("body").css("cursor","auto"),this._removeClass("ui-resizable-resizing"),this._propagate("stop",e),this._helper&&this.helper.remove(),!1},_updatePrevProperties:function(){this.prevPosition={top:this.position.top,left:this.position.left},this.prevSize={width:this.size.width,height:this.size.height}},_applyChanges:function(){var t={};return this.position.top!==this.prevPosition.top&&(t.top=this.position.top+"px"),this.position.left!==this.prevPosition.left&&(t.left=this.position.left+"px"),this.size.width!==this.prevSize.width&&(t.width=this.size.width+"px"),this.size.height!==this.prevSize.height&&(t.height=this.size.height+"px"),this.helper.css(t),t},_updateVirtualBoundaries:function(t){var e,i,s,n,o,a=this.options;o={minWidth:this._isNumber(a.minWidth)?a.minWidth:0,maxWidth:this._isNumber(a.maxWidth)?a.maxWidth:1/0,minHeight:this._isNumber(a.minHeight)?a.minHeight:0,maxHeight:this._isNumber(a.maxHeight)?a.maxHeight:1/0},(this._aspectRatio||t)&&(e=o.minHeight*this.aspectRatio,s=o.minWidth/this.aspectRatio,i=o.maxHeight*this.aspectRatio,n=o.maxWidth/this.aspectRatio,e>o.minWidth&&(o.minWidth=e),s>o.minHeight&&(o.minHeight=s),o.maxWidth>i&&(o.maxWidth=i),o.maxHeight>n&&(o.maxHeight=n)),this._vBoundaries=o},_updateCache:function(t){this.offset=this.helper.offset(),this._isNumber(t.left)&&(this.position.left=t.left),this._isNumber(t.top)&&(this.position.top=t.top),this._isNumber(t.height)&&(this.size.height=t.height),this._isNumber(t.width)&&(this.size.width=t.width)},_updateRatio:function(t){var e=this.position,i=this.size,s=this.axis;return this._isNumber(t.height)?t.width=t.height*this.aspectRatio:this._isNumber(t.width)&&(t.height=t.width/this.aspectRatio),"sw"===s&&(t.left=e.left+(i.width-t.width),t.top=null),"nw"===s&&(t.top=e.top+(i.height-t.height),t.left=e.left+(i.width-t.width)),t},_respectSize:function(t){var e=this._vBoundaries,i=this.axis,s=this._isNumber(t.width)&&e.maxWidth&&e.maxWidth<t.width,n=this._isNumber(t.height)&&e.maxHeight&&e.maxHeight<t.height,o=this._isNumber(t.width)&&e.minWidth&&e.minWidth>t.width,a=this._isNumber(t.height)&&e.minHeight&&e.minHeight>t.height,r=this.originalPosition.left+this.originalSize.width,h=this.originalPosition.top+this.originalSize.height,l=/sw|nw|w/.test(i),c=/nw|ne|n/.test(i);return o&&(t.width=e.minWidth),a&&(t.height=e.minHeight),s&&(t.width=e.maxWidth),n&&(t.height=e.maxHeight),o&&l&&(t.left=r-e.minWidth),s&&l&&(t.left=r-e.maxWidth),a&&c&&(t.top=h-e.minHeight),n&&c&&(t.top=h-e.maxHeight),t.width||t.height||t.left||!t.top?t.width||t.height||t.top||!t.left||(t.left=null):t.top=null,t},_getPaddingPlusBorderDimensions:function(t){for(var e=0,i=[],s=[t.css("borderTopWidth"),t.css("borderRightWidth"),t.css("borderBottomWidth"),t.css("borderLeftWidth")],n=[t.css("paddingTop"),t.css("paddingRight"),t.css("paddingBottom"),t.css("paddingLeft")];4>e;e++)i[e]=parseFloat(s[e])||0,i[e]+=parseFloat(n[e])||0;return{height:i[0]+i[2],width:i[1]+i[3]}},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var t,e=0,i=this.helper||this.element;this._proportionallyResizeElements.length>e;e++)t=this._proportionallyResizeElements[e],this.outerDimensions||(this.outerDimensions=this._getPaddingPlusBorderDimensions(t)),t.css({height:i.height()-this.outerDimensions.height||0,width:i.width()-this.outerDimensions.width||0})},_renderProxy:function(){var e=this.element,i=this.options;this.elementOffset=e.offset(),this._helper?(this.helper=this.helper||t("<div style='overflow:hidden;'></div>"),this._addClass(this.helper,this._helper),this.helper.css({width:this.element.outerWidth(),height:this.element.outerHeight(),position:"absolute",left:this.elementOffset.left+"px",top:this.elementOffset.top+"px",zIndex:++i.zIndex}),this.helper.appendTo("body").disableSelection()):this.helper=this.element},_change:{e:function(t,e){return{width:this.originalSize.width+e}},w:function(t,e){var i=this.originalSize,s=this.originalPosition;return{left:s.left+e,width:i.width-e}},n:function(t,e,i){var s=this.originalSize,n=this.originalPosition;return{top:n.top+i,height:s.height-i}},s:function(t,e,i){return{height:this.originalSize.height+i}},se:function(e,i,s){return t.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[e,i,s]))},sw:function(e,i,s){return t.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[e,i,s]))},ne:function(e,i,s){return t.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[e,i,s]))},nw:function(e,i,s){return t.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[e,i,s]))}},_propagate:function(e,i){t.ui.plugin.call(this,e,[i,this.ui()]),"resize"!==e&&this._trigger(e,i,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),t.ui.plugin.add("resizable","animate",{stop:function(e){var i=t(this).resizable("instance"),s=i.options,n=i._proportionallyResizeElements,o=n.length&&/textarea/i.test(n[0].nodeName),a=o&&i._hasScroll(n[0],"left")?0:i.sizeDiff.height,r=o?0:i.sizeDiff.width,h={width:i.size.width-r,height:i.size.height-a},l=parseFloat(i.element.css("left"))+(i.position.left-i.originalPosition.left)||null,c=parseFloat(i.element.css("top"))+(i.position.top-i.originalPosition.top)||null;i.element.animate(t.extend(h,c&&l?{top:c,left:l}:{}),{duration:s.animateDuration,easing:s.animateEasing,step:function(){var s={width:parseFloat(i.element.css("width")),height:parseFloat(i.element.css("height")),top:parseFloat(i.element.css("top")),left:parseFloat(i.element.css("left"))};n&&n.length&&t(n[0]).css({width:s.width,height:s.height}),i._updateCache(s),i._propagate("resize",e)}})}}),t.ui.plugin.add("resizable","containment",{start:function(){var e,i,s,n,o,a,r,h=t(this).resizable("instance"),l=h.options,c=h.element,u=l.containment,d=u instanceof t?u.get(0):/parent/.test(u)?c.parent().get(0):u;d&&(h.containerElement=t(d),/document/.test(u)||u===document?(h.containerOffset={left:0,top:0},h.containerPosition={left:0,top:0},h.parentData={element:t(document),left:0,top:0,width:t(document).width(),height:t(document).height()||document.body.parentNode.scrollHeight}):(e=t(d),i=[],t(["Top","Right","Left","Bottom"]).each(function(t,s){i[t]=h._num(e.css("padding"+s))}),h.containerOffset=e.offset(),h.containerPosition=e.position(),h.containerSize={height:e.innerHeight()-i[3],width:e.innerWidth()-i[1]},s=h.containerOffset,n=h.containerSize.height,o=h.containerSize.width,a=h._hasScroll(d,"left")?d.scrollWidth:o,r=h._hasScroll(d)?d.scrollHeight:n,h.parentData={element:d,left:s.left,top:s.top,width:a,height:r}))},resize:function(e){var i,s,n,o,a=t(this).resizable("instance"),r=a.options,h=a.containerOffset,l=a.position,c=a._aspectRatio||e.shiftKey,u={top:0,left:0},d=a.containerElement,p=!0;d[0]!==document&&/static/.test(d.css("position"))&&(u=h),l.left<(a._helper?h.left:0)&&(a.size.width=a.size.width+(a._helper?a.position.left-h.left:a.position.left-u.left),c&&(a.size.height=a.size.width/a.aspectRatio,p=!1),a.position.left=r.helper?h.left:0),l.top<(a._helper?h.top:0)&&(a.size.height=a.size.height+(a._helper?a.position.top-h.top:a.position.top),c&&(a.size.width=a.size.height*a.aspectRatio,p=!1),a.position.top=a._helper?h.top:0),n=a.containerElement.get(0)===a.element.parent().get(0),o=/relative|absolute/.test(a.containerElement.css("position")),n&&o?(a.offset.left=a.parentData.left+a.position.left,a.offset.top=a.parentData.top+a.position.top):(a.offset.left=a.element.offset().left,a.offset.top=a.element.offset().top),i=Math.abs(a.sizeDiff.width+(a._helper?a.offset.left-u.left:a.offset.left-h.left)),s=Math.abs(a.sizeDiff.height+(a._helper?a.offset.top-u.top:a.offset.top-h.top)),i+a.size.width>=a.parentData.width&&(a.size.width=a.parentData.width-i,c&&(a.size.height=a.size.width/a.aspectRatio,p=!1)),s+a.size.height>=a.parentData.height&&(a.size.height=a.parentData.height-s,c&&(a.size.width=a.size.height*a.aspectRatio,p=!1)),p||(a.position.left=a.prevPosition.left,a.position.top=a.prevPosition.top,a.size.width=a.prevSize.width,a.size.height=a.prevSize.height)},stop:function(){var e=t(this).resizable("instance"),i=e.options,s=e.containerOffset,n=e.containerPosition,o=e.containerElement,a=t(e.helper),r=a.offset(),h=a.outerWidth()-e.sizeDiff.width,l=a.outerHeight()-e.sizeDiff.height;e._helper&&!i.animate&&/relative/.test(o.css("position"))&&t(this).css({left:r.left-n.left-s.left,width:h,height:l}),e._helper&&!i.animate&&/static/.test(o.css("position"))&&t(this).css({left:r.left-n.left-s.left,width:h,height:l})}}),t.ui.plugin.add("resizable","alsoResize",{start:function(){var e=t(this).resizable("instance"),i=e.options;t(i.alsoResize).each(function(){var e=t(this);e.data("ui-resizable-alsoresize",{width:parseFloat(e.width()),height:parseFloat(e.height()),left:parseFloat(e.css("left")),top:parseFloat(e.css("top"))})})},resize:function(e,i){var s=t(this).resizable("instance"),n=s.options,o=s.originalSize,a=s.originalPosition,r={height:s.size.height-o.height||0,width:s.size.width-o.width||0,top:s.position.top-a.top||0,left:s.position.left-a.left||0};t(n.alsoResize).each(function(){var e=t(this),s=t(this).data("ui-resizable-alsoresize"),n={},o=e.parents(i.originalElement[0]).length?["width","height"]:["width","height","top","left"];t.each(o,function(t,e){var i=(s[e]||0)+(r[e]||0);i&&i>=0&&(n[e]=i||null)}),e.css(n)})},stop:function(){t(this).removeData("ui-resizable-alsoresize")}}),t.ui.plugin.add("resizable","ghost",{start:function(){var e=t(this).resizable("instance"),i=e.size;e.ghost=e.originalElement.clone(),e.ghost.css({opacity:.25,display:"block",position:"relative",height:i.height,width:i.width,margin:0,left:0,top:0}),e._addClass(e.ghost,"ui-resizable-ghost"),t.uiBackCompat!==!1&&"string"==typeof e.options.ghost&&e.ghost.addClass(this.options.ghost),e.ghost.appendTo(e.helper)},resize:function(){var e=t(this).resizable("instance");e.ghost&&e.ghost.css({position:"relative",height:e.size.height,width:e.size.width})},stop:function(){var e=t(this).resizable("instance");e.ghost&&e.helper&&e.helper.get(0).removeChild(e.ghost.get(0))}}),t.ui.plugin.add("resizable","grid",{resize:function(){var e,i=t(this).resizable("instance"),s=i.options,n=i.size,o=i.originalSize,a=i.originalPosition,r=i.axis,h="number"==typeof s.grid?[s.grid,s.grid]:s.grid,l=h[0]||1,c=h[1]||1,u=Math.round((n.width-o.width)/l)*l,d=Math.round((n.height-o.height)/c)*c,p=o.width+u,f=o.height+d,g=s.maxWidth&&p>s.maxWidth,m=s.maxHeight&&f>s.maxHeight,_=s.minWidth&&s.minWidth>p,v=s.minHeight&&s.minHeight>f;s.grid=h,_&&(p+=l),v&&(f+=c),g&&(p-=l),m&&(f-=c),/^(se|s|e)$/.test(r)?(i.size.width=p,i.size.height=f):/^(ne)$/.test(r)?(i.size.width=p,i.size.height=f,i.position.top=a.top-d):/^(sw)$/.test(r)?(i.size.width=p,i.size.height=f,i.position.left=a.left-u):((0>=f-c||0>=p-l)&&(e=i._getPaddingPlusBorderDimensions(this)),f-c>0?(i.size.height=f,i.position.top=a.top-d):(f=c-e.height,i.size.height=f,i.position.top=a.top+o.height-f),p-l>0?(i.size.width=p,i.position.left=a.left-u):(p=l-e.width,i.size.width=p,i.position.left=a.left+o.width-p))}}),t.ui.resizable,t.widget("ui.dialog",{version:"1.12.1",options:{appendTo:"body",autoOpen:!0,buttons:[],classes:{"ui-dialog":"ui-corner-all","ui-dialog-titlebar":"ui-corner-all"},closeOnEscape:!0,closeText:"Close",draggable:!0,hide:null,height:"auto",maxHeight:null,maxWidth:null,minHeight:150,minWidth:150,modal:!1,position:{my:"center",at:"center",of:window,collision:"fit",using:function(e){var i=t(this).css(e).offset().top;0>i&&t(this).css("top",e.top-i)}},resizable:!0,show:null,title:null,width:300,beforeClose:null,close:null,drag:null,dragStart:null,dragStop:null,focus:null,open:null,resize:null,resizeStart:null,resizeStop:null},sizeRelatedOptions:{buttons:!0,height:!0,maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0,width:!0},resizableRelatedOptions:{maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0},_create:function(){this.originalCss={display:this.element[0].style.display,width:this.element[0].style.width,minHeight:this.element[0].style.minHeight,maxHeight:this.element[0].style.maxHeight,height:this.element[0].style.height},this.originalPosition={parent:this.element.parent(),index:this.element.parent().children().index(this.element)},this.originalTitle=this.element.attr("title"),null==this.options.title&&null!=this.originalTitle&&(this.options.title=this.originalTitle),this.options.disabled&&(this.options.disabled=!1),this._createWrapper(),this.element.show().removeAttr("title").appendTo(this.uiDialog),this._addClass("ui-dialog-content","ui-widget-content"),this._createTitlebar(),this._createButtonPane(),this.options.draggable&&t.fn.draggable&&this._makeDraggable(),this.options.resizable&&t.fn.resizable&&this._makeResizable(),this._isOpen=!1,this._trackFocus()},_init:function(){this.options.autoOpen&&this.open()},_appendTo:function(){var e=this.options.appendTo;return e&&(e.jquery||e.nodeType)?t(e):this.document.find(e||"body").eq(0)},_destroy:function(){var t,e=this.originalPosition;this._untrackInstance(),this._destroyOverlay(),this.element.removeUniqueId().css(this.originalCss).detach(),this.uiDialog.remove(),this.originalTitle&&this.element.attr("title",this.originalTitle),t=e.parent.children().eq(e.index),t.length&&t[0]!==this.element[0]?t.before(this.element):e.parent.append(this.element)},widget:function(){return this.uiDialog +},disable:t.noop,enable:t.noop,close:function(e){var i=this;this._isOpen&&this._trigger("beforeClose",e)!==!1&&(this._isOpen=!1,this._focusedElement=null,this._destroyOverlay(),this._untrackInstance(),this.opener.filter(":focusable").trigger("focus").length||t.ui.safeBlur(t.ui.safeActiveElement(this.document[0])),this._hide(this.uiDialog,this.options.hide,function(){i._trigger("close",e)}))},isOpen:function(){return this._isOpen},moveToTop:function(){this._moveToTop()},_moveToTop:function(e,i){var s=!1,n=this.uiDialog.siblings(".ui-front:visible").map(function(){return+t(this).css("z-index")}).get(),o=Math.max.apply(null,n);return o>=+this.uiDialog.css("z-index")&&(this.uiDialog.css("z-index",o+1),s=!0),s&&!i&&this._trigger("focus",e),s},open:function(){var e=this;return this._isOpen?(this._moveToTop()&&this._focusTabbable(),void 0):(this._isOpen=!0,this.opener=t(t.ui.safeActiveElement(this.document[0])),this._size(),this._position(),this._createOverlay(),this._moveToTop(null,!0),this.overlay&&this.overlay.css("z-index",this.uiDialog.css("z-index")-1),this._show(this.uiDialog,this.options.show,function(){e._focusTabbable(),e._trigger("focus")}),this._makeFocusTarget(),this._trigger("open"),void 0)},_focusTabbable:function(){var t=this._focusedElement;t||(t=this.element.find("[autofocus]")),t.length||(t=this.element.find(":tabbable")),t.length||(t=this.uiDialogButtonPane.find(":tabbable")),t.length||(t=this.uiDialogTitlebarClose.filter(":tabbable")),t.length||(t=this.uiDialog),t.eq(0).trigger("focus")},_keepFocus:function(e){function i(){var e=t.ui.safeActiveElement(this.document[0]),i=this.uiDialog[0]===e||t.contains(this.uiDialog[0],e);i||this._focusTabbable()}e.preventDefault(),i.call(this),this._delay(i)},_createWrapper:function(){this.uiDialog=t("<div>").hide().attr({tabIndex:-1,role:"dialog"}).appendTo(this._appendTo()),this._addClass(this.uiDialog,"ui-dialog","ui-widget ui-widget-content ui-front"),this._on(this.uiDialog,{keydown:function(e){if(this.options.closeOnEscape&&!e.isDefaultPrevented()&&e.keyCode&&e.keyCode===t.ui.keyCode.ESCAPE)return e.preventDefault(),this.close(e),void 0;if(e.keyCode===t.ui.keyCode.TAB&&!e.isDefaultPrevented()){var i=this.uiDialog.find(":tabbable"),s=i.filter(":first"),n=i.filter(":last");e.target!==n[0]&&e.target!==this.uiDialog[0]||e.shiftKey?e.target!==s[0]&&e.target!==this.uiDialog[0]||!e.shiftKey||(this._delay(function(){n.trigger("focus")}),e.preventDefault()):(this._delay(function(){s.trigger("focus")}),e.preventDefault())}},mousedown:function(t){this._moveToTop(t)&&this._focusTabbable()}}),this.element.find("[aria-describedby]").length||this.uiDialog.attr({"aria-describedby":this.element.uniqueId().attr("id")})},_createTitlebar:function(){var e;this.uiDialogTitlebar=t("<div>"),this._addClass(this.uiDialogTitlebar,"ui-dialog-titlebar","ui-widget-header ui-helper-clearfix"),this._on(this.uiDialogTitlebar,{mousedown:function(e){t(e.target).closest(".ui-dialog-titlebar-close")||this.uiDialog.trigger("focus")}}),this.uiDialogTitlebarClose=t("<button type='button'></button>").button({label:t("<a>").text(this.options.closeText).html(),icon:"ui-icon-closethick",showLabel:!1}).appendTo(this.uiDialogTitlebar),this._addClass(this.uiDialogTitlebarClose,"ui-dialog-titlebar-close"),this._on(this.uiDialogTitlebarClose,{click:function(t){t.preventDefault(),this.close(t)}}),e=t("<span>").uniqueId().prependTo(this.uiDialogTitlebar),this._addClass(e,"ui-dialog-title"),this._title(e),this.uiDialogTitlebar.prependTo(this.uiDialog),this.uiDialog.attr({"aria-labelledby":e.attr("id")})},_title:function(t){this.options.title?t.text(this.options.title):t.html(" ")},_createButtonPane:function(){this.uiDialogButtonPane=t("<div>"),this._addClass(this.uiDialogButtonPane,"ui-dialog-buttonpane","ui-widget-content ui-helper-clearfix"),this.uiButtonSet=t("<div>").appendTo(this.uiDialogButtonPane),this._addClass(this.uiButtonSet,"ui-dialog-buttonset"),this._createButtons()},_createButtons:function(){var e=this,i=this.options.buttons;return this.uiDialogButtonPane.remove(),this.uiButtonSet.empty(),t.isEmptyObject(i)||t.isArray(i)&&!i.length?(this._removeClass(this.uiDialog,"ui-dialog-buttons"),void 0):(t.each(i,function(i,s){var n,o;s=t.isFunction(s)?{click:s,text:i}:s,s=t.extend({type:"button"},s),n=s.click,o={icon:s.icon,iconPosition:s.iconPosition,showLabel:s.showLabel,icons:s.icons,text:s.text},delete s.click,delete s.icon,delete s.iconPosition,delete s.showLabel,delete s.icons,"boolean"==typeof s.text&&delete s.text,t("<button></button>",s).button(o).appendTo(e.uiButtonSet).on("click",function(){n.apply(e.element[0],arguments)})}),this._addClass(this.uiDialog,"ui-dialog-buttons"),this.uiDialogButtonPane.appendTo(this.uiDialog),void 0)},_makeDraggable:function(){function e(t){return{position:t.position,offset:t.offset}}var i=this,s=this.options;this.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(s,n){i._addClass(t(this),"ui-dialog-dragging"),i._blockFrames(),i._trigger("dragStart",s,e(n))},drag:function(t,s){i._trigger("drag",t,e(s))},stop:function(n,o){var a=o.offset.left-i.document.scrollLeft(),r=o.offset.top-i.document.scrollTop();s.position={my:"left top",at:"left"+(a>=0?"+":"")+a+" "+"top"+(r>=0?"+":"")+r,of:i.window},i._removeClass(t(this),"ui-dialog-dragging"),i._unblockFrames(),i._trigger("dragStop",n,e(o))}})},_makeResizable:function(){function e(t){return{originalPosition:t.originalPosition,originalSize:t.originalSize,position:t.position,size:t.size}}var i=this,s=this.options,n=s.resizable,o=this.uiDialog.css("position"),a="string"==typeof n?n:"n,e,s,w,se,sw,ne,nw";this.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:this.element,maxWidth:s.maxWidth,maxHeight:s.maxHeight,minWidth:s.minWidth,minHeight:this._minHeight(),handles:a,start:function(s,n){i._addClass(t(this),"ui-dialog-resizing"),i._blockFrames(),i._trigger("resizeStart",s,e(n))},resize:function(t,s){i._trigger("resize",t,e(s))},stop:function(n,o){var a=i.uiDialog.offset(),r=a.left-i.document.scrollLeft(),h=a.top-i.document.scrollTop();s.height=i.uiDialog.height(),s.width=i.uiDialog.width(),s.position={my:"left top",at:"left"+(r>=0?"+":"")+r+" "+"top"+(h>=0?"+":"")+h,of:i.window},i._removeClass(t(this),"ui-dialog-resizing"),i._unblockFrames(),i._trigger("resizeStop",n,e(o))}}).css("position",o)},_trackFocus:function(){this._on(this.widget(),{focusin:function(e){this._makeFocusTarget(),this._focusedElement=t(e.target)}})},_makeFocusTarget:function(){this._untrackInstance(),this._trackingInstances().unshift(this)},_untrackInstance:function(){var e=this._trackingInstances(),i=t.inArray(this,e);-1!==i&&e.splice(i,1)},_trackingInstances:function(){var t=this.document.data("ui-dialog-instances");return t||(t=[],this.document.data("ui-dialog-instances",t)),t},_minHeight:function(){var t=this.options;return"auto"===t.height?t.minHeight:Math.min(t.minHeight,t.height)},_position:function(){var t=this.uiDialog.is(":visible");t||this.uiDialog.show(),this.uiDialog.position(this.options.position),t||this.uiDialog.hide()},_setOptions:function(e){var i=this,s=!1,n={};t.each(e,function(t,e){i._setOption(t,e),t in i.sizeRelatedOptions&&(s=!0),t in i.resizableRelatedOptions&&(n[t]=e)}),s&&(this._size(),this._position()),this.uiDialog.is(":data(ui-resizable)")&&this.uiDialog.resizable("option",n)},_setOption:function(e,i){var s,n,o=this.uiDialog;"disabled"!==e&&(this._super(e,i),"appendTo"===e&&this.uiDialog.appendTo(this._appendTo()),"buttons"===e&&this._createButtons(),"closeText"===e&&this.uiDialogTitlebarClose.button({label:t("<a>").text(""+this.options.closeText).html()}),"draggable"===e&&(s=o.is(":data(ui-draggable)"),s&&!i&&o.draggable("destroy"),!s&&i&&this._makeDraggable()),"position"===e&&this._position(),"resizable"===e&&(n=o.is(":data(ui-resizable)"),n&&!i&&o.resizable("destroy"),n&&"string"==typeof i&&o.resizable("option","handles",i),n||i===!1||this._makeResizable()),"title"===e&&this._title(this.uiDialogTitlebar.find(".ui-dialog-title")))},_size:function(){var t,e,i,s=this.options;this.element.show().css({width:"auto",minHeight:0,maxHeight:"none",height:0}),s.minWidth>s.width&&(s.width=s.minWidth),t=this.uiDialog.css({height:"auto",width:s.width}).outerHeight(),e=Math.max(0,s.minHeight-t),i="number"==typeof s.maxHeight?Math.max(0,s.maxHeight-t):"none","auto"===s.height?this.element.css({minHeight:e,maxHeight:i,height:"auto"}):this.element.height(Math.max(0,s.height-t)),this.uiDialog.is(":data(ui-resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())},_blockFrames:function(){this.iframeBlocks=this.document.find("iframe").map(function(){var e=t(this);return t("<div>").css({position:"absolute",width:e.outerWidth(),height:e.outerHeight()}).appendTo(e.parent()).offset(e.offset())[0]})},_unblockFrames:function(){this.iframeBlocks&&(this.iframeBlocks.remove(),delete this.iframeBlocks)},_allowInteraction:function(e){return t(e.target).closest(".ui-dialog").length?!0:!!t(e.target).closest(".ui-datepicker").length},_createOverlay:function(){if(this.options.modal){var e=!0;this._delay(function(){e=!1}),this.document.data("ui-dialog-overlays")||this._on(this.document,{focusin:function(t){e||this._allowInteraction(t)||(t.preventDefault(),this._trackingInstances()[0]._focusTabbable())}}),this.overlay=t("<div>").appendTo(this._appendTo()),this._addClass(this.overlay,null,"ui-widget-overlay ui-front"),this._on(this.overlay,{mousedown:"_keepFocus"}),this.document.data("ui-dialog-overlays",(this.document.data("ui-dialog-overlays")||0)+1)}},_destroyOverlay:function(){if(this.options.modal&&this.overlay){var t=this.document.data("ui-dialog-overlays")-1;t?this.document.data("ui-dialog-overlays",t):(this._off(this.document,"focusin"),this.document.removeData("ui-dialog-overlays")),this.overlay.remove(),this.overlay=null}}}),t.uiBackCompat!==!1&&t.widget("ui.dialog",t.ui.dialog,{options:{dialogClass:""},_createWrapper:function(){this._super(),this.uiDialog.addClass(this.options.dialogClass)},_setOption:function(t,e){"dialogClass"===t&&this.uiDialog.removeClass(this.options.dialogClass).addClass(e),this._superApply(arguments)}}),t.ui.dialog,t.widget("ui.droppable",{version:"1.12.1",widgetEventPrefix:"drop",options:{accept:"*",addClasses:!0,greedy:!1,scope:"default",tolerance:"intersect",activate:null,deactivate:null,drop:null,out:null,over:null},_create:function(){var e,i=this.options,s=i.accept;this.isover=!1,this.isout=!0,this.accept=t.isFunction(s)?s:function(t){return t.is(s)},this.proportions=function(){return arguments.length?(e=arguments[0],void 0):e?e:e={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight}},this._addToManager(i.scope),i.addClasses&&this._addClass("ui-droppable")},_addToManager:function(e){t.ui.ddmanager.droppables[e]=t.ui.ddmanager.droppables[e]||[],t.ui.ddmanager.droppables[e].push(this)},_splice:function(t){for(var e=0;t.length>e;e++)t[e]===this&&t.splice(e,1)},_destroy:function(){var e=t.ui.ddmanager.droppables[this.options.scope];this._splice(e)},_setOption:function(e,i){if("accept"===e)this.accept=t.isFunction(i)?i:function(t){return t.is(i)};else if("scope"===e){var s=t.ui.ddmanager.droppables[this.options.scope];this._splice(s),this._addToManager(i)}this._super(e,i)},_activate:function(e){var i=t.ui.ddmanager.current;this._addActiveClass(),i&&this._trigger("activate",e,this.ui(i))},_deactivate:function(e){var i=t.ui.ddmanager.current;this._removeActiveClass(),i&&this._trigger("deactivate",e,this.ui(i))},_over:function(e){var i=t.ui.ddmanager.current;i&&(i.currentItem||i.element)[0]!==this.element[0]&&this.accept.call(this.element[0],i.currentItem||i.element)&&(this._addHoverClass(),this._trigger("over",e,this.ui(i)))},_out:function(e){var i=t.ui.ddmanager.current;i&&(i.currentItem||i.element)[0]!==this.element[0]&&this.accept.call(this.element[0],i.currentItem||i.element)&&(this._removeHoverClass(),this._trigger("out",e,this.ui(i)))},_drop:function(e,i){var s=i||t.ui.ddmanager.current,n=!1;return s&&(s.currentItem||s.element)[0]!==this.element[0]?(this.element.find(":data(ui-droppable)").not(".ui-draggable-dragging").each(function(){var i=t(this).droppable("instance");return i.options.greedy&&!i.options.disabled&&i.options.scope===s.options.scope&&i.accept.call(i.element[0],s.currentItem||s.element)&&v(s,t.extend(i,{offset:i.element.offset()}),i.options.tolerance,e)?(n=!0,!1):void 0}),n?!1:this.accept.call(this.element[0],s.currentItem||s.element)?(this._removeActiveClass(),this._removeHoverClass(),this._trigger("drop",e,this.ui(s)),this.element):!1):!1},ui:function(t){return{draggable:t.currentItem||t.element,helper:t.helper,position:t.position,offset:t.positionAbs}},_addHoverClass:function(){this._addClass("ui-droppable-hover")},_removeHoverClass:function(){this._removeClass("ui-droppable-hover")},_addActiveClass:function(){this._addClass("ui-droppable-active")},_removeActiveClass:function(){this._removeClass("ui-droppable-active")}});var v=t.ui.intersect=function(){function t(t,e,i){return t>=e&&e+i>t}return function(e,i,s,n){if(!i.offset)return!1;var o=(e.positionAbs||e.position.absolute).left+e.margins.left,a=(e.positionAbs||e.position.absolute).top+e.margins.top,r=o+e.helperProportions.width,h=a+e.helperProportions.height,l=i.offset.left,c=i.offset.top,u=l+i.proportions().width,d=c+i.proportions().height;switch(s){case"fit":return o>=l&&u>=r&&a>=c&&d>=h;case"intersect":return o+e.helperProportions.width/2>l&&u>r-e.helperProportions.width/2&&a+e.helperProportions.height/2>c&&d>h-e.helperProportions.height/2;case"pointer":return t(n.pageY,c,i.proportions().height)&&t(n.pageX,l,i.proportions().width);case"touch":return(a>=c&&d>=a||h>=c&&d>=h||c>a&&h>d)&&(o>=l&&u>=o||r>=l&&u>=r||l>o&&r>u);default:return!1}}}();t.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(e,i){var s,n,o=t.ui.ddmanager.droppables[e.options.scope]||[],a=i?i.type:null,r=(e.currentItem||e.element).find(":data(ui-droppable)").addBack();t:for(s=0;o.length>s;s++)if(!(o[s].options.disabled||e&&!o[s].accept.call(o[s].element[0],e.currentItem||e.element))){for(n=0;r.length>n;n++)if(r[n]===o[s].element[0]){o[s].proportions().height=0;continue t}o[s].visible="none"!==o[s].element.css("display"),o[s].visible&&("mousedown"===a&&o[s]._activate.call(o[s],i),o[s].offset=o[s].element.offset(),o[s].proportions({width:o[s].element[0].offsetWidth,height:o[s].element[0].offsetHeight}))}},drop:function(e,i){var s=!1;return t.each((t.ui.ddmanager.droppables[e.options.scope]||[]).slice(),function(){this.options&&(!this.options.disabled&&this.visible&&v(e,this,this.options.tolerance,i)&&(s=this._drop.call(this,i)||s),!this.options.disabled&&this.visible&&this.accept.call(this.element[0],e.currentItem||e.element)&&(this.isout=!0,this.isover=!1,this._deactivate.call(this,i)))}),s},dragStart:function(e,i){e.element.parentsUntil("body").on("scroll.droppable",function(){e.options.refreshPositions||t.ui.ddmanager.prepareOffsets(e,i)})},drag:function(e,i){e.options.refreshPositions&&t.ui.ddmanager.prepareOffsets(e,i),t.each(t.ui.ddmanager.droppables[e.options.scope]||[],function(){if(!this.options.disabled&&!this.greedyChild&&this.visible){var s,n,o,a=v(e,this,this.options.tolerance,i),r=!a&&this.isover?"isout":a&&!this.isover?"isover":null;r&&(this.options.greedy&&(n=this.options.scope,o=this.element.parents(":data(ui-droppable)").filter(function(){return t(this).droppable("instance").options.scope===n}),o.length&&(s=t(o[0]).droppable("instance"),s.greedyChild="isover"===r)),s&&"isover"===r&&(s.isover=!1,s.isout=!0,s._out.call(s,i)),this[r]=!0,this["isout"===r?"isover":"isout"]=!1,this["isover"===r?"_over":"_out"].call(this,i),s&&"isout"===r&&(s.isout=!1,s.isover=!0,s._over.call(s,i)))}})},dragStop:function(e,i){e.element.parentsUntil("body").off("scroll.droppable"),e.options.refreshPositions||t.ui.ddmanager.prepareOffsets(e,i)}},t.uiBackCompat!==!1&&t.widget("ui.droppable",t.ui.droppable,{options:{hoverClass:!1,activeClass:!1},_addActiveClass:function(){this._super(),this.options.activeClass&&this.element.addClass(this.options.activeClass)},_removeActiveClass:function(){this._super(),this.options.activeClass&&this.element.removeClass(this.options.activeClass)},_addHoverClass:function(){this._super(),this.options.hoverClass&&this.element.addClass(this.options.hoverClass)},_removeHoverClass:function(){this._super(),this.options.hoverClass&&this.element.removeClass(this.options.hoverClass)}}),t.ui.droppable,t.widget("ui.progressbar",{version:"1.12.1",options:{classes:{"ui-progressbar":"ui-corner-all","ui-progressbar-value":"ui-corner-left","ui-progressbar-complete":"ui-corner-right"},max:100,value:0,change:null,complete:null},min:0,_create:function(){this.oldValue=this.options.value=this._constrainedValue(),this.element.attr({role:"progressbar","aria-valuemin":this.min}),this._addClass("ui-progressbar","ui-widget ui-widget-content"),this.valueDiv=t("<div>").appendTo(this.element),this._addClass(this.valueDiv,"ui-progressbar-value","ui-widget-header"),this._refreshValue()},_destroy:function(){this.element.removeAttr("role aria-valuemin aria-valuemax aria-valuenow"),this.valueDiv.remove()},value:function(t){return void 0===t?this.options.value:(this.options.value=this._constrainedValue(t),this._refreshValue(),void 0)},_constrainedValue:function(t){return void 0===t&&(t=this.options.value),this.indeterminate=t===!1,"number"!=typeof t&&(t=0),this.indeterminate?!1:Math.min(this.options.max,Math.max(this.min,t))},_setOptions:function(t){var e=t.value;delete t.value,this._super(t),this.options.value=this._constrainedValue(e),this._refreshValue()},_setOption:function(t,e){"max"===t&&(e=Math.max(this.min,e)),this._super(t,e)},_setOptionDisabled:function(t){this._super(t),this.element.attr("aria-disabled",t),this._toggleClass(null,"ui-state-disabled",!!t)},_percentage:function(){return this.indeterminate?100:100*(this.options.value-this.min)/(this.options.max-this.min)},_refreshValue:function(){var e=this.options.value,i=this._percentage();this.valueDiv.toggle(this.indeterminate||e>this.min).width(i.toFixed(0)+"%"),this._toggleClass(this.valueDiv,"ui-progressbar-complete",null,e===this.options.max)._toggleClass("ui-progressbar-indeterminate",null,this.indeterminate),this.indeterminate?(this.element.removeAttr("aria-valuenow"),this.overlayDiv||(this.overlayDiv=t("<div>").appendTo(this.valueDiv),this._addClass(this.overlayDiv,"ui-progressbar-overlay"))):(this.element.attr({"aria-valuemax":this.options.max,"aria-valuenow":e}),this.overlayDiv&&(this.overlayDiv.remove(),this.overlayDiv=null)),this.oldValue!==e&&(this.oldValue=e,this._trigger("change")),e===this.options.max&&this._trigger("complete")}}),t.widget("ui.selectable",t.ui.mouse,{version:"1.12.1",options:{appendTo:"body",autoRefresh:!0,distance:0,filter:"*",tolerance:"touch",selected:null,selecting:null,start:null,stop:null,unselected:null,unselecting:null},_create:function(){var e=this;this._addClass("ui-selectable"),this.dragged=!1,this.refresh=function(){e.elementPos=t(e.element[0]).offset(),e.selectees=t(e.options.filter,e.element[0]),e._addClass(e.selectees,"ui-selectee"),e.selectees.each(function(){var i=t(this),s=i.offset(),n={left:s.left-e.elementPos.left,top:s.top-e.elementPos.top};t.data(this,"selectable-item",{element:this,$element:i,left:n.left,top:n.top,right:n.left+i.outerWidth(),bottom:n.top+i.outerHeight(),startselected:!1,selected:i.hasClass("ui-selected"),selecting:i.hasClass("ui-selecting"),unselecting:i.hasClass("ui-unselecting")})})},this.refresh(),this._mouseInit(),this.helper=t("<div>"),this._addClass(this.helper,"ui-selectable-helper")},_destroy:function(){this.selectees.removeData("selectable-item"),this._mouseDestroy()},_mouseStart:function(e){var i=this,s=this.options;this.opos=[e.pageX,e.pageY],this.elementPos=t(this.element[0]).offset(),this.options.disabled||(this.selectees=t(s.filter,this.element[0]),this._trigger("start",e),t(s.appendTo).append(this.helper),this.helper.css({left:e.pageX,top:e.pageY,width:0,height:0}),s.autoRefresh&&this.refresh(),this.selectees.filter(".ui-selected").each(function(){var s=t.data(this,"selectable-item");s.startselected=!0,e.metaKey||e.ctrlKey||(i._removeClass(s.$element,"ui-selected"),s.selected=!1,i._addClass(s.$element,"ui-unselecting"),s.unselecting=!0,i._trigger("unselecting",e,{unselecting:s.element}))}),t(e.target).parents().addBack().each(function(){var s,n=t.data(this,"selectable-item");return n?(s=!e.metaKey&&!e.ctrlKey||!n.$element.hasClass("ui-selected"),i._removeClass(n.$element,s?"ui-unselecting":"ui-selected")._addClass(n.$element,s?"ui-selecting":"ui-unselecting"),n.unselecting=!s,n.selecting=s,n.selected=s,s?i._trigger("selecting",e,{selecting:n.element}):i._trigger("unselecting",e,{unselecting:n.element}),!1):void 0}))},_mouseDrag:function(e){if(this.dragged=!0,!this.options.disabled){var i,s=this,n=this.options,o=this.opos[0],a=this.opos[1],r=e.pageX,h=e.pageY;return o>r&&(i=r,r=o,o=i),a>h&&(i=h,h=a,a=i),this.helper.css({left:o,top:a,width:r-o,height:h-a}),this.selectees.each(function(){var i=t.data(this,"selectable-item"),l=!1,c={};i&&i.element!==s.element[0]&&(c.left=i.left+s.elementPos.left,c.right=i.right+s.elementPos.left,c.top=i.top+s.elementPos.top,c.bottom=i.bottom+s.elementPos.top,"touch"===n.tolerance?l=!(c.left>r||o>c.right||c.top>h||a>c.bottom):"fit"===n.tolerance&&(l=c.left>o&&r>c.right&&c.top>a&&h>c.bottom),l?(i.selected&&(s._removeClass(i.$element,"ui-selected"),i.selected=!1),i.unselecting&&(s._removeClass(i.$element,"ui-unselecting"),i.unselecting=!1),i.selecting||(s._addClass(i.$element,"ui-selecting"),i.selecting=!0,s._trigger("selecting",e,{selecting:i.element}))):(i.selecting&&((e.metaKey||e.ctrlKey)&&i.startselected?(s._removeClass(i.$element,"ui-selecting"),i.selecting=!1,s._addClass(i.$element,"ui-selected"),i.selected=!0):(s._removeClass(i.$element,"ui-selecting"),i.selecting=!1,i.startselected&&(s._addClass(i.$element,"ui-unselecting"),i.unselecting=!0),s._trigger("unselecting",e,{unselecting:i.element}))),i.selected&&(e.metaKey||e.ctrlKey||i.startselected||(s._removeClass(i.$element,"ui-selected"),i.selected=!1,s._addClass(i.$element,"ui-unselecting"),i.unselecting=!0,s._trigger("unselecting",e,{unselecting:i.element})))))}),!1}},_mouseStop:function(e){var i=this;return this.dragged=!1,t(".ui-unselecting",this.element[0]).each(function(){var s=t.data(this,"selectable-item");i._removeClass(s.$element,"ui-unselecting"),s.unselecting=!1,s.startselected=!1,i._trigger("unselected",e,{unselected:s.element})}),t(".ui-selecting",this.element[0]).each(function(){var s=t.data(this,"selectable-item");i._removeClass(s.$element,"ui-selecting")._addClass(s.$element,"ui-selected"),s.selecting=!1,s.selected=!0,s.startselected=!0,i._trigger("selected",e,{selected:s.element})}),this._trigger("stop",e),this.helper.remove(),!1}}),t.widget("ui.selectmenu",[t.ui.formResetMixin,{version:"1.12.1",defaultElement:"<select>",options:{appendTo:null,classes:{"ui-selectmenu-button-open":"ui-corner-top","ui-selectmenu-button-closed":"ui-corner-all"},disabled:null,icons:{button:"ui-icon-triangle-1-s"},position:{my:"left top",at:"left bottom",collision:"none"},width:!1,change:null,close:null,focus:null,open:null,select:null},_create:function(){var e=this.element.uniqueId().attr("id");this.ids={element:e,button:e+"-button",menu:e+"-menu"},this._drawButton(),this._drawMenu(),this._bindFormResetHandler(),this._rendered=!1,this.menuItems=t()},_drawButton:function(){var e,i=this,s=this._parseOption(this.element.find("option:selected"),this.element[0].selectedIndex);this.labels=this.element.labels().attr("for",this.ids.button),this._on(this.labels,{click:function(t){this.button.focus(),t.preventDefault()}}),this.element.hide(),this.button=t("<span>",{tabindex:this.options.disabled?-1:0,id:this.ids.button,role:"combobox","aria-expanded":"false","aria-autocomplete":"list","aria-owns":this.ids.menu,"aria-haspopup":"true",title:this.element.attr("title")}).insertAfter(this.element),this._addClass(this.button,"ui-selectmenu-button ui-selectmenu-button-closed","ui-button ui-widget"),e=t("<span>").appendTo(this.button),this._addClass(e,"ui-selectmenu-icon","ui-icon "+this.options.icons.button),this.buttonItem=this._renderButtonItem(s).appendTo(this.button),this.options.width!==!1&&this._resizeButton(),this._on(this.button,this._buttonEvents),this.button.one("focusin",function(){i._rendered||i._refreshMenu()})},_drawMenu:function(){var e=this;this.menu=t("<ul>",{"aria-hidden":"true","aria-labelledby":this.ids.button,id:this.ids.menu}),this.menuWrap=t("<div>").append(this.menu),this._addClass(this.menuWrap,"ui-selectmenu-menu","ui-front"),this.menuWrap.appendTo(this._appendTo()),this.menuInstance=this.menu.menu({classes:{"ui-menu":"ui-corner-bottom"},role:"listbox",select:function(t,i){t.preventDefault(),e._setSelection(),e._select(i.item.data("ui-selectmenu-item"),t)},focus:function(t,i){var s=i.item.data("ui-selectmenu-item");null!=e.focusIndex&&s.index!==e.focusIndex&&(e._trigger("focus",t,{item:s}),e.isOpen||e._select(s,t)),e.focusIndex=s.index,e.button.attr("aria-activedescendant",e.menuItems.eq(s.index).attr("id"))}}).menu("instance"),this.menuInstance._off(this.menu,"mouseleave"),this.menuInstance._closeOnDocumentClick=function(){return!1},this.menuInstance._isDivider=function(){return!1}},refresh:function(){this._refreshMenu(),this.buttonItem.replaceWith(this.buttonItem=this._renderButtonItem(this._getSelectedItem().data("ui-selectmenu-item")||{})),null===this.options.width&&this._resizeButton()},_refreshMenu:function(){var t,e=this.element.find("option");this.menu.empty(),this._parseOptions(e),this._renderMenu(this.menu,this.items),this.menuInstance.refresh(),this.menuItems=this.menu.find("li").not(".ui-selectmenu-optgroup").find(".ui-menu-item-wrapper"),this._rendered=!0,e.length&&(t=this._getSelectedItem(),this.menuInstance.focus(null,t),this._setAria(t.data("ui-selectmenu-item")),this._setOption("disabled",this.element.prop("disabled")))},open:function(t){this.options.disabled||(this._rendered?(this._removeClass(this.menu.find(".ui-state-active"),null,"ui-state-active"),this.menuInstance.focus(null,this._getSelectedItem())):this._refreshMenu(),this.menuItems.length&&(this.isOpen=!0,this._toggleAttr(),this._resizeMenu(),this._position(),this._on(this.document,this._documentClick),this._trigger("open",t)))},_position:function(){this.menuWrap.position(t.extend({of:this.button},this.options.position))},close:function(t){this.isOpen&&(this.isOpen=!1,this._toggleAttr(),this.range=null,this._off(this.document),this._trigger("close",t))},widget:function(){return this.button},menuWidget:function(){return this.menu},_renderButtonItem:function(e){var i=t("<span>");return this._setText(i,e.label),this._addClass(i,"ui-selectmenu-text"),i},_renderMenu:function(e,i){var s=this,n="";t.each(i,function(i,o){var a;o.optgroup!==n&&(a=t("<li>",{text:o.optgroup}),s._addClass(a,"ui-selectmenu-optgroup","ui-menu-divider"+(o.element.parent("optgroup").prop("disabled")?" ui-state-disabled":"")),a.appendTo(e),n=o.optgroup),s._renderItemData(e,o)})},_renderItemData:function(t,e){return this._renderItem(t,e).data("ui-selectmenu-item",e)},_renderItem:function(e,i){var s=t("<li>"),n=t("<div>",{title:i.element.attr("title")});return i.disabled&&this._addClass(s,null,"ui-state-disabled"),this._setText(n,i.label),s.append(n).appendTo(e)},_setText:function(t,e){e?t.text(e):t.html(" ")},_move:function(t,e){var i,s,n=".ui-menu-item";this.isOpen?i=this.menuItems.eq(this.focusIndex).parent("li"):(i=this.menuItems.eq(this.element[0].selectedIndex).parent("li"),n+=":not(.ui-state-disabled)"),s="first"===t||"last"===t?i["first"===t?"prevAll":"nextAll"](n).eq(-1):i[t+"All"](n).eq(0),s.length&&this.menuInstance.focus(e,s)},_getSelectedItem:function(){return this.menuItems.eq(this.element[0].selectedIndex).parent("li")},_toggle:function(t){this[this.isOpen?"close":"open"](t)},_setSelection:function(){var t;this.range&&(window.getSelection?(t=window.getSelection(),t.removeAllRanges(),t.addRange(this.range)):this.range.select(),this.button.focus())},_documentClick:{mousedown:function(e){this.isOpen&&(t(e.target).closest(".ui-selectmenu-menu, #"+t.ui.escapeSelector(this.ids.button)).length||this.close(e))}},_buttonEvents:{mousedown:function(){var t;window.getSelection?(t=window.getSelection(),t.rangeCount&&(this.range=t.getRangeAt(0))):this.range=document.selection.createRange()},click:function(t){this._setSelection(),this._toggle(t)},keydown:function(e){var i=!0;switch(e.keyCode){case t.ui.keyCode.TAB:case t.ui.keyCode.ESCAPE:this.close(e),i=!1;break;case t.ui.keyCode.ENTER:this.isOpen&&this._selectFocusedItem(e);break;case t.ui.keyCode.UP:e.altKey?this._toggle(e):this._move("prev",e);break;case t.ui.keyCode.DOWN:e.altKey?this._toggle(e):this._move("next",e);break;case t.ui.keyCode.SPACE:this.isOpen?this._selectFocusedItem(e):this._toggle(e);break;case t.ui.keyCode.LEFT:this._move("prev",e);break;case t.ui.keyCode.RIGHT:this._move("next",e);break;case t.ui.keyCode.HOME:case t.ui.keyCode.PAGE_UP:this._move("first",e);break;case t.ui.keyCode.END:case t.ui.keyCode.PAGE_DOWN:this._move("last",e);break;default:this.menu.trigger(e),i=!1}i&&e.preventDefault()}},_selectFocusedItem:function(t){var e=this.menuItems.eq(this.focusIndex).parent("li");e.hasClass("ui-state-disabled")||this._select(e.data("ui-selectmenu-item"),t)},_select:function(t,e){var i=this.element[0].selectedIndex;this.element[0].selectedIndex=t.index,this.buttonItem.replaceWith(this.buttonItem=this._renderButtonItem(t)),this._setAria(t),this._trigger("select",e,{item:t}),t.index!==i&&this._trigger("change",e,{item:t}),this.close(e)},_setAria:function(t){var e=this.menuItems.eq(t.index).attr("id");this.button.attr({"aria-labelledby":e,"aria-activedescendant":e}),this.menu.attr("aria-activedescendant",e)},_setOption:function(t,e){if("icons"===t){var i=this.button.find("span.ui-icon");this._removeClass(i,null,this.options.icons.button)._addClass(i,null,e.button)}this._super(t,e),"appendTo"===t&&this.menuWrap.appendTo(this._appendTo()),"width"===t&&this._resizeButton()},_setOptionDisabled:function(t){this._super(t),this.menuInstance.option("disabled",t),this.button.attr("aria-disabled",t),this._toggleClass(this.button,null,"ui-state-disabled",t),this.element.prop("disabled",t),t?(this.button.attr("tabindex",-1),this.close()):this.button.attr("tabindex",0)},_appendTo:function(){var e=this.options.appendTo;return e&&(e=e.jquery||e.nodeType?t(e):this.document.find(e).eq(0)),e&&e[0]||(e=this.element.closest(".ui-front, dialog")),e.length||(e=this.document[0].body),e},_toggleAttr:function(){this.button.attr("aria-expanded",this.isOpen),this._removeClass(this.button,"ui-selectmenu-button-"+(this.isOpen?"closed":"open"))._addClass(this.button,"ui-selectmenu-button-"+(this.isOpen?"open":"closed"))._toggleClass(this.menuWrap,"ui-selectmenu-open",null,this.isOpen),this.menu.attr("aria-hidden",!this.isOpen)},_resizeButton:function(){var t=this.options.width;return t===!1?(this.button.css("width",""),void 0):(null===t&&(t=this.element.show().outerWidth(),this.element.hide()),this.button.outerWidth(t),void 0)},_resizeMenu:function(){this.menu.outerWidth(Math.max(this.button.outerWidth(),this.menu.width("").outerWidth()+1))},_getCreateOptions:function(){var t=this._super();return t.disabled=this.element.prop("disabled"),t},_parseOptions:function(e){var i=this,s=[];e.each(function(e,n){s.push(i._parseOption(t(n),e))}),this.items=s},_parseOption:function(t,e){var i=t.parent("optgroup");return{element:t,index:e,value:t.val(),label:t.text(),optgroup:i.attr("label")||"",disabled:i.prop("disabled")||t.prop("disabled")}},_destroy:function(){this._unbindFormResetHandler(),this.menuWrap.remove(),this.button.remove(),this.element.show(),this.element.removeUniqueId(),this.labels.attr("for",this.ids.element)}}]),t.widget("ui.slider",t.ui.mouse,{version:"1.12.1",widgetEventPrefix:"slide",options:{animate:!1,classes:{"ui-slider":"ui-corner-all","ui-slider-handle":"ui-corner-all","ui-slider-range":"ui-corner-all ui-widget-header"},distance:0,max:100,min:0,orientation:"horizontal",range:!1,step:1,value:0,values:null,change:null,slide:null,start:null,stop:null},numPages:5,_create:function(){this._keySliding=!1,this._mouseSliding=!1,this._animateOff=!0,this._handleIndex=null,this._detectOrientation(),this._mouseInit(),this._calculateNewMax(),this._addClass("ui-slider ui-slider-"+this.orientation,"ui-widget ui-widget-content"),this._refresh(),this._animateOff=!1 +},_refresh:function(){this._createRange(),this._createHandles(),this._setupEvents(),this._refreshValue()},_createHandles:function(){var e,i,s=this.options,n=this.element.find(".ui-slider-handle"),o="<span tabindex='0'></span>",a=[];for(i=s.values&&s.values.length||1,n.length>i&&(n.slice(i).remove(),n=n.slice(0,i)),e=n.length;i>e;e++)a.push(o);this.handles=n.add(t(a.join("")).appendTo(this.element)),this._addClass(this.handles,"ui-slider-handle","ui-state-default"),this.handle=this.handles.eq(0),this.handles.each(function(e){t(this).data("ui-slider-handle-index",e).attr("tabIndex",0)})},_createRange:function(){var e=this.options;e.range?(e.range===!0&&(e.values?e.values.length&&2!==e.values.length?e.values=[e.values[0],e.values[0]]:t.isArray(e.values)&&(e.values=e.values.slice(0)):e.values=[this._valueMin(),this._valueMin()]),this.range&&this.range.length?(this._removeClass(this.range,"ui-slider-range-min ui-slider-range-max"),this.range.css({left:"",bottom:""})):(this.range=t("<div>").appendTo(this.element),this._addClass(this.range,"ui-slider-range")),("min"===e.range||"max"===e.range)&&this._addClass(this.range,"ui-slider-range-"+e.range)):(this.range&&this.range.remove(),this.range=null)},_setupEvents:function(){this._off(this.handles),this._on(this.handles,this._handleEvents),this._hoverable(this.handles),this._focusable(this.handles)},_destroy:function(){this.handles.remove(),this.range&&this.range.remove(),this._mouseDestroy()},_mouseCapture:function(e){var i,s,n,o,a,r,h,l,c=this,u=this.options;return u.disabled?!1:(this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()},this.elementOffset=this.element.offset(),i={x:e.pageX,y:e.pageY},s=this._normValueFromMouse(i),n=this._valueMax()-this._valueMin()+1,this.handles.each(function(e){var i=Math.abs(s-c.values(e));(n>i||n===i&&(e===c._lastChangedValue||c.values(e)===u.min))&&(n=i,o=t(this),a=e)}),r=this._start(e,a),r===!1?!1:(this._mouseSliding=!0,this._handleIndex=a,this._addClass(o,null,"ui-state-active"),o.trigger("focus"),h=o.offset(),l=!t(e.target).parents().addBack().is(".ui-slider-handle"),this._clickOffset=l?{left:0,top:0}:{left:e.pageX-h.left-o.width()/2,top:e.pageY-h.top-o.height()/2-(parseInt(o.css("borderTopWidth"),10)||0)-(parseInt(o.css("borderBottomWidth"),10)||0)+(parseInt(o.css("marginTop"),10)||0)},this.handles.hasClass("ui-state-hover")||this._slide(e,a,s),this._animateOff=!0,!0))},_mouseStart:function(){return!0},_mouseDrag:function(t){var e={x:t.pageX,y:t.pageY},i=this._normValueFromMouse(e);return this._slide(t,this._handleIndex,i),!1},_mouseStop:function(t){return this._removeClass(this.handles,null,"ui-state-active"),this._mouseSliding=!1,this._stop(t,this._handleIndex),this._change(t,this._handleIndex),this._handleIndex=null,this._clickOffset=null,this._animateOff=!1,!1},_detectOrientation:function(){this.orientation="vertical"===this.options.orientation?"vertical":"horizontal"},_normValueFromMouse:function(t){var e,i,s,n,o;return"horizontal"===this.orientation?(e=this.elementSize.width,i=t.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)):(e=this.elementSize.height,i=t.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)),s=i/e,s>1&&(s=1),0>s&&(s=0),"vertical"===this.orientation&&(s=1-s),n=this._valueMax()-this._valueMin(),o=this._valueMin()+s*n,this._trimAlignValue(o)},_uiHash:function(t,e,i){var s={handle:this.handles[t],handleIndex:t,value:void 0!==e?e:this.value()};return this._hasMultipleValues()&&(s.value=void 0!==e?e:this.values(t),s.values=i||this.values()),s},_hasMultipleValues:function(){return this.options.values&&this.options.values.length},_start:function(t,e){return this._trigger("start",t,this._uiHash(e))},_slide:function(t,e,i){var s,n,o=this.value(),a=this.values();this._hasMultipleValues()&&(n=this.values(e?0:1),o=this.values(e),2===this.options.values.length&&this.options.range===!0&&(i=0===e?Math.min(n,i):Math.max(n,i)),a[e]=i),i!==o&&(s=this._trigger("slide",t,this._uiHash(e,i,a)),s!==!1&&(this._hasMultipleValues()?this.values(e,i):this.value(i)))},_stop:function(t,e){this._trigger("stop",t,this._uiHash(e))},_change:function(t,e){this._keySliding||this._mouseSliding||(this._lastChangedValue=e,this._trigger("change",t,this._uiHash(e)))},value:function(t){return arguments.length?(this.options.value=this._trimAlignValue(t),this._refreshValue(),this._change(null,0),void 0):this._value()},values:function(e,i){var s,n,o;if(arguments.length>1)return this.options.values[e]=this._trimAlignValue(i),this._refreshValue(),this._change(null,e),void 0;if(!arguments.length)return this._values();if(!t.isArray(arguments[0]))return this._hasMultipleValues()?this._values(e):this.value();for(s=this.options.values,n=arguments[0],o=0;s.length>o;o+=1)s[o]=this._trimAlignValue(n[o]),this._change(null,o);this._refreshValue()},_setOption:function(e,i){var s,n=0;switch("range"===e&&this.options.range===!0&&("min"===i?(this.options.value=this._values(0),this.options.values=null):"max"===i&&(this.options.value=this._values(this.options.values.length-1),this.options.values=null)),t.isArray(this.options.values)&&(n=this.options.values.length),this._super(e,i),e){case"orientation":this._detectOrientation(),this._removeClass("ui-slider-horizontal ui-slider-vertical")._addClass("ui-slider-"+this.orientation),this._refreshValue(),this.options.range&&this._refreshRange(i),this.handles.css("horizontal"===i?"bottom":"left","");break;case"value":this._animateOff=!0,this._refreshValue(),this._change(null,0),this._animateOff=!1;break;case"values":for(this._animateOff=!0,this._refreshValue(),s=n-1;s>=0;s--)this._change(null,s);this._animateOff=!1;break;case"step":case"min":case"max":this._animateOff=!0,this._calculateNewMax(),this._refreshValue(),this._animateOff=!1;break;case"range":this._animateOff=!0,this._refresh(),this._animateOff=!1}},_setOptionDisabled:function(t){this._super(t),this._toggleClass(null,"ui-state-disabled",!!t)},_value:function(){var t=this.options.value;return t=this._trimAlignValue(t)},_values:function(t){var e,i,s;if(arguments.length)return e=this.options.values[t],e=this._trimAlignValue(e);if(this._hasMultipleValues()){for(i=this.options.values.slice(),s=0;i.length>s;s+=1)i[s]=this._trimAlignValue(i[s]);return i}return[]},_trimAlignValue:function(t){if(this._valueMin()>=t)return this._valueMin();if(t>=this._valueMax())return this._valueMax();var e=this.options.step>0?this.options.step:1,i=(t-this._valueMin())%e,s=t-i;return 2*Math.abs(i)>=e&&(s+=i>0?e:-e),parseFloat(s.toFixed(5))},_calculateNewMax:function(){var t=this.options.max,e=this._valueMin(),i=this.options.step,s=Math.round((t-e)/i)*i;t=s+e,t>this.options.max&&(t-=i),this.max=parseFloat(t.toFixed(this._precision()))},_precision:function(){var t=this._precisionOf(this.options.step);return null!==this.options.min&&(t=Math.max(t,this._precisionOf(this.options.min))),t},_precisionOf:function(t){var e=""+t,i=e.indexOf(".");return-1===i?0:e.length-i-1},_valueMin:function(){return this.options.min},_valueMax:function(){return this.max},_refreshRange:function(t){"vertical"===t&&this.range.css({width:"",left:""}),"horizontal"===t&&this.range.css({height:"",bottom:""})},_refreshValue:function(){var e,i,s,n,o,a=this.options.range,r=this.options,h=this,l=this._animateOff?!1:r.animate,c={};this._hasMultipleValues()?this.handles.each(function(s){i=100*((h.values(s)-h._valueMin())/(h._valueMax()-h._valueMin())),c["horizontal"===h.orientation?"left":"bottom"]=i+"%",t(this).stop(1,1)[l?"animate":"css"](c,r.animate),h.options.range===!0&&("horizontal"===h.orientation?(0===s&&h.range.stop(1,1)[l?"animate":"css"]({left:i+"%"},r.animate),1===s&&h.range[l?"animate":"css"]({width:i-e+"%"},{queue:!1,duration:r.animate})):(0===s&&h.range.stop(1,1)[l?"animate":"css"]({bottom:i+"%"},r.animate),1===s&&h.range[l?"animate":"css"]({height:i-e+"%"},{queue:!1,duration:r.animate}))),e=i}):(s=this.value(),n=this._valueMin(),o=this._valueMax(),i=o!==n?100*((s-n)/(o-n)):0,c["horizontal"===this.orientation?"left":"bottom"]=i+"%",this.handle.stop(1,1)[l?"animate":"css"](c,r.animate),"min"===a&&"horizontal"===this.orientation&&this.range.stop(1,1)[l?"animate":"css"]({width:i+"%"},r.animate),"max"===a&&"horizontal"===this.orientation&&this.range.stop(1,1)[l?"animate":"css"]({width:100-i+"%"},r.animate),"min"===a&&"vertical"===this.orientation&&this.range.stop(1,1)[l?"animate":"css"]({height:i+"%"},r.animate),"max"===a&&"vertical"===this.orientation&&this.range.stop(1,1)[l?"animate":"css"]({height:100-i+"%"},r.animate))},_handleEvents:{keydown:function(e){var i,s,n,o,a=t(e.target).data("ui-slider-handle-index");switch(e.keyCode){case t.ui.keyCode.HOME:case t.ui.keyCode.END:case t.ui.keyCode.PAGE_UP:case t.ui.keyCode.PAGE_DOWN:case t.ui.keyCode.UP:case t.ui.keyCode.RIGHT:case t.ui.keyCode.DOWN:case t.ui.keyCode.LEFT:if(e.preventDefault(),!this._keySliding&&(this._keySliding=!0,this._addClass(t(e.target),null,"ui-state-active"),i=this._start(e,a),i===!1))return}switch(o=this.options.step,s=n=this._hasMultipleValues()?this.values(a):this.value(),e.keyCode){case t.ui.keyCode.HOME:n=this._valueMin();break;case t.ui.keyCode.END:n=this._valueMax();break;case t.ui.keyCode.PAGE_UP:n=this._trimAlignValue(s+(this._valueMax()-this._valueMin())/this.numPages);break;case t.ui.keyCode.PAGE_DOWN:n=this._trimAlignValue(s-(this._valueMax()-this._valueMin())/this.numPages);break;case t.ui.keyCode.UP:case t.ui.keyCode.RIGHT:if(s===this._valueMax())return;n=this._trimAlignValue(s+o);break;case t.ui.keyCode.DOWN:case t.ui.keyCode.LEFT:if(s===this._valueMin())return;n=this._trimAlignValue(s-o)}this._slide(e,a,n)},keyup:function(e){var i=t(e.target).data("ui-slider-handle-index");this._keySliding&&(this._keySliding=!1,this._stop(e,i),this._change(e,i),this._removeClass(t(e.target),null,"ui-state-active"))}}}),t.widget("ui.sortable",t.ui.mouse,{version:"1.12.1",widgetEventPrefix:"sort",ready:!1,options:{appendTo:"parent",axis:!1,connectWith:!1,containment:!1,cursor:"auto",cursorAt:!1,dropOnEmpty:!0,forcePlaceholderSize:!1,forceHelperSize:!1,grid:!1,handle:!1,helper:"original",items:"> *",opacity:!1,placeholder:!1,revert:!1,scroll:!0,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1e3,activate:null,beforeStop:null,change:null,deactivate:null,out:null,over:null,receive:null,remove:null,sort:null,start:null,stop:null,update:null},_isOverAxis:function(t,e,i){return t>=e&&e+i>t},_isFloating:function(t){return/left|right/.test(t.css("float"))||/inline|table-cell/.test(t.css("display"))},_create:function(){this.containerCache={},this._addClass("ui-sortable"),this.refresh(),this.offset=this.element.offset(),this._mouseInit(),this._setHandleClassName(),this.ready=!0},_setOption:function(t,e){this._super(t,e),"handle"===t&&this._setHandleClassName()},_setHandleClassName:function(){var e=this;this._removeClass(this.element.find(".ui-sortable-handle"),"ui-sortable-handle"),t.each(this.items,function(){e._addClass(this.instance.options.handle?this.item.find(this.instance.options.handle):this.item,"ui-sortable-handle")})},_destroy:function(){this._mouseDestroy();for(var t=this.items.length-1;t>=0;t--)this.items[t].item.removeData(this.widgetName+"-item");return this},_mouseCapture:function(e,i){var s=null,n=!1,o=this;return this.reverting?!1:this.options.disabled||"static"===this.options.type?!1:(this._refreshItems(e),t(e.target).parents().each(function(){return t.data(this,o.widgetName+"-item")===o?(s=t(this),!1):void 0}),t.data(e.target,o.widgetName+"-item")===o&&(s=t(e.target)),s?!this.options.handle||i||(t(this.options.handle,s).find("*").addBack().each(function(){this===e.target&&(n=!0)}),n)?(this.currentItem=s,this._removeCurrentsFromItems(),!0):!1:!1)},_mouseStart:function(e,i,s){var n,o,a=this.options;if(this.currentContainer=this,this.refreshPositions(),this.helper=this._createHelper(e),this._cacheHelperProportions(),this._cacheMargins(),this.scrollParent=this.helper.scrollParent(),this.offset=this.currentItem.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},t.extend(this.offset,{click:{left:e.pageX-this.offset.left,top:e.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.helper.css("position","absolute"),this.cssPosition=this.helper.css("position"),this.originalPosition=this._generatePosition(e),this.originalPageX=e.pageX,this.originalPageY=e.pageY,a.cursorAt&&this._adjustOffsetFromHelper(a.cursorAt),this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]},this.helper[0]!==this.currentItem[0]&&this.currentItem.hide(),this._createPlaceholder(),a.containment&&this._setContainment(),a.cursor&&"auto"!==a.cursor&&(o=this.document.find("body"),this.storedCursor=o.css("cursor"),o.css("cursor",a.cursor),this.storedStylesheet=t("<style>*{ cursor: "+a.cursor+" !important; }</style>").appendTo(o)),a.opacity&&(this.helper.css("opacity")&&(this._storedOpacity=this.helper.css("opacity")),this.helper.css("opacity",a.opacity)),a.zIndex&&(this.helper.css("zIndex")&&(this._storedZIndex=this.helper.css("zIndex")),this.helper.css("zIndex",a.zIndex)),this.scrollParent[0]!==this.document[0]&&"HTML"!==this.scrollParent[0].tagName&&(this.overflowOffset=this.scrollParent.offset()),this._trigger("start",e,this._uiHash()),this._preserveHelperProportions||this._cacheHelperProportions(),!s)for(n=this.containers.length-1;n>=0;n--)this.containers[n]._trigger("activate",e,this._uiHash(this));return t.ui.ddmanager&&(t.ui.ddmanager.current=this),t.ui.ddmanager&&!a.dropBehaviour&&t.ui.ddmanager.prepareOffsets(this,e),this.dragging=!0,this._addClass(this.helper,"ui-sortable-helper"),this._mouseDrag(e),!0},_mouseDrag:function(e){var i,s,n,o,a=this.options,r=!1;for(this.position=this._generatePosition(e),this.positionAbs=this._convertPositionTo("absolute"),this.lastPositionAbs||(this.lastPositionAbs=this.positionAbs),this.options.scroll&&(this.scrollParent[0]!==this.document[0]&&"HTML"!==this.scrollParent[0].tagName?(this.overflowOffset.top+this.scrollParent[0].offsetHeight-e.pageY<a.scrollSensitivity?this.scrollParent[0].scrollTop=r=this.scrollParent[0].scrollTop+a.scrollSpeed:e.pageY-this.overflowOffset.top<a.scrollSensitivity&&(this.scrollParent[0].scrollTop=r=this.scrollParent[0].scrollTop-a.scrollSpeed),this.overflowOffset.left+this.scrollParent[0].offsetWidth-e.pageX<a.scrollSensitivity?this.scrollParent[0].scrollLeft=r=this.scrollParent[0].scrollLeft+a.scrollSpeed:e.pageX-this.overflowOffset.left<a.scrollSensitivity&&(this.scrollParent[0].scrollLeft=r=this.scrollParent[0].scrollLeft-a.scrollSpeed)):(e.pageY-this.document.scrollTop()<a.scrollSensitivity?r=this.document.scrollTop(this.document.scrollTop()-a.scrollSpeed):this.window.height()-(e.pageY-this.document.scrollTop())<a.scrollSensitivity&&(r=this.document.scrollTop(this.document.scrollTop()+a.scrollSpeed)),e.pageX-this.document.scrollLeft()<a.scrollSensitivity?r=this.document.scrollLeft(this.document.scrollLeft()-a.scrollSpeed):this.window.width()-(e.pageX-this.document.scrollLeft())<a.scrollSensitivity&&(r=this.document.scrollLeft(this.document.scrollLeft()+a.scrollSpeed))),r!==!1&&t.ui.ddmanager&&!a.dropBehaviour&&t.ui.ddmanager.prepareOffsets(this,e)),this.positionAbs=this._convertPositionTo("absolute"),this.options.axis&&"y"===this.options.axis||(this.helper[0].style.left=this.position.left+"px"),this.options.axis&&"x"===this.options.axis||(this.helper[0].style.top=this.position.top+"px"),i=this.items.length-1;i>=0;i--)if(s=this.items[i],n=s.item[0],o=this._intersectsWithPointer(s),o&&s.instance===this.currentContainer&&n!==this.currentItem[0]&&this.placeholder[1===o?"next":"prev"]()[0]!==n&&!t.contains(this.placeholder[0],n)&&("semi-dynamic"===this.options.type?!t.contains(this.element[0],n):!0)){if(this.direction=1===o?"down":"up","pointer"!==this.options.tolerance&&!this._intersectsWithSides(s))break;this._rearrange(e,s),this._trigger("change",e,this._uiHash());break}return this._contactContainers(e),t.ui.ddmanager&&t.ui.ddmanager.drag(this,e),this._trigger("sort",e,this._uiHash()),this.lastPositionAbs=this.positionAbs,!1},_mouseStop:function(e,i){if(e){if(t.ui.ddmanager&&!this.options.dropBehaviour&&t.ui.ddmanager.drop(this,e),this.options.revert){var s=this,n=this.placeholder.offset(),o=this.options.axis,a={};o&&"x"!==o||(a.left=n.left-this.offset.parent.left-this.margins.left+(this.offsetParent[0]===this.document[0].body?0:this.offsetParent[0].scrollLeft)),o&&"y"!==o||(a.top=n.top-this.offset.parent.top-this.margins.top+(this.offsetParent[0]===this.document[0].body?0:this.offsetParent[0].scrollTop)),this.reverting=!0,t(this.helper).animate(a,parseInt(this.options.revert,10)||500,function(){s._clear(e)})}else this._clear(e,i);return!1}},cancel:function(){if(this.dragging){this._mouseUp(new t.Event("mouseup",{target:null})),"original"===this.options.helper?(this.currentItem.css(this._storedCSS),this._removeClass(this.currentItem,"ui-sortable-helper")):this.currentItem.show();for(var e=this.containers.length-1;e>=0;e--)this.containers[e]._trigger("deactivate",null,this._uiHash(this)),this.containers[e].containerCache.over&&(this.containers[e]._trigger("out",null,this._uiHash(this)),this.containers[e].containerCache.over=0)}return this.placeholder&&(this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]),"original"!==this.options.helper&&this.helper&&this.helper[0].parentNode&&this.helper.remove(),t.extend(this,{helper:null,dragging:!1,reverting:!1,_noFinalSort:null}),this.domPosition.prev?t(this.domPosition.prev).after(this.currentItem):t(this.domPosition.parent).prepend(this.currentItem)),this},serialize:function(e){var i=this._getItemsAsjQuery(e&&e.connected),s=[];return e=e||{},t(i).each(function(){var i=(t(e.item||this).attr(e.attribute||"id")||"").match(e.expression||/(.+)[\-=_](.+)/);i&&s.push((e.key||i[1]+"[]")+"="+(e.key&&e.expression?i[1]:i[2]))}),!s.length&&e.key&&s.push(e.key+"="),s.join("&")},toArray:function(e){var i=this._getItemsAsjQuery(e&&e.connected),s=[];return e=e||{},i.each(function(){s.push(t(e.item||this).attr(e.attribute||"id")||"")}),s},_intersectsWith:function(t){var e=this.positionAbs.left,i=e+this.helperProportions.width,s=this.positionAbs.top,n=s+this.helperProportions.height,o=t.left,a=o+t.width,r=t.top,h=r+t.height,l=this.offset.click.top,c=this.offset.click.left,u="x"===this.options.axis||s+l>r&&h>s+l,d="y"===this.options.axis||e+c>o&&a>e+c,p=u&&d;return"pointer"===this.options.tolerance||this.options.forcePointerForContainers||"pointer"!==this.options.tolerance&&this.helperProportions[this.floating?"width":"height"]>t[this.floating?"width":"height"]?p:e+this.helperProportions.width/2>o&&a>i-this.helperProportions.width/2&&s+this.helperProportions.height/2>r&&h>n-this.helperProportions.height/2},_intersectsWithPointer:function(t){var e,i,s="x"===this.options.axis||this._isOverAxis(this.positionAbs.top+this.offset.click.top,t.top,t.height),n="y"===this.options.axis||this._isOverAxis(this.positionAbs.left+this.offset.click.left,t.left,t.width),o=s&&n;return o?(e=this._getDragVerticalDirection(),i=this._getDragHorizontalDirection(),this.floating?"right"===i||"down"===e?2:1:e&&("down"===e?2:1)):!1},_intersectsWithSides:function(t){var e=this._isOverAxis(this.positionAbs.top+this.offset.click.top,t.top+t.height/2,t.height),i=this._isOverAxis(this.positionAbs.left+this.offset.click.left,t.left+t.width/2,t.width),s=this._getDragVerticalDirection(),n=this._getDragHorizontalDirection();return this.floating&&n?"right"===n&&i||"left"===n&&!i:s&&("down"===s&&e||"up"===s&&!e)},_getDragVerticalDirection:function(){var t=this.positionAbs.top-this.lastPositionAbs.top;return 0!==t&&(t>0?"down":"up")},_getDragHorizontalDirection:function(){var t=this.positionAbs.left-this.lastPositionAbs.left;return 0!==t&&(t>0?"right":"left")},refresh:function(t){return this._refreshItems(t),this._setHandleClassName(),this.refreshPositions(),this},_connectWith:function(){var t=this.options;return t.connectWith.constructor===String?[t.connectWith]:t.connectWith},_getItemsAsjQuery:function(e){function i(){r.push(this)}var s,n,o,a,r=[],h=[],l=this._connectWith();if(l&&e)for(s=l.length-1;s>=0;s--)for(o=t(l[s],this.document[0]),n=o.length-1;n>=0;n--)a=t.data(o[n],this.widgetFullName),a&&a!==this&&!a.options.disabled&&h.push([t.isFunction(a.options.items)?a.options.items.call(a.element):t(a.options.items,a.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),a]);for(h.push([t.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):t(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]),s=h.length-1;s>=0;s--)h[s][0].each(i);return t(r)},_removeCurrentsFromItems:function(){var e=this.currentItem.find(":data("+this.widgetName+"-item)");this.items=t.grep(this.items,function(t){for(var i=0;e.length>i;i++)if(e[i]===t.item[0])return!1;return!0})},_refreshItems:function(e){this.items=[],this.containers=[this];var i,s,n,o,a,r,h,l,c=this.items,u=[[t.isFunction(this.options.items)?this.options.items.call(this.element[0],e,{item:this.currentItem}):t(this.options.items,this.element),this]],d=this._connectWith();if(d&&this.ready)for(i=d.length-1;i>=0;i--)for(n=t(d[i],this.document[0]),s=n.length-1;s>=0;s--)o=t.data(n[s],this.widgetFullName),o&&o!==this&&!o.options.disabled&&(u.push([t.isFunction(o.options.items)?o.options.items.call(o.element[0],e,{item:this.currentItem}):t(o.options.items,o.element),o]),this.containers.push(o));for(i=u.length-1;i>=0;i--)for(a=u[i][1],r=u[i][0],s=0,l=r.length;l>s;s++)h=t(r[s]),h.data(this.widgetName+"-item",a),c.push({item:h,instance:a,width:0,height:0,left:0,top:0})},refreshPositions:function(e){this.floating=this.items.length?"x"===this.options.axis||this._isFloating(this.items[0].item):!1,this.offsetParent&&this.helper&&(this.offset.parent=this._getParentOffset());var i,s,n,o;for(i=this.items.length-1;i>=0;i--)s=this.items[i],s.instance!==this.currentContainer&&this.currentContainer&&s.item[0]!==this.currentItem[0]||(n=this.options.toleranceElement?t(this.options.toleranceElement,s.item):s.item,e||(s.width=n.outerWidth(),s.height=n.outerHeight()),o=n.offset(),s.left=o.left,s.top=o.top);if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(i=this.containers.length-1;i>=0;i--)o=this.containers[i].element.offset(),this.containers[i].containerCache.left=o.left,this.containers[i].containerCache.top=o.top,this.containers[i].containerCache.width=this.containers[i].element.outerWidth(),this.containers[i].containerCache.height=this.containers[i].element.outerHeight();return this},_createPlaceholder:function(e){e=e||this;var i,s=e.options;s.placeholder&&s.placeholder.constructor!==String||(i=s.placeholder,s.placeholder={element:function(){var s=e.currentItem[0].nodeName.toLowerCase(),n=t("<"+s+">",e.document[0]);return e._addClass(n,"ui-sortable-placeholder",i||e.currentItem[0].className)._removeClass(n,"ui-sortable-helper"),"tbody"===s?e._createTrPlaceholder(e.currentItem.find("tr").eq(0),t("<tr>",e.document[0]).appendTo(n)):"tr"===s?e._createTrPlaceholder(e.currentItem,n):"img"===s&&n.attr("src",e.currentItem.attr("src")),i||n.css("visibility","hidden"),n},update:function(t,n){(!i||s.forcePlaceholderSize)&&(n.height()||n.height(e.currentItem.innerHeight()-parseInt(e.currentItem.css("paddingTop")||0,10)-parseInt(e.currentItem.css("paddingBottom")||0,10)),n.width()||n.width(e.currentItem.innerWidth()-parseInt(e.currentItem.css("paddingLeft")||0,10)-parseInt(e.currentItem.css("paddingRight")||0,10)))}}),e.placeholder=t(s.placeholder.element.call(e.element,e.currentItem)),e.currentItem.after(e.placeholder),s.placeholder.update(e,e.placeholder)},_createTrPlaceholder:function(e,i){var s=this;e.children().each(function(){t("<td> </td>",s.document[0]).attr("colspan",t(this).attr("colspan")||1).appendTo(i)})},_contactContainers:function(e){var i,s,n,o,a,r,h,l,c,u,d=null,p=null;for(i=this.containers.length-1;i>=0;i--)if(!t.contains(this.currentItem[0],this.containers[i].element[0]))if(this._intersectsWith(this.containers[i].containerCache)){if(d&&t.contains(this.containers[i].element[0],d.element[0]))continue;d=this.containers[i],p=i}else this.containers[i].containerCache.over&&(this.containers[i]._trigger("out",e,this._uiHash(this)),this.containers[i].containerCache.over=0);if(d)if(1===this.containers.length)this.containers[p].containerCache.over||(this.containers[p]._trigger("over",e,this._uiHash(this)),this.containers[p].containerCache.over=1);else{for(n=1e4,o=null,c=d.floating||this._isFloating(this.currentItem),a=c?"left":"top",r=c?"width":"height",u=c?"pageX":"pageY",s=this.items.length-1;s>=0;s--)t.contains(this.containers[p].element[0],this.items[s].item[0])&&this.items[s].item[0]!==this.currentItem[0]&&(h=this.items[s].item.offset()[a],l=!1,e[u]-h>this.items[s][r]/2&&(l=!0),n>Math.abs(e[u]-h)&&(n=Math.abs(e[u]-h),o=this.items[s],this.direction=l?"up":"down"));if(!o&&!this.options.dropOnEmpty)return;if(this.currentContainer===this.containers[p])return this.currentContainer.containerCache.over||(this.containers[p]._trigger("over",e,this._uiHash()),this.currentContainer.containerCache.over=1),void 0;o?this._rearrange(e,o,null,!0):this._rearrange(e,null,this.containers[p].element,!0),this._trigger("change",e,this._uiHash()),this.containers[p]._trigger("change",e,this._uiHash(this)),this.currentContainer=this.containers[p],this.options.placeholder.update(this.currentContainer,this.placeholder),this.containers[p]._trigger("over",e,this._uiHash(this)),this.containers[p].containerCache.over=1}},_createHelper:function(e){var i=this.options,s=t.isFunction(i.helper)?t(i.helper.apply(this.element[0],[e,this.currentItem])):"clone"===i.helper?this.currentItem.clone():this.currentItem;return s.parents("body").length||t("parent"!==i.appendTo?i.appendTo:this.currentItem[0].parentNode)[0].appendChild(s[0]),s[0]===this.currentItem[0]&&(this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")}),(!s[0].style.width||i.forceHelperSize)&&s.width(this.currentItem.width()),(!s[0].style.height||i.forceHelperSize)&&s.height(this.currentItem.height()),s},_adjustOffsetFromHelper:function(e){"string"==typeof e&&(e=e.split(" ")),t.isArray(e)&&(e={left:+e[0],top:+e[1]||0}),"left"in e&&(this.offset.click.left=e.left+this.margins.left),"right"in e&&(this.offset.click.left=this.helperProportions.width-e.right+this.margins.left),"top"in e&&(this.offset.click.top=e.top+this.margins.top),"bottom"in e&&(this.offset.click.top=this.helperProportions.height-e.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var e=this.offsetParent.offset();return"absolute"===this.cssPosition&&this.scrollParent[0]!==this.document[0]&&t.contains(this.scrollParent[0],this.offsetParent[0])&&(e.left+=this.scrollParent.scrollLeft(),e.top+=this.scrollParent.scrollTop()),(this.offsetParent[0]===this.document[0].body||this.offsetParent[0].tagName&&"html"===this.offsetParent[0].tagName.toLowerCase()&&t.ui.ie)&&(e={top:0,left:0}),{top:e.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:e.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"===this.cssPosition){var t=this.currentItem.position();return{top:t.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:t.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"),10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var e,i,s,n=this.options;"parent"===n.containment&&(n.containment=this.helper[0].parentNode),("document"===n.containment||"window"===n.containment)&&(this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,"document"===n.containment?this.document.width():this.window.width()-this.helperProportions.width-this.margins.left,("document"===n.containment?this.document.height()||document.body.parentNode.scrollHeight:this.window.height()||this.document[0].body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top]),/^(document|window|parent)$/.test(n.containment)||(e=t(n.containment)[0],i=t(n.containment).offset(),s="hidden"!==t(e).css("overflow"),this.containment=[i.left+(parseInt(t(e).css("borderLeftWidth"),10)||0)+(parseInt(t(e).css("paddingLeft"),10)||0)-this.margins.left,i.top+(parseInt(t(e).css("borderTopWidth"),10)||0)+(parseInt(t(e).css("paddingTop"),10)||0)-this.margins.top,i.left+(s?Math.max(e.scrollWidth,e.offsetWidth):e.offsetWidth)-(parseInt(t(e).css("borderLeftWidth"),10)||0)-(parseInt(t(e).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,i.top+(s?Math.max(e.scrollHeight,e.offsetHeight):e.offsetHeight)-(parseInt(t(e).css("borderTopWidth"),10)||0)-(parseInt(t(e).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top])},_convertPositionTo:function(e,i){i||(i=this.position);var s="absolute"===e?1:-1,n="absolute"!==this.cssPosition||this.scrollParent[0]!==this.document[0]&&t.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,o=/(html|body)/i.test(n[0].tagName);return{top:i.top+this.offset.relative.top*s+this.offset.parent.top*s-("fixed"===this.cssPosition?-this.scrollParent.scrollTop():o?0:n.scrollTop())*s,left:i.left+this.offset.relative.left*s+this.offset.parent.left*s-("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():o?0:n.scrollLeft())*s}},_generatePosition:function(e){var i,s,n=this.options,o=e.pageX,a=e.pageY,r="absolute"!==this.cssPosition||this.scrollParent[0]!==this.document[0]&&t.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,h=/(html|body)/i.test(r[0].tagName);return"relative"!==this.cssPosition||this.scrollParent[0]!==this.document[0]&&this.scrollParent[0]!==this.offsetParent[0]||(this.offset.relative=this._getRelativeOffset()),this.originalPosition&&(this.containment&&(e.pageX-this.offset.click.left<this.containment[0]&&(o=this.containment[0]+this.offset.click.left),e.pageY-this.offset.click.top<this.containment[1]&&(a=this.containment[1]+this.offset.click.top),e.pageX-this.offset.click.left>this.containment[2]&&(o=this.containment[2]+this.offset.click.left),e.pageY-this.offset.click.top>this.containment[3]&&(a=this.containment[3]+this.offset.click.top)),n.grid&&(i=this.originalPageY+Math.round((a-this.originalPageY)/n.grid[1])*n.grid[1],a=this.containment?i-this.offset.click.top>=this.containment[1]&&i-this.offset.click.top<=this.containment[3]?i:i-this.offset.click.top>=this.containment[1]?i-n.grid[1]:i+n.grid[1]:i,s=this.originalPageX+Math.round((o-this.originalPageX)/n.grid[0])*n.grid[0],o=this.containment?s-this.offset.click.left>=this.containment[0]&&s-this.offset.click.left<=this.containment[2]?s:s-this.offset.click.left>=this.containment[0]?s-n.grid[0]:s+n.grid[0]:s)),{top:a-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.scrollParent.scrollTop():h?0:r.scrollTop()),left:o-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():h?0:r.scrollLeft())}},_rearrange:function(t,e,i,s){i?i[0].appendChild(this.placeholder[0]):e.item[0].parentNode.insertBefore(this.placeholder[0],"down"===this.direction?e.item[0]:e.item[0].nextSibling),this.counter=this.counter?++this.counter:1;var n=this.counter; +this._delay(function(){n===this.counter&&this.refreshPositions(!s)})},_clear:function(t,e){function i(t,e,i){return function(s){i._trigger(t,s,e._uiHash(e))}}this.reverting=!1;var s,n=[];if(!this._noFinalSort&&this.currentItem.parent().length&&this.placeholder.before(this.currentItem),this._noFinalSort=null,this.helper[0]===this.currentItem[0]){for(s in this._storedCSS)("auto"===this._storedCSS[s]||"static"===this._storedCSS[s])&&(this._storedCSS[s]="");this.currentItem.css(this._storedCSS),this._removeClass(this.currentItem,"ui-sortable-helper")}else this.currentItem.show();for(this.fromOutside&&!e&&n.push(function(t){this._trigger("receive",t,this._uiHash(this.fromOutside))}),!this.fromOutside&&this.domPosition.prev===this.currentItem.prev().not(".ui-sortable-helper")[0]&&this.domPosition.parent===this.currentItem.parent()[0]||e||n.push(function(t){this._trigger("update",t,this._uiHash())}),this!==this.currentContainer&&(e||(n.push(function(t){this._trigger("remove",t,this._uiHash())}),n.push(function(t){return function(e){t._trigger("receive",e,this._uiHash(this))}}.call(this,this.currentContainer)),n.push(function(t){return function(e){t._trigger("update",e,this._uiHash(this))}}.call(this,this.currentContainer)))),s=this.containers.length-1;s>=0;s--)e||n.push(i("deactivate",this,this.containers[s])),this.containers[s].containerCache.over&&(n.push(i("out",this,this.containers[s])),this.containers[s].containerCache.over=0);if(this.storedCursor&&(this.document.find("body").css("cursor",this.storedCursor),this.storedStylesheet.remove()),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex","auto"===this._storedZIndex?"":this._storedZIndex),this.dragging=!1,e||this._trigger("beforeStop",t,this._uiHash()),this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.cancelHelperRemoval||(this.helper[0]!==this.currentItem[0]&&this.helper.remove(),this.helper=null),!e){for(s=0;n.length>s;s++)n[s].call(this,t);this._trigger("stop",t,this._uiHash())}return this.fromOutside=!1,!this.cancelHelperRemoval},_trigger:function(){t.Widget.prototype._trigger.apply(this,arguments)===!1&&this.cancel()},_uiHash:function(e){var i=e||this;return{helper:i.helper,placeholder:i.placeholder||t([]),position:i.position,originalPosition:i.originalPosition,offset:i.positionAbs,item:i.currentItem,sender:e?e.element:null}}}),t.widget("ui.spinner",{version:"1.12.1",defaultElement:"<input>",widgetEventPrefix:"spin",options:{classes:{"ui-spinner":"ui-corner-all","ui-spinner-down":"ui-corner-br","ui-spinner-up":"ui-corner-tr"},culture:null,icons:{down:"ui-icon-triangle-1-s",up:"ui-icon-triangle-1-n"},incremental:!0,max:null,min:null,numberFormat:null,page:10,step:1,change:null,spin:null,start:null,stop:null},_create:function(){this._setOption("max",this.options.max),this._setOption("min",this.options.min),this._setOption("step",this.options.step),""!==this.value()&&this._value(this.element.val(),!0),this._draw(),this._on(this._events),this._refresh(),this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete")}})},_getCreateOptions:function(){var e=this._super(),i=this.element;return t.each(["min","max","step"],function(t,s){var n=i.attr(s);null!=n&&n.length&&(e[s]=n)}),e},_events:{keydown:function(t){this._start(t)&&this._keydown(t)&&t.preventDefault()},keyup:"_stop",focus:function(){this.previous=this.element.val()},blur:function(t){return this.cancelBlur?(delete this.cancelBlur,void 0):(this._stop(),this._refresh(),this.previous!==this.element.val()&&this._trigger("change",t),void 0)},mousewheel:function(t,e){if(e){if(!this.spinning&&!this._start(t))return!1;this._spin((e>0?1:-1)*this.options.step,t),clearTimeout(this.mousewheelTimer),this.mousewheelTimer=this._delay(function(){this.spinning&&this._stop(t)},100),t.preventDefault()}},"mousedown .ui-spinner-button":function(e){function i(){var e=this.element[0]===t.ui.safeActiveElement(this.document[0]);e||(this.element.trigger("focus"),this.previous=s,this._delay(function(){this.previous=s}))}var s;s=this.element[0]===t.ui.safeActiveElement(this.document[0])?this.previous:this.element.val(),e.preventDefault(),i.call(this),this.cancelBlur=!0,this._delay(function(){delete this.cancelBlur,i.call(this)}),this._start(e)!==!1&&this._repeat(null,t(e.currentTarget).hasClass("ui-spinner-up")?1:-1,e)},"mouseup .ui-spinner-button":"_stop","mouseenter .ui-spinner-button":function(e){return t(e.currentTarget).hasClass("ui-state-active")?this._start(e)===!1?!1:(this._repeat(null,t(e.currentTarget).hasClass("ui-spinner-up")?1:-1,e),void 0):void 0},"mouseleave .ui-spinner-button":"_stop"},_enhance:function(){this.uiSpinner=this.element.attr("autocomplete","off").wrap("<span>").parent().append("<a></a><a></a>")},_draw:function(){this._enhance(),this._addClass(this.uiSpinner,"ui-spinner","ui-widget ui-widget-content"),this._addClass("ui-spinner-input"),this.element.attr("role","spinbutton"),this.buttons=this.uiSpinner.children("a").attr("tabIndex",-1).attr("aria-hidden",!0).button({classes:{"ui-button":""}}),this._removeClass(this.buttons,"ui-corner-all"),this._addClass(this.buttons.first(),"ui-spinner-button ui-spinner-up"),this._addClass(this.buttons.last(),"ui-spinner-button ui-spinner-down"),this.buttons.first().button({icon:this.options.icons.up,showLabel:!1}),this.buttons.last().button({icon:this.options.icons.down,showLabel:!1}),this.buttons.height()>Math.ceil(.5*this.uiSpinner.height())&&this.uiSpinner.height()>0&&this.uiSpinner.height(this.uiSpinner.height())},_keydown:function(e){var i=this.options,s=t.ui.keyCode;switch(e.keyCode){case s.UP:return this._repeat(null,1,e),!0;case s.DOWN:return this._repeat(null,-1,e),!0;case s.PAGE_UP:return this._repeat(null,i.page,e),!0;case s.PAGE_DOWN:return this._repeat(null,-i.page,e),!0}return!1},_start:function(t){return this.spinning||this._trigger("start",t)!==!1?(this.counter||(this.counter=1),this.spinning=!0,!0):!1},_repeat:function(t,e,i){t=t||500,clearTimeout(this.timer),this.timer=this._delay(function(){this._repeat(40,e,i)},t),this._spin(e*this.options.step,i)},_spin:function(t,e){var i=this.value()||0;this.counter||(this.counter=1),i=this._adjustValue(i+t*this._increment(this.counter)),this.spinning&&this._trigger("spin",e,{value:i})===!1||(this._value(i),this.counter++)},_increment:function(e){var i=this.options.incremental;return i?t.isFunction(i)?i(e):Math.floor(e*e*e/5e4-e*e/500+17*e/200+1):1},_precision:function(){var t=this._precisionOf(this.options.step);return null!==this.options.min&&(t=Math.max(t,this._precisionOf(this.options.min))),t},_precisionOf:function(t){var e=""+t,i=e.indexOf(".");return-1===i?0:e.length-i-1},_adjustValue:function(t){var e,i,s=this.options;return e=null!==s.min?s.min:0,i=t-e,i=Math.round(i/s.step)*s.step,t=e+i,t=parseFloat(t.toFixed(this._precision())),null!==s.max&&t>s.max?s.max:null!==s.min&&s.min>t?s.min:t},_stop:function(t){this.spinning&&(clearTimeout(this.timer),clearTimeout(this.mousewheelTimer),this.counter=0,this.spinning=!1,this._trigger("stop",t))},_setOption:function(t,e){var i,s,n;return"culture"===t||"numberFormat"===t?(i=this._parse(this.element.val()),this.options[t]=e,this.element.val(this._format(i)),void 0):(("max"===t||"min"===t||"step"===t)&&"string"==typeof e&&(e=this._parse(e)),"icons"===t&&(s=this.buttons.first().find(".ui-icon"),this._removeClass(s,null,this.options.icons.up),this._addClass(s,null,e.up),n=this.buttons.last().find(".ui-icon"),this._removeClass(n,null,this.options.icons.down),this._addClass(n,null,e.down)),this._super(t,e),void 0)},_setOptionDisabled:function(t){this._super(t),this._toggleClass(this.uiSpinner,null,"ui-state-disabled",!!t),this.element.prop("disabled",!!t),this.buttons.button(t?"disable":"enable")},_setOptions:r(function(t){this._super(t)}),_parse:function(t){return"string"==typeof t&&""!==t&&(t=window.Globalize&&this.options.numberFormat?Globalize.parseFloat(t,10,this.options.culture):+t),""===t||isNaN(t)?null:t},_format:function(t){return""===t?"":window.Globalize&&this.options.numberFormat?Globalize.format(t,this.options.numberFormat,this.options.culture):t},_refresh:function(){this.element.attr({"aria-valuemin":this.options.min,"aria-valuemax":this.options.max,"aria-valuenow":this._parse(this.element.val())})},isValid:function(){var t=this.value();return null===t?!1:t===this._adjustValue(t)},_value:function(t,e){var i;""!==t&&(i=this._parse(t),null!==i&&(e||(i=this._adjustValue(i)),t=this._format(i))),this.element.val(t),this._refresh()},_destroy:function(){this.element.prop("disabled",!1).removeAttr("autocomplete role aria-valuemin aria-valuemax aria-valuenow"),this.uiSpinner.replaceWith(this.element)},stepUp:r(function(t){this._stepUp(t)}),_stepUp:function(t){this._start()&&(this._spin((t||1)*this.options.step),this._stop())},stepDown:r(function(t){this._stepDown(t)}),_stepDown:function(t){this._start()&&(this._spin((t||1)*-this.options.step),this._stop())},pageUp:r(function(t){this._stepUp((t||1)*this.options.page)}),pageDown:r(function(t){this._stepDown((t||1)*this.options.page)}),value:function(t){return arguments.length?(r(this._value).call(this,t),void 0):this._parse(this.element.val())},widget:function(){return this.uiSpinner}}),t.uiBackCompat!==!1&&t.widget("ui.spinner",t.ui.spinner,{_enhance:function(){this.uiSpinner=this.element.attr("autocomplete","off").wrap(this._uiSpinnerHtml()).parent().append(this._buttonHtml())},_uiSpinnerHtml:function(){return"<span>"},_buttonHtml:function(){return"<a></a><a></a>"}}),t.ui.spinner,t.widget("ui.tabs",{version:"1.12.1",delay:300,options:{active:null,classes:{"ui-tabs":"ui-corner-all","ui-tabs-nav":"ui-corner-all","ui-tabs-panel":"ui-corner-bottom","ui-tabs-tab":"ui-corner-top"},collapsible:!1,event:"click",heightStyle:"content",hide:null,show:null,activate:null,beforeActivate:null,beforeLoad:null,load:null},_isLocal:function(){var t=/#.*$/;return function(e){var i,s;i=e.href.replace(t,""),s=location.href.replace(t,"");try{i=decodeURIComponent(i)}catch(n){}try{s=decodeURIComponent(s)}catch(n){}return e.hash.length>1&&i===s}}(),_create:function(){var e=this,i=this.options;this.running=!1,this._addClass("ui-tabs","ui-widget ui-widget-content"),this._toggleClass("ui-tabs-collapsible",null,i.collapsible),this._processTabs(),i.active=this._initialActive(),t.isArray(i.disabled)&&(i.disabled=t.unique(i.disabled.concat(t.map(this.tabs.filter(".ui-state-disabled"),function(t){return e.tabs.index(t)}))).sort()),this.active=this.options.active!==!1&&this.anchors.length?this._findActive(i.active):t(),this._refresh(),this.active.length&&this.load(i.active)},_initialActive:function(){var e=this.options.active,i=this.options.collapsible,s=location.hash.substring(1);return null===e&&(s&&this.tabs.each(function(i,n){return t(n).attr("aria-controls")===s?(e=i,!1):void 0}),null===e&&(e=this.tabs.index(this.tabs.filter(".ui-tabs-active"))),(null===e||-1===e)&&(e=this.tabs.length?0:!1)),e!==!1&&(e=this.tabs.index(this.tabs.eq(e)),-1===e&&(e=i?!1:0)),!i&&e===!1&&this.anchors.length&&(e=0),e},_getCreateEventData:function(){return{tab:this.active,panel:this.active.length?this._getPanelForTab(this.active):t()}},_tabKeydown:function(e){var i=t(t.ui.safeActiveElement(this.document[0])).closest("li"),s=this.tabs.index(i),n=!0;if(!this._handlePageNav(e)){switch(e.keyCode){case t.ui.keyCode.RIGHT:case t.ui.keyCode.DOWN:s++;break;case t.ui.keyCode.UP:case t.ui.keyCode.LEFT:n=!1,s--;break;case t.ui.keyCode.END:s=this.anchors.length-1;break;case t.ui.keyCode.HOME:s=0;break;case t.ui.keyCode.SPACE:return e.preventDefault(),clearTimeout(this.activating),this._activate(s),void 0;case t.ui.keyCode.ENTER:return e.preventDefault(),clearTimeout(this.activating),this._activate(s===this.options.active?!1:s),void 0;default:return}e.preventDefault(),clearTimeout(this.activating),s=this._focusNextTab(s,n),e.ctrlKey||e.metaKey||(i.attr("aria-selected","false"),this.tabs.eq(s).attr("aria-selected","true"),this.activating=this._delay(function(){this.option("active",s)},this.delay))}},_panelKeydown:function(e){this._handlePageNav(e)||e.ctrlKey&&e.keyCode===t.ui.keyCode.UP&&(e.preventDefault(),this.active.trigger("focus"))},_handlePageNav:function(e){return e.altKey&&e.keyCode===t.ui.keyCode.PAGE_UP?(this._activate(this._focusNextTab(this.options.active-1,!1)),!0):e.altKey&&e.keyCode===t.ui.keyCode.PAGE_DOWN?(this._activate(this._focusNextTab(this.options.active+1,!0)),!0):void 0},_findNextTab:function(e,i){function s(){return e>n&&(e=0),0>e&&(e=n),e}for(var n=this.tabs.length-1;-1!==t.inArray(s(),this.options.disabled);)e=i?e+1:e-1;return e},_focusNextTab:function(t,e){return t=this._findNextTab(t,e),this.tabs.eq(t).trigger("focus"),t},_setOption:function(t,e){return"active"===t?(this._activate(e),void 0):(this._super(t,e),"collapsible"===t&&(this._toggleClass("ui-tabs-collapsible",null,e),e||this.options.active!==!1||this._activate(0)),"event"===t&&this._setupEvents(e),"heightStyle"===t&&this._setupHeightStyle(e),void 0)},_sanitizeSelector:function(t){return t?t.replace(/[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g,"\\$&"):""},refresh:function(){var e=this.options,i=this.tablist.children(":has(a[href])");e.disabled=t.map(i.filter(".ui-state-disabled"),function(t){return i.index(t)}),this._processTabs(),e.active!==!1&&this.anchors.length?this.active.length&&!t.contains(this.tablist[0],this.active[0])?this.tabs.length===e.disabled.length?(e.active=!1,this.active=t()):this._activate(this._findNextTab(Math.max(0,e.active-1),!1)):e.active=this.tabs.index(this.active):(e.active=!1,this.active=t()),this._refresh()},_refresh:function(){this._setOptionDisabled(this.options.disabled),this._setupEvents(this.options.event),this._setupHeightStyle(this.options.heightStyle),this.tabs.not(this.active).attr({"aria-selected":"false","aria-expanded":"false",tabIndex:-1}),this.panels.not(this._getPanelForTab(this.active)).hide().attr({"aria-hidden":"true"}),this.active.length?(this.active.attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0}),this._addClass(this.active,"ui-tabs-active","ui-state-active"),this._getPanelForTab(this.active).show().attr({"aria-hidden":"false"})):this.tabs.eq(0).attr("tabIndex",0)},_processTabs:function(){var e=this,i=this.tabs,s=this.anchors,n=this.panels;this.tablist=this._getList().attr("role","tablist"),this._addClass(this.tablist,"ui-tabs-nav","ui-helper-reset ui-helper-clearfix ui-widget-header"),this.tablist.on("mousedown"+this.eventNamespace,"> li",function(e){t(this).is(".ui-state-disabled")&&e.preventDefault()}).on("focus"+this.eventNamespace,".ui-tabs-anchor",function(){t(this).closest("li").is(".ui-state-disabled")&&this.blur()}),this.tabs=this.tablist.find("> li:has(a[href])").attr({role:"tab",tabIndex:-1}),this._addClass(this.tabs,"ui-tabs-tab","ui-state-default"),this.anchors=this.tabs.map(function(){return t("a",this)[0]}).attr({role:"presentation",tabIndex:-1}),this._addClass(this.anchors,"ui-tabs-anchor"),this.panels=t(),this.anchors.each(function(i,s){var n,o,a,r=t(s).uniqueId().attr("id"),h=t(s).closest("li"),l=h.attr("aria-controls");e._isLocal(s)?(n=s.hash,a=n.substring(1),o=e.element.find(e._sanitizeSelector(n))):(a=h.attr("aria-controls")||t({}).uniqueId()[0].id,n="#"+a,o=e.element.find(n),o.length||(o=e._createPanel(a),o.insertAfter(e.panels[i-1]||e.tablist)),o.attr("aria-live","polite")),o.length&&(e.panels=e.panels.add(o)),l&&h.data("ui-tabs-aria-controls",l),h.attr({"aria-controls":a,"aria-labelledby":r}),o.attr("aria-labelledby",r)}),this.panels.attr("role","tabpanel"),this._addClass(this.panels,"ui-tabs-panel","ui-widget-content"),i&&(this._off(i.not(this.tabs)),this._off(s.not(this.anchors)),this._off(n.not(this.panels)))},_getList:function(){return this.tablist||this.element.find("ol, ul").eq(0)},_createPanel:function(e){return t("<div>").attr("id",e).data("ui-tabs-destroy",!0)},_setOptionDisabled:function(e){var i,s,n;for(t.isArray(e)&&(e.length?e.length===this.anchors.length&&(e=!0):e=!1),n=0;s=this.tabs[n];n++)i=t(s),e===!0||-1!==t.inArray(n,e)?(i.attr("aria-disabled","true"),this._addClass(i,null,"ui-state-disabled")):(i.removeAttr("aria-disabled"),this._removeClass(i,null,"ui-state-disabled"));this.options.disabled=e,this._toggleClass(this.widget(),this.widgetFullName+"-disabled",null,e===!0)},_setupEvents:function(e){var i={};e&&t.each(e.split(" "),function(t,e){i[e]="_eventHandler"}),this._off(this.anchors.add(this.tabs).add(this.panels)),this._on(!0,this.anchors,{click:function(t){t.preventDefault()}}),this._on(this.anchors,i),this._on(this.tabs,{keydown:"_tabKeydown"}),this._on(this.panels,{keydown:"_panelKeydown"}),this._focusable(this.tabs),this._hoverable(this.tabs)},_setupHeightStyle:function(e){var i,s=this.element.parent();"fill"===e?(i=s.height(),i-=this.element.outerHeight()-this.element.height(),this.element.siblings(":visible").each(function(){var e=t(this),s=e.css("position");"absolute"!==s&&"fixed"!==s&&(i-=e.outerHeight(!0))}),this.element.children().not(this.panels).each(function(){i-=t(this).outerHeight(!0)}),this.panels.each(function(){t(this).height(Math.max(0,i-t(this).innerHeight()+t(this).height()))}).css("overflow","auto")):"auto"===e&&(i=0,this.panels.each(function(){i=Math.max(i,t(this).height("").height())}).height(i))},_eventHandler:function(e){var i=this.options,s=this.active,n=t(e.currentTarget),o=n.closest("li"),a=o[0]===s[0],r=a&&i.collapsible,h=r?t():this._getPanelForTab(o),l=s.length?this._getPanelForTab(s):t(),c={oldTab:s,oldPanel:l,newTab:r?t():o,newPanel:h};e.preventDefault(),o.hasClass("ui-state-disabled")||o.hasClass("ui-tabs-loading")||this.running||a&&!i.collapsible||this._trigger("beforeActivate",e,c)===!1||(i.active=r?!1:this.tabs.index(o),this.active=a?t():o,this.xhr&&this.xhr.abort(),l.length||h.length||t.error("jQuery UI Tabs: Mismatching fragment identifier."),h.length&&this.load(this.tabs.index(o),e),this._toggle(e,c))},_toggle:function(e,i){function s(){o.running=!1,o._trigger("activate",e,i)}function n(){o._addClass(i.newTab.closest("li"),"ui-tabs-active","ui-state-active"),a.length&&o.options.show?o._show(a,o.options.show,s):(a.show(),s())}var o=this,a=i.newPanel,r=i.oldPanel;this.running=!0,r.length&&this.options.hide?this._hide(r,this.options.hide,function(){o._removeClass(i.oldTab.closest("li"),"ui-tabs-active","ui-state-active"),n()}):(this._removeClass(i.oldTab.closest("li"),"ui-tabs-active","ui-state-active"),r.hide(),n()),r.attr("aria-hidden","true"),i.oldTab.attr({"aria-selected":"false","aria-expanded":"false"}),a.length&&r.length?i.oldTab.attr("tabIndex",-1):a.length&&this.tabs.filter(function(){return 0===t(this).attr("tabIndex")}).attr("tabIndex",-1),a.attr("aria-hidden","false"),i.newTab.attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0})},_activate:function(e){var i,s=this._findActive(e);s[0]!==this.active[0]&&(s.length||(s=this.active),i=s.find(".ui-tabs-anchor")[0],this._eventHandler({target:i,currentTarget:i,preventDefault:t.noop}))},_findActive:function(e){return e===!1?t():this.tabs.eq(e)},_getIndex:function(e){return"string"==typeof e&&(e=this.anchors.index(this.anchors.filter("[href$='"+t.ui.escapeSelector(e)+"']"))),e},_destroy:function(){this.xhr&&this.xhr.abort(),this.tablist.removeAttr("role").off(this.eventNamespace),this.anchors.removeAttr("role tabIndex").removeUniqueId(),this.tabs.add(this.panels).each(function(){t.data(this,"ui-tabs-destroy")?t(this).remove():t(this).removeAttr("role tabIndex aria-live aria-busy aria-selected aria-labelledby aria-hidden aria-expanded")}),this.tabs.each(function(){var e=t(this),i=e.data("ui-tabs-aria-controls");i?e.attr("aria-controls",i).removeData("ui-tabs-aria-controls"):e.removeAttr("aria-controls")}),this.panels.show(),"content"!==this.options.heightStyle&&this.panels.css("height","")},enable:function(e){var i=this.options.disabled;i!==!1&&(void 0===e?i=!1:(e=this._getIndex(e),i=t.isArray(i)?t.map(i,function(t){return t!==e?t:null}):t.map(this.tabs,function(t,i){return i!==e?i:null})),this._setOptionDisabled(i))},disable:function(e){var i=this.options.disabled;if(i!==!0){if(void 0===e)i=!0;else{if(e=this._getIndex(e),-1!==t.inArray(e,i))return;i=t.isArray(i)?t.merge([e],i).sort():[e]}this._setOptionDisabled(i)}},load:function(e,i){e=this._getIndex(e);var s=this,n=this.tabs.eq(e),o=n.find(".ui-tabs-anchor"),a=this._getPanelForTab(n),r={tab:n,panel:a},h=function(t,e){"abort"===e&&s.panels.stop(!1,!0),s._removeClass(n,"ui-tabs-loading"),a.removeAttr("aria-busy"),t===s.xhr&&delete s.xhr};this._isLocal(o[0])||(this.xhr=t.ajax(this._ajaxSettings(o,i,r)),this.xhr&&"canceled"!==this.xhr.statusText&&(this._addClass(n,"ui-tabs-loading"),a.attr("aria-busy","true"),this.xhr.done(function(t,e,n){setTimeout(function(){a.html(t),s._trigger("load",i,r),h(n,e)},1)}).fail(function(t,e){setTimeout(function(){h(t,e)},1)})))},_ajaxSettings:function(e,i,s){var n=this;return{url:e.attr("href").replace(/#.*$/,""),beforeSend:function(e,o){return n._trigger("beforeLoad",i,t.extend({jqXHR:e,ajaxSettings:o},s))}}},_getPanelForTab:function(e){var i=t(e).attr("aria-controls");return this.element.find(this._sanitizeSelector("#"+i))}}),t.uiBackCompat!==!1&&t.widget("ui.tabs",t.ui.tabs,{_processTabs:function(){this._superApply(arguments),this._addClass(this.tabs,"ui-tab")}}),t.ui.tabs,t.widget("ui.tooltip",{version:"1.12.1",options:{classes:{"ui-tooltip":"ui-corner-all ui-widget-shadow"},content:function(){var e=t(this).attr("title")||"";return t("<a>").text(e).html()},hide:!0,items:"[title]:not([disabled])",position:{my:"left top+15",at:"left bottom",collision:"flipfit flip"},show:!0,track:!1,close:null,open:null},_addDescribedBy:function(e,i){var s=(e.attr("aria-describedby")||"").split(/\s+/);s.push(i),e.data("ui-tooltip-id",i).attr("aria-describedby",t.trim(s.join(" ")))},_removeDescribedBy:function(e){var i=e.data("ui-tooltip-id"),s=(e.attr("aria-describedby")||"").split(/\s+/),n=t.inArray(i,s);-1!==n&&s.splice(n,1),e.removeData("ui-tooltip-id"),s=t.trim(s.join(" ")),s?e.attr("aria-describedby",s):e.removeAttr("aria-describedby")},_create:function(){this._on({mouseover:"open",focusin:"open"}),this.tooltips={},this.parents={},this.liveRegion=t("<div>").attr({role:"log","aria-live":"assertive","aria-relevant":"additions"}).appendTo(this.document[0].body),this._addClass(this.liveRegion,null,"ui-helper-hidden-accessible"),this.disabledTitles=t([])},_setOption:function(e,i){var s=this;this._super(e,i),"content"===e&&t.each(this.tooltips,function(t,e){s._updateContent(e.element)})},_setOptionDisabled:function(t){this[t?"_disable":"_enable"]()},_disable:function(){var e=this;t.each(this.tooltips,function(i,s){var n=t.Event("blur");n.target=n.currentTarget=s.element[0],e.close(n,!0)}),this.disabledTitles=this.disabledTitles.add(this.element.find(this.options.items).addBack().filter(function(){var e=t(this);return e.is("[title]")?e.data("ui-tooltip-title",e.attr("title")).removeAttr("title"):void 0}))},_enable:function(){this.disabledTitles.each(function(){var e=t(this);e.data("ui-tooltip-title")&&e.attr("title",e.data("ui-tooltip-title"))}),this.disabledTitles=t([])},open:function(e){var i=this,s=t(e?e.target:this.element).closest(this.options.items);s.length&&!s.data("ui-tooltip-id")&&(s.attr("title")&&s.data("ui-tooltip-title",s.attr("title")),s.data("ui-tooltip-open",!0),e&&"mouseover"===e.type&&s.parents().each(function(){var e,s=t(this);s.data("ui-tooltip-open")&&(e=t.Event("blur"),e.target=e.currentTarget=this,i.close(e,!0)),s.attr("title")&&(s.uniqueId(),i.parents[this.id]={element:this,title:s.attr("title")},s.attr("title",""))}),this._registerCloseHandlers(e,s),this._updateContent(s,e))},_updateContent:function(t,e){var i,s=this.options.content,n=this,o=e?e.type:null;return"string"==typeof s||s.nodeType||s.jquery?this._open(e,t,s):(i=s.call(t[0],function(i){n._delay(function(){t.data("ui-tooltip-open")&&(e&&(e.type=o),this._open(e,t,i))})}),i&&this._open(e,t,i),void 0)},_open:function(e,i,s){function n(t){l.of=t,a.is(":hidden")||a.position(l)}var o,a,r,h,l=t.extend({},this.options.position);if(s){if(o=this._find(i))return o.tooltip.find(".ui-tooltip-content").html(s),void 0;i.is("[title]")&&(e&&"mouseover"===e.type?i.attr("title",""):i.removeAttr("title")),o=this._tooltip(i),a=o.tooltip,this._addDescribedBy(i,a.attr("id")),a.find(".ui-tooltip-content").html(s),this.liveRegion.children().hide(),h=t("<div>").html(a.find(".ui-tooltip-content").html()),h.removeAttr("name").find("[name]").removeAttr("name"),h.removeAttr("id").find("[id]").removeAttr("id"),h.appendTo(this.liveRegion),this.options.track&&e&&/^mouse/.test(e.type)?(this._on(this.document,{mousemove:n}),n(e)):a.position(t.extend({of:i},this.options.position)),a.hide(),this._show(a,this.options.show),this.options.track&&this.options.show&&this.options.show.delay&&(r=this.delayedShow=setInterval(function(){a.is(":visible")&&(n(l.of),clearInterval(r))},t.fx.interval)),this._trigger("open",e,{tooltip:a})}},_registerCloseHandlers:function(e,i){var s={keyup:function(e){if(e.keyCode===t.ui.keyCode.ESCAPE){var s=t.Event(e);s.currentTarget=i[0],this.close(s,!0)}}};i[0]!==this.element[0]&&(s.remove=function(){this._removeTooltip(this._find(i).tooltip)}),e&&"mouseover"!==e.type||(s.mouseleave="close"),e&&"focusin"!==e.type||(s.focusout="close"),this._on(!0,i,s)},close:function(e){var i,s=this,n=t(e?e.currentTarget:this.element),o=this._find(n);return o?(i=o.tooltip,o.closing||(clearInterval(this.delayedShow),n.data("ui-tooltip-title")&&!n.attr("title")&&n.attr("title",n.data("ui-tooltip-title")),this._removeDescribedBy(n),o.hiding=!0,i.stop(!0),this._hide(i,this.options.hide,function(){s._removeTooltip(t(this))}),n.removeData("ui-tooltip-open"),this._off(n,"mouseleave focusout keyup"),n[0]!==this.element[0]&&this._off(n,"remove"),this._off(this.document,"mousemove"),e&&"mouseleave"===e.type&&t.each(this.parents,function(e,i){t(i.element).attr("title",i.title),delete s.parents[e]}),o.closing=!0,this._trigger("close",e,{tooltip:i}),o.hiding||(o.closing=!1)),void 0):(n.removeData("ui-tooltip-open"),void 0)},_tooltip:function(e){var i=t("<div>").attr("role","tooltip"),s=t("<div>").appendTo(i),n=i.uniqueId().attr("id");return this._addClass(s,"ui-tooltip-content"),this._addClass(i,"ui-tooltip","ui-widget ui-widget-content"),i.appendTo(this._appendTo(e)),this.tooltips[n]={element:e,tooltip:i}},_find:function(t){var e=t.data("ui-tooltip-id");return e?this.tooltips[e]:null},_removeTooltip:function(t){t.remove(),delete this.tooltips[t.attr("id")]},_appendTo:function(t){var e=t.closest(".ui-front, dialog");return e.length||(e=this.document[0].body),e},_destroy:function(){var e=this;t.each(this.tooltips,function(i,s){var n=t.Event("blur"),o=s.element;n.target=n.currentTarget=o[0],e.close(n,!0),t("#"+i).remove(),o.data("ui-tooltip-title")&&(o.attr("title")||o.attr("title",o.data("ui-tooltip-title")),o.removeData("ui-tooltip-title"))}),this.liveRegion.remove()}}),t.uiBackCompat!==!1&&t.widget("ui.tooltip",t.ui.tooltip,{options:{tooltipClass:null},_tooltip:function(){var t=this._superApply(arguments);return this.options.tooltipClass&&t.tooltip.addClass(this.options.tooltipClass),t}}),t.ui.tooltip}); \ No newline at end of file diff --git a/js/scripts/jquery.min.js b/js/scripts/jquery.min.js new file mode 100644 index 00000000000..b8c4187de18 --- /dev/null +++ b/js/scripts/jquery.min.js @@ -0,0 +1,4 @@ +/*! jQuery v2.2.3 | (c) jQuery Foundation | jquery.org/license */ +!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=a.document,e=c.slice,f=c.concat,g=c.push,h=c.indexOf,i={},j=i.toString,k=i.hasOwnProperty,l={},m="2.2.3",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return e.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:e.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a){return n.each(this,a)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(e.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor()},push:g,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(n.isPlainObject(d)||(e=n.isArray(d)))?(e?(e=!1,f=c&&n.isArray(c)?c:[]):f=c&&n.isPlainObject(c)?c:{},g[b]=n.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){var b=a&&a.toString();return!n.isArray(a)&&b-parseFloat(b)+1>=0},isPlainObject:function(a){var b;if("object"!==n.type(a)||a.nodeType||n.isWindow(a))return!1;if(a.constructor&&!k.call(a,"constructor")&&!k.call(a.constructor.prototype||{},"isPrototypeOf"))return!1;for(b in a);return void 0===b||k.call(a,b)},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?i[j.call(a)]||"object":typeof a},globalEval:function(a){var b,c=eval;a=n.trim(a),a&&(1===a.indexOf("use strict")?(b=d.createElement("script"),b.text=a,d.head.appendChild(b).parentNode.removeChild(b)):c(a))},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b){var c,d=0;if(s(a)){for(c=a.length;c>d;d++)if(b.call(a[d],d,a[d])===!1)break}else for(d in a)if(b.call(a[d],d,a[d])===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):g.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:h.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,e,g=0,h=[];if(s(a))for(d=a.length;d>g;g++)e=b(a[g],g,c),null!=e&&h.push(e);else for(g in a)e=b(a[g],g,c),null!=e&&h.push(e);return f.apply([],h)},guid:1,proxy:function(a,b){var c,d,f;return"string"==typeof b&&(c=a[b],b=a,a=c),n.isFunction(a)?(d=e.call(arguments,2),f=function(){return a.apply(b||this,d.concat(e.call(arguments)))},f.guid=a.guid=a.guid||n.guid++,f):void 0},now:Date.now,support:l}),"function"==typeof Symbol&&(n.fn[Symbol.iterator]=c[Symbol.iterator]),n.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(a,b){i["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=!!a&&"length"in a&&a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ga(),z=ga(),A=ga(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+M+"))|)"+L+"*\\]",O=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+N+")*)|.*)\\)|)",P=new RegExp(L+"+","g"),Q=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),R=new RegExp("^"+L+"*,"+L+"*"),S=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),T=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),U=new RegExp(O),V=new RegExp("^"+M+"$"),W={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M+"|[*])"),ATTR:new RegExp("^"+N),PSEUDO:new RegExp("^"+O),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},X=/^(?:input|select|textarea|button)$/i,Y=/^h\d$/i,Z=/^[^{]+\{\s*\[native \w/,$=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,_=/[+~]/,aa=/'|\\/g,ba=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),ca=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},da=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(ea){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fa(a,b,d,e){var f,h,j,k,l,o,r,s,w=b&&b.ownerDocument,x=b?b.nodeType:9;if(d=d||[],"string"!=typeof a||!a||1!==x&&9!==x&&11!==x)return d;if(!e&&((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,p)){if(11!==x&&(o=$.exec(a)))if(f=o[1]){if(9===x){if(!(j=b.getElementById(f)))return d;if(j.id===f)return d.push(j),d}else if(w&&(j=w.getElementById(f))&&t(b,j)&&j.id===f)return d.push(j),d}else{if(o[2])return H.apply(d,b.getElementsByTagName(a)),d;if((f=o[3])&&c.getElementsByClassName&&b.getElementsByClassName)return H.apply(d,b.getElementsByClassName(f)),d}if(c.qsa&&!A[a+" "]&&(!q||!q.test(a))){if(1!==x)w=b,s=a;else if("object"!==b.nodeName.toLowerCase()){(k=b.getAttribute("id"))?k=k.replace(aa,"\\$&"):b.setAttribute("id",k=u),r=g(a),h=r.length,l=V.test(k)?"#"+k:"[id='"+k+"']";while(h--)r[h]=l+" "+qa(r[h]);s=r.join(","),w=_.test(a)&&oa(b.parentNode)||b}if(s)try{return H.apply(d,w.querySelectorAll(s)),d}catch(y){}finally{k===u&&b.removeAttribute("id")}}}return i(a.replace(Q,"$1"),b,d,e)}function ga(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ha(a){return a[u]=!0,a}function ia(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ja(a,b){var c=a.split("|"),e=c.length;while(e--)d.attrHandle[c[e]]=b}function ka(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function la(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function na(a){return ha(function(b){return b=+b,ha(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function oa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=fa.support={},f=fa.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fa.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=n.documentElement,p=!f(n),(e=n.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener("unload",da,!1):e.attachEvent&&e.attachEvent("onunload",da)),c.attributes=ia(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ia(function(a){return a.appendChild(n.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Z.test(n.getElementsByClassName),c.getById=ia(function(a){return o.appendChild(a).id=u,!n.getElementsByName||!n.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ba,ca);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ba,ca);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return"undefined"!=typeof b.getElementsByClassName&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=Z.test(n.querySelectorAll))&&(ia(function(a){o.appendChild(a).innerHTML="<a id='"+u+"'></a><select id='"+u+"-\r\\' msallowcapture=''><option selected=''></option></select>",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ia(function(a){var b=n.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=Z.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ia(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",O)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=Z.test(o.compareDocumentPosition),t=b||Z.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===n||a.ownerDocument===v&&t(v,a)?-1:b===n||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,g=[a],h=[b];if(!e||!f)return a===n?-1:b===n?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return ka(a,b);c=a;while(c=c.parentNode)g.unshift(c);c=b;while(c=c.parentNode)h.unshift(c);while(g[d]===h[d])d++;return d?ka(g[d],h[d]):g[d]===v?-1:h[d]===v?1:0},n):n},fa.matches=function(a,b){return fa(a,null,null,b)},fa.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(T,"='$1']"),c.matchesSelector&&p&&!A[b+" "]&&(!r||!r.test(b))&&(!q||!q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fa(b,n,null,[a]).length>0},fa.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fa.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fa.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fa.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fa.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fa.selectors={cacheLength:50,createPseudo:ha,match:W,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ba,ca),a[3]=(a[3]||a[4]||a[5]||"").replace(ba,ca),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fa.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fa.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return W.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&U.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ba,ca).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fa.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(P," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h,t=!1;if(q){if(f){while(p){m=b;while(m=m[p])if(h?m.nodeName.toLowerCase()===r:1===m.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){m=q,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n&&j[2],m=n&&q.childNodes[n];while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if(1===m.nodeType&&++t&&m===b){k[a]=[w,n,t];break}}else if(s&&(m=b,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n),t===!1)while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if((h?m.nodeName.toLowerCase()===r:1===m.nodeType)&&++t&&(s&&(l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),k[a]=[w,t]),m===b))break;return t-=e,t===d||t%d===0&&t/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fa.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ha(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ha(function(a){var b=[],c=[],d=h(a.replace(Q,"$1"));return d[u]?ha(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ha(function(a){return function(b){return fa(a,b).length>0}}),contains:ha(function(a){return a=a.replace(ba,ca),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ha(function(a){return V.test(a||"")||fa.error("unsupported lang: "+a),a=a.replace(ba,ca).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Y.test(a.nodeName)},input:function(a){return X.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:na(function(){return[0]}),last:na(function(a,b){return[b-1]}),eq:na(function(a,b,c){return[0>c?c+b:c]}),even:na(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:na(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:na(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:na(function(a,b,c){for(var d=0>c?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=la(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=ma(b);function pa(){}pa.prototype=d.filters=d.pseudos,d.setFilters=new pa,g=fa.tokenize=function(a,b){var c,e,f,g,h,i,j,k=z[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){c&&!(e=R.exec(h))||(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=S.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(Q," ")}),h=h.slice(c.length));for(g in d.filter)!(e=W[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?fa.error(a):z(a,i).slice(0)};function qa(a){for(var b=0,c=a.length,d="";c>b;b++)d+=a[b].value;return d}function ra(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j,k=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(j=b[u]||(b[u]={}),i=j[b.uniqueID]||(j[b.uniqueID]={}),(h=i[d])&&h[0]===w&&h[1]===f)return k[2]=h[2];if(i[d]=k,k[2]=a(b,c,g))return!0}}}function sa(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ta(a,b,c){for(var d=0,e=b.length;e>d;d++)fa(a,b[d],c);return c}function ua(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(c&&!c(f,d,e)||(g.push(f),j&&b.push(h)));return g}function va(a,b,c,d,e,f){return d&&!d[u]&&(d=va(d)),e&&!e[u]&&(e=va(e,f)),ha(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ta(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ua(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ua(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ua(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function wa(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=ra(function(a){return a===b},h,!0),l=ra(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[ra(sa(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return va(i>1&&sa(m),i>1&&qa(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(Q,"$1"),c,e>i&&wa(a.slice(i,e)),f>e&&wa(a=a.slice(e)),f>e&&qa(a))}m.push(c)}return sa(m)}function xa(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,o,q,r=0,s="0",t=f&&[],u=[],v=j,x=f||e&&d.find.TAG("*",k),y=w+=null==v?1:Math.random()||.1,z=x.length;for(k&&(j=g===n||g||k);s!==z&&null!=(l=x[s]);s++){if(e&&l){o=0,g||l.ownerDocument===n||(m(l),h=!p);while(q=a[o++])if(q(l,g||n,h)){i.push(l);break}k&&(w=y)}c&&((l=!q&&l)&&r--,f&&t.push(l))}if(r+=s,c&&s!==r){o=0;while(q=b[o++])q(t,u,g,h);if(f){if(r>0)while(s--)t[s]||u[s]||(u[s]=F.call(i));u=ua(u)}H.apply(i,u),k&&!f&&u.length>0&&r+b.length>1&&fa.uniqueSort(i)}return k&&(w=y,j=v),t};return c?ha(f):f}return h=fa.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wa(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xa(e,d)),f.selector=a}return f},i=fa.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(ba,ca),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=W.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(ba,ca),_.test(j[0].type)&&oa(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qa(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,!b||_.test(a)&&oa(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ia(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ia(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||ja("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ia(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ja("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ia(function(a){return null==a.getAttribute("disabled")})||ja(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fa}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.uniqueSort=n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},v=function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c},w=n.expr.match.needsContext,x=/^<([\w-]+)\s*\/?>(?:<\/\1>|)$/,y=/^.[^:#\[\.,]*$/;function z(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(y.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return h.call(b,a)>-1!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=this.length,d=[],e=this;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;c>b;b++)if(n.contains(e[b],this))return!0}));for(b=0;c>b;b++)n.find(a,e[b],d);return d=this.pushStack(c>1?n.unique(d):d),d.selector=this.selector?this.selector+" "+a:a,d},filter:function(a){return this.pushStack(z(this,a||[],!1))},not:function(a){return this.pushStack(z(this,a||[],!0))},is:function(a){return!!z(this,"string"==typeof a&&w.test(a)?n(a):a||[],!1).length}});var A,B=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=n.fn.init=function(a,b,c){var e,f;if(!a)return this;if(c=c||A,"string"==typeof a){if(e="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:B.exec(a),!e||!e[1]&&b)return!b||b.jquery?(b||c).find(a):this.constructor(b).find(a);if(e[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(e[1],b&&b.nodeType?b.ownerDocument||b:d,!0)),x.test(e[1])&&n.isPlainObject(b))for(e in b)n.isFunction(this[e])?this[e](b[e]):this.attr(e,b[e]);return this}return f=d.getElementById(e[2]),f&&f.parentNode&&(this.length=1,this[0]=f),this.context=d,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?void 0!==c.ready?c.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};C.prototype=n.fn,A=n(d);var D=/^(?:parents|prev(?:Until|All))/,E={children:!0,contents:!0,next:!0,prev:!0};n.fn.extend({has:function(a){var b=n(a,this),c=b.length;return this.filter(function(){for(var a=0;c>a;a++)if(n.contains(this,b[a]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=w.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.uniqueSort(f):f)},index:function(a){return a?"string"==typeof a?h.call(n(a),this[0]):h.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.uniqueSort(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function F(a,b){while((a=a[b])&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return u(a,"parentNode")},parentsUntil:function(a,b,c){return u(a,"parentNode",c)},next:function(a){return F(a,"nextSibling")},prev:function(a){return F(a,"previousSibling")},nextAll:function(a){return u(a,"nextSibling")},prevAll:function(a){return u(a,"previousSibling")},nextUntil:function(a,b,c){return u(a,"nextSibling",c)},prevUntil:function(a,b,c){return u(a,"previousSibling",c)},siblings:function(a){return v((a.parentNode||{}).firstChild,a)},children:function(a){return v(a.firstChild)},contents:function(a){return a.contentDocument||n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(E[a]||n.uniqueSort(e),D.test(a)&&e.reverse()),this.pushStack(e)}});var G=/\S+/g;function H(a){var b={};return n.each(a.match(G)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?H(a):n.extend({},a);var b,c,d,e,f=[],g=[],h=-1,i=function(){for(e=a.once,d=b=!0;g.length;h=-1){c=g.shift();while(++h<f.length)f[h].apply(c[0],c[1])===!1&&a.stopOnFalse&&(h=f.length,c=!1)}a.memory||(c=!1),b=!1,e&&(f=c?[]:"")},j={add:function(){return f&&(c&&!b&&(h=f.length-1,g.push(c)),function d(b){n.each(b,function(b,c){n.isFunction(c)?a.unique&&j.has(c)||f.push(c):c&&c.length&&"string"!==n.type(c)&&d(c)})}(arguments),c&&!b&&i()),this},remove:function(){return n.each(arguments,function(a,b){var c;while((c=n.inArray(b,f,c))>-1)f.splice(c,1),h>=c&&h--}),this},has:function(a){return a?n.inArray(a,f)>-1:f.length>0},empty:function(){return f&&(f=[]),this},disable:function(){return e=g=[],f=c="",this},disabled:function(){return!f},lock:function(){return e=g=[],c||(f=c=""),this},locked:function(){return!!e},fireWith:function(a,c){return e||(c=c||[],c=[a,c.slice?c.slice():c],g.push(c),b||i()),this},fire:function(){return j.fireWith(this,arguments),this},fired:function(){return!!d}};return j},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().progress(c.notify).done(c.resolve).fail(c.reject):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=e.call(arguments),d=c.length,f=1!==d||a&&n.isFunction(a.promise)?d:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(d){b[a]=this,c[a]=arguments.length>1?e.call(arguments):d,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(d>1)for(i=new Array(d),j=new Array(d),k=new Array(d);d>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().progress(h(b,j,i)).done(h(b,k,c)).fail(g.reject):--f;return f||g.resolveWith(k,c),g.promise()}});var I;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(I.resolveWith(d,[n]),n.fn.triggerHandler&&(n(d).triggerHandler("ready"),n(d).off("ready"))))}});function J(){d.removeEventListener("DOMContentLoaded",J),a.removeEventListener("load",J),n.ready()}n.ready.promise=function(b){return I||(I=n.Deferred(),"complete"===d.readyState||"loading"!==d.readyState&&!d.documentElement.doScroll?a.setTimeout(n.ready):(d.addEventListener("DOMContentLoaded",J),a.addEventListener("load",J))),I.promise(b)},n.ready.promise();var K=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===n.type(c)){e=!0;for(h in c)K(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,n.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(n(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},L=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function M(){this.expando=n.expando+M.uid++}M.uid=1,M.prototype={register:function(a,b){var c=b||{};return a.nodeType?a[this.expando]=c:Object.defineProperty(a,this.expando,{value:c,writable:!0,configurable:!0}),a[this.expando]},cache:function(a){if(!L(a))return{};var b=a[this.expando];return b||(b={},L(a)&&(a.nodeType?a[this.expando]=b:Object.defineProperty(a,this.expando,{value:b,configurable:!0}))),b},set:function(a,b,c){var d,e=this.cache(a);if("string"==typeof b)e[b]=c;else for(d in b)e[d]=b[d];return e},get:function(a,b){return void 0===b?this.cache(a):a[this.expando]&&a[this.expando][b]},access:function(a,b,c){var d;return void 0===b||b&&"string"==typeof b&&void 0===c?(d=this.get(a,b),void 0!==d?d:this.get(a,n.camelCase(b))):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d,e,f=a[this.expando];if(void 0!==f){if(void 0===b)this.register(a);else{n.isArray(b)?d=b.concat(b.map(n.camelCase)):(e=n.camelCase(b),b in f?d=[b,e]:(d=e,d=d in f?[d]:d.match(G)||[])),c=d.length;while(c--)delete f[d[c]]}(void 0===b||n.isEmptyObject(f))&&(a.nodeType?a[this.expando]=void 0:delete a[this.expando])}},hasData:function(a){var b=a[this.expando];return void 0!==b&&!n.isEmptyObject(b)}};var N=new M,O=new M,P=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,Q=/[A-Z]/g;function R(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(Q,"-$&").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:P.test(c)?n.parseJSON(c):c; +}catch(e){}O.set(a,b,c)}else c=void 0;return c}n.extend({hasData:function(a){return O.hasData(a)||N.hasData(a)},data:function(a,b,c){return O.access(a,b,c)},removeData:function(a,b){O.remove(a,b)},_data:function(a,b,c){return N.access(a,b,c)},_removeData:function(a,b){N.remove(a,b)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=O.get(f),1===f.nodeType&&!N.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),R(f,d,e[d])));N.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){O.set(this,a)}):K(this,function(b){var c,d;if(f&&void 0===b){if(c=O.get(f,a)||O.get(f,a.replace(Q,"-$&").toLowerCase()),void 0!==c)return c;if(d=n.camelCase(a),c=O.get(f,d),void 0!==c)return c;if(c=R(f,d,void 0),void 0!==c)return c}else d=n.camelCase(a),this.each(function(){var c=O.get(this,d);O.set(this,d,b),a.indexOf("-")>-1&&void 0!==c&&O.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){O.remove(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=N.get(a,b),c&&(!d||n.isArray(c)?d=N.access(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return N.get(a,c)||N.access(a,c,{empty:n.Callbacks("once memory").add(function(){N.remove(a,[b+"queue",c])})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?n.queue(this[0],a):void 0===b?this:this.each(function(){var c=n.queue(this,a,b);n._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&n.dequeue(this,a)})},dequeue:function(a){return this.each(function(){n.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=n.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=N.get(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var S=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,T=new RegExp("^(?:([+-])=|)("+S+")([a-z%]*)$","i"),U=["Top","Right","Bottom","Left"],V=function(a,b){return a=b||a,"none"===n.css(a,"display")||!n.contains(a.ownerDocument,a)};function W(a,b,c,d){var e,f=1,g=20,h=d?function(){return d.cur()}:function(){return n.css(a,b,"")},i=h(),j=c&&c[3]||(n.cssNumber[b]?"":"px"),k=(n.cssNumber[b]||"px"!==j&&+i)&&T.exec(n.css(a,b));if(k&&k[3]!==j){j=j||k[3],c=c||[],k=+i||1;do f=f||".5",k/=f,n.style(a,b,k+j);while(f!==(f=h()/i)&&1!==f&&--g)}return c&&(k=+k||+i||0,e=c[1]?k+(c[1]+1)*c[2]:+c[2],d&&(d.unit=j,d.start=k,d.end=e)),e}var X=/^(?:checkbox|radio)$/i,Y=/<([\w:-]+)/,Z=/^$|\/(?:java|ecma)script/i,$={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};$.optgroup=$.option,$.tbody=$.tfoot=$.colgroup=$.caption=$.thead,$.th=$.td;function _(a,b){var c="undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||"*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&n.nodeName(a,b)?n.merge([a],c):c}function aa(a,b){for(var c=0,d=a.length;d>c;c++)N.set(a[c],"globalEval",!b||N.get(b[c],"globalEval"))}var ba=/<|&#?\w+;/;function ca(a,b,c,d,e){for(var f,g,h,i,j,k,l=b.createDocumentFragment(),m=[],o=0,p=a.length;p>o;o++)if(f=a[o],f||0===f)if("object"===n.type(f))n.merge(m,f.nodeType?[f]:f);else if(ba.test(f)){g=g||l.appendChild(b.createElement("div")),h=(Y.exec(f)||["",""])[1].toLowerCase(),i=$[h]||$._default,g.innerHTML=i[1]+n.htmlPrefilter(f)+i[2],k=i[0];while(k--)g=g.lastChild;n.merge(m,g.childNodes),g=l.firstChild,g.textContent=""}else m.push(b.createTextNode(f));l.textContent="",o=0;while(f=m[o++])if(d&&n.inArray(f,d)>-1)e&&e.push(f);else if(j=n.contains(f.ownerDocument,f),g=_(l.appendChild(f),"script"),j&&aa(g),c){k=0;while(f=g[k++])Z.test(f.type||"")&&c.push(f)}return l}!function(){var a=d.createDocumentFragment(),b=a.appendChild(d.createElement("div")),c=d.createElement("input");c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),b.appendChild(c),l.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="<textarea>x</textarea>",l.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var da=/^key/,ea=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,fa=/^([^.]*)(?:\.(.+)|)/;function ga(){return!0}function ha(){return!1}function ia(){try{return d.activeElement}catch(a){}}function ja(a,b,c,d,e,f){var g,h;if("object"==typeof b){"string"!=typeof c&&(d=d||c,c=void 0);for(h in b)ja(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&("string"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=ha;else if(!e)return a;return 1===f&&(g=e,e=function(a){return n().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=n.guid++)),a.each(function(){n.event.add(this,b,e,d,c)})}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=N.get(a);if(r){c.handler&&(f=c,c=f.handler,e=f.selector),c.guid||(c.guid=n.guid++),(i=r.events)||(i=r.events={}),(g=r.handle)||(g=r.handle=function(b){return"undefined"!=typeof n&&n.event.triggered!==b.type?n.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(G)||[""],j=b.length;while(j--)h=fa.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o&&(l=n.event.special[o]||{},o=(e?l.delegateType:l.bindType)||o,l=n.event.special[o]||{},k=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},f),(m=i[o])||(m=i[o]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,p,g)!==!1||a.addEventListener&&a.addEventListener(o,g)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),n.event.global[o]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=N.hasData(a)&&N.get(a);if(r&&(i=r.events)){b=(b||"").match(G)||[""],j=b.length;while(j--)if(h=fa.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=i[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&q!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete i[o])}else for(o in i)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(i)&&N.remove(a,"handle events")}},dispatch:function(a){a=n.event.fix(a);var b,c,d,f,g,h=[],i=e.call(arguments),j=(N.get(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())a.rnamespace&&!a.rnamespace.test(g.namespace)||(a.handleObj=g,a.data=g.data,d=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==d&&(a.result=d)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&("click"!==a.type||isNaN(a.button)||a.button<1))for(;i!==this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>-1:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h<b.length&&g.push({elem:this,handlers:b.slice(h)}),g},props:"altKey bubbles cancelable ctrlKey currentTarget detail eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return null==a.which&&(a.which=null!=b.charCode?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,b){var c,e,f,g=b.button;return null==a.pageX&&null!=b.clientX&&(c=a.target.ownerDocument||d,e=c.documentElement,f=c.body,a.pageX=b.clientX+(e&&e.scrollLeft||f&&f.scrollLeft||0)-(e&&e.clientLeft||f&&f.clientLeft||0),a.pageY=b.clientY+(e&&e.scrollTop||f&&f.scrollTop||0)-(e&&e.clientTop||f&&f.clientTop||0)),a.which||void 0===g||(a.which=1&g?1:2&g?3:4&g?2:0),a}},fix:function(a){if(a[n.expando])return a;var b,c,e,f=a.type,g=a,h=this.fixHooks[f];h||(this.fixHooks[f]=h=ea.test(f)?this.mouseHooks:da.test(f)?this.keyHooks:{}),e=h.props?this.props.concat(h.props):this.props,a=new n.Event(g),b=e.length;while(b--)c=e[b],a[c]=g[c];return a.target||(a.target=d),3===a.target.nodeType&&(a.target=a.target.parentNode),h.filter?h.filter(a,g):a},special:{load:{noBubble:!0},focus:{trigger:function(){return this!==ia()&&this.focus?(this.focus(),!1):void 0},delegateType:"focusin"},blur:{trigger:function(){return this===ia()&&this.blur?(this.blur(),!1):void 0},delegateType:"focusout"},click:{trigger:function(){return"checkbox"===this.type&&this.click&&n.nodeName(this,"input")?(this.click(),!1):void 0},_default:function(a){return n.nodeName(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&a.originalEvent&&(a.originalEvent.returnValue=a.result)}}}},n.removeEvent=function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c)},n.Event=function(a,b){return this instanceof n.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.returnValue===!1?ga:ha):this.type=a,b&&n.extend(this,b),this.timeStamp=a&&a.timeStamp||n.now(),void(this[n.expando]=!0)):new n.Event(a,b)},n.Event.prototype={constructor:n.Event,isDefaultPrevented:ha,isPropagationStopped:ha,isImmediatePropagationStopped:ha,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=ga,a&&a.preventDefault()},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=ga,a&&a.stopPropagation()},stopImmediatePropagation:function(){var a=this.originalEvent;this.isImmediatePropagationStopped=ga,a&&a.stopImmediatePropagation(),this.stopPropagation()}},n.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(a,b){n.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return e&&(e===d||n.contains(d,e))||(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),n.fn.extend({on:function(a,b,c,d){return ja(this,a,b,c,d)},one:function(a,b,c,d){return ja(this,a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,n(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return b!==!1&&"function"!=typeof b||(c=b,b=void 0),c===!1&&(c=ha),this.each(function(){n.event.remove(this,a,c,b)})}});var ka=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi,la=/<script|<style|<link/i,ma=/checked\s*(?:[^=]|=\s*.checked.)/i,na=/^true\/(.*)/,oa=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;function pa(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function qa(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function ra(a){var b=na.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function sa(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(N.hasData(a)&&(f=N.access(a),g=N.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)n.event.add(b,e,j[e][c])}O.hasData(a)&&(h=O.access(a),i=n.extend({},h),O.set(b,i))}}function ta(a,b){var c=b.nodeName.toLowerCase();"input"===c&&X.test(a.type)?b.checked=a.checked:"input"!==c&&"textarea"!==c||(b.defaultValue=a.defaultValue)}function ua(a,b,c,d){b=f.apply([],b);var e,g,h,i,j,k,m=0,o=a.length,p=o-1,q=b[0],r=n.isFunction(q);if(r||o>1&&"string"==typeof q&&!l.checkClone&&ma.test(q))return a.each(function(e){var f=a.eq(e);r&&(b[0]=q.call(this,e,f.html())),ua(f,b,c,d)});if(o&&(e=ca(b,a[0].ownerDocument,!1,a,d),g=e.firstChild,1===e.childNodes.length&&(e=g),g||d)){for(h=n.map(_(e,"script"),qa),i=h.length;o>m;m++)j=e,m!==p&&(j=n.clone(j,!0,!0),i&&n.merge(h,_(j,"script"))),c.call(a[m],j,m);if(i)for(k=h[h.length-1].ownerDocument,n.map(h,ra),m=0;i>m;m++)j=h[m],Z.test(j.type||"")&&!N.access(j,"globalEval")&&n.contains(k,j)&&(j.src?n._evalUrl&&n._evalUrl(j.src):n.globalEval(j.textContent.replace(oa,"")))}return a}function va(a,b,c){for(var d,e=b?n.filter(b,a):a,f=0;null!=(d=e[f]);f++)c||1!==d.nodeType||n.cleanData(_(d)),d.parentNode&&(c&&n.contains(d.ownerDocument,d)&&aa(_(d,"script")),d.parentNode.removeChild(d));return a}n.extend({htmlPrefilter:function(a){return a.replace(ka,"<$1></$2>")},clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=n.contains(a.ownerDocument,a);if(!(l.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(g=_(h),f=_(a),d=0,e=f.length;e>d;d++)ta(f[d],g[d]);if(b)if(c)for(f=f||_(a),g=g||_(h),d=0,e=f.length;e>d;d++)sa(f[d],g[d]);else sa(a,h);return g=_(h,"script"),g.length>0&&aa(g,!i&&_(a,"script")),h},cleanData:function(a){for(var b,c,d,e=n.event.special,f=0;void 0!==(c=a[f]);f++)if(L(c)){if(b=c[N.expando]){if(b.events)for(d in b.events)e[d]?n.event.remove(c,d):n.removeEvent(c,d,b.handle);c[N.expando]=void 0}c[O.expando]&&(c[O.expando]=void 0)}}}),n.fn.extend({domManip:ua,detach:function(a){return va(this,a,!0)},remove:function(a){return va(this,a)},text:function(a){return K(this,function(a){return void 0===a?n.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=a)})},null,a,arguments.length)},append:function(){return ua(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=pa(this,a);b.appendChild(a)}})},prepend:function(){return ua(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=pa(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return ua(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return ua(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(n.cleanData(_(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return K(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!la.test(a)&&!$[(Y.exec(a)||["",""])[1].toLowerCase()]){a=n.htmlPrefilter(a);try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(_(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=[];return ua(this,arguments,function(b){var c=this.parentNode;n.inArray(this,a)<0&&(n.cleanData(_(this)),c&&c.replaceChild(b,this))},a)}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=[],e=n(a),f=e.length-1,h=0;f>=h;h++)c=h===f?this:this.clone(!0),n(e[h])[b](c),g.apply(d,c.get());return this.pushStack(d)}});var wa,xa={HTML:"block",BODY:"block"};function ya(a,b){var c=n(b.createElement(a)).appendTo(b.body),d=n.css(c[0],"display");return c.detach(),d}function za(a){var b=d,c=xa[a];return c||(c=ya(a,b),"none"!==c&&c||(wa=(wa||n("<iframe frameborder='0' width='0' height='0'/>")).appendTo(b.documentElement),b=wa[0].contentDocument,b.write(),b.close(),c=ya(a,b),wa.detach()),xa[a]=c),c}var Aa=/^margin/,Ba=new RegExp("^("+S+")(?!px)[a-z%]+$","i"),Ca=function(b){var c=b.ownerDocument.defaultView;return c&&c.opener||(c=a),c.getComputedStyle(b)},Da=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e},Ea=d.documentElement;!function(){var b,c,e,f,g=d.createElement("div"),h=d.createElement("div");if(h.style){h.style.backgroundClip="content-box",h.cloneNode(!0).style.backgroundClip="",l.clearCloneStyle="content-box"===h.style.backgroundClip,g.style.cssText="border:0;width:8px;height:0;top:0;left:-9999px;padding:0;margin-top:1px;position:absolute",g.appendChild(h);function i(){h.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;position:relative;display:block;margin:auto;border:1px;padding:1px;top:1%;width:50%",h.innerHTML="",Ea.appendChild(g);var d=a.getComputedStyle(h);b="1%"!==d.top,f="2px"===d.marginLeft,c="4px"===d.width,h.style.marginRight="50%",e="4px"===d.marginRight,Ea.removeChild(g)}n.extend(l,{pixelPosition:function(){return i(),b},boxSizingReliable:function(){return null==c&&i(),c},pixelMarginRight:function(){return null==c&&i(),e},reliableMarginLeft:function(){return null==c&&i(),f},reliableMarginRight:function(){var b,c=h.appendChild(d.createElement("div"));return c.style.cssText=h.style.cssText="-webkit-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0",c.style.marginRight=c.style.width="0",h.style.width="1px",Ea.appendChild(g),b=!parseFloat(a.getComputedStyle(c).marginRight),Ea.removeChild(g),h.removeChild(c),b}})}}();function Fa(a,b,c){var d,e,f,g,h=a.style;return c=c||Ca(a),g=c?c.getPropertyValue(b)||c[b]:void 0,""!==g&&void 0!==g||n.contains(a.ownerDocument,a)||(g=n.style(a,b)),c&&!l.pixelMarginRight()&&Ba.test(g)&&Aa.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f),void 0!==g?g+"":g}function Ga(a,b){return{get:function(){return a()?void delete this.get:(this.get=b).apply(this,arguments)}}}var Ha=/^(none|table(?!-c[ea]).+)/,Ia={position:"absolute",visibility:"hidden",display:"block"},Ja={letterSpacing:"0",fontWeight:"400"},Ka=["Webkit","O","Moz","ms"],La=d.createElement("div").style;function Ma(a){if(a in La)return a;var b=a[0].toUpperCase()+a.slice(1),c=Ka.length;while(c--)if(a=Ka[c]+b,a in La)return a}function Na(a,b,c){var d=T.exec(b);return d?Math.max(0,d[2]-(c||0))+(d[3]||"px"):b}function Oa(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;4>f;f+=2)"margin"===c&&(g+=n.css(a,c+U[f],!0,e)),d?("content"===c&&(g-=n.css(a,"padding"+U[f],!0,e)),"margin"!==c&&(g-=n.css(a,"border"+U[f]+"Width",!0,e))):(g+=n.css(a,"padding"+U[f],!0,e),"padding"!==c&&(g+=n.css(a,"border"+U[f]+"Width",!0,e)));return g}function Pa(b,c,e){var f=!0,g="width"===c?b.offsetWidth:b.offsetHeight,h=Ca(b),i="border-box"===n.css(b,"boxSizing",!1,h);if(d.msFullscreenElement&&a.top!==a&&b.getClientRects().length&&(g=Math.round(100*b.getBoundingClientRect()[c])),0>=g||null==g){if(g=Fa(b,c,h),(0>g||null==g)&&(g=b.style[c]),Ba.test(g))return g;f=i&&(l.boxSizingReliable()||g===b.style[c]),g=parseFloat(g)||0}return g+Oa(b,c,e||(i?"border":"content"),f,h)+"px"}function Qa(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=N.get(d,"olddisplay"),c=d.style.display,b?(f[g]||"none"!==c||(d.style.display=""),""===d.style.display&&V(d)&&(f[g]=N.access(d,"olddisplay",za(d.nodeName)))):(e=V(d),"none"===c&&e||N.set(d,"olddisplay",e?c:n.css(d,"display"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&"none"!==d.style.display&&""!==d.style.display||(d.style.display=b?f[g]||"":"none"));return a}n.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=Fa(a,"opacity");return""===c?"1":c}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":"cssFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=n.camelCase(b),i=a.style;return b=n.cssProps[h]||(n.cssProps[h]=Ma(h)||h),g=n.cssHooks[b]||n.cssHooks[h],void 0===c?g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b]:(f=typeof c,"string"===f&&(e=T.exec(c))&&e[1]&&(c=W(a,b,e),f="number"),null!=c&&c===c&&("number"===f&&(c+=e&&e[3]||(n.cssNumber[h]?"":"px")),l.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),g&&"set"in g&&void 0===(c=g.set(a,c,d))||(i[b]=c)),void 0)}},css:function(a,b,c,d){var e,f,g,h=n.camelCase(b);return b=n.cssProps[h]||(n.cssProps[h]=Ma(h)||h),g=n.cssHooks[b]||n.cssHooks[h],g&&"get"in g&&(e=g.get(a,!0,c)),void 0===e&&(e=Fa(a,b,d)),"normal"===e&&b in Ja&&(e=Ja[b]),""===c||c?(f=parseFloat(e),c===!0||isFinite(f)?f||0:e):e}}),n.each(["height","width"],function(a,b){n.cssHooks[b]={get:function(a,c,d){return c?Ha.test(n.css(a,"display"))&&0===a.offsetWidth?Da(a,Ia,function(){return Pa(a,b,d)}):Pa(a,b,d):void 0},set:function(a,c,d){var e,f=d&&Ca(a),g=d&&Oa(a,b,d,"border-box"===n.css(a,"boxSizing",!1,f),f);return g&&(e=T.exec(c))&&"px"!==(e[3]||"px")&&(a.style[b]=c,c=n.css(a,b)),Na(a,c,g)}}}),n.cssHooks.marginLeft=Ga(l.reliableMarginLeft,function(a,b){return b?(parseFloat(Fa(a,"marginLeft"))||a.getBoundingClientRect().left-Da(a,{marginLeft:0},function(){return a.getBoundingClientRect().left}))+"px":void 0}),n.cssHooks.marginRight=Ga(l.reliableMarginRight,function(a,b){return b?Da(a,{display:"inline-block"},Fa,[a,"marginRight"]):void 0}),n.each({margin:"",padding:"",border:"Width"},function(a,b){n.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+U[d]+b]=f[d]||f[d-2]||f[0];return e}},Aa.test(a)||(n.cssHooks[a+b].set=Na)}),n.fn.extend({css:function(a,b){return K(this,function(a,b,c){var d,e,f={},g=0;if(n.isArray(b)){for(d=Ca(a),e=b.length;e>g;g++)f[b[g]]=n.css(a,b[g],!1,d);return f}return void 0!==c?n.style(a,b,c):n.css(a,b)},a,b,arguments.length>1)},show:function(){return Qa(this,!0)},hide:function(){return Qa(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){V(this)?n(this).show():n(this).hide()})}});function Ra(a,b,c,d,e){return new Ra.prototype.init(a,b,c,d,e)}n.Tween=Ra,Ra.prototype={constructor:Ra,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||n.easing._default,this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(n.cssNumber[c]?"":"px")},cur:function(){var a=Ra.propHooks[this.prop];return a&&a.get?a.get(this):Ra.propHooks._default.get(this)},run:function(a){var b,c=Ra.propHooks[this.prop];return this.options.duration?this.pos=b=n.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):Ra.propHooks._default.set(this),this}},Ra.prototype.init.prototype=Ra.prototype,Ra.propHooks={_default:{get:function(a){var b;return 1!==a.elem.nodeType||null!=a.elem[a.prop]&&null==a.elem.style[a.prop]?a.elem[a.prop]:(b=n.css(a.elem,a.prop,""),b&&"auto"!==b?b:0)},set:function(a){n.fx.step[a.prop]?n.fx.step[a.prop](a):1!==a.elem.nodeType||null==a.elem.style[n.cssProps[a.prop]]&&!n.cssHooks[a.prop]?a.elem[a.prop]=a.now:n.style(a.elem,a.prop,a.now+a.unit)}}},Ra.propHooks.scrollTop=Ra.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},n.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2},_default:"swing"},n.fx=Ra.prototype.init,n.fx.step={};var Sa,Ta,Ua=/^(?:toggle|show|hide)$/,Va=/queueHooks$/;function Wa(){return a.setTimeout(function(){Sa=void 0}),Sa=n.now()}function Xa(a,b){var c,d=0,e={height:a};for(b=b?1:0;4>d;d+=2-b)c=U[d],e["margin"+c]=e["padding"+c]=a;return b&&(e.opacity=e.width=a),e}function Ya(a,b,c){for(var d,e=(_a.tweeners[b]||[]).concat(_a.tweeners["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function Za(a,b,c){var d,e,f,g,h,i,j,k,l=this,m={},o=a.style,p=a.nodeType&&V(a),q=N.get(a,"fxshow");c.queue||(h=n._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,l.always(function(){l.always(function(){h.unqueued--,n.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[o.overflow,o.overflowX,o.overflowY],j=n.css(a,"display"),k="none"===j?N.get(a,"olddisplay")||za(a.nodeName):j,"inline"===k&&"none"===n.css(a,"float")&&(o.display="inline-block")),c.overflow&&(o.overflow="hidden",l.always(function(){o.overflow=c.overflow[0],o.overflowX=c.overflow[1],o.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],Ua.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(p?"hide":"show")){if("show"!==e||!q||void 0===q[d])continue;p=!0}m[d]=q&&q[d]||n.style(a,d)}else j=void 0;if(n.isEmptyObject(m))"inline"===("none"===j?za(a.nodeName):j)&&(o.display=j);else{q?"hidden"in q&&(p=q.hidden):q=N.access(a,"fxshow",{}),f&&(q.hidden=!p),p?n(a).show():l.done(function(){n(a).hide()}),l.done(function(){var b;N.remove(a,"fxshow");for(b in m)n.style(a,b,m[b])});for(d in m)g=Ya(p?q[d]:0,d,l),d in q||(q[d]=g.start,p&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function $a(a,b){var c,d,e,f,g;for(c in a)if(d=n.camelCase(c),e=b[d],f=a[c],n.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=n.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function _a(a,b,c){var d,e,f=0,g=_a.prefilters.length,h=n.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=Sa||Wa(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:n.extend({},b),opts:n.extend(!0,{specialEasing:{},easing:n.easing._default},c),originalProperties:b,originalOptions:c,startTime:Sa||Wa(),duration:c.duration,tweens:[],createTween:function(b,c){var d=n.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?(h.notifyWith(a,[j,1,0]),h.resolveWith(a,[j,b])):h.rejectWith(a,[j,b]),this}}),k=j.props;for($a(k,j.opts.specialEasing);g>f;f++)if(d=_a.prefilters[f].call(j,a,k,j.opts))return n.isFunction(d.stop)&&(n._queueHooks(j.elem,j.opts.queue).stop=n.proxy(d.stop,d)),d;return n.map(k,Ya,j),n.isFunction(j.opts.start)&&j.opts.start.call(a,j),n.fx.timer(n.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}n.Animation=n.extend(_a,{tweeners:{"*":[function(a,b){var c=this.createTween(a,b);return W(c.elem,a,T.exec(b),c),c}]},tweener:function(a,b){n.isFunction(a)?(b=a,a=["*"]):a=a.match(G);for(var c,d=0,e=a.length;e>d;d++)c=a[d],_a.tweeners[c]=_a.tweeners[c]||[],_a.tweeners[c].unshift(b)},prefilters:[Za],prefilter:function(a,b){b?_a.prefilters.unshift(a):_a.prefilters.push(a)}}),n.speed=function(a,b,c){var d=a&&"object"==typeof a?n.extend({},a):{complete:c||!c&&b||n.isFunction(a)&&a,duration:a,easing:c&&b||b&&!n.isFunction(b)&&b};return d.duration=n.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in n.fx.speeds?n.fx.speeds[d.duration]:n.fx.speeds._default,null!=d.queue&&d.queue!==!0||(d.queue="fx"),d.old=d.complete,d.complete=function(){n.isFunction(d.old)&&d.old.call(this),d.queue&&n.dequeue(this,d.queue)},d},n.fn.extend({fadeTo:function(a,b,c,d){return this.filter(V).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=n.isEmptyObject(a),f=n.speed(b,c,d),g=function(){var b=_a(this,n.extend({},a),f);(e||N.get(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=n.timers,g=N.get(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&Va.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));!b&&c||n.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=N.get(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=n.timers,g=d?d.length:0;for(c.finish=!0,n.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),n.each(["toggle","show","hide"],function(a,b){var c=n.fn[b];n.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(Xa(b,!0),a,d,e)}}),n.each({slideDown:Xa("show"),slideUp:Xa("hide"),slideToggle:Xa("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){n.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),n.timers=[],n.fx.tick=function(){var a,b=0,c=n.timers;for(Sa=n.now();b<c.length;b++)a=c[b],a()||c[b]!==a||c.splice(b--,1);c.length||n.fx.stop(),Sa=void 0},n.fx.timer=function(a){n.timers.push(a),a()?n.fx.start():n.timers.pop()},n.fx.interval=13,n.fx.start=function(){Ta||(Ta=a.setInterval(n.fx.tick,n.fx.interval))},n.fx.stop=function(){a.clearInterval(Ta),Ta=null},n.fx.speeds={slow:600,fast:200,_default:400},n.fn.delay=function(b,c){return b=n.fx?n.fx.speeds[b]||b:b,c=c||"fx",this.queue(c,function(c,d){var e=a.setTimeout(c,b);d.stop=function(){a.clearTimeout(e)}})},function(){var a=d.createElement("input"),b=d.createElement("select"),c=b.appendChild(d.createElement("option"));a.type="checkbox",l.checkOn=""!==a.value,l.optSelected=c.selected,b.disabled=!0,l.optDisabled=!c.disabled,a=d.createElement("input"),a.value="t",a.type="radio",l.radioValue="t"===a.value}();var ab,bb=n.expr.attrHandle;n.fn.extend({attr:function(a,b){return K(this,n.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){n.removeAttr(this,a)})}}),n.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return"undefined"==typeof a.getAttribute?n.prop(a,b,c):(1===f&&n.isXMLDoc(a)||(b=b.toLowerCase(),e=n.attrHooks[b]||(n.expr.match.bool.test(b)?ab:void 0)),void 0!==c?null===c?void n.removeAttr(a,b):e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:(a.setAttribute(b,c+""),c):e&&"get"in e&&null!==(d=e.get(a,b))?d:(d=n.find.attr(a,b),null==d?void 0:d))},attrHooks:{type:{set:function(a,b){if(!l.radioValue&&"radio"===b&&n.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(G);if(f&&1===a.nodeType)while(c=f[e++])d=n.propFix[c]||c,n.expr.match.bool.test(c)&&(a[d]=!1),a.removeAttribute(c)}}),ab={set:function(a,b,c){return b===!1?n.removeAttr(a,c):a.setAttribute(c,c),c}},n.each(n.expr.match.bool.source.match(/\w+/g),function(a,b){var c=bb[b]||n.find.attr;bb[b]=function(a,b,d){var e,f;return d||(f=bb[b],bb[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,bb[b]=f),e}});var cb=/^(?:input|select|textarea|button)$/i,db=/^(?:a|area)$/i;n.fn.extend({prop:function(a,b){return K(this,n.prop,a,b,arguments.length>1)},removeProp:function(a){return this.each(function(){delete this[n.propFix[a]||a]})}}),n.extend({prop:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return 1===f&&n.isXMLDoc(a)||(b=n.propFix[b]||b, +e=n.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=n.find.attr(a,"tabindex");return b?parseInt(b,10):cb.test(a.nodeName)||db.test(a.nodeName)&&a.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),l.optSelected||(n.propHooks.selected={get:function(a){var b=a.parentNode;return b&&b.parentNode&&b.parentNode.selectedIndex,null},set:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex)}}),n.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){n.propFix[this.toLowerCase()]=this});var eb=/[\t\r\n\f]/g;function fb(a){return a.getAttribute&&a.getAttribute("class")||""}n.fn.extend({addClass:function(a){var b,c,d,e,f,g,h,i=0;if(n.isFunction(a))return this.each(function(b){n(this).addClass(a.call(this,b,fb(this)))});if("string"==typeof a&&a){b=a.match(G)||[];while(c=this[i++])if(e=fb(c),d=1===c.nodeType&&(" "+e+" ").replace(eb," ")){g=0;while(f=b[g++])d.indexOf(" "+f+" ")<0&&(d+=f+" ");h=n.trim(d),e!==h&&c.setAttribute("class",h)}}return this},removeClass:function(a){var b,c,d,e,f,g,h,i=0;if(n.isFunction(a))return this.each(function(b){n(this).removeClass(a.call(this,b,fb(this)))});if(!arguments.length)return this.attr("class","");if("string"==typeof a&&a){b=a.match(G)||[];while(c=this[i++])if(e=fb(c),d=1===c.nodeType&&(" "+e+" ").replace(eb," ")){g=0;while(f=b[g++])while(d.indexOf(" "+f+" ")>-1)d=d.replace(" "+f+" "," ");h=n.trim(d),e!==h&&c.setAttribute("class",h)}}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):n.isFunction(a)?this.each(function(c){n(this).toggleClass(a.call(this,c,fb(this),b),b)}):this.each(function(){var b,d,e,f;if("string"===c){d=0,e=n(this),f=a.match(G)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else void 0!==a&&"boolean"!==c||(b=fb(this),b&&N.set(this,"__className__",b),this.setAttribute&&this.setAttribute("class",b||a===!1?"":N.get(this,"__className__")||""))})},hasClass:function(a){var b,c,d=0;b=" "+a+" ";while(c=this[d++])if(1===c.nodeType&&(" "+fb(c)+" ").replace(eb," ").indexOf(b)>-1)return!0;return!1}});var gb=/\r/g,hb=/[\x20\t\r\n\f]+/g;n.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=n.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,n(this).val()):a,null==e?e="":"number"==typeof e?e+="":n.isArray(e)&&(e=n.map(e,function(a){return null==a?"":a+""})),b=n.valHooks[this.type]||n.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=n.valHooks[e.type]||n.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(gb,""):null==c?"":c)}}}),n.extend({valHooks:{option:{get:function(a){var b=n.find.attr(a,"value");return null!=b?b:n.trim(n.text(a)).replace(hb," ")}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],(c.selected||i===e)&&(l.optDisabled?!c.disabled:null===c.getAttribute("disabled"))&&(!c.parentNode.disabled||!n.nodeName(c.parentNode,"optgroup"))){if(b=n(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=n.makeArray(b),g=e.length;while(g--)d=e[g],(d.selected=n.inArray(n.valHooks.option.get(d),f)>-1)&&(c=!0);return c||(a.selectedIndex=-1),f}}}}),n.each(["radio","checkbox"],function(){n.valHooks[this]={set:function(a,b){return n.isArray(b)?a.checked=n.inArray(n(a).val(),b)>-1:void 0}},l.checkOn||(n.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var ib=/^(?:focusinfocus|focusoutblur)$/;n.extend(n.event,{trigger:function(b,c,e,f){var g,h,i,j,l,m,o,p=[e||d],q=k.call(b,"type")?b.type:b,r=k.call(b,"namespace")?b.namespace.split("."):[];if(h=i=e=e||d,3!==e.nodeType&&8!==e.nodeType&&!ib.test(q+n.event.triggered)&&(q.indexOf(".")>-1&&(r=q.split("."),q=r.shift(),r.sort()),l=q.indexOf(":")<0&&"on"+q,b=b[n.expando]?b:new n.Event(q,"object"==typeof b&&b),b.isTrigger=f?2:3,b.namespace=r.join("."),b.rnamespace=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=e),c=null==c?[b]:n.makeArray(c,[b]),o=n.event.special[q]||{},f||!o.trigger||o.trigger.apply(e,c)!==!1)){if(!f&&!o.noBubble&&!n.isWindow(e)){for(j=o.delegateType||q,ib.test(j+q)||(h=h.parentNode);h;h=h.parentNode)p.push(h),i=h;i===(e.ownerDocument||d)&&p.push(i.defaultView||i.parentWindow||a)}g=0;while((h=p[g++])&&!b.isPropagationStopped())b.type=g>1?j:o.bindType||q,m=(N.get(h,"events")||{})[b.type]&&N.get(h,"handle"),m&&m.apply(h,c),m=l&&h[l],m&&m.apply&&L(h)&&(b.result=m.apply(h,c),b.result===!1&&b.preventDefault());return b.type=q,f||b.isDefaultPrevented()||o._default&&o._default.apply(p.pop(),c)!==!1||!L(e)||l&&n.isFunction(e[q])&&!n.isWindow(e)&&(i=e[l],i&&(e[l]=null),n.event.triggered=q,e[q](),n.event.triggered=void 0,i&&(e[l]=i)),b.result}},simulate:function(a,b,c){var d=n.extend(new n.Event,c,{type:a,isSimulated:!0});n.event.trigger(d,null,b),d.isDefaultPrevented()&&c.preventDefault()}}),n.fn.extend({trigger:function(a,b){return this.each(function(){n.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];return c?n.event.trigger(a,b,c,!0):void 0}}),n.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){n.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),n.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),l.focusin="onfocusin"in a,l.focusin||n.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){n.event.simulate(b,a.target,n.event.fix(a))};n.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=N.access(d,b);e||d.addEventListener(a,c,!0),N.access(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=N.access(d,b)-1;e?N.access(d,b,e):(d.removeEventListener(a,c,!0),N.remove(d,b))}}});var jb=a.location,kb=n.now(),lb=/\?/;n.parseJSON=function(a){return JSON.parse(a+"")},n.parseXML=function(b){var c;if(!b||"string"!=typeof b)return null;try{c=(new a.DOMParser).parseFromString(b,"text/xml")}catch(d){c=void 0}return c&&!c.getElementsByTagName("parsererror").length||n.error("Invalid XML: "+b),c};var mb=/#.*$/,nb=/([?&])_=[^&]*/,ob=/^(.*?):[ \t]*([^\r\n]*)$/gm,pb=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,qb=/^(?:GET|HEAD)$/,rb=/^\/\//,sb={},tb={},ub="*/".concat("*"),vb=d.createElement("a");vb.href=jb.href;function wb(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(G)||[];if(n.isFunction(c))while(d=f[e++])"+"===d[0]?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function xb(a,b,c,d){var e={},f=a===tb;function g(h){var i;return e[h]=!0,n.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function yb(a,b){var c,d,e=n.ajaxSettings.flatOptions||{};for(c in b)void 0!==b[c]&&((e[c]?a:d||(d={}))[c]=b[c]);return d&&n.extend(!0,a,d),a}function zb(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===d&&(d=a.mimeType||b.getResponseHeader("Content-Type"));if(d)for(e in h)if(h[e]&&h[e].test(d)){i.unshift(e);break}if(i[0]in c)f=i[0];else{for(e in c){if(!i[0]||a.converters[e+" "+i[0]]){f=e;break}g||(g=e)}f=f||g}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function Ab(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}n.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:jb.href,type:"GET",isLocal:pb.test(jb.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":ub,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":n.parseJSON,"text xml":n.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?yb(yb(a,n.ajaxSettings),b):yb(n.ajaxSettings,a)},ajaxPrefilter:wb(sb),ajaxTransport:wb(tb),ajax:function(b,c){"object"==typeof b&&(c=b,b=void 0),c=c||{};var e,f,g,h,i,j,k,l,m=n.ajaxSetup({},c),o=m.context||m,p=m.context&&(o.nodeType||o.jquery)?n(o):n.event,q=n.Deferred(),r=n.Callbacks("once memory"),s=m.statusCode||{},t={},u={},v=0,w="canceled",x={readyState:0,getResponseHeader:function(a){var b;if(2===v){if(!h){h={};while(b=ob.exec(g))h[b[1].toLowerCase()]=b[2]}b=h[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===v?g:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return v||(a=u[c]=u[c]||a,t[a]=b),this},overrideMimeType:function(a){return v||(m.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>v)for(b in a)s[b]=[s[b],a[b]];else x.always(a[x.status]);return this},abort:function(a){var b=a||w;return e&&e.abort(b),z(0,b),this}};if(q.promise(x).complete=r.add,x.success=x.done,x.error=x.fail,m.url=((b||m.url||jb.href)+"").replace(mb,"").replace(rb,jb.protocol+"//"),m.type=c.method||c.type||m.method||m.type,m.dataTypes=n.trim(m.dataType||"*").toLowerCase().match(G)||[""],null==m.crossDomain){j=d.createElement("a");try{j.href=m.url,j.href=j.href,m.crossDomain=vb.protocol+"//"+vb.host!=j.protocol+"//"+j.host}catch(y){m.crossDomain=!0}}if(m.data&&m.processData&&"string"!=typeof m.data&&(m.data=n.param(m.data,m.traditional)),xb(sb,m,c,x),2===v)return x;k=n.event&&m.global,k&&0===n.active++&&n.event.trigger("ajaxStart"),m.type=m.type.toUpperCase(),m.hasContent=!qb.test(m.type),f=m.url,m.hasContent||(m.data&&(f=m.url+=(lb.test(f)?"&":"?")+m.data,delete m.data),m.cache===!1&&(m.url=nb.test(f)?f.replace(nb,"$1_="+kb++):f+(lb.test(f)?"&":"?")+"_="+kb++)),m.ifModified&&(n.lastModified[f]&&x.setRequestHeader("If-Modified-Since",n.lastModified[f]),n.etag[f]&&x.setRequestHeader("If-None-Match",n.etag[f])),(m.data&&m.hasContent&&m.contentType!==!1||c.contentType)&&x.setRequestHeader("Content-Type",m.contentType),x.setRequestHeader("Accept",m.dataTypes[0]&&m.accepts[m.dataTypes[0]]?m.accepts[m.dataTypes[0]]+("*"!==m.dataTypes[0]?", "+ub+"; q=0.01":""):m.accepts["*"]);for(l in m.headers)x.setRequestHeader(l,m.headers[l]);if(m.beforeSend&&(m.beforeSend.call(o,x,m)===!1||2===v))return x.abort();w="abort";for(l in{success:1,error:1,complete:1})x[l](m[l]);if(e=xb(tb,m,c,x)){if(x.readyState=1,k&&p.trigger("ajaxSend",[x,m]),2===v)return x;m.async&&m.timeout>0&&(i=a.setTimeout(function(){x.abort("timeout")},m.timeout));try{v=1,e.send(t,z)}catch(y){if(!(2>v))throw y;z(-1,y)}}else z(-1,"No Transport");function z(b,c,d,h){var j,l,t,u,w,y=c;2!==v&&(v=2,i&&a.clearTimeout(i),e=void 0,g=h||"",x.readyState=b>0?4:0,j=b>=200&&300>b||304===b,d&&(u=zb(m,x,d)),u=Ab(m,u,x,j),j?(m.ifModified&&(w=x.getResponseHeader("Last-Modified"),w&&(n.lastModified[f]=w),w=x.getResponseHeader("etag"),w&&(n.etag[f]=w)),204===b||"HEAD"===m.type?y="nocontent":304===b?y="notmodified":(y=u.state,l=u.data,t=u.error,j=!t)):(t=y,!b&&y||(y="error",0>b&&(b=0))),x.status=b,x.statusText=(c||y)+"",j?q.resolveWith(o,[l,y,x]):q.rejectWith(o,[x,y,t]),x.statusCode(s),s=void 0,k&&p.trigger(j?"ajaxSuccess":"ajaxError",[x,m,j?l:t]),r.fireWith(o,[x,y]),k&&(p.trigger("ajaxComplete",[x,m]),--n.active||n.event.trigger("ajaxStop")))}return x},getJSON:function(a,b,c){return n.get(a,b,c,"json")},getScript:function(a,b){return n.get(a,void 0,b,"script")}}),n.each(["get","post"],function(a,b){n[b]=function(a,c,d,e){return n.isFunction(c)&&(e=e||d,d=c,c=void 0),n.ajax(n.extend({url:a,type:b,dataType:e,data:c,success:d},n.isPlainObject(a)&&a))}}),n._evalUrl=function(a){return n.ajax({url:a,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})},n.fn.extend({wrapAll:function(a){var b;return n.isFunction(a)?this.each(function(b){n(this).wrapAll(a.call(this,b))}):(this[0]&&(b=n(a,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstElementChild)a=a.firstElementChild;return a}).append(this)),this)},wrapInner:function(a){return n.isFunction(a)?this.each(function(b){n(this).wrapInner(a.call(this,b))}):this.each(function(){var b=n(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=n.isFunction(a);return this.each(function(c){n(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){n.nodeName(this,"body")||n(this).replaceWith(this.childNodes)}).end()}}),n.expr.filters.hidden=function(a){return!n.expr.filters.visible(a)},n.expr.filters.visible=function(a){return a.offsetWidth>0||a.offsetHeight>0||a.getClientRects().length>0};var Bb=/%20/g,Cb=/\[\]$/,Db=/\r?\n/g,Eb=/^(?:submit|button|image|reset|file)$/i,Fb=/^(?:input|select|textarea|keygen)/i;function Gb(a,b,c,d){var e;if(n.isArray(b))n.each(b,function(b,e){c||Cb.test(a)?d(a,e):Gb(a+"["+("object"==typeof e&&null!=e?b:"")+"]",e,c,d)});else if(c||"object"!==n.type(b))d(a,b);else for(e in b)Gb(a+"["+e+"]",b[e],c,d)}n.param=function(a,b){var c,d=[],e=function(a,b){b=n.isFunction(b)?b():null==b?"":b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(void 0===b&&(b=n.ajaxSettings&&n.ajaxSettings.traditional),n.isArray(a)||a.jquery&&!n.isPlainObject(a))n.each(a,function(){e(this.name,this.value)});else for(c in a)Gb(c,a[c],b,e);return d.join("&").replace(Bb,"+")},n.fn.extend({serialize:function(){return n.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=n.prop(this,"elements");return a?n.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!n(this).is(":disabled")&&Fb.test(this.nodeName)&&!Eb.test(a)&&(this.checked||!X.test(a))}).map(function(a,b){var c=n(this).val();return null==c?null:n.isArray(c)?n.map(c,function(a){return{name:b.name,value:a.replace(Db,"\r\n")}}):{name:b.name,value:c.replace(Db,"\r\n")}}).get()}}),n.ajaxSettings.xhr=function(){try{return new a.XMLHttpRequest}catch(b){}};var Hb={0:200,1223:204},Ib=n.ajaxSettings.xhr();l.cors=!!Ib&&"withCredentials"in Ib,l.ajax=Ib=!!Ib,n.ajaxTransport(function(b){var c,d;return l.cors||Ib&&!b.crossDomain?{send:function(e,f){var g,h=b.xhr();if(h.open(b.type,b.url,b.async,b.username,b.password),b.xhrFields)for(g in b.xhrFields)h[g]=b.xhrFields[g];b.mimeType&&h.overrideMimeType&&h.overrideMimeType(b.mimeType),b.crossDomain||e["X-Requested-With"]||(e["X-Requested-With"]="XMLHttpRequest");for(g in e)h.setRequestHeader(g,e[g]);c=function(a){return function(){c&&(c=d=h.onload=h.onerror=h.onabort=h.onreadystatechange=null,"abort"===a?h.abort():"error"===a?"number"!=typeof h.status?f(0,"error"):f(h.status,h.statusText):f(Hb[h.status]||h.status,h.statusText,"text"!==(h.responseType||"text")||"string"!=typeof h.responseText?{binary:h.response}:{text:h.responseText},h.getAllResponseHeaders()))}},h.onload=c(),d=h.onerror=c("error"),void 0!==h.onabort?h.onabort=d:h.onreadystatechange=function(){4===h.readyState&&a.setTimeout(function(){c&&d()})},c=c("abort");try{h.send(b.hasContent&&b.data||null)}catch(i){if(c)throw i}},abort:function(){c&&c()}}:void 0}),n.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(a){return n.globalEval(a),a}}}),n.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET")}),n.ajaxTransport("script",function(a){if(a.crossDomain){var b,c;return{send:function(e,f){b=n("<script>").prop({charset:a.scriptCharset,src:a.url}).on("load error",c=function(a){b.remove(),c=null,a&&f("error"===a.type?404:200,a.type)}),d.head.appendChild(b[0])},abort:function(){c&&c()}}}});var Jb=[],Kb=/(=)\?(?=&|$)|\?\?/;n.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=Jb.pop()||n.expando+"_"+kb++;return this[a]=!0,a}}),n.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(Kb.test(b.url)?"url":"string"==typeof b.data&&0===(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&Kb.test(b.data)&&"data");return h||"jsonp"===b.dataTypes[0]?(e=b.jsonpCallback=n.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(Kb,"$1"+e):b.jsonp!==!1&&(b.url+=(lb.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||n.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){void 0===f?n(a).removeProp(e):a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,Jb.push(e)),g&&n.isFunction(f)&&f(g[0]),g=f=void 0}),"script"):void 0}),n.parseHTML=function(a,b,c){if(!a||"string"!=typeof a)return null;"boolean"==typeof b&&(c=b,b=!1),b=b||d;var e=x.exec(a),f=!c&&[];return e?[b.createElement(e[1])]:(e=ca([a],b,f),f&&f.length&&n(f).remove(),n.merge([],e.childNodes))};var Lb=n.fn.load;n.fn.load=function(a,b,c){if("string"!=typeof a&&Lb)return Lb.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(" ");return h>-1&&(d=n.trim(a.slice(h)),a=a.slice(0,h)),n.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(e="POST"),g.length>0&&n.ajax({url:a,type:e||"GET",dataType:"html",data:b}).done(function(a){f=arguments,g.html(d?n("<div>").append(n.parseHTML(a)).find(d):a)}).always(c&&function(a,b){g.each(function(){c.apply(this,f||[a.responseText,b,a])})}),this},n.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){n.fn[b]=function(a){return this.on(b,a)}}),n.expr.filters.animated=function(a){return n.grep(n.timers,function(b){return a===b.elem}).length};function Mb(a){return n.isWindow(a)?a:9===a.nodeType&&a.defaultView}n.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=n.css(a,"position"),l=n(a),m={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=n.css(a,"top"),i=n.css(a,"left"),j=("absolute"===k||"fixed"===k)&&(f+i).indexOf("auto")>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),n.isFunction(b)&&(b=b.call(a,c,n.extend({},h))),null!=b.top&&(m.top=b.top-h.top+g),null!=b.left&&(m.left=b.left-h.left+e),"using"in b?b.using.call(a,m):l.css(m)}},n.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){n.offset.setOffset(this,a,b)});var b,c,d=this[0],e={top:0,left:0},f=d&&d.ownerDocument;if(f)return b=f.documentElement,n.contains(b,d)?(e=d.getBoundingClientRect(),c=Mb(f),{top:e.top+c.pageYOffset-b.clientTop,left:e.left+c.pageXOffset-b.clientLeft}):e},position:function(){if(this[0]){var a,b,c=this[0],d={top:0,left:0};return"fixed"===n.css(c,"position")?b=c.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),n.nodeName(a[0],"html")||(d=a.offset()),d.top+=n.css(a[0],"borderTopWidth",!0),d.left+=n.css(a[0],"borderLeftWidth",!0)),{top:b.top-d.top-n.css(c,"marginTop",!0),left:b.left-d.left-n.css(c,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent;while(a&&"static"===n.css(a,"position"))a=a.offsetParent;return a||Ea})}}),n.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,b){var c="pageYOffset"===b;n.fn[a]=function(d){return K(this,function(a,d,e){var f=Mb(a);return void 0===e?f?f[b]:a[d]:void(f?f.scrollTo(c?f.pageXOffset:e,c?e:f.pageYOffset):a[d]=e)},a,d,arguments.length)}}),n.each(["top","left"],function(a,b){n.cssHooks[b]=Ga(l.pixelPosition,function(a,c){return c?(c=Fa(a,b),Ba.test(c)?n(a).position()[b]+"px":c):void 0})}),n.each({Height:"height",Width:"width"},function(a,b){n.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){n.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return K(this,function(b,c,d){var e;return n.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?n.css(b,c,g):n.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),n.fn.extend({bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)},size:function(){return this.length}}),n.fn.andSelf=n.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return n});var Nb=a.jQuery,Ob=a.$;return n.noConflict=function(b){return a.$===n&&(a.$=Ob),b&&a.jQuery===n&&(a.jQuery=Nb),n},b||(a.jQuery=a.$=n),n}); diff --git a/js/scripts/jquery.mousewheel.min.js b/js/scripts/jquery.mousewheel.min.js new file mode 100644 index 00000000000..81f43ef6ace --- /dev/null +++ b/js/scripts/jquery.mousewheel.min.js @@ -0,0 +1,8 @@ +/*! Copyright (c) 2013 Brandon Aaron (http://brandon.aaron.sh) + * Licensed under the MIT License (LICENSE.txt). + * + * Version: 3.1.12 + * + * Requires: jQuery 1.2.2+ + */ +(function(a){if(typeof define==="function"&&define.amd){define(["jquery"],a)}else{if(typeof exports==="object"){module.exports=a}else{a(jQuery)}}}(function(c){var d=["wheel","mousewheel","DOMMouseScroll","MozMousePixelScroll"],k=("onwheel" in document||document.documentMode>=9)?["wheel"]:["mousewheel","DomMouseScroll","MozMousePixelScroll"],h=Array.prototype.slice,j,b;if(c.event.fixHooks){for(var e=d.length;e;){c.event.fixHooks[d[--e]]=c.event.mouseHooks}}var f=c.event.special.mousewheel={version:"3.1.12",setup:function(){if(this.addEventListener){for(var m=k.length;m;){this.addEventListener(k[--m],l,false)}}else{this.onmousewheel=l}c.data(this,"mousewheel-line-height",f.getLineHeight(this));c.data(this,"mousewheel-page-height",f.getPageHeight(this))},teardown:function(){if(this.removeEventListener){for(var m=k.length;m;){this.removeEventListener(k[--m],l,false)}}else{this.onmousewheel=null}c.removeData(this,"mousewheel-line-height");c.removeData(this,"mousewheel-page-height")},getLineHeight:function(m){var i=c(m),n=i["offsetParent" in c.fn?"offsetParent":"parent"]();if(!n.length){n=c("body")}return parseInt(n.css("fontSize"),10)||parseInt(i.css("fontSize"),10)||16},getPageHeight:function(i){return c(i).height()},settings:{adjustOldDeltas:true,normalizeOffset:true}};c.fn.extend({mousewheel:function(i){return i?this.bind("mousewheel",i):this.trigger("mousewheel")},unmousewheel:function(i){return this.unbind("mousewheel",i)}});function l(i){var o=i||window.event,u=h.call(arguments,1),w=0,q=0,p=0,t=0,s=0,r=0;i=c.event.fix(o);i.type="mousewheel";if("detail" in o){p=o.detail*-1}if("wheelDelta" in o){p=o.wheelDelta}if("wheelDeltaY" in o){p=o.wheelDeltaY}if("wheelDeltaX" in o){q=o.wheelDeltaX*-1}if("axis" in o&&o.axis===o.HORIZONTAL_AXIS){q=p*-1;p=0}w=p===0?q:p;if("deltaY" in o){p=o.deltaY*-1;w=p}if("deltaX" in o){q=o.deltaX;if(p===0){w=q*-1}}if(p===0&&q===0){return}if(o.deltaMode===1){var v=c.data(this,"mousewheel-line-height");w*=v;p*=v;q*=v}else{if(o.deltaMode===2){var n=c.data(this,"mousewheel-page-height");w*=n;p*=n;q*=n}}t=Math.max(Math.abs(p),Math.abs(q));if(!b||t<b){b=t;if(a(o,t)){b/=40}}if(a(o,t)){w/=40;q/=40;p/=40}w=Math[w>=1?"floor":"ceil"](w/b);q=Math[q>=1?"floor":"ceil"](q/b);p=Math[p>=1?"floor":"ceil"](p/b);if(f.settings.normalizeOffset&&this.getBoundingClientRect){var m=this.getBoundingClientRect();s=i.clientX-m.left;r=i.clientY-m.top}i.deltaX=q;i.deltaY=p;i.deltaFactor=b;i.offsetX=s;i.offsetY=r;i.deltaMode=0;u.unshift(i,w,q,p);if(j){clearTimeout(j)}j=setTimeout(g,200);return(c.event.dispatch||c.event.handle).apply(this,u)}function g(){b=null}function a(m,i){return f.settings.adjustOldDeltas&&m.type==="mousewheel"&&i%120===0}})); \ No newline at end of file diff --git a/js/scripts/rawinflate.min.js b/js/scripts/rawinflate.min.js new file mode 100644 index 00000000000..432477b2732 --- /dev/null +++ b/js/scripts/rawinflate.min.js @@ -0,0 +1 @@ +(function(a){if(typeof define==="function"&&define.amd){define(["JSRootCore"],a)}else{if(typeof exports==="object"&&typeof module!=="undefined"){a(require("./JSRootCore.js"))}else{if(typeof JSROOT=="undefined"){throw new Error("JSROOT is not defined","rawinflate.js")}if(typeof JSROOT.ZIP!=="undefined"){throw new Error("JSROOT.ZIP already exists","rawinflate.js")}a(JSROOT)}}}(function(o){var j=32768,w=null,g,I=null,a,E,G,n,m,L,F,K,s,i,k,d,f,v,D,x,H=new Array(0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535),b=new Array(3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,0,0),C=new Array(0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,99,99),A=new Array(1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577),t=new Array(0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13),l=new Array(16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15);var r=function(){this.next=null;this.list=null};var z=function(){this.e=0;this.b=0;this.n=0;this.t=null};var h=function(aq,ae,Z,ao,an,ak){this.status=0;this.root=null;this.m=0;var af=16,N=288,ap=new Array(af+1),O=new Array(af+1),Y=new Array(af),X=new Array(N),U=new Array(af+1),aa=new z(),R=null,ar,M,am,al,aj,ai,ah,ag,ac,P,ab,W,V,T,S,ad,Q=this.root=null;for(ai=0;ai<=af;++ai){ap[ai]=O[ai]=U[ai]=0}for(ai=0;ai<af;++ai){Y[ai]=null}for(ai=0;ai<N;++ai){X[ai]=0}M=(ae>256)?aq[256]:af;ac=aq;P=0;ai=ae;do{ap[ac[P++]]++}while(--ai>0);if(ap[0]==ae){this.root=null;this.m=0;this.status=0;return this}for(ah=1;ah<=af;++ah){if(ap[ah]!=0){break}}ag=ah;if(ak<ah){ak=ah}for(ai=af;ai!=0;--ai){if(ap[ai]!=0){break}}al=ai;if(ak>ai){ak=ai}for(T=1<<ah;ah<ai;++ah,T<<=1){if((T-=ap[ah])<0){this.status=2;this.m=ak;return this}}if((T-=ap[ai])<0){this.status=2;this.m=ak;return this}ap[ai]+=T;U[1]=ah=0;ac=ap;P=1;V=2;while(--ai>0){U[V++]=(ah+=ac[P++])}ac=aq;P=0;ai=0;do{if((ah=ac[P++])!=0){X[U[ah]++]=ai}}while(++ai<ae);ae=U[al];U[0]=ai=0;ac=X;P=0;aj=-1;W=O[0]=0;ab=null;S=0;for(;ag<=al;++ag){ar=ap[ag];while(ar-->0){while(ag>W+O[1+aj]){W+=O[1+aj++];S=(S=al-W)>ak?ak:S;if((am=1<<(ah=ag-W))>ar+1){am-=ar+1;V=ag;while(++ah<S){if((am<<=1)<=ap[++V]){break}am-=ap[V]}}if(W+ah>M&&W<M){ah=M-W}S=1<<ah;O[1+aj]=ah;ab=new Array(S);for(ad=0;ad<S;++ad){ab[ad]=new z()}if(Q==null){Q=this.root=new r()}else{Q=Q.next=new r()}Q.next=null;Q.list=ab;Y[aj]=ab;if(aj>0){U[aj]=ai;aa.b=O[aj];aa.e=16+ah;aa.t=ab;ah=(ai&((1<<W)-1))>>(W-O[aj]);R=Y[aj-1][ah];R.e=aa.e;R.b=aa.b;R.n=aa.n;R.t=aa.t}}aa.b=ag-W;if(P>=ae){aa.e=99}else{if(ac[P]<Z){aa.e=(ac[P]<256?16:15);aa.n=ac[P++]}else{aa.e=an[ac[P]-Z];aa.n=ao[ac[P++]-Z]}}am=1<<(ag-W);for(ah=ai>>W;ah<S;ah+=am){R=ab[ah];R.e=aa.e;R.b=aa.b;R.n=aa.n;R.t=aa.t}for(ah=1<<(ag-1);(ai&ah)!=0;ah>>=1){ai^=ah}ai^=ah;while((ai&((1<<W)-1))!=U[aj]){W-=O[aj--]}}}this.m=O[1];this.status=((T!=0&&al!=1)?1:0);return this};var J=function(M){while(m<M){if(x<D){n|=v[x++]<<m}m+=8}};var p=function(M){return n&H[M]};var c=function(M){n>>=M;m-=M};var e=function(R,P,N){if(N==0){return 0}var O,M,Q=0;for(;;){J(d);M=i.list[p(d)];O=M.e;while(O>16){if(O==99){return -1}c(M.b);O-=16;J(O);M=M.t[p(O)];O=M.e}c(M.b);if(O==16){g&=j-1;R[P+Q++]=w[g++]=M.n;if(Q==N){return N}continue}if(O==15){break}J(O);K=M.n+p(O);c(O);J(f);M=k.list[p(f)];O=M.e;while(O>16){if(O==99){return -1}c(M.b);O-=16;J(O);M=M.t[p(O)];O=M.e}c(M.b);J(O);s=g-M.n-p(O);c(O);while(K>0&&Q<N){--K;s&=j-1;g&=j-1;R[P+Q++]=w[g++]=w[s++]}if(Q==N){return N}}L=-1;return Q};var q=function(P,N,M){var O=m&7;c(O);J(16);O=p(16);c(16);J(16);if(O!=((~n)&65535)){return -1}c(16);K=O;O=0;while(K>0&&O<M){--K;g&=j-1;J(8);P[N+O++]=w[g++]=p(8);c(8)}if(K==0){L=-1}return O};var B=function(R,Q,O){if(I==null){var N=0,M=new Array(288);while(N<144){M[N++]=8}while(N<256){M[N++]=9}while(N<280){M[N++]=7}while(N<288){M[N++]=8}E=7;var P=new h(M,288,257,b,C,E);if(P.status!=0){throw new Error("HufBuild error: "+P.status,"rawinflate.js");return -1}I=P.root;E=P.m;for(N=0;N<30;++N){M[N]=5}G=5;P=new h(M,30,0,A,t,G);if(P.status>1){I=null;throw new Error("HufBuild error: "+P.status,"rawinflate.js");return -1}a=P.root;G=P.m}i=I;k=a;d=E;f=G;return e(R,Q,O)};var u=function(W,O,Y){var S,R,P,N,X,U,V=new Array(286+30);for(S=0;S<V.length;++S){V[S]=0}J(5);var M=257+p(5);c(5);J(5);var Q=1+p(5);c(5);J(4);var T=4+p(4);c(4);if(M>286||Q>30){return -1}for(R=0;R<T;++R){J(3);V[l[R]]=p(3);c(3)}for(;R<19;++R){V[l[R]]=0}d=7;U=new h(V,19,19,null,null,d);if(U.status!=0){return -1}i=U.root;d=U.m;N=M+Q;S=P=0;while(S<N){J(d);X=i.list[p(d)];R=X.b;c(R);R=X.n;if(R<16){V[S++]=P=R}else{if(R==16){J(2);R=3+p(2);c(2);if(S+R>N){return -1}while(R-->0){V[S++]=P}}else{if(R==17){J(3);R=3+p(3);c(3);if(S+R>N){return -1}while(R-->0){V[S++]=0}P=0}else{J(7);R=11+p(7);c(7);if(S+R>N){return -1}while(R-->0){V[S++]=0}P=0}}}}d=9;U=new h(V,M,257,b,C,d);if(d==0){U.status=1}if(U.status!=0){return -1}i=U.root;d=U.m;for(S=0;S<Q;++S){V[S]=V[S+M]}f=6;U=new h(V,Q,0,A,t,f);k=U.root;f=U.m;if(f==0&&M>257){return -1}if(U.status!=0){return -1}return e(W,O,Y)};var y=function(Q,O,N){var P=0,M;while(P<N){if(F&&L==-1){return P}if(K>0){if(L!=0){while(K>0&&P<N){--K;s&=j-1;g&=j-1;Q[O+P++]=w[g++]=w[s++]}}else{while(K>0&&P<N){--K;g&=j-1;J(8);Q[O+P++]=w[g++]=p(8);c(8)}if(K==0){L=-1}}if(P==N){return P}}if(L==-1){if(F){break}J(1);if(p(1)!=0){F=true}c(1);J(2);L=p(2);c(2);i=null;K=0}switch(L){case 0:M=q(Q,O+P,N-P);break;case 1:if(i!=null){M=e(Q,O+P,N-P)}else{M=B(Q,O+P,N-P)}break;case 2:if(i!=null){M=e(Q,O+P,N-P)}else{M=u(Q,O+P,N-P)}break;default:M=-1;break}if(M==-1){return F?0:-1}P+=M}return P};o.ZIP={};o.ZIP.inflate=function(M,P){if(!w){w=new Array(2*j)}g=0;n=0;m=0;L=-1;F=false;K=s=0;i=null;v=M;D=M.byteLength;x=0;var O,N=0;while((O=y(P,N,Math.min(1024,P.byteLength-N)))>0){N+=O}v=null;return N};o.LZ4={};o.LZ4.uncompress=function(X,N,Y,U){Y=Y||0;U=U||(X.length-Y);for(var T=Y,M=U,S=0;T<M;){var P=X[T++];var Z=(P>>4);if(Z>0){var O=Z+240;while(O===255){O=X[T++];Z+=O}var Q=T+Z;while(T<Q){N[S++]=X[T++]}if(T===M){return S}}var R=X[T++]|(X[T++]<<8);if(R===0||R>S){return -(T-2)}var V=(P&15);var O=V+240;while(O===255){O=X[T++];V+=O}var W=S-R;var Q=S+V+4;while(S<Q){N[S++]=N[W++]}}return S};return o})); \ No newline at end of file diff --git a/js/scripts/three.LICENSE b/js/scripts/three.LICENSE new file mode 100644 index 00000000000..492c23e29a3 --- /dev/null +++ b/js/scripts/three.LICENSE @@ -0,0 +1,21 @@ +The MIT License + +Copyright © 2010-2018 three.js authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/js/scripts/three.extra.min.js b/js/scripts/three.extra.min.js new file mode 100644 index 00000000000..e152bb92aa0 --- /dev/null +++ b/js/scripts/three.extra.min.js @@ -0,0 +1 @@ +(function(a){if(typeof define==="function"&&define.amd){define(["JSRootCore","threejs"],a)}else{if(typeof exports==="object"&&typeof module!=="undefined"){var b=require("./JSRootCore.js");a(b,require("./three.min.js"),b.nodejs||(typeof document=="undefined")?b.nodejs_document:document)}else{if(typeof JSROOT=="undefined"){throw new Error("JSROOT is not defined","three.extra.js")}if(typeof THREE=="undefined"){throw new Error("THREE is not defined","three.extra.js")}a(JSROOT,THREE,document)}}}(function(b,c,a){if((typeof a=="undefined")&&(typeof window=="object")){a=window.document}b.threejs_font_helvetiker_regular=new c.Font({glyphs:{"ο":{x_min:0,x_max:712,ha:815,o:"m 356 -25 q 96 88 192 -25 q 0 368 0 201 q 92 642 0 533 q 356 761 192 761 q 617 644 517 761 q 712 368 712 533 q 619 91 712 201 q 356 -25 520 -25 m 356 85 q 527 175 465 85 q 583 369 583 255 q 528 562 583 484 q 356 651 466 651 q 189 560 250 651 q 135 369 135 481 q 187 177 135 257 q 356 85 250 85 "},S:{x_min:0,x_max:788,ha:890,o:"m 788 291 q 662 54 788 144 q 397 -26 550 -26 q 116 68 226 -26 q 0 337 0 168 l 131 337 q 200 152 131 220 q 384 85 269 85 q 557 129 479 85 q 650 270 650 183 q 490 429 650 379 q 194 513 341 470 q 33 739 33 584 q 142 964 33 881 q 388 1041 242 1041 q 644 957 543 1041 q 756 716 756 867 l 625 716 q 561 874 625 816 q 395 933 497 933 q 243 891 309 933 q 164 759 164 841 q 325 609 164 656 q 625 526 475 568 q 788 291 788 454 "},"¦":{x_min:343,x_max:449,ha:792,o:"m 449 462 l 343 462 l 343 986 l 449 986 l 449 462 m 449 -242 l 343 -242 l 343 280 l 449 280 l 449 -242 "},"/":{x_min:183.25,x_max:608.328125,ha:792,o:"m 608 1041 l 266 -129 l 183 -129 l 520 1041 l 608 1041 "},"Τ":{x_min:-0.4375,x_max:777.453125,ha:839,o:"m 777 893 l 458 893 l 458 0 l 319 0 l 319 892 l 0 892 l 0 1013 l 777 1013 l 777 893 "},y:{x_min:0,x_max:684.78125,ha:771,o:"m 684 738 l 388 -83 q 311 -216 356 -167 q 173 -279 252 -279 q 97 -266 133 -279 l 97 -149 q 132 -155 109 -151 q 168 -160 155 -160 q 240 -114 213 -160 q 274 -26 248 -98 l 0 738 l 137 737 l 341 139 l 548 737 l 684 738 "},"Î ":{x_min:0,x_max:803,ha:917,o:"m 803 0 l 667 0 l 667 886 l 140 886 l 140 0 l 0 0 l 0 1012 l 803 1012 l 803 0 "},"Î":{x_min:-111,x_max:339,ha:361,o:"m 339 800 l 229 800 l 229 925 l 339 925 l 339 800 m -1 800 l -111 800 l -111 925 l -1 925 l -1 800 m 284 3 q 233 -10 258 -5 q 182 -15 207 -15 q 85 26 119 -15 q 42 200 42 79 l 42 737 l 167 737 l 168 215 q 172 141 168 157 q 226 101 183 101 q 248 103 239 101 q 284 112 257 104 l 284 3 m 302 1040 l 113 819 l 30 819 l 165 1040 l 302 1040 "},g:{x_min:0,x_max:686,ha:838,o:"m 686 34 q 586 -213 686 -121 q 331 -306 487 -306 q 131 -252 216 -306 q 31 -84 31 -190 l 155 -84 q 228 -174 166 -138 q 345 -207 284 -207 q 514 -109 454 -207 q 564 89 564 -27 q 461 6 521 36 q 335 -23 401 -23 q 88 100 184 -23 q 0 370 0 215 q 87 634 0 522 q 330 758 183 758 q 457 728 398 758 q 564 644 515 699 l 564 737 l 686 737 l 686 34 m 582 367 q 529 560 582 481 q 358 652 468 652 q 189 561 250 652 q 135 369 135 482 q 189 176 135 255 q 361 85 251 85 q 529 176 468 85 q 582 367 582 255 "},"²":{x_min:0,x_max:442,ha:539,o:"m 442 383 l 0 383 q 91 566 0 492 q 260 668 176 617 q 354 798 354 727 q 315 875 354 845 q 227 905 277 905 q 136 869 173 905 q 99 761 99 833 l 14 761 q 82 922 14 864 q 232 974 141 974 q 379 926 316 974 q 442 797 442 878 q 351 635 442 704 q 183 539 321 611 q 92 455 92 491 l 442 455 l 442 383 "},"–":{x_min:0,x_max:705.5625,ha:803,o:"m 705 334 l 0 334 l 0 410 l 705 410 l 705 334 "},"Κ":{x_min:0,x_max:819.5625,ha:893,o:"m 819 0 l 650 0 l 294 509 l 139 356 l 139 0 l 0 0 l 0 1013 l 139 1013 l 139 526 l 626 1013 l 809 1013 l 395 600 l 819 0 "},"Æ’":{x_min:-46.265625,x_max:392,ha:513,o:"m 392 651 l 259 651 l 79 -279 l -46 -278 l 134 651 l 14 651 l 14 751 l 135 751 q 151 948 135 900 q 304 1041 185 1041 q 334 1040 319 1041 q 392 1034 348 1039 l 392 922 q 337 931 360 931 q 271 883 287 931 q 260 793 260 853 l 260 751 l 392 751 l 392 651 "},e:{x_min:0,x_max:714,ha:813,o:"m 714 326 l 140 326 q 200 157 140 227 q 359 87 260 87 q 488 130 431 87 q 561 245 545 174 l 697 245 q 577 48 670 123 q 358 -26 484 -26 q 97 85 195 -26 q 0 363 0 197 q 94 642 0 529 q 358 765 195 765 q 626 627 529 765 q 714 326 714 503 m 576 429 q 507 583 564 522 q 355 650 445 650 q 206 583 266 650 q 140 429 152 522 l 576 429 "},"ÏŒ":{x_min:0,x_max:712,ha:815,o:"m 356 -25 q 94 91 194 -25 q 0 368 0 202 q 92 642 0 533 q 356 761 192 761 q 617 644 517 761 q 712 368 712 533 q 619 91 712 201 q 356 -25 520 -25 m 356 85 q 527 175 465 85 q 583 369 583 255 q 528 562 583 484 q 356 651 466 651 q 189 560 250 651 q 135 369 135 481 q 187 177 135 257 q 356 85 250 85 m 576 1040 l 387 819 l 303 819 l 438 1040 l 576 1040 "},J:{x_min:0,x_max:588,ha:699,o:"m 588 279 q 287 -26 588 -26 q 58 73 126 -26 q 0 327 0 158 l 133 327 q 160 172 133 227 q 288 96 198 96 q 426 171 391 96 q 449 336 449 219 l 449 1013 l 588 1013 l 588 279 "},"»":{x_min:-1,x_max:503,ha:601,o:"m 503 302 l 280 136 l 281 256 l 429 373 l 281 486 l 280 608 l 503 440 l 503 302 m 221 302 l 0 136 l 0 255 l 145 372 l 0 486 l -1 608 l 221 440 l 221 302 "},"©":{x_min:-3,x_max:1008,ha:1106,o:"m 502 -7 q 123 151 263 -7 q -3 501 -3 294 q 123 851 -3 706 q 502 1011 263 1011 q 881 851 739 1011 q 1008 501 1008 708 q 883 151 1008 292 q 502 -7 744 -7 m 502 60 q 830 197 709 60 q 940 501 940 322 q 831 805 940 681 q 502 944 709 944 q 174 805 296 944 q 65 501 65 680 q 173 197 65 320 q 502 60 294 60 m 741 394 q 661 246 731 302 q 496 190 591 190 q 294 285 369 190 q 228 497 228 370 q 295 714 228 625 q 499 813 370 813 q 656 762 588 813 q 733 625 724 711 l 634 625 q 589 704 629 673 q 498 735 550 735 q 377 666 421 735 q 334 504 334 597 q 374 340 334 408 q 490 272 415 272 q 589 304 549 272 q 638 394 628 337 l 741 394 "},"ÏŽ":{x_min:0,x_max:922,ha:1030,o:"m 687 1040 l 498 819 l 415 819 l 549 1040 l 687 1040 m 922 339 q 856 97 922 203 q 650 -26 780 -26 q 538 9 587 -26 q 461 103 489 44 q 387 12 436 46 q 277 -22 339 -22 q 69 97 147 -22 q 0 338 0 202 q 45 551 0 444 q 161 737 84 643 l 302 737 q 175 552 219 647 q 124 336 124 446 q 155 179 124 248 q 275 88 197 88 q 375 163 341 88 q 400 294 400 219 l 400 572 l 524 572 l 524 294 q 561 135 524 192 q 643 88 591 88 q 762 182 719 88 q 797 341 797 257 q 745 555 797 450 q 619 737 705 637 l 760 737 q 874 551 835 640 q 922 339 922 444 "},"^":{x_min:193.0625,x_max:598.609375,ha:792,o:"m 598 772 l 515 772 l 395 931 l 277 772 l 193 772 l 326 1013 l 462 1013 l 598 772 "},"«":{x_min:0,x_max:507.203125,ha:604,o:"m 506 136 l 284 302 l 284 440 l 506 608 l 507 485 l 360 371 l 506 255 l 506 136 m 222 136 l 0 302 l 0 440 l 222 608 l 221 486 l 73 373 l 222 256 l 222 136 "},D:{x_min:0,x_max:828,ha:935,o:"m 389 1013 q 714 867 593 1013 q 828 521 828 729 q 712 161 828 309 q 382 0 587 0 l 0 0 l 0 1013 l 389 1013 m 376 124 q 607 247 523 124 q 681 510 681 355 q 607 771 681 662 q 376 896 522 896 l 139 896 l 139 124 l 376 124 "},"∙":{x_min:0,x_max:142,ha:239,o:"m 142 585 l 0 585 l 0 738 l 142 738 l 142 585 "},"ÿ":{x_min:0,x_max:47,ha:125,o:"m 47 3 q 37 -7 47 -7 q 28 0 30 -7 q 39 -4 32 -4 q 45 3 45 -1 l 37 0 q 28 9 28 0 q 39 19 28 19 l 47 16 l 47 19 l 47 3 m 37 1 q 44 8 44 1 q 37 16 44 16 q 30 8 30 16 q 37 1 30 1 m 26 1 l 23 22 l 14 0 l 3 22 l 3 3 l 0 25 l 13 1 l 22 25 l 26 1 "},w:{x_min:0,x_max:1009.71875,ha:1100,o:"m 1009 738 l 783 0 l 658 0 l 501 567 l 345 0 l 222 0 l 0 738 l 130 738 l 284 174 l 432 737 l 576 738 l 721 173 l 881 737 l 1009 738 "},"$":{x_min:0,x_max:700,ha:793,o:"m 664 717 l 542 717 q 490 825 531 785 q 381 872 450 865 l 381 551 q 620 446 540 522 q 700 241 700 370 q 618 45 700 116 q 381 -25 536 -25 l 381 -152 l 307 -152 l 307 -25 q 81 62 162 -25 q 0 297 0 149 l 124 297 q 169 146 124 204 q 307 81 215 89 l 307 441 q 80 536 148 469 q 13 725 13 603 q 96 910 13 839 q 307 982 180 982 l 307 1077 l 381 1077 l 381 982 q 574 917 494 982 q 664 717 664 845 m 307 565 l 307 872 q 187 831 233 872 q 142 724 142 791 q 180 618 142 656 q 307 565 218 580 m 381 76 q 562 237 562 96 q 517 361 562 313 q 381 423 472 409 l 381 76 "},"\\":{x_min:-0.015625,x_max:425.0625,ha:522,o:"m 425 -129 l 337 -129 l 0 1041 l 83 1041 l 425 -129 "},"µ":{x_min:0,x_max:697.21875,ha:747,o:"m 697 -4 q 629 -14 658 -14 q 498 97 513 -14 q 422 9 470 41 q 313 -23 374 -23 q 207 4 258 -23 q 119 81 156 32 l 119 -278 l 0 -278 l 0 738 l 124 738 l 124 343 q 165 173 124 246 q 308 83 216 83 q 452 178 402 83 q 493 359 493 255 l 493 738 l 617 738 l 617 214 q 623 136 617 160 q 673 92 637 92 q 697 96 684 92 l 697 -4 "},"Ι":{x_min:42,x_max:181,ha:297,o:"m 181 0 l 42 0 l 42 1013 l 181 1013 l 181 0 "},"ÎŽ":{x_min:0,x_max:1144.5,ha:1214,o:"m 1144 1012 l 807 416 l 807 0 l 667 0 l 667 416 l 325 1012 l 465 1012 l 736 533 l 1004 1012 l 1144 1012 m 277 1040 l 83 799 l 0 799 l 140 1040 l 277 1040 "},"’":{x_min:0,x_max:139,ha:236,o:"m 139 851 q 102 737 139 784 q 0 669 65 690 l 0 734 q 59 787 42 741 q 72 873 72 821 l 0 873 l 0 1013 l 139 1013 l 139 851 "},"Î":{x_min:0,x_max:801,ha:915,o:"m 801 0 l 651 0 l 131 822 l 131 0 l 0 0 l 0 1013 l 151 1013 l 670 191 l 670 1013 l 801 1013 l 801 0 "},"-":{x_min:8.71875,x_max:350.390625,ha:478,o:"m 350 317 l 8 317 l 8 428 l 350 428 l 350 317 "},Q:{x_min:0,x_max:968,ha:1072,o:"m 954 5 l 887 -79 l 744 35 q 622 -11 687 2 q 483 -26 556 -26 q 127 130 262 -26 q 0 504 0 279 q 127 880 0 728 q 484 1041 262 1041 q 841 884 708 1041 q 968 507 968 735 q 933 293 968 398 q 832 104 899 188 l 954 5 m 723 191 q 802 330 777 248 q 828 499 828 412 q 744 790 828 673 q 483 922 650 922 q 228 791 322 922 q 142 505 142 673 q 227 221 142 337 q 487 91 323 91 q 632 123 566 91 l 520 215 l 587 301 l 723 191 "},"Ï‚":{x_min:1,x_max:676.28125,ha:740,o:"m 676 460 l 551 460 q 498 595 542 546 q 365 651 448 651 q 199 578 263 651 q 136 401 136 505 q 266 178 136 241 q 508 106 387 142 q 640 -50 640 62 q 625 -158 640 -105 q 583 -278 611 -211 l 465 -278 q 498 -182 490 -211 q 515 -80 515 -126 q 381 12 515 -15 q 134 91 197 51 q 1 388 1 179 q 100 651 1 542 q 354 761 199 761 q 587 680 498 761 q 676 460 676 599 "},M:{x_min:0,x_max:954,ha:1067,o:"m 954 0 l 819 0 l 819 869 l 537 0 l 405 0 l 128 866 l 128 0 l 0 0 l 0 1013 l 200 1013 l 472 160 l 757 1013 l 954 1013 l 954 0 "},"Ψ":{x_min:0,x_max:1006,ha:1094,o:"m 1006 678 q 914 319 1006 429 q 571 200 814 200 l 571 0 l 433 0 l 433 200 q 92 319 194 200 q 0 678 0 429 l 0 1013 l 139 1013 l 139 679 q 191 417 139 492 q 433 326 255 326 l 433 1013 l 571 1013 l 571 326 l 580 326 q 813 423 747 326 q 868 679 868 502 l 868 1013 l 1006 1013 l 1006 678 "},C:{x_min:0,x_max:886,ha:944,o:"m 886 379 q 760 87 886 201 q 455 -26 634 -26 q 112 136 236 -26 q 0 509 0 283 q 118 882 0 737 q 469 1041 245 1041 q 748 955 630 1041 q 879 708 879 859 l 745 708 q 649 862 724 805 q 473 920 573 920 q 219 791 312 920 q 136 509 136 675 q 217 229 136 344 q 470 99 311 99 q 672 179 591 99 q 753 379 753 259 l 886 379 "},"!":{x_min:0,x_max:138,ha:236,o:"m 138 684 q 116 409 138 629 q 105 244 105 299 l 33 244 q 16 465 33 313 q 0 684 0 616 l 0 1013 l 138 1013 l 138 684 m 138 0 l 0 0 l 0 151 l 138 151 l 138 0 "},"{":{x_min:0,x_max:480.5625,ha:578,o:"m 480 -286 q 237 -213 303 -286 q 187 -45 187 -159 q 194 48 187 -15 q 201 141 201 112 q 164 264 201 225 q 0 314 118 314 l 0 417 q 164 471 119 417 q 201 605 201 514 q 199 665 201 644 q 193 772 193 769 q 241 941 193 887 q 480 1015 308 1015 l 480 915 q 336 866 375 915 q 306 742 306 828 q 310 662 306 717 q 314 577 314 606 q 288 452 314 500 q 176 365 256 391 q 289 275 257 337 q 314 143 314 226 q 313 84 314 107 q 310 -11 310 -5 q 339 -131 310 -94 q 480 -182 377 -182 l 480 -286 "},X:{x_min:-0.015625,x_max:854.15625,ha:940,o:"m 854 0 l 683 0 l 423 409 l 166 0 l 0 0 l 347 519 l 18 1013 l 186 1013 l 428 637 l 675 1013 l 836 1013 l 504 520 l 854 0 "},"#":{x_min:0,x_max:963.890625,ha:1061,o:"m 963 690 l 927 590 l 719 590 l 655 410 l 876 410 l 840 310 l 618 310 l 508 -3 l 393 -2 l 506 309 l 329 310 l 215 -2 l 102 -3 l 212 310 l 0 310 l 36 410 l 248 409 l 312 590 l 86 590 l 120 690 l 347 690 l 459 1006 l 573 1006 l 462 690 l 640 690 l 751 1006 l 865 1006 l 754 690 l 963 690 m 606 590 l 425 590 l 362 410 l 543 410 l 606 590 "},"ι":{x_min:42,x_max:284,ha:361,o:"m 284 3 q 233 -10 258 -5 q 182 -15 207 -15 q 85 26 119 -15 q 42 200 42 79 l 42 738 l 167 738 l 168 215 q 172 141 168 157 q 226 101 183 101 q 248 103 239 101 q 284 112 257 104 l 284 3 "},"Ά":{x_min:0,x_max:906.953125,ha:982,o:"m 283 1040 l 88 799 l 5 799 l 145 1040 l 283 1040 m 906 0 l 756 0 l 650 303 l 251 303 l 143 0 l 0 0 l 376 1012 l 529 1012 l 906 0 m 609 421 l 452 866 l 293 421 l 609 421 "},")":{x_min:0,x_max:318,ha:415,o:"m 318 365 q 257 25 318 191 q 87 -290 197 -141 l 0 -290 q 140 21 93 -128 q 193 360 193 189 q 141 704 193 537 q 0 1024 97 850 l 87 1024 q 257 706 197 871 q 318 365 318 542 "},"ε":{x_min:0,x_max:634.71875,ha:714,o:"m 634 234 q 527 38 634 110 q 300 -25 433 -25 q 98 29 183 -25 q 0 204 0 93 q 37 314 0 265 q 128 390 67 353 q 56 460 82 419 q 26 555 26 505 q 114 712 26 654 q 295 763 191 763 q 499 700 416 763 q 589 515 589 631 l 478 515 q 419 618 464 580 q 307 657 374 657 q 207 630 253 657 q 151 547 151 598 q 238 445 151 469 q 389 434 280 434 l 389 331 l 349 331 q 206 315 255 331 q 125 210 125 287 q 183 107 125 145 q 302 76 233 76 q 436 117 379 76 q 509 234 493 159 l 634 234 "},"Δ":{x_min:0,x_max:952.78125,ha:1028,o:"m 952 0 l 0 0 l 400 1013 l 551 1013 l 952 0 m 762 124 l 476 867 l 187 124 l 762 124 "},"}":{x_min:0,x_max:481,ha:578,o:"m 481 314 q 318 262 364 314 q 282 136 282 222 q 284 65 282 97 q 293 -58 293 -48 q 241 -217 293 -166 q 0 -286 174 -286 l 0 -182 q 143 -130 105 -182 q 171 -2 171 -93 q 168 81 171 22 q 165 144 165 140 q 188 275 165 229 q 306 365 220 339 q 191 455 224 391 q 165 588 165 505 q 168 681 165 624 q 171 742 171 737 q 141 865 171 827 q 0 915 102 915 l 0 1015 q 243 942 176 1015 q 293 773 293 888 q 287 675 293 741 q 282 590 282 608 q 318 466 282 505 q 481 417 364 417 l 481 314 "},"‰":{x_min:-3,x_max:1672,ha:1821,o:"m 846 0 q 664 76 732 0 q 603 244 603 145 q 662 412 603 344 q 846 489 729 489 q 1027 412 959 489 q 1089 244 1089 343 q 1029 76 1089 144 q 846 0 962 0 m 845 103 q 945 143 910 103 q 981 243 981 184 q 947 340 981 301 q 845 385 910 385 q 745 342 782 385 q 709 243 709 300 q 742 147 709 186 q 845 103 781 103 m 888 986 l 284 -25 l 199 -25 l 803 986 l 888 986 m 241 468 q 58 545 126 468 q -3 715 -3 615 q 56 881 -3 813 q 238 958 124 958 q 421 881 353 958 q 483 712 483 813 q 423 544 483 612 q 241 468 356 468 m 241 855 q 137 811 175 855 q 100 710 100 768 q 136 612 100 653 q 240 572 172 572 q 344 614 306 572 q 382 713 382 656 q 347 810 382 771 q 241 855 308 855 m 1428 0 q 1246 76 1314 0 q 1185 244 1185 145 q 1244 412 1185 344 q 1428 489 1311 489 q 1610 412 1542 489 q 1672 244 1672 343 q 1612 76 1672 144 q 1428 0 1545 0 m 1427 103 q 1528 143 1492 103 q 1564 243 1564 184 q 1530 340 1564 301 q 1427 385 1492 385 q 1327 342 1364 385 q 1291 243 1291 300 q 1324 147 1291 186 q 1427 103 1363 103 "},a:{x_min:0,x_max:698.609375,ha:794,o:"m 698 0 q 661 -12 679 -7 q 615 -17 643 -17 q 536 12 564 -17 q 500 96 508 41 q 384 6 456 37 q 236 -25 312 -25 q 65 31 130 -25 q 0 194 0 88 q 118 390 0 334 q 328 435 180 420 q 488 483 476 451 q 495 523 495 504 q 442 619 495 584 q 325 654 389 654 q 209 617 257 654 q 152 513 161 580 l 33 513 q 123 705 33 633 q 332 772 207 772 q 528 712 448 772 q 617 531 617 645 l 617 163 q 624 108 617 126 q 664 90 632 90 l 698 94 l 698 0 m 491 262 l 491 372 q 272 329 350 347 q 128 201 128 294 q 166 113 128 144 q 264 83 205 83 q 414 130 346 83 q 491 262 491 183 "},"—":{x_min:0,x_max:941.671875,ha:1039,o:"m 941 334 l 0 334 l 0 410 l 941 410 l 941 334 "},"=":{x_min:8.71875,x_max:780.953125,ha:792,o:"m 780 510 l 8 510 l 8 606 l 780 606 l 780 510 m 780 235 l 8 235 l 8 332 l 780 332 l 780 235 "},N:{x_min:0,x_max:801,ha:914,o:"m 801 0 l 651 0 l 131 823 l 131 0 l 0 0 l 0 1013 l 151 1013 l 670 193 l 670 1013 l 801 1013 l 801 0 "},"Ï":{x_min:0,x_max:712,ha:797,o:"m 712 369 q 620 94 712 207 q 362 -26 521 -26 q 230 2 292 -26 q 119 83 167 30 l 119 -278 l 0 -278 l 0 362 q 91 643 0 531 q 355 764 190 764 q 617 647 517 764 q 712 369 712 536 m 583 366 q 530 559 583 480 q 359 651 469 651 q 190 562 252 651 q 135 370 135 483 q 189 176 135 257 q 359 85 250 85 q 528 175 466 85 q 583 366 583 254 "},"2":{x_min:59,x_max:731,ha:792,o:"m 731 0 l 59 0 q 197 314 59 188 q 457 487 199 315 q 598 691 598 580 q 543 819 598 772 q 411 867 488 867 q 272 811 328 867 q 209 630 209 747 l 81 630 q 182 901 81 805 q 408 986 271 986 q 629 909 536 986 q 731 694 731 826 q 613 449 731 541 q 378 316 495 383 q 201 122 235 234 l 731 122 l 731 0 "},"¯":{x_min:0,x_max:941.671875,ha:938,o:"m 941 1033 l 0 1033 l 0 1109 l 941 1109 l 941 1033 "},Z:{x_min:0,x_max:779,ha:849,o:"m 779 0 l 0 0 l 0 113 l 621 896 l 40 896 l 40 1013 l 779 1013 l 778 887 l 171 124 l 779 124 l 779 0 "},u:{x_min:0,x_max:617,ha:729,o:"m 617 0 l 499 0 l 499 110 q 391 10 460 45 q 246 -25 322 -25 q 61 58 127 -25 q 0 258 0 136 l 0 738 l 125 738 l 125 284 q 156 148 125 202 q 273 82 197 82 q 433 165 369 82 q 493 340 493 243 l 493 738 l 617 738 l 617 0 "},k:{x_min:0,x_max:612.484375,ha:697,o:"m 612 738 l 338 465 l 608 0 l 469 0 l 251 382 l 121 251 l 121 0 l 0 0 l 0 1013 l 121 1013 l 121 402 l 456 738 l 612 738 "},"Η":{x_min:0,x_max:803,ha:917,o:"m 803 0 l 667 0 l 667 475 l 140 475 l 140 0 l 0 0 l 0 1013 l 140 1013 l 140 599 l 667 599 l 667 1013 l 803 1013 l 803 0 "},"Α":{x_min:0,x_max:906.953125,ha:985,o:"m 906 0 l 756 0 l 650 303 l 251 303 l 143 0 l 0 0 l 376 1013 l 529 1013 l 906 0 m 609 421 l 452 866 l 293 421 l 609 421 "},s:{x_min:0,x_max:604,ha:697,o:"m 604 217 q 501 36 604 104 q 292 -23 411 -23 q 86 43 166 -23 q 0 238 0 114 l 121 237 q 175 122 121 164 q 300 85 223 85 q 415 112 363 85 q 479 207 479 147 q 361 309 479 276 q 140 372 141 370 q 21 544 21 426 q 111 708 21 647 q 298 761 190 761 q 492 705 413 761 q 583 531 583 643 l 462 531 q 412 625 462 594 q 298 657 363 657 q 199 636 242 657 q 143 558 143 608 q 262 454 143 486 q 484 394 479 397 q 604 217 604 341 "},B:{x_min:0,x_max:778,ha:876,o:"m 580 546 q 724 469 670 535 q 778 311 778 403 q 673 83 778 171 q 432 0 575 0 l 0 0 l 0 1013 l 411 1013 q 629 957 541 1013 q 732 768 732 892 q 691 633 732 693 q 580 546 650 572 m 393 899 l 139 899 l 139 588 l 379 588 q 521 624 462 588 q 592 744 592 667 q 531 859 592 819 q 393 899 471 899 m 419 124 q 566 169 504 124 q 635 303 635 219 q 559 436 635 389 q 402 477 494 477 l 139 477 l 139 124 l 419 124 "},"…":{x_min:0,x_max:614,ha:708,o:"m 142 0 l 0 0 l 0 151 l 142 151 l 142 0 m 378 0 l 236 0 l 236 151 l 378 151 l 378 0 m 614 0 l 472 0 l 472 151 l 614 151 l 614 0 "},"?":{x_min:0,x_max:607,ha:704,o:"m 607 777 q 543 599 607 674 q 422 474 482 537 q 357 272 357 391 l 236 272 q 297 487 236 395 q 411 619 298 490 q 474 762 474 691 q 422 885 474 838 q 301 933 371 933 q 179 880 228 933 q 124 706 124 819 l 0 706 q 94 963 0 872 q 302 1044 177 1044 q 511 973 423 1044 q 607 777 607 895 m 370 0 l 230 0 l 230 151 l 370 151 l 370 0 "},H:{x_min:0,x_max:803,ha:915,o:"m 803 0 l 667 0 l 667 475 l 140 475 l 140 0 l 0 0 l 0 1013 l 140 1013 l 140 599 l 667 599 l 667 1013 l 803 1013 l 803 0 "},"ν":{x_min:0,x_max:675,ha:761,o:"m 675 738 l 404 0 l 272 0 l 0 738 l 133 738 l 340 147 l 541 738 l 675 738 "},c:{x_min:1,x_max:701.390625,ha:775,o:"m 701 264 q 584 53 681 133 q 353 -26 487 -26 q 91 91 188 -26 q 1 370 1 201 q 92 645 1 537 q 353 761 190 761 q 572 688 479 761 q 690 493 666 615 l 556 493 q 487 606 545 562 q 356 650 428 650 q 186 563 246 650 q 134 372 134 487 q 188 179 134 258 q 359 88 250 88 q 492 136 437 88 q 566 264 548 185 l 701 264 "},"¶":{x_min:0,x_max:566.671875,ha:678,o:"m 21 892 l 52 892 l 98 761 l 145 892 l 176 892 l 178 741 l 157 741 l 157 867 l 108 741 l 88 741 l 40 871 l 40 741 l 21 741 l 21 892 m 308 854 l 308 731 q 252 691 308 691 q 227 691 240 691 q 207 696 213 695 l 207 712 l 253 706 q 288 733 288 706 l 288 763 q 244 741 279 741 q 193 797 193 741 q 261 860 193 860 q 287 860 273 860 q 308 854 302 855 m 288 842 l 263 843 q 213 796 213 843 q 248 756 213 756 q 288 796 288 756 l 288 842 m 566 988 l 502 988 l 502 -1 l 439 -1 l 439 988 l 317 988 l 317 -1 l 252 -1 l 252 602 q 81 653 155 602 q 0 805 0 711 q 101 989 0 918 q 309 1053 194 1053 l 566 1053 l 566 988 "},"β":{x_min:0,x_max:660,ha:745,o:"m 471 550 q 610 450 561 522 q 660 280 660 378 q 578 64 660 151 q 367 -22 497 -22 q 239 5 299 -22 q 126 82 178 32 l 126 -278 l 0 -278 l 0 593 q 54 903 0 801 q 318 1042 127 1042 q 519 964 436 1042 q 603 771 603 887 q 567 644 603 701 q 471 550 532 586 m 337 79 q 476 138 418 79 q 535 279 535 198 q 427 437 535 386 q 226 477 344 477 l 226 583 q 398 620 329 583 q 486 762 486 668 q 435 884 486 833 q 312 935 384 935 q 169 861 219 935 q 126 698 126 797 l 126 362 q 170 169 126 242 q 337 79 224 79 "},"Îœ":{x_min:0,x_max:954,ha:1068,o:"m 954 0 l 819 0 l 819 868 l 537 0 l 405 0 l 128 865 l 128 0 l 0 0 l 0 1013 l 199 1013 l 472 158 l 758 1013 l 954 1013 l 954 0 "},"ÎŒ":{x_min:0.109375,x_max:1120,ha:1217,o:"m 1120 505 q 994 132 1120 282 q 642 -29 861 -29 q 290 130 422 -29 q 167 505 167 280 q 294 883 167 730 q 650 1046 430 1046 q 999 882 868 1046 q 1120 505 1120 730 m 977 504 q 896 784 977 669 q 644 915 804 915 q 391 785 484 915 q 307 504 307 669 q 391 224 307 339 q 644 95 486 95 q 894 224 803 95 q 977 504 977 339 m 277 1040 l 83 799 l 0 799 l 140 1040 l 277 1040 "},"Ή":{x_min:0,x_max:1158,ha:1275,o:"m 1158 0 l 1022 0 l 1022 475 l 496 475 l 496 0 l 356 0 l 356 1012 l 496 1012 l 496 599 l 1022 599 l 1022 1012 l 1158 1012 l 1158 0 m 277 1040 l 83 799 l 0 799 l 140 1040 l 277 1040 "},"•":{x_min:0,x_max:663.890625,ha:775,o:"m 663 529 q 566 293 663 391 q 331 196 469 196 q 97 294 194 196 q 0 529 0 393 q 96 763 0 665 q 331 861 193 861 q 566 763 469 861 q 663 529 663 665 "},"Â¥":{x_min:0.1875,x_max:819.546875,ha:886,o:"m 563 561 l 697 561 l 696 487 l 520 487 l 482 416 l 482 380 l 697 380 l 695 308 l 482 308 l 482 0 l 342 0 l 342 308 l 125 308 l 125 380 l 342 380 l 342 417 l 303 487 l 125 487 l 125 561 l 258 561 l 0 1013 l 140 1013 l 411 533 l 679 1013 l 819 1013 l 563 561 "},"(":{x_min:0,x_max:318.0625,ha:415,o:"m 318 -290 l 230 -290 q 61 23 122 -142 q 0 365 0 190 q 62 712 0 540 q 230 1024 119 869 l 318 1024 q 175 705 219 853 q 125 360 125 542 q 176 22 125 187 q 318 -290 223 -127 "},U:{x_min:0,x_max:796,ha:904,o:"m 796 393 q 681 93 796 212 q 386 -25 566 -25 q 101 95 208 -25 q 0 393 0 211 l 0 1013 l 138 1013 l 138 391 q 204 191 138 270 q 394 107 276 107 q 586 191 512 107 q 656 391 656 270 l 656 1013 l 796 1013 l 796 393 "},"γ":{x_min:0.5,x_max:744.953125,ha:822,o:"m 744 737 l 463 54 l 463 -278 l 338 -278 l 338 54 l 154 495 q 104 597 124 569 q 13 651 67 651 l 0 651 l 0 751 l 39 753 q 168 711 121 753 q 242 594 207 676 l 403 208 l 617 737 l 744 737 "},"α":{x_min:0,x_max:765.5625,ha:809,o:"m 765 -4 q 698 -14 726 -14 q 564 97 586 -14 q 466 7 525 40 q 337 -26 407 -26 q 88 98 186 -26 q 0 369 0 212 q 88 637 0 525 q 337 760 184 760 q 465 728 407 760 q 563 637 524 696 l 563 739 l 685 739 l 685 222 q 693 141 685 168 q 748 94 708 94 q 765 96 760 94 l 765 -4 m 584 371 q 531 562 584 485 q 360 653 470 653 q 192 566 254 653 q 135 379 135 489 q 186 181 135 261 q 358 84 247 84 q 528 176 465 84 q 584 371 584 260 "},F:{x_min:0,x_max:683.328125,ha:717,o:"m 683 888 l 140 888 l 140 583 l 613 583 l 613 458 l 140 458 l 140 0 l 0 0 l 0 1013 l 683 1013 l 683 888 "},"":{x_min:0,x_max:705.5625,ha:803,o:"m 705 334 l 0 334 l 0 410 l 705 410 l 705 334 "},":":{x_min:0,x_max:142,ha:239,o:"m 142 585 l 0 585 l 0 738 l 142 738 l 142 585 m 142 0 l 0 0 l 0 151 l 142 151 l 142 0 "},"Χ":{x_min:0,x_max:854.171875,ha:935,o:"m 854 0 l 683 0 l 423 409 l 166 0 l 0 0 l 347 519 l 18 1013 l 186 1013 l 427 637 l 675 1013 l 836 1013 l 504 521 l 854 0 "},"*":{x_min:116,x_max:674,ha:792,o:"m 674 768 l 475 713 l 610 544 l 517 477 l 394 652 l 272 478 l 178 544 l 314 713 l 116 766 l 153 876 l 341 812 l 342 1013 l 446 1013 l 446 811 l 635 874 l 674 768 "},"†":{x_min:0,x_max:777,ha:835,o:"m 458 804 l 777 804 l 777 683 l 458 683 l 458 0 l 319 0 l 319 681 l 0 683 l 0 804 l 319 804 l 319 1015 l 458 1013 l 458 804 "},"°":{x_min:0,x_max:347,ha:444,o:"m 173 802 q 43 856 91 802 q 0 977 0 905 q 45 1101 0 1049 q 173 1153 90 1153 q 303 1098 255 1153 q 347 977 347 1049 q 303 856 347 905 q 173 802 256 802 m 173 884 q 238 910 214 884 q 262 973 262 937 q 239 1038 262 1012 q 173 1064 217 1064 q 108 1037 132 1064 q 85 973 85 1010 q 108 910 85 937 q 173 884 132 884 "},V:{x_min:0,x_max:862.71875,ha:940,o:"m 862 1013 l 505 0 l 361 0 l 0 1013 l 143 1013 l 434 165 l 718 1012 l 862 1013 "},"Ξ":{x_min:0,x_max:734.71875,ha:763,o:"m 723 889 l 9 889 l 9 1013 l 723 1013 l 723 889 m 673 463 l 61 463 l 61 589 l 673 589 l 673 463 m 734 0 l 0 0 l 0 124 l 734 124 l 734 0 "}," ":{x_min:0,x_max:0,ha:853},"Ϋ":{x_min:0.328125,x_max:819.515625,ha:889,o:"m 588 1046 l 460 1046 l 460 1189 l 588 1189 l 588 1046 m 360 1046 l 232 1046 l 232 1189 l 360 1189 l 360 1046 m 819 1012 l 482 416 l 482 0 l 342 0 l 342 416 l 0 1012 l 140 1012 l 411 533 l 679 1012 l 819 1012 "},"0":{x_min:73,x_max:715,ha:792,o:"m 394 -29 q 153 129 242 -29 q 73 479 73 272 q 152 829 73 687 q 394 989 241 989 q 634 829 545 989 q 715 479 715 684 q 635 129 715 270 q 394 -29 546 -29 m 394 89 q 546 211 489 89 q 598 479 598 322 q 548 748 598 640 q 394 871 491 871 q 241 748 298 871 q 190 479 190 637 q 239 211 190 319 q 394 89 296 89 "},"â€":{x_min:0,x_max:347,ha:454,o:"m 139 851 q 102 737 139 784 q 0 669 65 690 l 0 734 q 59 787 42 741 q 72 873 72 821 l 0 873 l 0 1013 l 139 1013 l 139 851 m 347 851 q 310 737 347 784 q 208 669 273 690 l 208 734 q 267 787 250 741 q 280 873 280 821 l 208 873 l 208 1013 l 347 1013 l 347 851 "},"@":{x_min:0,x_max:1260,ha:1357,o:"m 1098 -45 q 877 -160 1001 -117 q 633 -203 752 -203 q 155 -29 327 -203 q 0 360 0 127 q 176 802 0 616 q 687 1008 372 1008 q 1123 854 969 1008 q 1260 517 1260 718 q 1155 216 1260 341 q 868 82 1044 82 q 772 106 801 82 q 737 202 737 135 q 647 113 700 144 q 527 82 594 82 q 367 147 420 82 q 314 312 314 212 q 401 565 314 452 q 639 690 498 690 q 810 588 760 690 l 849 668 l 938 668 q 877 441 900 532 q 833 226 833 268 q 853 182 833 198 q 902 167 873 167 q 1088 272 1012 167 q 1159 512 1159 372 q 1051 793 1159 681 q 687 925 925 925 q 248 747 415 925 q 97 361 97 586 q 226 26 97 159 q 627 -122 370 -122 q 856 -87 737 -122 q 1061 8 976 -53 l 1098 -45 m 786 488 q 738 580 777 545 q 643 615 700 615 q 483 517 548 615 q 425 322 425 430 q 457 203 425 250 q 552 156 490 156 q 722 273 665 156 q 786 488 738 309 "},"Ί":{x_min:0,x_max:499,ha:613,o:"m 277 1040 l 83 799 l 0 799 l 140 1040 l 277 1040 m 499 0 l 360 0 l 360 1012 l 499 1012 l 499 0 "},i:{x_min:14,x_max:136,ha:275,o:"m 136 873 l 14 873 l 14 1013 l 136 1013 l 136 873 m 136 0 l 14 0 l 14 737 l 136 737 l 136 0 "},"Î’":{x_min:0,x_max:778,ha:877,o:"m 580 545 q 724 468 671 534 q 778 310 778 402 q 673 83 778 170 q 432 0 575 0 l 0 0 l 0 1013 l 411 1013 q 629 957 541 1013 q 732 768 732 891 q 691 632 732 692 q 580 545 650 571 m 393 899 l 139 899 l 139 587 l 379 587 q 521 623 462 587 q 592 744 592 666 q 531 859 592 819 q 393 899 471 899 m 419 124 q 566 169 504 124 q 635 302 635 219 q 559 435 635 388 q 402 476 494 476 l 139 476 l 139 124 l 419 124 "},"Ï…":{x_min:0,x_max:617,ha:725,o:"m 617 352 q 540 94 617 199 q 308 -24 455 -24 q 76 94 161 -24 q 0 352 0 199 l 0 739 l 126 739 l 126 355 q 169 185 126 257 q 312 98 220 98 q 451 185 402 98 q 492 355 492 257 l 492 739 l 617 739 l 617 352 "},"]":{x_min:0,x_max:275,ha:372,o:"m 275 -281 l 0 -281 l 0 -187 l 151 -187 l 151 920 l 0 920 l 0 1013 l 275 1013 l 275 -281 "},m:{x_min:0,x_max:1019,ha:1128,o:"m 1019 0 l 897 0 l 897 454 q 860 591 897 536 q 739 660 816 660 q 613 586 659 660 q 573 436 573 522 l 573 0 l 447 0 l 447 455 q 412 591 447 535 q 294 657 372 657 q 165 586 213 657 q 122 437 122 521 l 122 0 l 0 0 l 0 738 l 117 738 l 117 640 q 202 730 150 697 q 316 763 254 763 q 437 730 381 763 q 525 642 494 697 q 621 731 559 700 q 753 763 682 763 q 943 694 867 763 q 1019 512 1019 625 l 1019 0 "},"χ":{x_min:8.328125,x_max:780.5625,ha:815,o:"m 780 -278 q 715 -294 747 -294 q 616 -257 663 -294 q 548 -175 576 -227 l 379 133 l 143 -277 l 9 -277 l 313 254 l 163 522 q 127 586 131 580 q 36 640 91 640 q 8 637 27 640 l 8 752 l 52 757 q 162 719 113 757 q 236 627 200 690 l 383 372 l 594 737 l 726 737 l 448 250 l 625 -69 q 670 -153 647 -110 q 743 -188 695 -188 q 780 -184 759 -188 l 780 -278 "},"8":{x_min:55,x_max:736,ha:792,o:"m 571 527 q 694 424 652 491 q 736 280 736 358 q 648 71 736 158 q 395 -26 551 -26 q 142 69 238 -26 q 55 279 55 157 q 96 425 55 359 q 220 527 138 491 q 120 615 153 562 q 88 726 88 668 q 171 904 88 827 q 395 986 261 986 q 618 905 529 986 q 702 727 702 830 q 670 616 702 667 q 571 527 638 565 m 394 565 q 519 610 475 565 q 563 717 563 655 q 521 823 563 781 q 392 872 474 872 q 265 824 312 872 q 224 720 224 783 q 265 613 224 656 q 394 565 312 565 m 395 91 q 545 150 488 91 q 597 280 597 204 q 546 408 597 355 q 395 465 492 465 q 244 408 299 465 q 194 280 194 356 q 244 150 194 203 q 395 91 299 91 "},"ί":{x_min:42,x_max:326.71875,ha:361,o:"m 284 3 q 233 -10 258 -5 q 182 -15 207 -15 q 85 26 119 -15 q 42 200 42 79 l 42 737 l 167 737 l 168 215 q 172 141 168 157 q 226 101 183 101 q 248 102 239 101 q 284 112 257 104 l 284 3 m 326 1040 l 137 819 l 54 819 l 189 1040 l 326 1040 "},"Ζ":{x_min:0,x_max:779.171875,ha:850,o:"m 779 0 l 0 0 l 0 113 l 620 896 l 40 896 l 40 1013 l 779 1013 l 779 887 l 170 124 l 779 124 l 779 0 "},R:{x_min:0,x_max:781.953125,ha:907,o:"m 781 0 l 623 0 q 587 242 590 52 q 407 433 585 433 l 138 433 l 138 0 l 0 0 l 0 1013 l 396 1013 q 636 946 539 1013 q 749 731 749 868 q 711 597 749 659 q 608 502 674 534 q 718 370 696 474 q 729 207 722 352 q 781 26 736 62 l 781 0 m 373 551 q 533 594 465 551 q 614 731 614 645 q 532 859 614 815 q 373 896 465 896 l 138 896 l 138 551 l 373 551 "},o:{x_min:0,x_max:713,ha:821,o:"m 357 -25 q 94 91 194 -25 q 0 368 0 202 q 93 642 0 533 q 357 761 193 761 q 618 644 518 761 q 713 368 713 533 q 619 91 713 201 q 357 -25 521 -25 m 357 85 q 528 175 465 85 q 584 369 584 255 q 529 562 584 484 q 357 651 467 651 q 189 560 250 651 q 135 369 135 481 q 187 177 135 257 q 357 85 250 85 "},"5":{x_min:54.171875,x_max:738,ha:792,o:"m 738 314 q 626 60 738 153 q 382 -23 526 -23 q 155 47 248 -23 q 54 256 54 125 l 183 256 q 259 132 204 174 q 382 91 314 91 q 533 149 471 91 q 602 314 602 213 q 538 469 602 411 q 386 528 475 528 q 284 506 332 528 q 197 439 237 484 l 81 439 l 159 958 l 684 958 l 684 840 l 254 840 l 214 579 q 306 627 258 612 q 407 643 354 643 q 636 552 540 643 q 738 314 738 457 "},"7":{x_min:58.71875,x_max:730.953125,ha:792,o:"m 730 839 q 469 448 560 641 q 335 0 378 255 l 192 0 q 328 441 235 252 q 593 830 421 630 l 58 830 l 58 958 l 730 958 l 730 839 "},K:{x_min:0,x_max:819.46875,ha:906,o:"m 819 0 l 649 0 l 294 509 l 139 355 l 139 0 l 0 0 l 0 1013 l 139 1013 l 139 526 l 626 1013 l 809 1013 l 395 600 l 819 0 "},",":{x_min:0,x_max:142,ha:239,o:"m 142 -12 q 105 -132 142 -82 q 0 -205 68 -182 l 0 -138 q 57 -82 40 -124 q 70 0 70 -51 l 0 0 l 0 151 l 142 151 l 142 -12 "},d:{x_min:0,x_max:683,ha:796,o:"m 683 0 l 564 0 l 564 93 q 456 6 516 38 q 327 -25 395 -25 q 87 100 181 -25 q 0 365 0 215 q 90 639 0 525 q 343 763 187 763 q 564 647 486 763 l 564 1013 l 683 1013 l 683 0 m 582 373 q 529 562 582 484 q 361 653 468 653 q 190 561 253 653 q 135 365 135 479 q 189 175 135 254 q 358 85 251 85 q 529 178 468 85 q 582 373 582 258 "},"¨":{x_min:-109,x_max:247,ha:232,o:"m 247 1046 l 119 1046 l 119 1189 l 247 1189 l 247 1046 m 19 1046 l -109 1046 l -109 1189 l 19 1189 l 19 1046 "},E:{x_min:0,x_max:736.109375,ha:789,o:"m 736 0 l 0 0 l 0 1013 l 725 1013 l 725 889 l 139 889 l 139 585 l 677 585 l 677 467 l 139 467 l 139 125 l 736 125 l 736 0 "},Y:{x_min:0,x_max:820,ha:886,o:"m 820 1013 l 482 416 l 482 0 l 342 0 l 342 416 l 0 1013 l 140 1013 l 411 534 l 679 1012 l 820 1013 "},'"':{x_min:0,x_max:299,ha:396,o:"m 299 606 l 203 606 l 203 988 l 299 988 l 299 606 m 96 606 l 0 606 l 0 988 l 96 988 l 96 606 "},"‹":{x_min:17.984375,x_max:773.609375,ha:792,o:"m 773 40 l 18 376 l 17 465 l 773 799 l 773 692 l 159 420 l 773 149 l 773 40 "},"„":{x_min:0,x_max:364,ha:467,o:"m 141 -12 q 104 -132 141 -82 q 0 -205 67 -182 l 0 -138 q 56 -82 40 -124 q 69 0 69 -51 l 0 0 l 0 151 l 141 151 l 141 -12 m 364 -12 q 327 -132 364 -82 q 222 -205 290 -182 l 222 -138 q 279 -82 262 -124 q 292 0 292 -51 l 222 0 l 222 151 l 364 151 l 364 -12 "},"δ":{x_min:1,x_max:710,ha:810,o:"m 710 360 q 616 87 710 196 q 356 -28 518 -28 q 99 82 197 -28 q 1 356 1 192 q 100 606 1 509 q 355 703 199 703 q 180 829 288 754 q 70 903 124 866 l 70 1012 l 643 1012 l 643 901 l 258 901 q 462 763 422 794 q 636 592 577 677 q 710 360 710 485 m 584 365 q 552 501 584 447 q 451 602 521 555 q 372 611 411 611 q 197 541 258 611 q 136 355 136 472 q 190 171 136 245 q 358 85 252 85 q 528 173 465 85 q 584 365 584 252 "},"Î":{x_min:0,x_max:634.71875,ha:714,o:"m 634 234 q 527 38 634 110 q 300 -25 433 -25 q 98 29 183 -25 q 0 204 0 93 q 37 313 0 265 q 128 390 67 352 q 56 459 82 419 q 26 555 26 505 q 114 712 26 654 q 295 763 191 763 q 499 700 416 763 q 589 515 589 631 l 478 515 q 419 618 464 580 q 307 657 374 657 q 207 630 253 657 q 151 547 151 598 q 238 445 151 469 q 389 434 280 434 l 389 331 l 349 331 q 206 315 255 331 q 125 210 125 287 q 183 107 125 145 q 302 76 233 76 q 436 117 379 76 q 509 234 493 159 l 634 234 m 520 1040 l 331 819 l 248 819 l 383 1040 l 520 1040 "},"ω":{x_min:0,x_max:922,ha:1031,o:"m 922 339 q 856 97 922 203 q 650 -26 780 -26 q 538 9 587 -26 q 461 103 489 44 q 387 12 436 46 q 277 -22 339 -22 q 69 97 147 -22 q 0 339 0 203 q 45 551 0 444 q 161 738 84 643 l 302 738 q 175 553 219 647 q 124 336 124 446 q 155 179 124 249 q 275 88 197 88 q 375 163 341 88 q 400 294 400 219 l 400 572 l 524 572 l 524 294 q 561 135 524 192 q 643 88 591 88 q 762 182 719 88 q 797 342 797 257 q 745 556 797 450 q 619 738 705 638 l 760 738 q 874 551 835 640 q 922 339 922 444 "},"´":{x_min:0,x_max:96,ha:251,o:"m 96 606 l 0 606 l 0 988 l 96 988 l 96 606 "},"±":{x_min:11,x_max:781,ha:792,o:"m 781 490 l 446 490 l 446 255 l 349 255 l 349 490 l 11 490 l 11 586 l 349 586 l 349 819 l 446 819 l 446 586 l 781 586 l 781 490 m 781 21 l 11 21 l 11 115 l 781 115 l 781 21 "},"|":{x_min:343,x_max:449,ha:792,o:"m 449 462 l 343 462 l 343 986 l 449 986 l 449 462 m 449 -242 l 343 -242 l 343 280 l 449 280 l 449 -242 "},"Ï‹":{x_min:0,x_max:617,ha:725,o:"m 482 800 l 372 800 l 372 925 l 482 925 l 482 800 m 239 800 l 129 800 l 129 925 l 239 925 l 239 800 m 617 352 q 540 93 617 199 q 308 -24 455 -24 q 76 93 161 -24 q 0 352 0 199 l 0 738 l 126 738 l 126 354 q 169 185 126 257 q 312 98 220 98 q 451 185 402 98 q 492 354 492 257 l 492 738 l 617 738 l 617 352 "},"§":{x_min:0,x_max:593,ha:690,o:"m 593 425 q 554 312 593 369 q 467 233 516 254 q 537 83 537 172 q 459 -74 537 -12 q 288 -133 387 -133 q 115 -69 184 -133 q 47 96 47 -6 l 166 96 q 199 7 166 40 q 288 -26 232 -26 q 371 -5 332 -26 q 420 60 420 21 q 311 201 420 139 q 108 309 210 255 q 0 490 0 383 q 33 602 0 551 q 124 687 66 654 q 75 743 93 712 q 58 812 58 773 q 133 984 58 920 q 300 1043 201 1043 q 458 987 394 1043 q 529 814 529 925 l 411 814 q 370 908 404 877 q 289 939 336 939 q 213 911 246 939 q 180 841 180 883 q 286 720 180 779 q 484 612 480 615 q 593 425 593 534 m 467 409 q 355 544 467 473 q 196 630 228 612 q 146 587 162 609 q 124 525 124 558 q 239 387 124 462 q 398 298 369 315 q 448 345 429 316 q 467 409 467 375 "},b:{x_min:0,x_max:685,ha:783,o:"m 685 372 q 597 99 685 213 q 347 -25 501 -25 q 219 5 277 -25 q 121 93 161 36 l 121 0 l 0 0 l 0 1013 l 121 1013 l 121 634 q 214 723 157 692 q 341 754 272 754 q 591 637 493 754 q 685 372 685 526 m 554 356 q 499 550 554 470 q 328 644 437 644 q 162 556 223 644 q 108 369 108 478 q 160 176 108 256 q 330 83 221 83 q 498 169 435 83 q 554 356 554 245 "},q:{x_min:0,x_max:683,ha:876,o:"m 683 -278 l 564 -278 l 564 97 q 474 8 533 39 q 345 -23 415 -23 q 91 93 188 -23 q 0 364 0 203 q 87 635 0 522 q 337 760 184 760 q 466 727 408 760 q 564 637 523 695 l 564 737 l 683 737 l 683 -278 m 582 375 q 527 564 582 488 q 358 652 466 652 q 190 565 253 652 q 135 377 135 488 q 189 179 135 261 q 361 84 251 84 q 530 179 469 84 q 582 375 582 260 "},"Ω":{x_min:-0.171875,x_max:969.5625,ha:1068,o:"m 969 0 l 555 0 l 555 123 q 744 308 675 194 q 814 558 814 423 q 726 812 814 709 q 484 922 633 922 q 244 820 334 922 q 154 567 154 719 q 223 316 154 433 q 412 123 292 199 l 412 0 l 0 0 l 0 124 l 217 124 q 68 327 122 210 q 15 572 15 444 q 144 911 15 781 q 484 1041 274 1041 q 822 909 691 1041 q 953 569 953 777 q 899 326 953 443 q 750 124 846 210 l 969 124 l 969 0 "},"Ï":{x_min:0,x_max:617,ha:725,o:"m 617 352 q 540 93 617 199 q 308 -24 455 -24 q 76 93 161 -24 q 0 352 0 199 l 0 738 l 126 738 l 126 354 q 169 185 126 257 q 312 98 220 98 q 451 185 402 98 q 492 354 492 257 l 492 738 l 617 738 l 617 352 m 535 1040 l 346 819 l 262 819 l 397 1040 l 535 1040 "},z:{x_min:-0.015625,x_max:613.890625,ha:697,o:"m 613 0 l 0 0 l 0 100 l 433 630 l 20 630 l 20 738 l 594 738 l 593 636 l 163 110 l 613 110 l 613 0 "},"â„¢":{x_min:0,x_max:894,ha:1000,o:"m 389 951 l 229 951 l 229 503 l 160 503 l 160 951 l 0 951 l 0 1011 l 389 1011 l 389 951 m 894 503 l 827 503 l 827 939 l 685 503 l 620 503 l 481 937 l 481 503 l 417 503 l 417 1011 l 517 1011 l 653 580 l 796 1010 l 894 1011 l 894 503 "},"ή":{x_min:0.78125,x_max:697,ha:810,o:"m 697 -278 l 572 -278 l 572 454 q 540 587 572 536 q 425 650 501 650 q 271 579 337 650 q 206 420 206 509 l 206 0 l 81 0 l 81 489 q 73 588 81 562 q 0 644 56 644 l 0 741 q 68 755 38 755 q 158 721 124 755 q 200 630 193 687 q 297 726 234 692 q 434 761 359 761 q 620 692 544 761 q 697 516 697 624 l 697 -278 m 479 1040 l 290 819 l 207 819 l 341 1040 l 479 1040 "},"Θ":{x_min:0,x_max:960,ha:1056,o:"m 960 507 q 833 129 960 280 q 476 -32 698 -32 q 123 129 255 -32 q 0 507 0 280 q 123 883 0 732 q 476 1045 255 1045 q 832 883 696 1045 q 960 507 960 732 m 817 500 q 733 789 817 669 q 476 924 639 924 q 223 792 317 924 q 142 507 142 675 q 222 222 142 339 q 476 89 315 89 q 730 218 636 89 q 817 500 817 334 m 716 449 l 243 449 l 243 571 l 716 571 l 716 449 "},"®":{x_min:-3,x_max:1008,ha:1106,o:"m 503 532 q 614 562 566 532 q 672 658 672 598 q 614 747 672 716 q 503 772 569 772 l 338 772 l 338 532 l 503 532 m 502 -7 q 123 151 263 -7 q -3 501 -3 294 q 123 851 -3 706 q 502 1011 263 1011 q 881 851 739 1011 q 1008 501 1008 708 q 883 151 1008 292 q 502 -7 744 -7 m 502 60 q 830 197 709 60 q 940 501 940 322 q 831 805 940 681 q 502 944 709 944 q 174 805 296 944 q 65 501 65 680 q 173 197 65 320 q 502 60 294 60 m 788 146 l 678 146 q 653 316 655 183 q 527 449 652 449 l 338 449 l 338 146 l 241 146 l 241 854 l 518 854 q 688 808 621 854 q 766 658 766 755 q 739 563 766 607 q 668 497 713 519 q 751 331 747 472 q 788 164 756 190 l 788 146 "},"~":{x_min:0,x_max:833,ha:931,o:"m 833 958 q 778 753 833 831 q 594 665 716 665 q 402 761 502 665 q 240 857 302 857 q 131 795 166 857 q 104 665 104 745 l 0 665 q 54 867 0 789 q 237 958 116 958 q 429 861 331 958 q 594 765 527 765 q 704 827 670 765 q 729 958 729 874 l 833 958 "},"Ε":{x_min:0,x_max:736.21875,ha:778,o:"m 736 0 l 0 0 l 0 1013 l 725 1013 l 725 889 l 139 889 l 139 585 l 677 585 l 677 467 l 139 467 l 139 125 l 736 125 l 736 0 "},"³":{x_min:0,x_max:450,ha:547,o:"m 450 552 q 379 413 450 464 q 220 366 313 366 q 69 414 130 366 q 0 567 0 470 l 85 567 q 126 470 85 504 q 225 437 168 437 q 320 467 280 437 q 360 552 360 498 q 318 632 360 608 q 213 657 276 657 q 195 657 203 657 q 176 657 181 657 l 176 722 q 279 733 249 722 q 334 815 334 752 q 300 881 334 856 q 220 907 267 907 q 133 875 169 907 q 97 781 97 844 l 15 781 q 78 926 15 875 q 220 972 135 972 q 364 930 303 972 q 426 817 426 888 q 344 697 426 733 q 421 642 392 681 q 450 552 450 603 "},"[":{x_min:0,x_max:273.609375,ha:371,o:"m 273 -281 l 0 -281 l 0 1013 l 273 1013 l 273 920 l 124 920 l 124 -187 l 273 -187 l 273 -281 "},L:{x_min:0,x_max:645.828125,ha:696,o:"m 645 0 l 0 0 l 0 1013 l 140 1013 l 140 126 l 645 126 l 645 0 "},"σ":{x_min:0,x_max:803.390625,ha:894,o:"m 803 628 l 633 628 q 713 368 713 512 q 618 93 713 204 q 357 -25 518 -25 q 94 91 194 -25 q 0 368 0 201 q 94 644 0 533 q 356 761 194 761 q 481 750 398 761 q 608 739 564 739 l 803 739 l 803 628 m 360 85 q 529 180 467 85 q 584 374 584 262 q 527 566 584 490 q 352 651 463 651 q 187 559 247 651 q 135 368 135 478 q 189 175 135 254 q 360 85 251 85 "},"ζ":{x_min:0,x_max:573,ha:642,o:"m 573 -40 q 553 -162 573 -97 q 510 -278 543 -193 l 400 -278 q 441 -187 428 -219 q 462 -90 462 -132 q 378 -14 462 -14 q 108 45 197 -14 q 0 290 0 117 q 108 631 0 462 q 353 901 194 767 l 55 901 l 55 1012 l 561 1012 l 561 924 q 261 669 382 831 q 128 301 128 489 q 243 117 128 149 q 458 98 350 108 q 573 -40 573 80 "},"θ":{x_min:0,x_max:674,ha:778,o:"m 674 496 q 601 160 674 304 q 336 -26 508 -26 q 73 153 165 -26 q 0 485 0 296 q 72 840 0 683 q 343 1045 166 1045 q 605 844 516 1045 q 674 496 674 692 m 546 579 q 498 798 546 691 q 336 935 437 935 q 178 798 237 935 q 126 579 137 701 l 546 579 m 546 475 l 126 475 q 170 233 126 348 q 338 80 230 80 q 504 233 447 80 q 546 475 546 346 "},"Ο":{x_min:0,x_max:958,ha:1054,o:"m 485 1042 q 834 883 703 1042 q 958 511 958 735 q 834 136 958 287 q 481 -26 701 -26 q 126 130 261 -26 q 0 504 0 279 q 127 880 0 729 q 485 1042 263 1042 m 480 98 q 731 225 638 98 q 815 504 815 340 q 733 783 815 670 q 480 913 640 913 q 226 785 321 913 q 142 504 142 671 q 226 224 142 339 q 480 98 319 98 "},"Γ":{x_min:0,x_max:705.28125,ha:749,o:"m 705 886 l 140 886 l 140 0 l 0 0 l 0 1012 l 705 1012 l 705 886 "}," ":{x_min:0,x_max:0,ha:375},"%":{x_min:-3,x_max:1089,ha:1186,o:"m 845 0 q 663 76 731 0 q 602 244 602 145 q 661 412 602 344 q 845 489 728 489 q 1027 412 959 489 q 1089 244 1089 343 q 1029 76 1089 144 q 845 0 962 0 m 844 103 q 945 143 909 103 q 981 243 981 184 q 947 340 981 301 q 844 385 909 385 q 744 342 781 385 q 708 243 708 300 q 741 147 708 186 q 844 103 780 103 m 888 986 l 284 -25 l 199 -25 l 803 986 l 888 986 m 241 468 q 58 545 126 468 q -3 715 -3 615 q 56 881 -3 813 q 238 958 124 958 q 421 881 353 958 q 483 712 483 813 q 423 544 483 612 q 241 468 356 468 m 241 855 q 137 811 175 855 q 100 710 100 768 q 136 612 100 653 q 240 572 172 572 q 344 614 306 572 q 382 713 382 656 q 347 810 382 771 q 241 855 308 855 "},P:{x_min:0,x_max:726,ha:806,o:"m 424 1013 q 640 931 555 1013 q 726 719 726 850 q 637 506 726 587 q 413 426 548 426 l 140 426 l 140 0 l 0 0 l 0 1013 l 424 1013 m 379 889 l 140 889 l 140 548 l 372 548 q 522 589 459 548 q 593 720 593 637 q 528 845 593 801 q 379 889 463 889 "},"Έ":{x_min:0,x_max:1078.21875,ha:1118,o:"m 1078 0 l 342 0 l 342 1013 l 1067 1013 l 1067 889 l 481 889 l 481 585 l 1019 585 l 1019 467 l 481 467 l 481 125 l 1078 125 l 1078 0 m 277 1040 l 83 799 l 0 799 l 140 1040 l 277 1040 "},"Î":{x_min:0.125,x_max:1136.546875,ha:1235,o:"m 1136 0 l 722 0 l 722 123 q 911 309 842 194 q 981 558 981 423 q 893 813 981 710 q 651 923 800 923 q 411 821 501 923 q 321 568 321 720 q 390 316 321 433 q 579 123 459 200 l 579 0 l 166 0 l 166 124 l 384 124 q 235 327 289 210 q 182 572 182 444 q 311 912 182 782 q 651 1042 441 1042 q 989 910 858 1042 q 1120 569 1120 778 q 1066 326 1120 443 q 917 124 1013 210 l 1136 124 l 1136 0 m 277 1040 l 83 800 l 0 800 l 140 1041 l 277 1040 "},_:{x_min:0,x_max:705.5625,ha:803,o:"m 705 -334 l 0 -334 l 0 -234 l 705 -234 l 705 -334 "},"Ϊ":{x_min:-110,x_max:246,ha:275,o:"m 246 1046 l 118 1046 l 118 1189 l 246 1189 l 246 1046 m 18 1046 l -110 1046 l -110 1189 l 18 1189 l 18 1046 m 136 0 l 0 0 l 0 1012 l 136 1012 l 136 0 "},"+":{x_min:23,x_max:768,ha:792,o:"m 768 372 l 444 372 l 444 0 l 347 0 l 347 372 l 23 372 l 23 468 l 347 468 l 347 840 l 444 840 l 444 468 l 768 468 l 768 372 "},"½":{x_min:0,x_max:1050,ha:1149,o:"m 1050 0 l 625 0 q 712 178 625 108 q 878 277 722 187 q 967 385 967 328 q 932 456 967 429 q 850 484 897 484 q 759 450 798 484 q 721 352 721 416 l 640 352 q 706 502 640 448 q 851 551 766 551 q 987 509 931 551 q 1050 385 1050 462 q 976 251 1050 301 q 829 179 902 215 q 717 68 740 133 l 1050 68 l 1050 0 m 834 985 l 215 -28 l 130 -28 l 750 984 l 834 985 m 224 422 l 142 422 l 142 811 l 0 811 l 0 867 q 104 889 62 867 q 164 973 157 916 l 224 973 l 224 422 "},"Ρ":{x_min:0,x_max:720,ha:783,o:"m 424 1013 q 637 933 554 1013 q 720 723 720 853 q 633 508 720 591 q 413 426 546 426 l 140 426 l 140 0 l 0 0 l 0 1013 l 424 1013 m 378 889 l 140 889 l 140 548 l 371 548 q 521 589 458 548 q 592 720 592 637 q 527 845 592 801 q 378 889 463 889 "},"'":{x_min:0,x_max:139,ha:236,o:"m 139 851 q 102 737 139 784 q 0 669 65 690 l 0 734 q 59 787 42 741 q 72 873 72 821 l 0 873 l 0 1013 l 139 1013 l 139 851 "},"ª":{x_min:0,x_max:350,ha:397,o:"m 350 625 q 307 616 328 616 q 266 631 281 616 q 247 673 251 645 q 190 628 225 644 q 116 613 156 613 q 32 641 64 613 q 0 722 0 669 q 72 826 0 800 q 247 866 159 846 l 247 887 q 220 934 247 916 q 162 953 194 953 q 104 934 129 953 q 76 882 80 915 l 16 882 q 60 976 16 941 q 166 1011 104 1011 q 266 979 224 1011 q 308 891 308 948 l 308 706 q 311 679 308 688 q 331 670 315 670 l 350 672 l 350 625 m 247 757 l 247 811 q 136 790 175 798 q 64 726 64 773 q 83 682 64 697 q 132 667 103 667 q 207 690 174 667 q 247 757 247 718 "},"Î…":{x_min:0,x_max:450,ha:553,o:"m 450 800 l 340 800 l 340 925 l 450 925 l 450 800 m 406 1040 l 212 800 l 129 800 l 269 1040 l 406 1040 m 110 800 l 0 800 l 0 925 l 110 925 l 110 800 "},T:{x_min:0,x_max:777,ha:835,o:"m 777 894 l 458 894 l 458 0 l 319 0 l 319 894 l 0 894 l 0 1013 l 777 1013 l 777 894 "},"Φ":{x_min:0,x_max:915,ha:997,o:"m 527 0 l 389 0 l 389 122 q 110 231 220 122 q 0 509 0 340 q 110 785 0 677 q 389 893 220 893 l 389 1013 l 527 1013 l 527 893 q 804 786 693 893 q 915 509 915 679 q 805 231 915 341 q 527 122 696 122 l 527 0 m 527 226 q 712 310 641 226 q 779 507 779 389 q 712 705 779 627 q 527 787 641 787 l 527 226 m 389 226 l 389 787 q 205 698 275 775 q 136 505 136 620 q 206 308 136 391 q 389 226 276 226 "},"â‹":{x_min:0,x_max:0,ha:694},j:{x_min:-77.78125,x_max:167,ha:349,o:"m 167 871 l 42 871 l 42 1013 l 167 1013 l 167 871 m 167 -80 q 121 -231 167 -184 q -26 -278 76 -278 l -77 -278 l -77 -164 l -41 -164 q 26 -143 11 -164 q 42 -65 42 -122 l 42 737 l 167 737 l 167 -80 "},"Σ":{x_min:0,x_max:756.953125,ha:819,o:"m 756 0 l 0 0 l 0 107 l 395 523 l 22 904 l 22 1013 l 745 1013 l 745 889 l 209 889 l 566 523 l 187 125 l 756 125 l 756 0 "},"1":{x_min:215.671875,x_max:574,ha:792,o:"m 574 0 l 442 0 l 442 697 l 215 697 l 215 796 q 386 833 330 796 q 475 986 447 875 l 574 986 l 574 0 "},"›":{x_min:18.0625,x_max:774,ha:792,o:"m 774 376 l 18 40 l 18 149 l 631 421 l 18 692 l 18 799 l 774 465 l 774 376 "},"<":{x_min:17.984375,x_max:773.609375,ha:792,o:"m 773 40 l 18 376 l 17 465 l 773 799 l 773 692 l 159 420 l 773 149 l 773 40 "},"£":{x_min:0,x_max:704.484375,ha:801,o:"m 704 41 q 623 -10 664 5 q 543 -26 583 -26 q 359 15 501 -26 q 243 36 288 36 q 158 23 197 36 q 73 -21 119 10 l 6 76 q 125 195 90 150 q 175 331 175 262 q 147 443 175 383 l 0 443 l 0 512 l 108 512 q 43 734 43 623 q 120 929 43 854 q 358 1010 204 1010 q 579 936 487 1010 q 678 729 678 857 l 678 684 l 552 684 q 504 838 552 780 q 362 896 457 896 q 216 852 263 896 q 176 747 176 815 q 199 627 176 697 q 248 512 217 574 l 468 512 l 468 443 l 279 443 q 297 356 297 398 q 230 194 297 279 q 153 107 211 170 q 227 133 190 125 q 293 142 264 142 q 410 119 339 142 q 516 96 482 96 q 579 105 550 96 q 648 142 608 115 l 704 41 "},t:{x_min:0,x_max:367,ha:458,o:"m 367 0 q 312 -5 339 -2 q 262 -8 284 -8 q 145 28 183 -8 q 108 143 108 64 l 108 638 l 0 638 l 0 738 l 108 738 l 108 944 l 232 944 l 232 738 l 367 738 l 367 638 l 232 638 l 232 185 q 248 121 232 140 q 307 102 264 102 q 345 104 330 102 q 367 107 360 107 l 367 0 "},"¬":{x_min:0,x_max:706,ha:803,o:"m 706 411 l 706 158 l 630 158 l 630 335 l 0 335 l 0 411 l 706 411 "},"λ":{x_min:0,x_max:750,ha:803,o:"m 750 -7 q 679 -15 716 -15 q 538 59 591 -15 q 466 214 512 97 l 336 551 l 126 0 l 0 0 l 270 705 q 223 837 247 770 q 116 899 190 899 q 90 898 100 899 l 90 1004 q 152 1011 125 1011 q 298 938 244 1011 q 373 783 326 901 l 605 192 q 649 115 629 136 q 716 95 669 95 l 736 95 q 750 97 745 97 l 750 -7 "},W:{x_min:0,x_max:1263.890625,ha:1351,o:"m 1263 1013 l 995 0 l 859 0 l 627 837 l 405 0 l 265 0 l 0 1013 l 136 1013 l 342 202 l 556 1013 l 701 1013 l 921 207 l 1133 1012 l 1263 1013 "},">":{x_min:18.0625,x_max:774,ha:792,o:"m 774 376 l 18 40 l 18 149 l 631 421 l 18 692 l 18 799 l 774 465 l 774 376 "},v:{x_min:0,x_max:675.15625,ha:761,o:"m 675 738 l 404 0 l 272 0 l 0 738 l 133 737 l 340 147 l 541 737 l 675 738 "},"Ï„":{x_min:0.28125,x_max:644.5,ha:703,o:"m 644 628 l 382 628 l 382 179 q 388 120 382 137 q 436 91 401 91 q 474 94 447 91 q 504 97 501 97 l 504 0 q 454 -9 482 -5 q 401 -14 426 -14 q 278 67 308 -14 q 260 233 260 118 l 260 628 l 0 628 l 0 739 l 644 739 l 644 628 "},"ξ":{x_min:0,x_max:624.9375,ha:699,o:"m 624 -37 q 608 -153 624 -96 q 563 -278 593 -211 l 454 -278 q 491 -183 486 -200 q 511 -83 511 -126 q 484 -23 511 -44 q 370 1 452 1 q 323 0 354 1 q 283 -1 293 -1 q 84 76 169 -1 q 0 266 0 154 q 56 431 0 358 q 197 538 108 498 q 94 613 134 562 q 54 730 54 665 q 77 823 54 780 q 143 901 101 867 l 27 901 l 27 1012 l 576 1012 l 576 901 l 380 901 q 244 863 303 901 q 178 745 178 820 q 312 600 178 636 q 532 582 380 582 l 532 479 q 276 455 361 479 q 118 281 118 410 q 165 173 118 217 q 274 120 208 133 q 494 101 384 110 q 624 -37 624 76 "},"&":{x_min:-3,x_max:894.25,ha:992,o:"m 894 0 l 725 0 l 624 123 q 471 0 553 40 q 306 -41 390 -41 q 168 -7 231 -41 q 62 92 105 26 q 14 187 31 139 q -3 276 -3 235 q 55 433 -3 358 q 248 581 114 508 q 170 689 196 640 q 137 817 137 751 q 214 985 137 922 q 384 1041 284 1041 q 548 988 483 1041 q 622 824 622 928 q 563 666 622 739 q 431 556 516 608 l 621 326 q 649 407 639 361 q 663 493 653 426 l 781 493 q 703 229 781 352 l 894 0 m 504 818 q 468 908 504 877 q 384 940 433 940 q 293 907 331 940 q 255 818 255 875 q 289 714 255 767 q 363 628 313 678 q 477 729 446 682 q 504 818 504 771 m 556 209 l 314 499 q 179 395 223 449 q 135 283 135 341 q 146 222 135 253 q 183 158 158 192 q 333 80 241 80 q 556 209 448 80 "},"Λ":{x_min:0,x_max:862.5,ha:942,o:"m 862 0 l 719 0 l 426 847 l 143 0 l 0 0 l 356 1013 l 501 1013 l 862 0 "},I:{x_min:41,x_max:180,ha:293,o:"m 180 0 l 41 0 l 41 1013 l 180 1013 l 180 0 "},G:{x_min:0,x_max:921,ha:1011,o:"m 921 0 l 832 0 l 801 136 q 655 15 741 58 q 470 -28 568 -28 q 126 133 259 -28 q 0 499 0 284 q 125 881 0 731 q 486 1043 259 1043 q 763 957 647 1043 q 905 709 890 864 l 772 709 q 668 866 747 807 q 486 926 589 926 q 228 795 322 926 q 142 507 142 677 q 228 224 142 342 q 483 94 323 94 q 712 195 625 94 q 796 435 796 291 l 477 435 l 477 549 l 921 549 l 921 0 "},"ΰ":{x_min:0,x_max:617,ha:725,o:"m 524 800 l 414 800 l 414 925 l 524 925 l 524 800 m 183 800 l 73 800 l 73 925 l 183 925 l 183 800 m 617 352 q 540 93 617 199 q 308 -24 455 -24 q 76 93 161 -24 q 0 352 0 199 l 0 738 l 126 738 l 126 354 q 169 185 126 257 q 312 98 220 98 q 451 185 402 98 q 492 354 492 257 l 492 738 l 617 738 l 617 352 m 489 1040 l 300 819 l 216 819 l 351 1040 l 489 1040 "},"`":{x_min:0,x_max:138.890625,ha:236,o:"m 138 699 l 0 699 l 0 861 q 36 974 0 929 q 138 1041 72 1020 l 138 977 q 82 931 95 969 q 69 839 69 893 l 138 839 l 138 699 "},"·":{x_min:0,x_max:142,ha:239,o:"m 142 585 l 0 585 l 0 738 l 142 738 l 142 585 "},"Î¥":{x_min:0.328125,x_max:819.515625,ha:889,o:"m 819 1013 l 482 416 l 482 0 l 342 0 l 342 416 l 0 1013 l 140 1013 l 411 533 l 679 1013 l 819 1013 "},r:{x_min:0,x_max:355.5625,ha:432,o:"m 355 621 l 343 621 q 179 569 236 621 q 122 411 122 518 l 122 0 l 0 0 l 0 737 l 117 737 l 117 604 q 204 719 146 686 q 355 753 262 753 l 355 621 "},x:{x_min:0,x_max:675,ha:764,o:"m 675 0 l 525 0 l 331 286 l 144 0 l 0 0 l 256 379 l 12 738 l 157 737 l 336 473 l 516 738 l 661 738 l 412 380 l 675 0 "},"μ":{x_min:0,x_max:696.609375,ha:747,o:"m 696 -4 q 628 -14 657 -14 q 498 97 513 -14 q 422 8 470 41 q 313 -24 374 -24 q 207 3 258 -24 q 120 80 157 31 l 120 -278 l 0 -278 l 0 738 l 124 738 l 124 343 q 165 172 124 246 q 308 82 216 82 q 451 177 402 82 q 492 358 492 254 l 492 738 l 616 738 l 616 214 q 623 136 616 160 q 673 92 636 92 q 696 95 684 92 l 696 -4 "},h:{x_min:0,x_max:615,ha:724,o:"m 615 472 l 615 0 l 490 0 l 490 454 q 456 590 490 535 q 338 654 416 654 q 186 588 251 654 q 122 436 122 522 l 122 0 l 0 0 l 0 1013 l 122 1013 l 122 633 q 218 727 149 694 q 362 760 287 760 q 552 676 484 760 q 615 472 615 600 "},".":{x_min:0,x_max:142,ha:239,o:"m 142 0 l 0 0 l 0 151 l 142 151 l 142 0 "},"φ":{x_min:-2,x_max:878,ha:974,o:"m 496 -279 l 378 -279 l 378 -17 q 101 88 204 -17 q -2 367 -2 194 q 68 626 -2 510 q 283 758 151 758 l 283 646 q 167 537 209 626 q 133 373 133 462 q 192 177 133 254 q 378 93 259 93 l 378 758 q 445 764 426 763 q 476 765 464 765 q 765 659 653 765 q 878 377 878 553 q 771 96 878 209 q 496 -17 665 -17 l 496 -279 m 496 93 l 514 93 q 687 183 623 93 q 746 380 746 265 q 691 569 746 491 q 522 658 629 658 l 496 656 l 496 93 "},";":{x_min:0,x_max:142,ha:239,o:"m 142 585 l 0 585 l 0 738 l 142 738 l 142 585 m 142 -12 q 105 -132 142 -82 q 0 -206 68 -182 l 0 -138 q 58 -82 43 -123 q 68 0 68 -56 l 0 0 l 0 151 l 142 151 l 142 -12 "},f:{x_min:0,x_max:378,ha:472,o:"m 378 638 l 246 638 l 246 0 l 121 0 l 121 638 l 0 638 l 0 738 l 121 738 q 137 935 121 887 q 290 1028 171 1028 q 320 1027 305 1028 q 378 1021 334 1026 l 378 908 q 323 918 346 918 q 257 870 273 918 q 246 780 246 840 l 246 738 l 378 738 l 378 638 "},"“":{x_min:1,x_max:348.21875,ha:454,o:"m 140 670 l 1 670 l 1 830 q 37 943 1 897 q 140 1011 74 990 l 140 947 q 82 900 97 940 q 68 810 68 861 l 140 810 l 140 670 m 348 670 l 209 670 l 209 830 q 245 943 209 897 q 348 1011 282 990 l 348 947 q 290 900 305 940 q 276 810 276 861 l 348 810 l 348 670 "},A:{x_min:0.03125,x_max:906.953125,ha:1008,o:"m 906 0 l 756 0 l 648 303 l 251 303 l 142 0 l 0 0 l 376 1013 l 529 1013 l 906 0 m 610 421 l 452 867 l 293 421 l 610 421 "},"6":{x_min:53,x_max:739,ha:792,o:"m 739 312 q 633 62 739 162 q 400 -31 534 -31 q 162 78 257 -31 q 53 439 53 206 q 178 859 53 712 q 441 986 284 986 q 643 912 559 986 q 732 713 732 833 l 601 713 q 544 830 594 786 q 426 875 494 875 q 268 793 331 875 q 193 517 193 697 q 301 597 240 570 q 427 624 362 624 q 643 540 552 624 q 739 312 739 451 m 603 298 q 540 461 603 400 q 404 516 484 516 q 268 461 323 516 q 207 300 207 401 q 269 137 207 198 q 405 83 325 83 q 541 137 486 83 q 603 298 603 197 "},"‘":{x_min:1,x_max:139.890625,ha:236,o:"m 139 670 l 1 670 l 1 830 q 37 943 1 897 q 139 1011 74 990 l 139 947 q 82 900 97 940 q 68 810 68 861 l 139 810 l 139 670 "},"ÏŠ":{x_min:-70,x_max:283,ha:361,o:"m 283 800 l 173 800 l 173 925 l 283 925 l 283 800 m 40 800 l -70 800 l -70 925 l 40 925 l 40 800 m 283 3 q 232 -10 257 -5 q 181 -15 206 -15 q 84 26 118 -15 q 41 200 41 79 l 41 737 l 166 737 l 167 215 q 171 141 167 157 q 225 101 182 101 q 247 103 238 101 q 283 112 256 104 l 283 3 "},"Ï€":{x_min:-0.21875,x_max:773.21875,ha:857,o:"m 773 -7 l 707 -11 q 575 40 607 -11 q 552 174 552 77 l 552 226 l 552 626 l 222 626 l 222 0 l 97 0 l 97 626 l 0 626 l 0 737 l 773 737 l 773 626 l 676 626 l 676 171 q 695 103 676 117 q 773 90 714 90 l 773 -7 "},"ά":{x_min:0,x_max:765.5625,ha:809,o:"m 765 -4 q 698 -14 726 -14 q 564 97 586 -14 q 466 7 525 40 q 337 -26 407 -26 q 88 98 186 -26 q 0 369 0 212 q 88 637 0 525 q 337 760 184 760 q 465 727 407 760 q 563 637 524 695 l 563 738 l 685 738 l 685 222 q 693 141 685 168 q 748 94 708 94 q 765 95 760 94 l 765 -4 m 584 371 q 531 562 584 485 q 360 653 470 653 q 192 566 254 653 q 135 379 135 489 q 186 181 135 261 q 358 84 247 84 q 528 176 465 84 q 584 371 584 260 m 604 1040 l 415 819 l 332 819 l 466 1040 l 604 1040 "},O:{x_min:0,x_max:958,ha:1057,o:"m 485 1041 q 834 882 702 1041 q 958 512 958 734 q 834 136 958 287 q 481 -26 702 -26 q 126 130 261 -26 q 0 504 0 279 q 127 880 0 728 q 485 1041 263 1041 m 480 98 q 731 225 638 98 q 815 504 815 340 q 733 783 815 669 q 480 912 640 912 q 226 784 321 912 q 142 504 142 670 q 226 224 142 339 q 480 98 319 98 "},n:{x_min:0,x_max:615,ha:724,o:"m 615 463 l 615 0 l 490 0 l 490 454 q 453 592 490 537 q 331 656 410 656 q 178 585 240 656 q 117 421 117 514 l 117 0 l 0 0 l 0 738 l 117 738 l 117 630 q 218 728 150 693 q 359 764 286 764 q 552 675 484 764 q 615 463 615 593 "},"3":{x_min:54,x_max:737,ha:792,o:"m 737 284 q 635 55 737 141 q 399 -25 541 -25 q 156 52 248 -25 q 54 308 54 140 l 185 308 q 245 147 185 202 q 395 96 302 96 q 539 140 484 96 q 602 280 602 190 q 510 429 602 390 q 324 454 451 454 l 324 565 q 487 584 441 565 q 565 719 565 617 q 515 835 565 791 q 395 879 466 879 q 255 824 307 879 q 203 661 203 769 l 78 661 q 166 909 78 822 q 387 992 250 992 q 603 921 513 992 q 701 723 701 844 q 669 607 701 656 q 578 524 637 558 q 696 434 655 499 q 737 284 737 369 "},"9":{x_min:53,x_max:739,ha:792,o:"m 739 524 q 619 94 739 241 q 362 -32 516 -32 q 150 47 242 -32 q 59 244 59 126 l 191 244 q 246 129 191 176 q 373 82 301 82 q 526 161 466 82 q 597 440 597 255 q 363 334 501 334 q 130 432 216 334 q 53 650 53 521 q 134 880 53 786 q 383 986 226 986 q 659 841 566 986 q 739 524 739 719 m 388 449 q 535 514 480 449 q 585 658 585 573 q 535 805 585 744 q 388 873 480 873 q 242 809 294 873 q 191 658 191 745 q 239 514 191 572 q 388 449 292 449 "},l:{x_min:41,x_max:166,ha:279,o:"m 166 0 l 41 0 l 41 1013 l 166 1013 l 166 0 "},"¤":{x_min:40.09375,x_max:728.796875,ha:825,o:"m 728 304 l 649 224 l 512 363 q 383 331 458 331 q 256 363 310 331 l 119 224 l 40 304 l 177 441 q 150 553 150 493 q 184 673 150 621 l 40 818 l 119 898 l 267 749 q 321 766 291 759 q 384 773 351 773 q 447 766 417 773 q 501 749 477 759 l 649 898 l 728 818 l 585 675 q 612 618 604 648 q 621 553 621 587 q 591 441 621 491 l 728 304 m 384 682 q 280 643 318 682 q 243 551 243 604 q 279 461 243 499 q 383 423 316 423 q 487 461 449 423 q 525 553 525 500 q 490 641 525 605 q 384 682 451 682 "},"κ":{x_min:0,x_max:632.328125,ha:679,o:"m 632 0 l 482 0 l 225 384 l 124 288 l 124 0 l 0 0 l 0 738 l 124 738 l 124 446 l 433 738 l 596 738 l 312 466 l 632 0 "},"4":{x_min:48,x_max:742.453125,ha:792,o:"m 742 243 l 602 243 l 602 0 l 476 0 l 476 243 l 48 243 l 48 368 l 476 958 l 602 958 l 602 354 l 742 354 l 742 243 m 476 354 l 476 792 l 162 354 l 476 354 "},p:{x_min:0,x_max:685,ha:786,o:"m 685 364 q 598 96 685 205 q 350 -23 504 -23 q 121 89 205 -23 l 121 -278 l 0 -278 l 0 738 l 121 738 l 121 633 q 220 726 159 691 q 351 761 280 761 q 598 636 504 761 q 685 364 685 522 m 557 371 q 501 560 557 481 q 330 651 437 651 q 162 559 223 651 q 108 366 108 479 q 162 177 108 254 q 333 87 224 87 q 502 178 441 87 q 557 371 557 258 "},"‡":{x_min:0,x_max:777,ha:835,o:"m 458 238 l 458 0 l 319 0 l 319 238 l 0 238 l 0 360 l 319 360 l 319 681 l 0 683 l 0 804 l 319 804 l 319 1015 l 458 1013 l 458 804 l 777 804 l 777 683 l 458 683 l 458 360 l 777 360 l 777 238 l 458 238 "},"ψ":{x_min:0,x_max:808,ha:907,o:"m 465 -278 l 341 -278 l 341 -15 q 87 102 180 -15 q 0 378 0 210 l 0 739 l 133 739 l 133 379 q 182 195 133 275 q 341 98 242 98 l 341 922 l 465 922 l 465 98 q 623 195 563 98 q 675 382 675 278 l 675 742 l 808 742 l 808 381 q 720 104 808 213 q 466 -13 627 -13 l 465 -278 "},"η":{x_min:0.78125,x_max:697,ha:810,o:"m 697 -278 l 572 -278 l 572 454 q 540 587 572 536 q 425 650 501 650 q 271 579 337 650 q 206 420 206 509 l 206 0 l 81 0 l 81 489 q 73 588 81 562 q 0 644 56 644 l 0 741 q 68 755 38 755 q 158 720 124 755 q 200 630 193 686 q 297 726 234 692 q 434 761 359 761 q 620 692 544 761 q 697 516 697 624 l 697 -278 "}},cssFontWeight:"normal",ascender:1189,underlinePosition:-100,cssFontStyle:"normal",boundingBox:{yMin:-334,xMin:-111,yMax:1189,xMax:1672},resolution:1000,original_font_information:{postscript_name:"Helvetiker-Regular",version_string:"Version 1.00 2004 initial release",vendor_url:"http://www.magenta.gr/",full_font_name:"Helvetiker",font_family_name:"Helvetiker",copyright:"Copyright (c) Îœagenta ltd, 2004",description:"",trademark:"",designer:"",designer_url:"",unique_font_identifier:"Îœagenta ltd:Helvetiker:22-10-104",license_url:"http://www.ellak.gr/fonts/MgOpen/license.html",license_description:'Copyright (c) 2004 by MAGENTA Ltd. All Rights Reserved.\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license ("Fonts") and associated documentation files (the "Font Software"), to reproduce and distribute the Font Software, including without limitation the rights to use, copy, merge, publish, distribute, and/or sell copies of the Font Software, and to permit persons to whom the Font Software is furnished to do so, subject to the following conditions: \r\n\r\nThe above copyright and this permission notice shall be included in all copies of one or more of the Font Software typefaces.\r\n\r\nThe Font Software may be modified, altered, or added to, and in particular the designs of glyphs or characters in the Fonts may be modified and additional glyphs or characters may be added to the Fonts, only if the fonts are renamed to names not containing the word "MgOpen", or if the modifications are accepted for inclusion in the Font Software itself by the each appointed Administrator.\r\n\r\nThis License becomes null and void to the extent applicable to Fonts or Font Software that has been modified and is distributed under the "MgOpen" name.\r\n\r\nThe Font Software may be sold as part of a larger software package but no copy of one or more of the Font Software typefaces may be sold by itself. \r\n\r\nTHE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL MAGENTA OR PERSONS OR BODIES IN CHARGE OF ADMINISTRATION AND MAINTENANCE OF THE FONT SOFTWARE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.',manufacturer_name:"Îœagenta ltd",font_sub_family_name:"Regular"},descender:-334,familyName:"Helvetiker",lineHeight:1522,underlineThickness:50});c.RenderableObject=function(){this.id=0;this.object=null;this.z=0;this.renderOrder=0};c.RenderableFace=function(){this.id=0;this.v1=new c.RenderableVertex();this.v2=new c.RenderableVertex();this.v3=new c.RenderableVertex();this.normalModel=new c.Vector3();this.vertexNormalsModel=[new c.Vector3(),new c.Vector3(),new c.Vector3()];this.vertexNormalsLength=0;this.color=new c.Color();this.material=null;this.uvs=[new c.Vector2(),new c.Vector2(),new c.Vector2()];this.z=0;this.renderOrder=0};c.RenderableVertex=function(){this.position=new c.Vector3();this.positionWorld=new c.Vector3();this.positionScreen=new c.Vector4();this.visible=true};c.RenderableVertex.prototype.copy=function(d){this.positionWorld.copy(d.positionWorld);this.positionScreen.copy(d.positionScreen)};c.RenderableLine=function(){this.id=0;this.v1=new c.RenderableVertex();this.v2=new c.RenderableVertex();this.vertexColors=[new c.Color(),new c.Color()];this.material=null;this.z=0;this.renderOrder=0};c.RenderableSprite=function(){this.id=0;this.object=null;this.x=0;this.y=0;this.z=0;this.rotation=0;this.scale=new c.Vector2();this.material=null;this.renderOrder=0};c.Projector=function(){var V,I,P=[],r=0,A,f,i=[],e=0,p,F,L=[],C=0,l,R,T=[],x=0,D,u,h=[],U=0,N={objects:[],lights:[],elements:[]},O=new c.Vector3(),M=new c.Vector4(),v=new c.Box3(new c.Vector3(-1,-1,-1),new c.Vector3(1,1,1)),W=new c.Box3(),Q=new Array(3),d=new c.Matrix4(),j=new c.Matrix4(),E,H=new c.Matrix4(),s=new c.Matrix3(),S=new c.Frustum(),w=new c.Vector4(),k=new c.Vector4();this.projectVector=function(X,Y){console.warn("THREE.Projector: .projectVector() is now vector.project().");X.project(Y)};this.unprojectVector=function(X,Y){console.warn("THREE.Projector: .unprojectVector() is now vector.unproject().");X.unproject(Y)};this.pickingRay=function(){console.error("THREE.Projector: .pickingRay() is now raycaster.setFromCamera().")};var g=function(){var ak=[];var Z=[];var ag=[];var af=null;var ai=null;var ae=new c.Matrix3();function ac(an){af=an;ai=af.material;ae.getNormalMatrix(af.matrixWorld);ak.length=0;Z.length=0;ag.length=0}function ah(ap){var an=ap.position;var aq=ap.positionWorld;var ao=ap.positionScreen;aq.copy(an).applyMatrix4(E);ao.copy(aq).applyMatrix4(j);var ar=1/ao.w;ao.x*=ar;ao.y*=ar;ao.z*=ar;ap.visible=ao.x>=-1&&ao.x<=1&&ao.y>=-1&&ao.y<=1&&ao.z>=-1&&ao.z<=1}function Y(an,ap,ao){A=y();A.position.set(an,ap,ao);ah(A)}function ab(an,ap,ao){ak.push(an,ap,ao)}function al(ap,ao,an){Z.push(ap,ao,an)}function aa(an,ao){ag.push(an,ao)}function ad(ap,ao,an){if(ap.visible===true||ao.visible===true||an.visible===true){return true}Q[0]=ap.positionScreen;Q[1]=ao.positionScreen;Q[2]=an.positionScreen;return v.intersectsBox(W.setFromPoints(Q))}function aj(ap,ao,an){return((an.positionScreen.x-ap.positionScreen.x)*(ao.positionScreen.y-ap.positionScreen.y)-(an.positionScreen.y-ap.positionScreen.y)*(ao.positionScreen.x-ap.positionScreen.x))<0}function am(ao,an){var aq=i[ao];var ap=i[an];aq.positionScreen.copy(aq.position).applyMatrix4(H);ap.positionScreen.copy(ap.position).applyMatrix4(H);if(B(aq.positionScreen,ap.positionScreen)===true){aq.positionScreen.multiplyScalar(1/aq.positionScreen.w);ap.positionScreen.multiplyScalar(1/ap.positionScreen.w);l=K();l.id=af.id;l.v1.copy(aq);l.v2.copy(ap);l.z=Math.max(aq.positionScreen.z,ap.positionScreen.z);l.renderOrder=af.renderOrder;l.material=af.material;if(af.material.vertexColors===c.VertexColors){l.vertexColors[0].fromArray(Z,ao*3);l.vertexColors[1].fromArray(Z,an*3)}N.elements.push(l)}}function X(aw,au,ar,aq){var ax=i[aw];var av=i[au];var at=i[ar];if(ad(ax,av,at)===false){return}if(aq.side===c.DoubleSide||aj(ax,av,at)===true){p=o();p.id=af.id;p.v1.copy(ax);p.v2.copy(av);p.v3.copy(at);p.z=(ax.positionScreen.z+av.positionScreen.z+at.positionScreen.z)/3;p.renderOrder=af.renderOrder;O.subVectors(at.position,av.position);M.subVectors(ax.position,av.position);O.cross(M);p.normalModel.copy(O);p.normalModel.applyMatrix3(ae).normalize();for(var ao=0;ao<3;ao++){var ap=p.vertexNormalsModel[ao];ap.fromArray(ak,arguments[ao]*3);ap.applyMatrix3(ae).normalize();var an=p.uvs[ao];an.fromArray(ag,arguments[ao]*2)}p.vertexNormalsLength=3;p.material=aq;if(aq.vertexColors===c.FaceColors){p.color.fromArray(Z,aw*3)}N.elements.push(p)}}return{setObject:ac,projectVertex:ah,checkTriangleVisibility:ad,checkBackfaceCulling:aj,pushVertex:Y,pushNormal:ab,pushColor:al,pushUv:aa,pushLine:am,pushTriangle:X}};var J=new g();function G(Y){if(Y.visible===false){return}if(Y instanceof c.Light){N.lights.push(Y)}else{if(Y instanceof c.Mesh||Y instanceof c.Line||Y instanceof c.Points){if(Y.material.visible===false){return}if(Y.frustumCulled===true&&S.intersectsObject(Y)===false){return}z(Y)}else{if(Y instanceof c.Sprite){if(Y.material.visible===false){return}if(Y.frustumCulled===true&&S.intersectsSprite(Y)===false){return}z(Y)}}}var aa=Y.children;for(var Z=0,X=aa.length;Z<X;Z++){G(aa[Z])}}function z(X){V=q();V.id=X.id;V.object=X;O.setFromMatrixPosition(X.matrixWorld);O.applyMatrix4(j);V.z=O.z;V.renderOrder=X.renderOrder;N.objects.push(V)}this.projectScene=function(au,al,aw,ab){F=0;R=0;u=0;N.elements.length=0;if(au.autoUpdate===true){au.updateMatrixWorld()}if(al.parent===null){al.updateMatrixWorld()}d.copy(al.matrixWorldInverse);j.multiplyMatrices(al.projectionMatrix,d);S.setFromMatrix(j);I=0;N.objects.length=0;N.lights.length=0;G(au);if(aw===true){N.objects.sort(t)}var aL=N.objects;for(var aM=0,ay=aL.length;aM<ay;aM++){var aG=aL[aM].object;var ah=aG.geometry;J.setObject(aG);E=aG.matrixWorld;f=0;if(aG instanceof c.Mesh){if(ah instanceof c.BufferGeometry){var aQ=aG.material;var aq=Array.isArray(aQ);var aF=ah.attributes;var ad=ah.groups;if(aF.position===undefined){continue}var af=aF.position.array;for(var aR=0,aP=af.length;aR<aP;aR+=3){var aD=af[aR];var aB=af[aR+1];var aA=af[aR+2];if(aQ.morphTargets===true){var ai=ah.morphAttributes.position;var aO=aG.morphTargetInfluences;for(var aJ=0,Y=ai.length;aJ<Y;aJ++){var az=aO[aJ];if(az===0){continue}var X=ai[aJ];aD+=(X.getX(aR/3)-af[aR])*az;aB+=(X.getY(aR/3)-af[aR+1])*az;aA+=(X.getZ(aR/3)-af[aR+2])*az}}J.pushVertex(aD,aB,aA)}if(aF.normal!==undefined){var ap=aF.normal.array;for(var aR=0,aP=ap.length;aR<aP;aR+=3){J.pushNormal(ap[aR],ap[aR+1],ap[aR+2])}}if(aF.color!==undefined){var aK=aF.color.array;for(var aR=0,aP=aK.length;aR<aP;aR+=3){J.pushColor(aK[aR],aK[aR+1],aK[aR+2])}}if(aF.uv!==undefined){var aE=aF.uv.array;for(var aR=0,aP=aE.length;aR<aP;aR+=2){J.pushUv(aE[aR],aE[aR+1])}}if(ah.index!==null){var aa=ah.index.array;if(ad.length>0){for(var aS=0;aS<ad.length;aS++){var ao=ad[aS];aQ=aq===true?aG.material[ao.materialIndex]:aG.material;if(aQ===undefined){continue}for(var aR=ao.start,aP=ao.start+ao.count;aR<aP;aR+=3){J.pushTriangle(aa[aR],aa[aR+1],aa[aR+2],aQ)}}}else{for(var aR=0,aP=aa.length;aR<aP;aR+=3){J.pushTriangle(aa[aR],aa[aR+1],aa[aR+2],aQ)}}}else{if(ad.length>0){for(var aS=0;aS<ad.length;aS++){var ao=ad[aS];aQ=aq===true?aG.material[ao.materialIndex]:aG.material;if(aQ===undefined){continue}for(var aR=ao.start,aP=ao.start+ao.count;aR<aP;aR+=3){J.pushTriangle(aR,aR+1,aR+2,aQ)}}}else{for(var aR=0,aP=af.length/3;aR<aP;aR+=3){J.pushTriangle(aR,aR+1,aR+2,aQ)}}}}else{if(ah instanceof c.Geometry){var Z=ah.vertices;var ag=ah.faces;var aC=ah.faceVertexUvs[0];s.getNormalMatrix(E);var aQ=aG.material;var aq=Array.isArray(aQ);for(var aH=0,ak=Z.length;aH<ak;aH++){var an=Z[aH];O.copy(an);if(aQ.morphTargets===true){var ai=ah.morphTargets;var aO=aG.morphTargetInfluences;for(var aJ=0,Y=ai.length;aJ<Y;aJ++){var az=aO[aJ];if(az===0){continue}var X=ai[aJ];var at=X.vertices[aH];O.x+=(at.x-an.x)*az;O.y+=(at.y-an.y)*az;O.z+=(at.z-an.z)*az}}J.pushVertex(O.x,O.y,O.z)}for(var aT=0,av=ag.length;aT<av;aT++){var ae=ag[aT];aQ=aq===true?aG.material[ae.materialIndex]:aG.material;if(aQ===undefined){continue}var aj=aQ.side;var aY=i[ae.a];var aW=i[ae.b];var aU=i[ae.c];if(J.checkTriangleVisibility(aY,aW,aU)===false){continue}var ar=J.checkBackfaceCulling(aY,aW,aU);if(aj!==c.DoubleSide){if(aj===c.FrontSide&&ar===false){continue}if(aj===c.BackSide&&ar===true){continue}}p=o();p.id=aG.id;p.v1.copy(aY);p.v2.copy(aW);p.v3.copy(aU);p.normalModel.copy(ae.normal);if(ar===false&&(aj===c.BackSide||aj===c.DoubleSide)){p.normalModel.negate()}p.normalModel.applyMatrix3(s).normalize();var ac=ae.vertexNormals;for(var aN=0,aV=Math.min(ac.length,3);aN<aV;aN++){var aX=p.vertexNormalsModel[aN];aX.copy(ac[aN]);if(ar===false&&(aj===c.BackSide||aj===c.DoubleSide)){aX.negate()}aX.applyMatrix3(s).normalize()}p.vertexNormalsLength=ac.length;var am=aC[aT];if(am!==undefined){for(var aI=0;aI<3;aI++){p.uvs[aI].copy(am[aI])}}p.color=ae.color;p.material=aQ;p.z=(aY.positionScreen.z+aW.positionScreen.z+aU.positionScreen.z)/3;p.renderOrder=aG.renderOrder;N.elements.push(p)}}}}else{if(aG instanceof c.Line){H.multiplyMatrices(j,E);if(ah instanceof c.BufferGeometry){var aF=ah.attributes;if(aF.position!==undefined){var af=aF.position.array;for(var aR=0,aP=af.length;aR<aP;aR+=3){J.pushVertex(af[aR],af[aR+1],af[aR+2])}if(aF.color!==undefined){var aK=aF.color.array;for(var aR=0,aP=aK.length;aR<aP;aR+=3){J.pushColor(aK[aR],aK[aR+1],aK[aR+2])}}if(ah.index!==null){var aa=ah.index.array;for(var aR=0,aP=aa.length;aR<aP;aR+=2){J.pushLine(aa[aR],aa[aR+1])}}else{var ax=aG instanceof c.LineSegments?2:1;for(var aR=0,aP=(af.length/3)-1;aR<aP;aR+=ax){J.pushLine(aR,aR+1)}}}}else{if(ah instanceof c.Geometry){var Z=aG.geometry.vertices;if(Z.length===0){continue}aY=y();aY.positionScreen.copy(Z[0]).applyMatrix4(H);var ax=aG instanceof c.LineSegments?2:1;for(var aH=1,ak=Z.length;aH<ak;aH++){aY=y();aY.positionScreen.copy(Z[aH]).applyMatrix4(H);if((aH+1)%ax>0){continue}aW=i[f-2];w.copy(aY.positionScreen);k.copy(aW.positionScreen);if(B(w,k)===true){w.multiplyScalar(1/w.w);k.multiplyScalar(1/k.w);l=K();l.id=aG.id;l.v1.positionScreen.copy(w);l.v2.positionScreen.copy(k);l.z=Math.max(w.z,k.z);l.renderOrder=aG.renderOrder;l.material=aG.material;if(aG.material.vertexColors===c.VertexColors){l.vertexColors[0].copy(aG.geometry.colors[aH]);l.vertexColors[1].copy(aG.geometry.colors[aH-1])}N.elements.push(l)}}}}}else{if(aG instanceof c.Points){H.multiplyMatrices(j,E);if(ah instanceof c.Geometry){var Z=aG.geometry.vertices;for(var aH=0,ak=Z.length;aH<ak;aH++){var an=Z[aH];M.set(an.x,an.y,an.z,1);M.applyMatrix4(H);m(M,aG,al)}}else{if(ah instanceof c.BufferGeometry){var aF=ah.attributes;if(aF.position!==undefined){var af=aF.position.array;for(var aR=0,aP=af.length;aR<aP;aR+=3){M.set(af[aR],af[aR+1],af[aR+2],1);M.applyMatrix4(H);m(M,aG,al)}}}}}else{if(aG instanceof c.Sprite){aG.modelViewMatrix.multiplyMatrices(al.matrixWorldInverse,aG.matrixWorld);M.set(E.elements[12],E.elements[13],E.elements[14],1);M.applyMatrix4(j);m(M,aG,al)}}}}}if(ab===true){N.elements.sort(t)}return N};function m(X,Y,Z){var aa=1/X.w;X.z*=aa;if(X.z>=-1&&X.z<=1){D=n();D.id=Y.id;D.x=X.x*aa;D.y=X.y*aa;D.z=X.z;D.renderOrder=Y.renderOrder;D.object=Y;D.rotation=Y.rotation;D.scale.x=Y.scale.x*Math.abs(D.x-(X.x+Z.projectionMatrix.elements[0])/(X.w+Z.projectionMatrix.elements[12]));D.scale.y=Y.scale.y*Math.abs(D.y-(X.y+Z.projectionMatrix.elements[5])/(X.w+Z.projectionMatrix.elements[13]));D.material=Y.material;N.elements.push(D)}}function q(){if(I===r){var X=new c.RenderableObject();P.push(X);r++;I++;return X}return P[I++]}function y(){if(f===e){var X=new c.RenderableVertex();i.push(X);e++;f++;return X}return i[f++]}function o(){if(F===C){var X=new c.RenderableFace();L.push(X);C++;F++;return X}return L[F++]}function K(){if(R===x){var X=new c.RenderableLine();T.push(X);x++;R++;return X}return T[R++]}function n(){if(u===U){var X=new c.RenderableSprite();h.push(X);U++;u++;return X}return h[u++]}function t(Y,X){if(Y.renderOrder!==X.renderOrder){return Y.renderOrder-X.renderOrder}else{if(Y.z!==X.z){return X.z-Y.z}else{if(Y.id!==X.id){return Y.id-X.id}else{return 0}}}}function B(ab,aa){var Z=0,ae=1,ac=ab.z+ab.w,Y=aa.z+aa.w,X=-ab.z+ab.w,ad=-aa.z+aa.w;if(ac>=0&&Y>=0&&X>=0&&ad>=0){return true}else{if((ac<0&&Y<0)||(X<0&&ad<0)){return false}else{if(ac<0){Z=Math.max(Z,ac/(ac-Y))}else{if(Y<0){ae=Math.min(ae,ac/(ac-Y))}}if(X<0){Z=Math.max(Z,X/(X-ad))}else{if(ad<0){ae=Math.min(ae,X/(X-ad))}}if(ae<Z){return false}else{ab.lerp(aa,Z);aa.lerp(ab,1-ae);return true}}}}};c.SpriteCanvasMaterial=function(d){c.Material.call(this);this.type="SpriteCanvasMaterial";this.rotation=0;this.color=new c.Color(16777215);this.program=function(){};this.setValues(d)};c.SpriteCanvasMaterial.prototype=Object.create(c.Material.prototype);c.SpriteCanvasMaterial.prototype.constructor=c.SpriteCanvasMaterial;c.SpriteCanvasMaterial.prototype.isSpriteCanvasMaterial=true;c.SpriteCanvasMaterial.prototype.clone=function(){var d=new c.SpriteCanvasMaterial();d.copy(this);d.color.copy(this.color);d.program=this.program;return d};c.CanvasRenderer=function(E){console.log("THREE.CanvasRenderer",c.REVISION);E=E||{};var w=this,B,F,q,d=new c.Projector(),l=E.canvas!==undefined?E.canvas:a.createElement("canvas"),z=l.width,ap=l.height,aa=Math.floor(z/2),I=Math.floor(ap/2),f=0,e=0,ar=z,y=ap,X=1,i=l.getContext("2d",{alpha:E.alpha===true}),G=new c.Color(0),al=E.alpha===true?0:1,aq=1,an=0,x=null,am=null,K=null,o=null,ak=null,N=[],Z,Y,V,v,u,h,g,ay,aw,k=new c.Color(),T=new c.Color(),s=new c.Color(),ah=new c.Color(),H={},n,ax,au,ai,ag,Q,P,aA=new c.Box2(),t=new c.Box2(),A=new c.Box2(),at=new c.Color(),C=new c.Color(),W=new c.Color(),p=new c.Vector3(),aB=new c.Vector3(),S=new c.Vector3(),M=new c.Matrix3();if(i.setLineDash===undefined){i.setLineDash=function(){}}this.domElement=l;this.autoClear=true;this.sortObjects=true;this.sortElements=true;this.info={render:{vertices:0,faces:0}};this.getContext=function(){return i};this.getContextAttributes=function(){return i.getContextAttributes()};this.getPixelRatio=function(){return X};this.setPixelRatio=function(aD){if(aD!==undefined){X=aD}};this.setSize=function(aE,aD,aF){z=aE*X;ap=aD*X;l.width=z;l.height=ap;aa=Math.floor(z/2);I=Math.floor(ap/2);if(aF!==false){l.style.width=aE+"px";l.style.height=aD+"px"}aA.min.set(-aa,-I);aA.max.set(aa,I);t.min.set(-aa,-I);t.max.set(aa,I);aq=1;an=0;x=null;am=null;K=null;o=null;ak=null;this.setViewport(0,0,aE,aD)};this.setViewport=function(aE,aG,aF,aD){f=aE*X;e=aG*X;ar=aF*X;y=aD*X};this.setScissor=function(){};this.setScissorTest=function(){};this.setClearColor=function(aD,aE){G.set(aD);al=aE!==undefined?aE:1;t.min.set(-aa,-I);t.max.set(aa,I)};this.setClearColorHex=function(aD,aE){console.warn("THREE.CanvasRenderer: .setClearColorHex() is being removed. Use .setClearColor() instead.");this.setClearColor(aD,aE)};this.getClearColor=function(){return G};this.getClearAlpha=function(){return al};this.getMaxAnisotropy=function(){return 0};this.clear=function(){if(t.isEmpty()===false){t.intersect(aA);t.expandByScalar(2);t.min.x=t.min.x+aa;t.min.y=-t.min.y+I;t.max.x=t.max.x+aa;t.max.y=-t.max.y+I;if(al<1){i.clearRect(t.min.x|0,t.max.y|0,(t.max.x-t.min.x)|0,(t.min.y-t.max.y)|0)}if(al>0){D(1);ad(c.NormalBlending);ab("rgba("+Math.floor(G.r*255)+","+Math.floor(G.g*255)+","+Math.floor(G.b*255)+","+al+")");i.fillRect(t.min.x|0,t.max.y|0,(t.max.x-t.min.x)|0,(t.min.y-t.max.y)|0)}t.makeEmpty()}};this.clearColor=function(){};this.clearDepth=function(){};this.clearStencil=function(){};this.render=function(aJ,aH){if(aH.isCamera===undefined){console.error("THREE.CanvasRenderer.render: camera is not an instance of THREE.Camera.");return}var aE=aJ.background;if(aE&&aE.isColor){D(1);ad(c.NormalBlending);ab(aE.getStyle());i.fillRect(0,0,z,ap)}else{if(this.autoClear===true){this.clear()}}w.info.render.vertices=0;w.info.render.faces=0;i.setTransform(ar/z,0,0,-y/ap,f,ap-e);i.translate(aa,I);B=d.projectScene(aJ,aH,this.sortObjects,this.sortElements);F=B.elements;q=B.lights;M.getNormalMatrix(aH.matrixWorldInverse);af();for(var aI=0,aG=F.length;aI<aG;aI++){var aD=F[aI];var aF=aD.material;if(aF===undefined||aF.opacity===0){continue}A.makeEmpty();if(aD instanceof c.RenderableSprite){Z=aD;Z.x*=aa;Z.y*=I;r(Z,aD,aF)}else{if(aD instanceof c.RenderableLine){Z=aD.v1;Y=aD.v2;Z.positionScreen.x*=aa;Z.positionScreen.y*=I;Y.positionScreen.x*=aa;Y.positionScreen.y*=I;A.setFromPoints([Z.positionScreen,Y.positionScreen]);if(aA.intersectsBox(A)===true){aj(Z,Y,aD,aF)}}else{if(aD instanceof c.RenderableFace){Z=aD.v1;Y=aD.v2;V=aD.v3;if(Z.positionScreen.z<-1||Z.positionScreen.z>1){continue}if(Y.positionScreen.z<-1||Y.positionScreen.z>1){continue}if(V.positionScreen.z<-1||V.positionScreen.z>1){continue}Z.positionScreen.x*=aa;Z.positionScreen.y*=I;Y.positionScreen.x*=aa;Y.positionScreen.y*=I;V.positionScreen.x*=aa;V.positionScreen.y*=I;if(aF.overdraw>0){ac(Z.positionScreen,Y.positionScreen,aF.overdraw);ac(Y.positionScreen,V.positionScreen,aF.overdraw);ac(V.positionScreen,Z.positionScreen,aF.overdraw)}A.setFromPoints([Z.positionScreen,Y.positionScreen,V.positionScreen]);if(aA.intersectsBox(A)===true){aC(Z,Y,V,0,1,2,aD,aF)}}}}t.union(A)}i.setTransform(1,0,0,1,0,0)};function af(){at.setRGB(0,0,0);C.setRGB(0,0,0);W.setRGB(0,0,0);for(var aF=0,aG=q.length;aF<aG;aF++){var aE=q[aF];var aD=aE.color;if(aE.isAmbientLight){at.add(aD)}else{if(aE.isDirectionalLight){C.add(aD)}else{if(aE.isPointLight){W.add(aD)}}}}}function j(aD,aK,aH){for(var aG=0,aJ=q.length;aG<aJ;aG++){var aF=q[aG];ah.copy(aF.color);if(aF.isDirectionalLight){var aE=p.setFromMatrixPosition(aF.matrixWorld).normalize();var aI=aK.dot(aE);if(aI<=0){continue}aI*=aF.intensity;aH.add(ah.multiplyScalar(aI))}else{if(aF.isPointLight){var aE=p.setFromMatrixPosition(aF.matrixWorld);var aI=aK.dot(p.subVectors(aE,aD).normalize());if(aI<=0){continue}aI*=aF.distance==0?1:1-Math.min(aD.distanceTo(aE)/aF.distance,1);if(aI==0){continue}aI*=aF.intensity;aH.add(ah.multiplyScalar(aI))}}}}function r(aP,aH,aI){D(aI.opacity);ad(aI.blending);var aR=aH.scale.x*aa;var aQ=aH.scale.y*I;var aL=Math.sqrt(aR*aR+aQ*aQ);A.min.set(aP.x-aL,aP.y-aL);A.max.set(aP.x+aL,aP.y+aL);if(aI.isSpriteMaterial){var aK=aI.map;if(aK!==null){var aJ=H[aK.id];if(aJ===undefined||aJ.version!==aK.version){aJ=L(aK);H[aK.id]=aJ}if(aJ.canvas!==undefined){ab(aJ.canvas);var aO=aK.image;var aE=aO.width*aK.offset.x;var aD=aO.height*aK.offset.y;var aN=aO.width*aK.repeat.x;var aM=aO.height*aK.repeat.y;var aG=aR/aN;var aF=aQ/aM;i.save();i.translate(aP.x,aP.y);if(aI.rotation!==0){i.rotate(aI.rotation)}i.translate(-aR/2,-aQ/2);i.scale(aG,aF);i.translate(-aE,-aD);i.fillRect(aE,aD,aN,aM);i.restore()}}else{ab(aI.color.getStyle());i.save();i.translate(aP.x,aP.y);if(aI.rotation!==0){i.rotate(aI.rotation)}i.scale(aR,-aQ);i.fillRect(-0.5,-0.5,1,1);i.restore()}}else{if(aI.isSpriteCanvasMaterial){ao(aI.color.getStyle());ab(aI.color.getStyle());i.save();i.translate(aP.x,aP.y);if(aI.rotation!==0){i.rotate(aI.rotation)}i.scale(aR,aQ);aI.program(i);i.restore()}else{if(aI.isPointsMaterial){ab(aI.color.getStyle());i.save();i.translate(aP.x,aP.y);if(aI.rotation!==0){i.rotate(aI.rotation)}i.scale(aR*aI.size,-aQ*aI.size);i.fillRect(-0.5,-0.5,1,1);i.restore()}}}}function aj(aK,aI,aG,aH){D(aH.opacity);ad(aH.blending);i.beginPath();i.moveTo(aK.positionScreen.x,aK.positionScreen.y);i.lineTo(aI.positionScreen.x,aI.positionScreen.y);if(aH.isLineBasicMaterial){J(aH.linewidth);U(aH.linecap);av(aH.linejoin);if(aH.vertexColors!==c.VertexColors){ao(aH.color.getStyle())}else{var aF=aG.vertexColors[0].getStyle();var aD=aG.vertexColors[1].getStyle();if(aF===aD){ao(aF)}else{try{var aJ=i.createLinearGradient(aK.positionScreen.x,aK.positionScreen.y,aI.positionScreen.x,aI.positionScreen.y);aJ.addColorStop(0,aF);aJ.addColorStop(1,aD)}catch(aE){aJ=aF}ao(aJ)}}if(aH.isLineDashedMaterial){R([aH.dashSize,aH.gapSize])}i.stroke();A.expandByScalar(aH.linewidth*2);if(aH.isLineDashedMaterial){R([])}}}function aC(aL,aK,aJ,aG,aF,aE,aH,aI){w.info.render.vertices+=3;w.info.render.faces++;D(aI.opacity);ad(aI.blending);v=aL.positionScreen.x;u=aL.positionScreen.y;h=aK.positionScreen.x;g=aK.positionScreen.y;ay=aJ.positionScreen.x;aw=aJ.positionScreen.y;O(v,u,h,g,ay,aw);if((aI.isMeshLambertMaterial||aI.isMeshPhongMaterial||aI.isMeshStandardMaterial)&&aI.map===null){T.copy(aI.color);s.copy(aI.emissive);if(aI.vertexColors===c.FaceColors){T.multiply(aH.color)}k.copy(at);aB.copy(aL.positionWorld).add(aK.positionWorld).add(aJ.positionWorld).divideScalar(3);j(aB,aH.normalModel,k);k.multiply(T).add(s);aI.wireframe===true?az(k,aI.wireframeLinewidth,aI.wireframeLinecap,aI.wireframeLinejoin):m(k)}else{if(aI.isMeshBasicMaterial||aI.isMeshLambertMaterial||aI.isMeshPhongMaterial||aI.isMeshStandardMaterial){if(aI.map!==null){var aD=aI.map.mapping;if(aD===c.UVMapping){n=aH.uvs;ae(v,u,h,g,ay,aw,n[aG].x,n[aG].y,n[aF].x,n[aF].y,n[aE].x,n[aE].y,aI.map)}}else{if(aI.envMap!==null){if(aI.envMap.mapping===c.SphericalReflectionMapping){S.copy(aH.vertexNormalsModel[aG]).applyMatrix3(M);ax=0.5*S.x+0.5;au=0.5*S.y+0.5;S.copy(aH.vertexNormalsModel[aF]).applyMatrix3(M);ai=0.5*S.x+0.5;ag=0.5*S.y+0.5;S.copy(aH.vertexNormalsModel[aE]).applyMatrix3(M);Q=0.5*S.x+0.5;P=0.5*S.y+0.5;ae(v,u,h,g,ay,aw,ax,au,ai,ag,Q,P,aI.envMap)}}else{k.copy(aI.color);if(aI.vertexColors===c.FaceColors){k.multiply(aH.color)}aI.wireframe===true?az(k,aI.wireframeLinewidth,aI.wireframeLinecap,aI.wireframeLinejoin):m(k)}}}else{if(aI.isMeshNormalMaterial){S.copy(aH.normalModel).applyMatrix3(M);k.setRGB(S.x,S.y,S.z).multiplyScalar(0.5).addScalar(0.5);aI.wireframe===true?az(k,aI.wireframeLinewidth,aI.wireframeLinecap,aI.wireframeLinejoin):m(k)}else{k.setRGB(1,1,1);aI.wireframe===true?az(k,aI.wireframeLinewidth,aI.wireframeLinecap,aI.wireframeLinejoin):m(k)}}}}function O(aG,aI,aE,aH,aD,aF){i.beginPath();i.moveTo(aG,aI);i.lineTo(aE,aH);i.lineTo(aD,aF);i.closePath()}function az(aD,aG,aF,aE){J(aG);U(aF);av(aE);ao(aD.getStyle());i.stroke();A.expandByScalar(aG*2)}function m(aD){ab(aD.getStyle());i.fill()}function L(aL){if(aL.version===0||aL instanceof c.CompressedTexture||aL instanceof c.DataTexture){return{canvas:undefined,version:aL.version}}var aH=aL.image;if(aH.complete===false){return{canvas:undefined,version:0}}var aM=aL.wrapS===c.RepeatWrapping||aL.wrapS===c.MirroredRepeatWrapping;var aJ=aL.wrapT===c.RepeatWrapping||aL.wrapT===c.MirroredRepeatWrapping;var aI=aL.wrapS===c.MirroredRepeatWrapping;var aG=aL.wrapT===c.MirroredRepeatWrapping;var aF=a.createElement("canvas");aF.width=aH.width*(aI?2:1);aF.height=aH.height*(aG?2:1);var aE=aF.getContext("2d");aE.setTransform(1,0,0,-1,0,aH.height);aE.drawImage(aH,0,0);if(aI===true){aE.setTransform(-1,0,0,-1,aH.width,aH.height);aE.drawImage(aH,-aH.width,0)}if(aG===true){aE.setTransform(1,0,0,1,0,0);aE.drawImage(aH,0,aH.height)}if(aI===true&&aG===true){aE.setTransform(-1,0,0,1,aH.width,0);aE.drawImage(aH,-aH.width,aH.height)}var aD="no-repeat";if(aM===true&&aJ===true){aD="repeat"}else{if(aM===true){aD="repeat-x"}else{if(aJ===true){aD="repeat-y"}}}var aK=i.createPattern(aF,aD);if(aL.onUpdate){aL.onUpdate(aL)}return{canvas:aK,version:aL.version}}function ae(aV,aI,aS,aH,aP,aF,aR,aG,aO,aE,aN,aD,aK){var aQ=H[aK.id];if(aQ===undefined||aQ.version!==aK.version){aQ=L(aK);H[aK.id]=aQ}if(aQ.canvas!==undefined){ab(aQ.canvas)}else{ab("rgba( 0, 0, 0, 1)");i.fill();return}var a2,a1,a0,aZ,aX,aU,aJ,aY,aW=aK.offset.x/aK.repeat.x,aT=aK.offset.y/aK.repeat.y,aM=aK.image.width*aK.repeat.x,aL=aK.image.height*aK.repeat.y;aR=(aR+aW)*aM;aG=(aG+aT)*aL;aO=(aO+aW)*aM;aE=(aE+aT)*aL;aN=(aN+aW)*aM;aD=(aD+aT)*aL;aS-=aV;aH-=aI;aP-=aV;aF-=aI;aO-=aR;aE-=aG;aN-=aR;aD-=aG;aJ=aO*aD-aN*aE;if(aJ===0){return}aY=1/aJ;a2=(aD*aS-aE*aP)*aY;a1=(aD*aH-aE*aF)*aY;a0=(aO*aP-aN*aS)*aY;aZ=(aO*aF-aN*aH)*aY;aX=aV-a2*aR-a0*aG;aU=aI-a1*aR-aZ*aG;i.save();i.transform(a2,a1,a0,aZ,aX,aU);i.fill();i.restore()}function ac(aJ,aG,aI){var aD=aG.x-aJ.x,aH=aG.y-aJ.y,aE=aD*aD+aH*aH,aF;if(aE===0){return}aF=aI/Math.sqrt(aE);aD*=aF;aH*=aF;aG.x+=aD;aG.y+=aH;aJ.x-=aD;aJ.y-=aH}function D(aD){if(aq!==aD){i.globalAlpha=aD;aq=aD}}function ad(aD){if(an!==aD){if(aD===c.NormalBlending){i.globalCompositeOperation="source-over"}else{if(aD===c.AdditiveBlending){i.globalCompositeOperation="lighter"}else{if(aD===c.SubtractiveBlending){i.globalCompositeOperation="darker"}else{if(aD===c.MultiplyBlending){i.globalCompositeOperation="multiply"}}}}an=aD}}function J(aD){if(K!==aD){i.lineWidth=aD;K=aD}}function U(aD){if(o!==aD){i.lineCap=aD;o=aD}}function av(aD){if(ak!==aD){i.lineJoin=aD;ak=aD}}function ao(aD){if(x!==aD){i.strokeStyle=aD;x=aD}}function ab(aD){if(am!==aD){i.fillStyle=aD;am=aD}}function R(aD){if(N.length!==aD.length){i.setLineDash(aD);N=aD}}};c.CreateSVGRenderer=function(g,f,i){function e(j){c.SVGObject=function(k){c.Object3D.call(this);this.node=k};c.SVGObject.prototype=Object.create(c.Object3D.prototype);c.SVGObject.prototype.constructor=c.SVGObject;c.SVGRenderer=function(){console.log("THREE.SVGRenderer",c.REVISION);var o=this,T,K,C,E=new c.Projector(),n=j.createElementNS("http://www.w3.org/2000/svg","svg"),O,P,A,X,ad,ac,ab,F=new c.Box2(),B=new c.Box2(),I=new c.Color(),W=new c.Color(),V=new c.Color(),aa=new c.Color(),D=new c.Color(),z=new c.Color(),N=1,U=new c.Vector3(),q=new c.Vector3(),k=new c.Vector3(),y=new c.Matrix3(),l=new c.Matrix4(),u=new c.Matrix4(),x=[],Z,H=0,r,Y,J=1,M=null;this.domElement=n;this.autoClear=true;this.sortObjects=true;this.sortElements=true;this.info={render:{vertices:0,faces:0}};this.setQuality=function(ae){switch(ae){case"high":J=1;break;case"low":J=0;break}};this.setClearColor=function(ae,af){z.set(ae);N=af!==undefined?af:1};this.setPixelRatio=function(){};this.setSize=function(af,ae){O=af;P=ae;A=O/2;X=P/2;n.setAttribute("viewBox",(-A)+" "+(-X)+" "+O+" "+P);n.setAttribute("width",O);n.setAttribute("height",P);F.min.set(-A,-X);F.max.set(A,X)};this.setPrecision=function(ae){M=ae};function p(){H=0;while(n.childNodes.length>0){n.removeChild(n.childNodes[0])}}function L(af,ag){var ae=Math.floor(af.r*255)+","+Math.floor(af.g*255)+","+Math.floor(af.b*255);if(ag===undefined||ag===1){return"rgb("+ae+")"}return"rgb("+ae+"); fill-opacity: "+ag}function S(ae){return M!==null?ae.toFixed(M):ae}this.clear=function(){p();n.style.backgroundColor=L(z,N)};this.render=function(ak,ai){if(ai instanceof c.Camera===false){console.error("THREE.SVGRenderer.render: camera is not an instance of THREE.Camera.");return}var af=ak.background;if(af&&af.isColor){p();n.style.backgroundColor=L(af)}else{if(this.autoClear===true){this.clear()}}o.info.render.vertices=0;o.info.render.faces=0;l.copy(ai.matrixWorldInverse);u.multiplyMatrices(ai.projectionMatrix,l);T=E.projectScene(ak,ai,this.sortObjects,this.sortElements);K=T.elements;C=T.lights;y.getNormalMatrix(ai.matrixWorldInverse);v(C);r="";Y="";for(var aj=0,ah=K.length;aj<ah;aj++){var ae=K[aj];var ag=ae.material;if(ag===undefined||ag.opacity===0){continue}B.makeEmpty();if(ae instanceof c.RenderableSprite){ad=ae;ad.x*=A;ad.y*=-X;m(ad,ae,ag)}else{if(ae instanceof c.RenderableLine){ad=ae.v1;ac=ae.v2;ad.positionScreen.x*=A;ad.positionScreen.y*=-X;ac.positionScreen.x*=A;ac.positionScreen.y*=-X;B.setFromPoints([ad.positionScreen,ac.positionScreen]);if(F.intersectsBox(B)===true){G(ad,ac,ae,ag)}}else{if(ae instanceof c.RenderableFace){ad=ae.v1;ac=ae.v2;ab=ae.v3;if(ad.positionScreen.z<-1||ad.positionScreen.z>1){continue}if(ac.positionScreen.z<-1||ac.positionScreen.z>1){continue}if(ab.positionScreen.z<-1||ab.positionScreen.z>1){continue}ad.positionScreen.x*=A;ad.positionScreen.y*=-X;ac.positionScreen.x*=A;ac.positionScreen.y*=-X;ab.positionScreen.x*=A;ab.positionScreen.y*=-X;B.setFromPoints([ad.positionScreen,ac.positionScreen,ab.positionScreen]);if(F.intersectsBox(B)===true){w(ad,ac,ab,ae,ag)}}}}}Q();ak.traverseVisible(function(am){if(am instanceof c.SVGObject){U.setFromMatrixPosition(am.matrixWorld);U.applyMatrix4(u);var al=U.x*A;var ao=-U.y*X;var an=am.node;an.setAttribute("transform","translate("+al+","+ao+")");n.appendChild(an)}})};function v(ah){V.setRGB(0,0,0);aa.setRGB(0,0,0);D.setRGB(0,0,0);for(var ag=0,ai=ah.length;ag<ai;ag++){var af=ah[ag];var ae=af.color;if(af.isAmbientLight){V.r+=ae.r;V.g+=ae.g;V.b+=ae.b}else{if(af.isDirectionalLight){aa.r+=ae.r;aa.g+=ae.g;aa.b+=ae.b}else{if(af.isPointLight){D.r+=ae.r;D.g+=ae.g;D.b+=ae.b}}}}}function t(ah,ak,al,af){for(var ae=0,am=ah.length;ae<am;ae++){var ai=ah[ae];var ag=ai.color;if(ai.isDirectionalLight){var an=U.setFromMatrixPosition(ai.matrixWorld).normalize();var aj=al.dot(an);if(aj<=0){continue}aj*=ai.intensity;af.r+=ag.r*aj;af.g+=ag.g*aj;af.b+=ag.b*aj}else{if(ai.isPointLight){var an=U.setFromMatrixPosition(ai.matrixWorld);var aj=al.dot(U.subVectors(an,ak).normalize());if(aj<=0){continue}aj*=ai.distance==0?1:1-Math.min(ak.distanceTo(an)/ai.distance,1);if(aj==0){continue}aj*=ai.intensity;af.r+=ag.r*aj;af.g+=ag.g*aj;af.b+=ag.b*aj}}}}function m(ak,ag,ai){var af=ag.scale.x*A;var ae=ag.scale.y*X;if(ai.isPointsMaterial){af*=ai.size;ae*=ai.size}var aj="M"+S(ak.x-af*0.5)+","+S(ak.y-ae*0.5)+"h"+S(af)+"v"+S(ae)+"h"+S(-af)+"z";var ah="";if(ai.isSpriteMaterial||ai.isPointsMaterial){ah="fill:"+L(ai.color,ai.opacity)}s(ah,aj)}function G(aj,ai,ae,ag){var ah="M"+S(aj.positionScreen.x)+","+S(aj.positionScreen.y)+"L"+S(ai.positionScreen.x)+","+S(ai.positionScreen.y);if(ag.isLineBasicMaterial){var af="fill:none;stroke:"+L(ag.color,ag.opacity)+";stroke-width:"+ag.linewidth+";stroke-linecap:"+ag.linecap;if(ag.isLineDashedMaterial){af=af+";stroke-dasharray:"+ag.dashSize+","+ag.gapSize}s(af,ah)}}function w(ak,aj,ai,ae,ag){o.info.render.vertices+=3;o.info.render.faces++;var ah="M"+S(ak.positionScreen.x)+","+S(ak.positionScreen.y)+"L"+S(aj.positionScreen.x)+","+S(aj.positionScreen.y)+"L"+S(ai.positionScreen.x)+","+S(ai.positionScreen.y)+"z";var af="";if(ag.isMeshBasicMaterial){I.copy(ag.color);if(ag.vertexColors===c.FaceColors){I.multiply(ae.color)}}else{if(ag.isMeshLambertMaterial||ag.isMeshPhongMaterial||ag.isMeshStandardMaterial){W.copy(ag.color);if(ag.vertexColors===c.FaceColors){W.multiply(ae.color)}I.copy(V);q.copy(ak.positionWorld).add(aj.positionWorld).add(ai.positionWorld).divideScalar(3);t(C,q,ae.normalModel,I);I.multiply(W).add(ag.emissive)}else{if(ag.isMeshNormalMaterial){k.copy(ae.normalModel).applyMatrix3(y);I.setRGB(k.x,k.y,k.z).multiplyScalar(0.5).addScalar(0.5)}}}if(ag.wireframe){af="fill:none;stroke:"+L(I,ag.opacity)+";stroke-width:"+ag.wireframeLinewidth+";stroke-linecap:"+ag.wireframeLinecap+";stroke-linejoin:"+ag.wireframeLinejoin}else{af="fill:"+L(I,ag.opacity)}s(af,ah)}function s(ae,af){if(Y===ae){r+=af}else{Q();Y=ae;r=af}}function Q(){if(r){Z=R(H++);Z.setAttribute("d",r);Z.setAttribute("style",Y);n.appendChild(Z)}r="";Y=""}function R(ae){if(x[ae]==null){x[ae]=j.createElementNS("http://www.w3.org/2000/svg","path");if(J==0){x[ae].setAttribute("shape-rendering","crispEdges")}return x[ae]}return x[ae]}};return new c.SVGRenderer()}var h=null;if(g){if((typeof i=="undefined")&&(typeof window=="object")){i=window.document}h=e(i)}else{var d={svg_attr:{},svg_style:{},path_attr:{},accPath:"",createElementNS:function(k,j){if(j=="path"){return{_wrapper:this,setAttribute:function(l,m){this._wrapper.path_attr[l]=m}}}if(j!="svg"){console.error("not supported element for SVGRenderer",j);return null}return{_wrapper:this,childNodes:[],style:this.svg_style,setAttribute:function(l,m){this._wrapper.svg_attr[l]=m},appendChild:function(l){this._wrapper.accPath+='<path style="'+this._wrapper.path_attr.style+'" d="'+this._wrapper.path_attr.d+'"/>';this._wrapper.path_attr={}},removeChild:function(l){this.childNodes=[]}}}};h=e(d);h.doc_wrapper=d;h.makeOuterHTML=function(){var k=this.doc_wrapper;var l=' viewBox="'+k.svg_attr.viewBox+'" width="'+k.svg_attr.width+'" height="'+k.svg_attr.height+'"';var j="";if(k.svg_style.backgroundColor){j=' style="background:'+k.svg_style.backgroundColor+'"'}return'<svg xmlns="http://www.w3.org/2000/svg"'+l+j+">"+k.accPath+"</svg>"}}h.setPrecision(f);return h};c.OrbitControls=function(O,P){this.object=O;this.domElement=(P!==undefined)?P:a;this.enabled=true;this.target=new c.Vector3();this.minDistance=0;this.maxDistance=Infinity;this.minZoom=0;this.maxZoom=Infinity;this.minPolarAngle=0;this.maxPolarAngle=Math.PI;this.minAzimuthAngle=-Infinity;this.maxAzimuthAngle=Infinity;this.enableDamping=false;this.dampingFactor=0.25;this.enableZoom=true;this.zoomSpeed=1;this.enableRotate=true;this.rotateSpeed=1;this.enablePan=true;this.panSpeed=1;this.screenSpacePanning=false;this.keyPanSpeed=7;this.autoRotate=false;this.autoRotateSpeed=2;this.enableKeys=true;this.keys={LEFT:37,UP:38,RIGHT:39,BOTTOM:40};this.mouseButtons={LEFT:c.MOUSE.LEFT,MIDDLE:c.MOUSE.MIDDLE,RIGHT:c.MOUSE.RIGHT};this.target0=this.target.clone();this.position0=this.object.position.clone();this.zoom0=this.object.zoom;this.getPolarAngle=function(){return T.phi};this.getAzimuthalAngle=function(){return T.theta};this.saveState=function(){M.target0.copy(M.target);M.position0.copy(M.object.position);M.zoom0=M.object.zoom};this.reset=function(){M.target.copy(M.target0);M.object.position.copy(M.position0);M.object.zoom=M.zoom0;M.object.updateProjectionMatrix();M.dispatchEvent(Z);M.update();af=h.NONE};this.update=function(){var ak=new c.Vector3();var ai=new c.Quaternion().setFromUnitVectors(O.up,new c.Vector3(0,1,0));var aj=ai.clone().inverse();var ah=new c.Vector3();var ag=new c.Quaternion();return function al(){var am=M.object.position;ak.copy(am).sub(M.target);ak.applyQuaternion(ai);T.setFromVector3(ak);if(M.autoRotate&&af===h.NONE){A(i())}T.theta+=l.theta;T.phi+=l.phi;T.theta=Math.max(M.minAzimuthAngle,Math.min(M.maxAzimuthAngle,T.theta));T.phi=Math.max(M.minPolarAngle,Math.min(M.maxPolarAngle,T.phi));T.makeSafe();T.radius*=I;T.radius=Math.max(M.minDistance,Math.min(M.maxDistance,T.radius));M.target.add(U);ak.setFromSpherical(T);ak.applyQuaternion(aj);am.copy(M.target).add(ak);M.object.lookAt(M.target);if(M.enableDamping===true){l.theta*=(1-M.dampingFactor);l.phi*=(1-M.dampingFactor);U.multiplyScalar(1-M.dampingFactor)}else{l.set(0,0,0);U.set(0,0,0)}I=1;if(K||ah.distanceToSquared(M.object.position)>f||8*(1-ag.dot(M.object.quaternion))>f){M.dispatchEvent(Z);ah.copy(M.object.position);ag.copy(M.object.quaternion);K=false;return true}return false}}();this.dispose=function(){M.domElement.removeEventListener("contextmenu",G,false);M.domElement.removeEventListener("mousedown",Y,false);M.domElement.removeEventListener("wheel",R,false);M.domElement.removeEventListener("touchstart",X,false);M.domElement.removeEventListener("touchend",Q,false);M.domElement.removeEventListener("touchmove",aa,false);a.removeEventListener("mousemove",d,false);a.removeEventListener("mouseup",ad,false);window.removeEventListener("keydown",m,false)};var M=this;var Z={type:"change"};var S={type:"start"};var F={type:"end"};var h={NONE:-1,ROTATE:0,DOLLY:1,PAN:2,TOUCH_ROTATE:3,TOUCH_DOLLY_PAN:4};var af=h.NONE;var f=0.000001;var T=new c.Spherical();var l=new c.Spherical();var I=1;var U=new c.Vector3();var K=false;var C=new c.Vector2();var v=new c.Vector2();var N=new c.Vector2();var g=new c.Vector2();var y=new c.Vector2();var t=new c.Vector2();var z=new c.Vector2();var e=new c.Vector2();var L=new c.Vector2();function i(){return 2*Math.PI/60/60*M.autoRotateSpeed}function J(){return Math.pow(0.95,M.zoomSpeed)}function A(ag){l.theta-=ag}function E(ag){l.phi-=ag}var s=function(){var ag=new c.Vector3();return function ah(aj,ai){ag.setFromMatrixColumn(ai,0);ag.multiplyScalar(-aj);U.add(ag)}}();var D=function(){var ag=new c.Vector3();return function ah(aj,ai){if(M.screenSpacePanning===true){ag.setFromMatrixColumn(ai,1)}else{ag.setFromMatrixColumn(ai,0);ag.crossVectors(M.object.up,ag)}ag.multiplyScalar(aj);U.add(ag)}}();var q=function(){var ah=new c.Vector3();return function ag(ak,aj){var al=M.domElement===a?M.domElement.body:M.domElement;if(M.object.isPerspectiveCamera){var ai=M.object.position;ah.copy(ai).sub(M.target);var am=ah.length();am*=Math.tan((M.object.fov/2)*Math.PI/180);s(2*ak*am/al.clientHeight,M.object.matrix);D(2*aj*am/al.clientHeight,M.object.matrix)}else{if(M.object.isOrthographicCamera){s(ak*(M.object.right-M.object.left)/M.object.zoom/al.clientWidth,M.object.matrix);D(aj*(M.object.top-M.object.bottom)/M.object.zoom/al.clientHeight,M.object.matrix)}else{console.warn("WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.");M.enablePan=false}}}}();function u(ag){if(M.object.isPerspectiveCamera){I/=ag}else{if(M.object.isOrthographicCamera){M.object.zoom=Math.max(M.minZoom,Math.min(M.maxZoom,M.object.zoom*ag));M.object.updateProjectionMatrix();K=true}else{console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.");M.enableZoom=false}}}function w(ag){if(M.object.isPerspectiveCamera){I*=ag}else{if(M.object.isOrthographicCamera){M.object.zoom=Math.max(M.minZoom,Math.min(M.maxZoom,M.object.zoom/ag));M.object.updateProjectionMatrix();K=true}else{console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.");M.enableZoom=false}}}function x(ag){C.set(ag.clientX,ag.clientY)}function W(ag){z.set(ag.clientX,ag.clientY)}function H(ag){g.set(ag.clientX,ag.clientY)}function r(ah){v.set(ah.clientX,ah.clientY);N.subVectors(v,C).multiplyScalar(M.rotateSpeed);var ag=M.domElement===a?M.domElement.body:M.domElement;A(2*Math.PI*N.x/ag.clientHeight);E(2*Math.PI*N.y/ag.clientHeight);C.copy(v);M.update()}function ae(ag){e.set(ag.clientX,ag.clientY);L.subVectors(e,z);if(L.y>0){u(J())}else{if(L.y<0){w(J())}}z.copy(e);M.update()}function o(ag){y.set(ag.clientX,ag.clientY);t.subVectors(y,g).multiplyScalar(M.panSpeed);q(t.x,t.y);g.copy(y);M.update()}function ac(ag){}function V(ag){if(ag.deltaY<0){w(J())}else{if(ag.deltaY>0){u(J())}}M.update()}function k(ag){switch(ag.keyCode){case M.keys.UP:q(0,M.keyPanSpeed);M.update();break;case M.keys.BOTTOM:q(0,-M.keyPanSpeed);M.update();break;case M.keys.LEFT:q(M.keyPanSpeed,0);M.update();break;case M.keys.RIGHT:q(-M.keyPanSpeed,0);M.update();break}}function n(ag){C.set(ag.touches[0].pageX,ag.touches[0].pageY)}function ab(aj){if(M.enableZoom){var ai=aj.touches[0].pageX-aj.touches[1].pageX;var ah=aj.touches[0].pageY-aj.touches[1].pageY;var al=Math.sqrt(ai*ai+ah*ah);z.set(0,al)}if(M.enablePan){var ag=0.5*(aj.touches[0].pageX+aj.touches[1].pageX);var ak=0.5*(aj.touches[0].pageY+aj.touches[1].pageY);g.set(ag,ak)}}function p(ah){v.set(ah.touches[0].pageX,ah.touches[0].pageY);N.subVectors(v,C).multiplyScalar(M.rotateSpeed);var ag=M.domElement===a?M.domElement.body:M.domElement;A(2*Math.PI*N.x/ag.clientHeight);E(2*Math.PI*N.y/ag.clientHeight);C.copy(v);M.update()}function B(aj){if(M.enableZoom){var ai=aj.touches[0].pageX-aj.touches[1].pageX;var ah=aj.touches[0].pageY-aj.touches[1].pageY;var al=Math.sqrt(ai*ai+ah*ah);e.set(0,al);L.set(0,Math.pow(e.y/z.y,M.zoomSpeed));u(L.y);z.copy(e)}if(M.enablePan){var ag=0.5*(aj.touches[0].pageX+aj.touches[1].pageX);var ak=0.5*(aj.touches[0].pageY+aj.touches[1].pageY);y.set(ag,ak);t.subVectors(y,g).multiplyScalar(M.panSpeed);q(t.x,t.y);g.copy(y)}M.update()}function j(ag){}function Y(ag){if(M.enabled===false){return}ag.preventDefault();switch(ag.button){case M.mouseButtons.LEFT:if(ag.ctrlKey||ag.metaKey){if(M.enablePan===false){return}H(ag);af=h.PAN}else{if(M.enableRotate===false){return}x(ag);af=h.ROTATE}break;case M.mouseButtons.MIDDLE:if(M.enableZoom===false){return}W(ag);af=h.DOLLY;break;case M.mouseButtons.RIGHT:if(M.enablePan===false){return}H(ag);af=h.PAN;break}if(af!==h.NONE){a.addEventListener("mousemove",d,false);a.addEventListener("mouseup",ad,false);M.dispatchEvent(S)}}function d(ag){if(M.enabled===false){return}ag.preventDefault();switch(af){case h.ROTATE:if(M.enableRotate===false){return}r(ag);break;case h.DOLLY:if(M.enableZoom===false){return}ae(ag);break;case h.PAN:if(M.enablePan===false){return}o(ag);break}}function ad(ag){if(M.enabled===false){return}ac(ag);a.removeEventListener("mousemove",d,false);a.removeEventListener("mouseup",ad,false);M.dispatchEvent(F);af=h.NONE}function R(ag){if(M.enabled===false||M.enableZoom===false||(af!==h.NONE&&af!==h.ROTATE)){return}ag.preventDefault();ag.stopPropagation();M.dispatchEvent(S);V(ag);M.dispatchEvent(F)}function m(ag){if(M.enabled===false||M.enableKeys===false||M.enablePan===false){return}k(ag)}function X(ag){if(M.enabled===false){return}ag.preventDefault();switch(ag.touches.length){case 1:if(M.enableRotate===false){return}n(ag);af=h.TOUCH_ROTATE;break;case 2:if(M.enableZoom===false&&M.enablePan===false){return}ab(ag);af=h.TOUCH_DOLLY_PAN;break;default:af=h.NONE}if(af!==h.NONE){M.dispatchEvent(S)}}function aa(ag){if(M.enabled===false){return}ag.preventDefault();ag.stopPropagation();switch(ag.touches.length){case 1:if(M.enableRotate===false){return}if(af!==h.TOUCH_ROTATE){return}p(ag);break;case 2:if(M.enableZoom===false&&M.enablePan===false){return}if(af!==h.TOUCH_DOLLY_PAN){return}B(ag);break;default:af=h.NONE}}function Q(ag){if(M.enabled===false){return}j(ag);M.dispatchEvent(F);af=h.NONE}function G(ag){if(M.enabled===false){return}ag.preventDefault()}M.domElement.addEventListener("contextmenu",G,false);M.domElement.addEventListener("mousedown",Y,false);M.domElement.addEventListener("wheel",R,false);M.domElement.addEventListener("touchstart",X,false);M.domElement.addEventListener("touchend",Q,false);M.domElement.addEventListener("touchmove",aa,false);window.addEventListener("keydown",m,false);this.update()};c.OrbitControls.prototype=Object.create(c.EventDispatcher.prototype);c.OrbitControls.prototype.constructor=c.OrbitControls;Object.defineProperties(c.OrbitControls.prototype,{center:{get:function(){console.warn("THREE.OrbitControls: .center has been renamed to .target");return this.target}},noZoom:{get:function(){console.warn("THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.");return !this.enableZoom},set:function(d){console.warn("THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.");this.enableZoom=!d}},noRotate:{get:function(){console.warn("THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.");return !this.enableRotate},set:function(d){console.warn("THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.");this.enableRotate=!d}},noPan:{get:function(){console.warn("THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.");return !this.enablePan},set:function(d){console.warn("THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.");this.enablePan=!d}},noKeys:{get:function(){console.warn("THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.");return !this.enableKeys},set:function(d){console.warn("THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.");this.enableKeys=!d}},staticMoving:{get:function(){console.warn("THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.");return !this.enableDamping},set:function(d){console.warn("THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.");this.enableDamping=!d}},dynamicDampingFactor:{get:function(){console.warn("THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.");return this.dampingFactor},set:function(d){console.warn("THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.");this.dampingFactor=d}}});c.TransformControls=function(q,H){c.Object3D.call(this);H=(H!==undefined)?H:a;this.visible=false;var f=new c.TransformControlsGizmo();this.add(f);var u=new c.TransformControlsPlane();this.add(u);var C=this;F("camera",q);F("object",undefined);F("enabled",true);F("axis",null);F("mode","translate");F("translationSnap",null);F("rotationSnap",null);F("space","world");F("size",1);F("dragging",false);F("showX",true);F("showY",true);F("showZ",true);var P={type:"change"};var d={type:"mouseDown"};var h={type:"mouseUp",mode:C.mode};var S={type:"objectChange"};var O=new c.Raycaster();var R=new c.Vector3();var o=new c.Vector3();var l=new c.Quaternion();var L={X:new c.Vector3(1,0,0),Y:new c.Vector3(0,1,0),Z:new c.Vector3(0,0,1)};var A=new c.Quaternion();var w=new c.Vector3();var i=new c.Vector3();var N=new c.Vector3();var g=new c.Vector3();var p=0;var m=new c.Vector3();var z=new c.Quaternion();var s=new c.Vector3();var E=new c.Vector3();var Q=new c.Quaternion();var e=new c.Vector3();var T=new c.Vector3();var t=new c.Quaternion();var j=new c.Vector3();var n=new c.Vector3();var y=new c.Quaternion();var k=new c.Vector3();var G=new c.Vector3();var x=new c.Vector3();var r=new c.Quaternion();var I=new c.Vector3();F("parentQuaternion",Q);F("worldPosition",n);F("worldPositionStart",T);F("worldQuaternion",y);F("worldQuaternionStart",t);F("cameraPosition",m);F("cameraQuaternion",z);F("pointStart",i);F("pointEnd",N);F("rotationAxis",g);F("rotationAngle",p);F("eye",G);H.addEventListener("mousedown",B,false);H.addEventListener("touchstart",B,false);H.addEventListener("mousemove",v,false);H.addEventListener("touchmove",v,false);a.addEventListener("mousemove",J,false);H.addEventListener("touchmove",J,false);a.addEventListener("mouseup",D,false);H.addEventListener("touchend",D,false);H.addEventListener("touchcancel",D,false);H.addEventListener("touchleave",D,false);H.addEventListener("contextmenu",K,false);this.dispose=function(){H.removeEventListener("mousedown",B);H.removeEventListener("touchstart",B);H.removeEventListener("mousemove",v);H.removeEventListener("touchmove",v);a.removeEventListener("mousemove",J);H.removeEventListener("touchmove",J);a.removeEventListener("mouseup",D);H.removeEventListener("touchend",D);H.removeEventListener("touchcancel",D);H.removeEventListener("touchleave",D);H.removeEventListener("contextmenu",K)};this.attach=function(U){this.object=U;this.visible=true};this.detach=function(){this.object=undefined;this.visible=false;this.axis=null};function F(V,U){var W=U;Object.defineProperty(C,V,{get:function(){return W!==undefined?W:U},set:function(X){if(W!==X){W=X;u[V]=X;f[V]=X;C.dispatchEvent({type:V+"-changed",value:X});C.dispatchEvent(P)}}});C[V]=U;u[V]=U;f[V]=U}this.updateMatrixWorld=function(){if(this.object!==undefined){this.object.updateMatrixWorld();this.object.parent.matrixWorld.decompose(E,Q,e);this.object.matrixWorld.decompose(n,y,k)}this.camera.updateMatrixWorld();this.camera.matrixWorld.decompose(m,z,s);if(this.camera instanceof c.PerspectiveCamera){G.copy(m).sub(n).normalize()}else{if(this.camera instanceof c.OrthographicCamera){G.copy(m).normalize()}}c.Object3D.prototype.updateMatrixWorld.call(this)};this.pointerHover=function(V){if(this.object===undefined||this.dragging===true||(V.button!==undefined&&V.button!==0)){return}O.setFromCamera(V,this.camera);var U=O.intersectObjects(f.picker[this.mode].children,true)[0]||false;if(U){this.axis=U.object.name}else{this.axis=null}};this.pointerDown=function(X){if(this.object===undefined||this.dragging===true||(X.button!==undefined&&X.button!==0)){return}if((X.button===0||X.button===undefined)&&this.axis!==null){O.setFromCamera(X,this.camera);var V=O.intersectObjects([u],true)[0]||false;if(V){var W=this.space;if(this.mode==="scale"){W="local"}else{if(this.axis==="E"||this.axis==="XYZE"||this.axis==="XYZ"){W="world"}}if(W==="local"&&this.mode==="rotate"){var U=this.rotationSnap;if(this.axis==="X"&&U){this.object.rotation.x=Math.round(this.object.rotation.x/U)*U}if(this.axis==="Y"&&U){this.object.rotation.y=Math.round(this.object.rotation.y/U)*U}if(this.axis==="Z"&&U){this.object.rotation.z=Math.round(this.object.rotation.z/U)*U}}this.object.updateMatrixWorld();this.object.parent.updateMatrixWorld();x.copy(this.object.position);r.copy(this.object.quaternion);I.copy(this.object.scale);this.object.matrixWorld.decompose(T,t,j);i.copy(V.point).sub(T);if(W==="local"){i.applyQuaternion(t.clone().inverse())}}this.dragging=true;d.mode=this.mode;this.dispatchEvent(d)}};this.pointerMove=function(U){var W=this.axis;var aa=this.mode;var X=this.object;var V=this.space;if(aa==="scale"){V="local"}else{if(W==="E"||W==="XYZE"||W==="XYZ"){V="world"}}if(X===undefined||W===null||this.dragging===false||(U.button!==undefined&&U.button!==0)){return}O.setFromCamera(U,this.camera);var Z=O.intersectObjects([u],true)[0]||false;if(Z===false){return}N.copy(Z.point).sub(T);if(V==="local"){N.applyQuaternion(t.clone().inverse())}if(aa==="translate"){if(W.search("X")===-1){N.x=i.x}if(W.search("Y")===-1){N.y=i.y}if(W.search("Z")===-1){N.z=i.z}if(V==="local"){X.position.copy(N).sub(i).applyQuaternion(r)}else{X.position.copy(N).sub(i)}X.position.add(x);if(this.translationSnap){if(V==="local"){X.position.applyQuaternion(l.copy(r).inverse());if(W.search("X")!==-1){X.position.x=Math.round(X.position.x/this.translationSnap)*this.translationSnap}if(W.search("Y")!==-1){X.position.y=Math.round(X.position.y/this.translationSnap)*this.translationSnap}if(W.search("Z")!==-1){X.position.z=Math.round(X.position.z/this.translationSnap)*this.translationSnap}X.position.applyQuaternion(r)}if(V==="world"){if(X.parent){X.position.add(R.setFromMatrixPosition(X.parent.matrixWorld))}if(W.search("X")!==-1){X.position.x=Math.round(X.position.x/this.translationSnap)*this.translationSnap}if(W.search("Y")!==-1){X.position.y=Math.round(X.position.y/this.translationSnap)*this.translationSnap}if(W.search("Z")!==-1){X.position.z=Math.round(X.position.z/this.translationSnap)*this.translationSnap}if(X.parent){X.position.sub(R.setFromMatrixPosition(X.parent.matrixWorld))}}}}else{if(aa==="scale"){if(W.search("XYZ")!==-1){var ab=N.length()/i.length();if(N.dot(i)<0){ab*=-1}R.set(ab,ab,ab)}else{R.copy(N).divide(i);if(W.search("X")===-1){R.x=1}if(W.search("Y")===-1){R.y=1}if(W.search("Z")===-1){R.z=1}}X.scale.copy(I).multiply(R)}else{if(aa==="rotate"){var ad=20/n.distanceTo(R.setFromMatrixPosition(this.camera.matrixWorld));var Y=this.space==="local"?y:A;var ac=L[W];if(W==="E"){R.copy(N).cross(i);g.copy(G);p=N.angleTo(i)*(R.dot(G)<0?1:-1)}else{if(W==="XYZE"){R.copy(N).sub(i).cross(G).normalize();g.copy(R);p=N.sub(i).dot(R.cross(G))*ad}else{if(W==="X"||W==="Y"||W==="Z"){w.copy(ac).applyQuaternion(Y);g.copy(ac);R=ac.clone();o=N.clone().sub(i);if(V==="local"){R.applyQuaternion(Y);o.applyQuaternion(t)}p=o.dot(R.cross(G).normalize())*ad}}}if(this.rotationSnap){p=Math.round(p/this.rotationSnap)*this.rotationSnap}this.rotationAngle=p;if(V==="local"){X.quaternion.copy(r);X.quaternion.multiply(l.setFromAxisAngle(g,p))}else{X.quaternion.copy(l.setFromAxisAngle(g,p));X.quaternion.multiply(r)}}}}this.dispatchEvent(P);this.dispatchEvent(S)};this.pointerUp=function(U){if(U.button!==undefined&&U.button!==0){return}if(this.dragging&&(this.axis!==null)){h.mode=this.mode;this.dispatchEvent(h)}this.dragging=false;if(U.button===undefined){this.axis=null}};function M(V){var W=V.changedTouches?V.changedTouches[0]:V;var U=H.getBoundingClientRect();return{x:(W.clientX-U.left)/U.width*2-1,y:-(W.clientY-U.top)/U.height*2+1,button:V.button}}function K(U){U.preventDefault()}function v(U){if(!C.enabled){return}C.pointerHover(M(U))}function B(U){if(!C.enabled){return}U.preventDefault();C.pointerHover(M(U));C.pointerDown(M(U))}function J(U){if(!C.enabled){return}U.preventDefault();C.pointerMove(M(U))}function D(U){if(!C.enabled){return}U.preventDefault();C.pointerUp(M(U))}this.getMode=function(){return C.mode};this.setMode=function(U){C.mode=U};this.setTranslationSnap=function(U){C.translationSnap=U};this.setRotationSnap=function(U){C.rotationSnap=U};this.setSize=function(U){C.size=U};this.setSpace=function(U){C.space=U};this.update=function(){console.warn("THREE.TransformControls: update function has been depricated.")}};c.TransformControls.prototype=Object.assign(Object.create(c.Object3D.prototype),{constructor:c.TransformControls,isTransformControls:true});c.TransformControlsGizmo=function(){c.Object3D.call(this);this.type="TransformControlsGizmo";var q=new c.MeshBasicMaterial({depthTest:false,depthWrite:false,transparent:true,side:c.DoubleSide,fog:false});var e=new c.LineBasicMaterial({depthTest:false,depthWrite:false,transparent:true,linewidth:1,fog:false});var t=q.clone();t.opacity=0.15;var d=q.clone();d.opacity=0.33;var N=q.clone();N.color.set(16711680);var n=q.clone();n.color.set(65280);var T=q.clone();T.color.set(255);var g=q.clone();g.opacity=0.25;var x=g.clone();x.color.set(16776960);var V=g.clone();V.color.set(65535);var H=g.clone();H.color.set(16711935);var W=q.clone();W.color.set(16776960);var p=e.clone();p.color.set(16711680);var G=e.clone();G.color.set(65280);var O=e.clone();O.color.set(255);var j=e.clone();j.color.set(65535);var F=e.clone();F.color.set(16711935);var s=e.clone();s.color.set(16776960);var A=e.clone();A.color.set(7895160);var m=s.clone();m.opacity=0.25;var K=new c.CylinderBufferGeometry(0,0.05,0.2,12,1,false);var y=new c.BoxBufferGeometry(0.125,0.125,0.125);var I=new c.BufferGeometry();I.addAttribute("position",new c.Float32BufferAttribute([0,0,0,1,0,0],3));var w=function(X,aa){var ab=new c.BufferGeometry();var Y=[];for(var Z=0;Z<=64*aa;++Z){Y.push(0,Math.cos(Z/32*Math.PI)*X,Math.sin(Z/32*Math.PI)*X)}ab.addAttribute("position",new c.Float32BufferAttribute(Y,3));return ab};var r=function(X,Y){var Z=new c.BufferGeometry();Z.addAttribute("position",new c.Float32BufferAttribute([0,0,0,1,1,1],3));return Z};var C={X:[[new c.Mesh(K,N),[1,0,0],[0,0,-Math.PI/2],null,"fwd"],[new c.Mesh(K,N),[1,0,0],[0,0,Math.PI/2],null,"bwd"],[new c.Line(I,p)]],Y:[[new c.Mesh(K,n),[0,1,0],null,null,"fwd"],[new c.Mesh(K,n),[0,1,0],[Math.PI,0,0],null,"bwd"],[new c.Line(I,G),null,[0,0,Math.PI/2]]],Z:[[new c.Mesh(K,T),[0,0,1],[Math.PI/2,0,0],null,"fwd"],[new c.Mesh(K,T),[0,0,1],[-Math.PI/2,0,0],null,"bwd"],[new c.Line(I,O),null,[0,-Math.PI/2,0]]],XYZ:[[new c.Mesh(new c.OctahedronBufferGeometry(0.1,0),g),[0,0,0],[0,0,0]]],XY:[[new c.Mesh(new c.PlaneBufferGeometry(0.295,0.295),x),[0.15,0.15,0]],[new c.Line(I,s),[0.18,0.3,0],null,[0.125,1,1]],[new c.Line(I,s),[0.3,0.18,0],[0,0,Math.PI/2],[0.125,1,1]]],YZ:[[new c.Mesh(new c.PlaneBufferGeometry(0.295,0.295),V),[0,0.15,0.15],[0,Math.PI/2,0]],[new c.Line(I,j),[0,0.18,0.3],[0,0,Math.PI/2],[0.125,1,1]],[new c.Line(I,j),[0,0.3,0.18],[0,-Math.PI/2,0],[0.125,1,1]]],XZ:[[new c.Mesh(new c.PlaneBufferGeometry(0.295,0.295),H),[0.15,0,0.15],[-Math.PI/2,0,0]],[new c.Line(I,F),[0.18,0,0.3],null,[0.125,1,1]],[new c.Line(I,F),[0.3,0,0.18],[0,-Math.PI/2,0],[0.125,1,1]]]};var u={X:[[new c.Mesh(new c.CylinderBufferGeometry(0.2,0,1,4,1,false),t),[0.6,0,0],[0,0,-Math.PI/2]]],Y:[[new c.Mesh(new c.CylinderBufferGeometry(0.2,0,1,4,1,false),t),[0,0.6,0]]],Z:[[new c.Mesh(new c.CylinderBufferGeometry(0.2,0,1,4,1,false),t),[0,0,0.6],[Math.PI/2,0,0]]],XYZ:[[new c.Mesh(new c.OctahedronBufferGeometry(0.2,0),t)]],XY:[[new c.Mesh(new c.PlaneBufferGeometry(0.4,0.4),t),[0.2,0.2,0]]],YZ:[[new c.Mesh(new c.PlaneBufferGeometry(0.4,0.4),t),[0,0.2,0.2],[0,Math.PI/2,0]]],XZ:[[new c.Mesh(new c.PlaneBufferGeometry(0.4,0.4),t),[0.2,0,0.2],[-Math.PI/2,0,0]]]};var B={START:[[new c.Mesh(new c.OctahedronBufferGeometry(0.01,2),d),null,null,null,"helper"]],END:[[new c.Mesh(new c.OctahedronBufferGeometry(0.01,2),d),null,null,null,"helper"]],DELTA:[[new c.Line(r(),d),null,null,null,"helper"]],X:[[new c.Line(I,d.clone()),[-1000,0,0],null,[1000000,1,1],"helper"]],Y:[[new c.Line(I,d.clone()),[0,-1000,0],[0,0,Math.PI/2],[1000000,1,1],"helper"]],Z:[[new c.Line(I,d.clone()),[0,0,-1000],[0,-Math.PI/2,0],[1000000,1,1],"helper"]]};var U={X:[[new c.Line(w(1,0.5),p)],[new c.Mesh(new c.OctahedronBufferGeometry(0.04,0),N),[0,0,0.99],null,[1,3,1]]],Y:[[new c.Line(w(1,0.5),G),null,[0,0,-Math.PI/2]],[new c.Mesh(new c.OctahedronBufferGeometry(0.04,0),n),[0,0,0.99],null,[3,1,1]]],Z:[[new c.Line(w(1,0.5),O),null,[0,Math.PI/2,0]],[new c.Mesh(new c.OctahedronBufferGeometry(0.04,0),T),[0.99,0,0],null,[1,3,1]]],E:[[new c.Line(w(1.25,1),m),null,[0,Math.PI/2,0]],[new c.Mesh(new c.CylinderBufferGeometry(0.03,0,0.15,4,1,false),m),[1.17,0,0],[0,0,-Math.PI/2],[1,1,0.001]],[new c.Mesh(new c.CylinderBufferGeometry(0.03,0,0.15,4,1,false),m),[-1.17,0,0],[0,0,Math.PI/2],[1,1,0.001]],[new c.Mesh(new c.CylinderBufferGeometry(0.03,0,0.15,4,1,false),m),[0,-1.17,0],[Math.PI,0,0],[1,1,0.001]],[new c.Mesh(new c.CylinderBufferGeometry(0.03,0,0.15,4,1,false),m),[0,1.17,0],[0,0,0],[1,1,0.001]]],XYZE:[[new c.Line(w(1,1),A),null,[0,Math.PI/2,0]]]};var Q={AXIS:[[new c.Line(I,d.clone()),[-1000,0,0],null,[1000000,1,1],"helper"]]};var S={X:[[new c.Mesh(new c.TorusBufferGeometry(1,0.1,4,24),t),[0,0,0],[0,-Math.PI/2,-Math.PI/2]]],Y:[[new c.Mesh(new c.TorusBufferGeometry(1,0.1,4,24),t),[0,0,0],[Math.PI/2,0,0]]],Z:[[new c.Mesh(new c.TorusBufferGeometry(1,0.1,4,24),t),[0,0,0],[0,0,-Math.PI/2]]],E:[[new c.Mesh(new c.TorusBufferGeometry(1.25,0.1,2,24),t)]],XYZE:[[new c.Mesh(new c.SphereBufferGeometry(0.7,10,8),t)]]};var D={X:[[new c.Mesh(y,N),[0.8,0,0],[0,0,-Math.PI/2]],[new c.Line(I,p),null,null,[0.8,1,1]]],Y:[[new c.Mesh(y,n),[0,0.8,0]],[new c.Line(I,G),null,[0,0,Math.PI/2],[0.8,1,1]]],Z:[[new c.Mesh(y,T),[0,0,0.8],[Math.PI/2,0,0]],[new c.Line(I,O),null,[0,-Math.PI/2,0],[0.8,1,1]]],XY:[[new c.Mesh(y,x),[0.85,0.85,0],null,[2,2,0.2]],[new c.Line(I,s),[0.855,0.98,0],null,[0.125,1,1]],[new c.Line(I,s),[0.98,0.855,0],[0,0,Math.PI/2],[0.125,1,1]]],YZ:[[new c.Mesh(y,V),[0,0.85,0.85],null,[0.2,2,2]],[new c.Line(I,j),[0,0.855,0.98],[0,0,Math.PI/2],[0.125,1,1]],[new c.Line(I,j),[0,0.98,0.855],[0,-Math.PI/2,0],[0.125,1,1]]],XZ:[[new c.Mesh(y,H),[0.85,0,0.85],null,[2,0.2,2]],[new c.Line(I,F),[0.855,0,0.98],null,[0.125,1,1]],[new c.Line(I,F),[0.98,0,0.855],[0,-Math.PI/2,0],[0.125,1,1]]],XYZX:[[new c.Mesh(new c.BoxBufferGeometry(0.125,0.125,0.125),g),[1.1,0,0]]],XYZY:[[new c.Mesh(new c.BoxBufferGeometry(0.125,0.125,0.125),g),[0,1.1,0]]],XYZZ:[[new c.Mesh(new c.BoxBufferGeometry(0.125,0.125,0.125),g),[0,0,1.1]]]};var J={X:[[new c.Mesh(new c.CylinderBufferGeometry(0.2,0,0.8,4,1,false),t),[0.5,0,0],[0,0,-Math.PI/2]]],Y:[[new c.Mesh(new c.CylinderBufferGeometry(0.2,0,0.8,4,1,false),t),[0,0.5,0]]],Z:[[new c.Mesh(new c.CylinderBufferGeometry(0.2,0,0.8,4,1,false),t),[0,0,0.5],[Math.PI/2,0,0]]],XY:[[new c.Mesh(y,t),[0.85,0.85,0],null,[3,3,0.2]]],YZ:[[new c.Mesh(y,t),[0,0.85,0.85],null,[0.2,3,3]]],XZ:[[new c.Mesh(y,t),[0.85,0,0.85],null,[3,0.2,3]]],XYZX:[[new c.Mesh(new c.BoxBufferGeometry(0.2,0.2,0.2),t),[1.1,0,0]]],XYZY:[[new c.Mesh(new c.BoxBufferGeometry(0.2,0.2,0.2),t),[0,1.1,0]]],XYZZ:[[new c.Mesh(new c.BoxBufferGeometry(0.2,0.2,0.2),t),[0,0,1.1]]]};var E={X:[[new c.Line(I,d.clone()),[-1000,0,0],null,[1000000,1,1],"helper"]],Y:[[new c.Line(I,d.clone()),[0,-1000,0],[0,0,Math.PI/2],[1000000,1,1],"helper"]],Z:[[new c.Line(I,d.clone()),[0,0,-1000],[0,-Math.PI/2,0],[1000000,1,1],"helper"]]};var R=function(ae){var ab=new c.Object3D();for(var X in ae){for(var ac=ae[X].length;ac--;){var aa=ae[X][ac][0].clone();var ad=ae[X][ac][1];var af=ae[X][ac][2];var Z=ae[X][ac][3];var ag=ae[X][ac][4];aa.name=X;aa.tag=ag;if(ad){aa.position.set(ad[0],ad[1],ad[2])}if(af){aa.rotation.set(af[0],af[1],af[2])}if(Z){aa.scale.set(Z[0],Z[1],Z[2])}aa.updateMatrix();var Y=aa.geometry.clone();Y.applyMatrix(aa.matrix);aa.geometry=Y;aa.position.set(0,0,0);aa.rotation.set(0,0,0);aa.scale.set(1,1,1);ab.add(aa)}}return ab};var z=new c.Vector3(0,0,0);var P=new c.Euler();var v=new c.Vector3(0,1,0);var f=new c.Vector3(0,0,0);var L=new c.Matrix4();var h=new c.Quaternion();var o=new c.Quaternion();var M=new c.Quaternion();var l=new c.Vector3(1,0,0);var k=new c.Vector3(0,1,0);var i=new c.Vector3(0,0,1);this.gizmo={};this.picker={};this.helper={};this.add(this.gizmo.translate=R(C));this.add(this.gizmo.rotate=R(U));this.add(this.gizmo.scale=R(D));this.add(this.picker.translate=R(u));this.add(this.picker.rotate=R(S));this.add(this.picker.scale=R(J));this.add(this.helper.translate=R(B));this.add(this.helper.rotate=R(Q));this.add(this.helper.scale=R(E));this.picker.translate.visible=false;this.picker.rotate.visible=false;this.picker.scale.visible=false;this.updateMatrixWorld=function(){var X=this.space;if(this.mode==="scale"){X="local"}var Y=X==="local"?this.worldQuaternion:M;this.gizmo.translate.visible=this.mode==="translate";this.gizmo.rotate.visible=this.mode==="rotate";this.gizmo.scale.visible=this.mode==="scale";this.helper.translate.visible=this.mode==="translate";this.helper.rotate.visible=this.mode==="rotate";this.helper.scale.visible=this.mode==="scale";var ad=[];ad=ad.concat(this.picker[this.mode].children);ad=ad.concat(this.gizmo[this.mode].children);ad=ad.concat(this.helper[this.mode].children);for(var Z=0;Z<ad.length;Z++){var aa=ad[Z];aa.visible=true;aa.rotation.set(0,0,0);aa.position.copy(this.worldPosition);var ab=this.worldPosition.distanceTo(this.cameraPosition);aa.scale.set(1,1,1).multiplyScalar(ab*this.size/7);if(aa.tag==="helper"){aa.visible=false;if(aa.name==="AXIS"){aa.position.copy(this.worldPositionStart);aa.visible=!!this.axis;if(this.axis==="X"){h.setFromEuler(P.set(0,0,0));aa.quaternion.copy(Y).multiply(h);if(Math.abs(v.copy(l).applyQuaternion(Y).dot(this.eye))>0.9){aa.visible=false}}if(this.axis==="Y"){h.setFromEuler(P.set(0,0,Math.PI/2));aa.quaternion.copy(Y).multiply(h);if(Math.abs(v.copy(k).applyQuaternion(Y).dot(this.eye))>0.9){aa.visible=false}}if(this.axis==="Z"){h.setFromEuler(P.set(0,Math.PI/2,0));aa.quaternion.copy(Y).multiply(h);if(Math.abs(v.copy(i).applyQuaternion(Y).dot(this.eye))>0.9){aa.visible=false}}if(this.axis==="XYZE"){h.setFromEuler(P.set(0,Math.PI/2,0));v.copy(this.rotationAxis);aa.quaternion.setFromRotationMatrix(L.lookAt(f,v,k));aa.quaternion.multiply(h);aa.visible=this.dragging}if(this.axis==="E"){aa.visible=false}}else{if(aa.name==="START"){aa.position.copy(this.worldPositionStart);aa.visible=this.dragging}else{if(aa.name==="END"){aa.position.copy(this.worldPosition);aa.visible=this.dragging}else{if(aa.name==="DELTA"){aa.position.copy(this.worldPositionStart);aa.quaternion.copy(this.worldQuaternionStart);z.set(1e-10,1e-10,1e-10).add(this.worldPositionStart).sub(this.worldPosition).multiplyScalar(-1);z.applyQuaternion(this.worldQuaternionStart.clone().inverse());aa.scale.copy(z);aa.visible=this.dragging}else{aa.quaternion.copy(Y);if(this.dragging){aa.position.copy(this.worldPositionStart)}else{aa.position.copy(this.worldPosition)}if(this.axis){aa.visible=this.axis.search(aa.name)!==-1}}}}}continue}aa.quaternion.copy(Y);if(this.mode==="translate"||this.mode==="scale"){var af=0.99;var ae=0.2;var ac=-0.4;if(aa.name==="X"||aa.name==="XYZX"){if(Math.abs(v.copy(l).applyQuaternion(Y).dot(this.eye))>af){aa.scale.set(1e-10,1e-10,1e-10);aa.visible=false}}if(aa.name==="Y"||aa.name==="XYZY"){if(Math.abs(v.copy(k).applyQuaternion(Y).dot(this.eye))>af){aa.scale.set(1e-10,1e-10,1e-10);aa.visible=false}}if(aa.name==="Z"||aa.name==="XYZZ"){if(Math.abs(v.copy(i).applyQuaternion(Y).dot(this.eye))>af){aa.scale.set(1e-10,1e-10,1e-10);aa.visible=false}}if(aa.name==="XY"){if(Math.abs(v.copy(i).applyQuaternion(Y).dot(this.eye))<ae){aa.scale.set(1e-10,1e-10,1e-10);aa.visible=false}}if(aa.name==="YZ"){if(Math.abs(v.copy(l).applyQuaternion(Y).dot(this.eye))<ae){aa.scale.set(1e-10,1e-10,1e-10);aa.visible=false}}if(aa.name==="XZ"){if(Math.abs(v.copy(k).applyQuaternion(Y).dot(this.eye))<ae){aa.scale.set(1e-10,1e-10,1e-10);aa.visible=false}}if(aa.name.search("X")!==-1){if(v.copy(l).applyQuaternion(Y).dot(this.eye)<ac){if(aa.tag==="fwd"){aa.visible=false}else{aa.scale.x*=-1}}else{if(aa.tag==="bwd"){aa.visible=false}}}if(aa.name.search("Y")!==-1){if(v.copy(k).applyQuaternion(Y).dot(this.eye)<ac){if(aa.tag==="fwd"){aa.visible=false}else{aa.scale.y*=-1}}else{if(aa.tag==="bwd"){aa.visible=false}}}if(aa.name.search("Z")!==-1){if(v.copy(i).applyQuaternion(Y).dot(this.eye)<ac){if(aa.tag==="fwd"){aa.visible=false}else{aa.scale.z*=-1}}else{if(aa.tag==="bwd"){aa.visible=false}}}}else{if(this.mode==="rotate"){o.copy(Y);v.copy(this.eye).applyQuaternion(h.copy(Y).inverse());if(aa.name.search("E")!==-1){aa.quaternion.setFromRotationMatrix(L.lookAt(this.eye,f,k))}if(aa.name==="X"){h.setFromAxisAngle(l,Math.atan2(-v.y,v.z));h.multiplyQuaternions(o,h);aa.quaternion.copy(h)}if(aa.name==="Y"){h.setFromAxisAngle(k,Math.atan2(v.x,v.z));h.multiplyQuaternions(o,h);aa.quaternion.copy(h)}if(aa.name==="Z"){h.setFromAxisAngle(i,Math.atan2(v.y,v.x));h.multiplyQuaternions(o,h);aa.quaternion.copy(h)}}}aa.visible=aa.visible&&(aa.name.indexOf("X")===-1||this.showX);aa.visible=aa.visible&&(aa.name.indexOf("Y")===-1||this.showY);aa.visible=aa.visible&&(aa.name.indexOf("Z")===-1||this.showZ);aa.visible=aa.visible&&(aa.name.indexOf("E")===-1||(this.showX&&this.showY&&this.showZ));aa.material._opacity=aa.material._opacity||aa.material.opacity;aa.material._color=aa.material._color||aa.material.color.clone();aa.material.color.copy(aa.material._color);aa.material.opacity=aa.material._opacity;if(!this.enabled){aa.material.opacity*=0.5;aa.material.color.lerp(new c.Color(1,1,1),0.5)}else{if(this.axis){if(aa.name===this.axis){aa.material.opacity=1;aa.material.color.lerp(new c.Color(1,1,1),0.5)}else{if(this.axis.split("").some(function(ag){return aa.name===ag})){aa.material.opacity=1;aa.material.color.lerp(new c.Color(1,1,1),0.5)}else{aa.material.opacity*=0.25;aa.material.color.lerp(new c.Color(1,1,1),0.5)}}}}}c.Object3D.prototype.updateMatrixWorld.call(this)}};c.TransformControlsGizmo.prototype=Object.assign(Object.create(c.Object3D.prototype),{constructor:c.TransformControlsGizmo,isTransformControlsGizmo:true});c.TransformControlsPlane=function(){c.Mesh.call(this,new c.PlaneBufferGeometry(100000,100000,2,2),new c.MeshBasicMaterial({visible:false,wireframe:true,side:c.DoubleSide,transparent:true,opacity:0.1}));this.type="TransformControlsPlane";var k=new c.Vector3(1,0,0);var j=new c.Vector3(0,1,0);var i=new c.Vector3(0,0,1);var d=new c.Vector3();var h=new c.Vector3();var g=new c.Vector3();var f=new c.Matrix4();var e=new c.Quaternion();this.updateMatrixWorld=function(){var l=this.space;this.position.copy(this.worldPosition);if(this.mode==="scale"){l="local"}k.set(1,0,0).applyQuaternion(l==="local"?this.worldQuaternion:e);j.set(0,1,0).applyQuaternion(l==="local"?this.worldQuaternion:e);i.set(0,0,1).applyQuaternion(l==="local"?this.worldQuaternion:e);g.copy(j);switch(this.mode){case"translate":case"scale":switch(this.axis){case"X":g.copy(this.eye).cross(k);h.copy(k).cross(g);break;case"Y":g.copy(this.eye).cross(j);h.copy(j).cross(g);break;case"Z":g.copy(this.eye).cross(i);h.copy(i).cross(g);break;case"XY":h.copy(i);break;case"YZ":h.copy(k);break;case"XZ":g.copy(i);h.copy(j);break;case"XYZ":case"E":h.set(0,0,0);break}break;case"rotate":default:h.set(0,0,0)}if(h.length()===0){this.quaternion.copy(this.cameraQuaternion)}else{f.lookAt(d.set(0,0,0),h,g);this.quaternion.setFromRotationMatrix(f)}c.Object3D.prototype.updateMatrixWorld.call(this)}};c.TransformControlsPlane.prototype=Object.assign(Object.create(c.Mesh.prototype),{constructor:c.TransformControlsPlane,isTransformControlsPlane:true});c.CopyShader={uniforms:{tDiffuse:{value:null},opacity:{value:1}},vertexShader:["varying vec2 vUv;","void main() {","vUv = uv;","gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );","}"].join("\n"),fragmentShader:["uniform float opacity;","uniform sampler2D tDiffuse;","varying vec2 vUv;","void main() {","vec4 texel = texture2D( tDiffuse, vUv );","gl_FragColor = opacity * texel;","}"].join("\n")};c.EffectComposer=function(g,f){this.renderer=g;if(f===undefined){var e={minFilter:c.LinearFilter,magFilter:c.LinearFilter,format:c.RGBAFormat,stencilBuffer:false};var d=g.getDrawingBufferSize();f=new c.WebGLRenderTarget(d.width,d.height,e);f.texture.name="EffectComposer.rt1"}this.renderTarget1=f;this.renderTarget2=f.clone();this.renderTarget2.texture.name="EffectComposer.rt2";this.writeBuffer=this.renderTarget1;this.readBuffer=this.renderTarget2;this.passes=[];if(c.CopyShader===undefined){console.error("THREE.EffectComposer relies on THREE.CopyShader")}if(c.ShaderPass===undefined){console.error("THREE.EffectComposer relies on THREE.ShaderPass")}this.copyPass=new c.ShaderPass(c.CopyShader)};Object.assign(c.EffectComposer.prototype,{swapBuffers:function(){var d=this.readBuffer;this.readBuffer=this.writeBuffer;this.writeBuffer=d},addPass:function(e){this.passes.push(e);var d=this.renderer.getDrawingBufferSize();e.setSize(d.width,d.height)},insertPass:function(e,d){this.passes.splice(d,0,e)},render:function(j){var d=false;var h,g,e=this.passes.length;for(g=0;g<e;g++){h=this.passes[g];if(h.enabled===false){continue}h.render(this.renderer,this.writeBuffer,this.readBuffer,j,d);if(h.needsSwap){if(d){var f=this.renderer.context;f.stencilFunc(f.NOTEQUAL,1,4294967295);this.copyPass.render(this.renderer,this.writeBuffer,this.readBuffer,j);f.stencilFunc(f.EQUAL,1,4294967295)}this.swapBuffers()}if(c.MaskPass!==undefined){if(h instanceof c.MaskPass){d=true}else{if(h instanceof c.ClearMaskPass){d=false}}}}},reset:function(e){if(e===undefined){var d=this.renderer.getDrawingBufferSize();e=this.renderTarget1.clone();e.setSize(d.width,d.height)}this.renderTarget1.dispose();this.renderTarget2.dispose();this.renderTarget1=e;this.renderTarget2=e.clone();this.writeBuffer=this.renderTarget1;this.readBuffer=this.renderTarget2},setSize:function(f,d){this.renderTarget1.setSize(f,d);this.renderTarget2.setSize(f,d);for(var e=0;e<this.passes.length;e++){this.passes[e].setSize(f,d)}}});c.Pass=function(){this.enabled=true;this.needsSwap=true;this.clear=false;this.renderToScreen=false};Object.assign(c.Pass.prototype,{setSize:function(e,d){},render:function(f,g,e,h,d){console.error("THREE.Pass: .render() must be implemented in derived pass.")}});c.MaskPass=function(e,d){c.Pass.call(this);this.scene=e;this.camera=d;this.clear=true;this.needsSwap=false;this.inverse=false};c.MaskPass.prototype=Object.assign(Object.create(c.Pass.prototype),{constructor:c.MaskPass,render:function(i,h,l,k,g){var e=i.context;var d=i.state;d.buffers.color.setMask(false);d.buffers.depth.setMask(false);d.buffers.color.setLocked(true);d.buffers.depth.setLocked(true);var j,f;if(this.inverse){j=0;f=1}else{j=1;f=0}d.buffers.stencil.setTest(true);d.buffers.stencil.setOp(e.REPLACE,e.REPLACE,e.REPLACE);d.buffers.stencil.setFunc(e.ALWAYS,j,4294967295);d.buffers.stencil.setClear(f);i.render(this.scene,this.camera,l,this.clear);i.render(this.scene,this.camera,h,this.clear);d.buffers.color.setLocked(false);d.buffers.depth.setLocked(false);d.buffers.stencil.setFunc(e.EQUAL,1,4294967295);d.buffers.stencil.setOp(e.KEEP,e.KEEP,e.KEEP)}});c.ClearMaskPass=function(){c.Pass.call(this);this.needsSwap=false};c.ClearMaskPass.prototype=Object.create(c.Pass.prototype);Object.assign(c.ClearMaskPass.prototype,{render:function(f,g,e,h,d){f.state.buffers.stencil.setTest(false)}});c.RenderPass=function(h,f,d,g,e){c.Pass.call(this);this.scene=h;this.camera=f;this.overrideMaterial=d;this.clearColor=g;this.clearAlpha=(e!==undefined)?e:0;this.clear=true;this.clearDepth=false;this.needsSwap=false};c.RenderPass.prototype=Object.assign(Object.create(c.Pass.prototype),{constructor:c.RenderPass,render:function(h,i,g,k,e){var d=h.autoClear;h.autoClear=false;this.scene.overrideMaterial=this.overrideMaterial;var j,f;if(this.clearColor){j=h.getClearColor().getHex();f=h.getClearAlpha();h.setClearColor(this.clearColor,this.clearAlpha)}if(this.clearDepth){h.clearDepth()}h.render(this.scene,this.camera,this.renderToScreen?null:g,this.clear);if(this.clearColor){h.setClearColor(j,f)}this.scene.overrideMaterial=null;h.autoClear=d}});c.ShaderPass=function(d,e){c.Pass.call(this);this.textureID=(e!==undefined)?e:"tDiffuse";if(d instanceof c.ShaderMaterial){this.uniforms=d.uniforms;this.material=d}else{if(d){this.uniforms=c.UniformsUtils.clone(d.uniforms);this.material=new c.ShaderMaterial({defines:Object.assign({},d.defines),uniforms:this.uniforms,vertexShader:d.vertexShader,fragmentShader:d.fragmentShader})}}this.camera=new c.OrthographicCamera(-1,1,1,-1,0,1);this.scene=new c.Scene();this.quad=new c.Mesh(new c.PlaneBufferGeometry(2,2),null);this.quad.frustumCulled=false;this.scene.add(this.quad)};c.ShaderPass.prototype=Object.assign(Object.create(c.Pass.prototype),{constructor:c.ShaderPass,render:function(f,g,e,h,d){if(this.uniforms[this.textureID]){this.uniforms[this.textureID].value=e.texture}this.quad.material=this.material;if(this.renderToScreen){f.render(this.scene,this.camera)}else{f.render(this.scene,this.camera,g,this.clear)}}});c.SSAOShader={uniforms:{tDiffuse:{value:null},tDepth:{value:null},size:{value:new c.Vector2(512,512)},cameraNear:{value:1},cameraFar:{value:100},radius:{value:32},onlyAO:{value:0},aoClamp:{value:0.25},lumInfluence:{value:0.7}},vertexShader:["varying vec2 vUv;","void main() {","vUv = uv;","gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );","}"].join("\n"),fragmentShader:["uniform float cameraNear;","uniform float cameraFar;","#ifdef USE_LOGDEPTHBUF","uniform float logDepthBufFC;","#endif","uniform float radius;","uniform bool onlyAO;","uniform vec2 size;","uniform float aoClamp;","uniform float lumInfluence;","uniform sampler2D tDiffuse;","uniform sampler2D tDepth;","varying vec2 vUv;","#define DL 2.399963229728653","#define EULER 2.718281828459045","const int samples = 64;","const bool useNoise = true;","const float noiseAmount = 0.0004;","const float diffArea = 0.4;","const float gDisplace = 0.4;","#include <packing>","vec2 rand( const vec2 coord ) {","vec2 noise;","if ( useNoise ) {","float nx = dot ( coord, vec2( 12.9898, 78.233 ) );","float ny = dot ( coord, vec2( 12.9898, 78.233 ) * 2.0 );","noise = clamp( fract ( 43758.5453 * sin( vec2( nx, ny ) ) ), 0.0, 1.0 );","} else {","float ff = fract( 1.0 - coord.s * ( size.x / 2.0 ) );","float gg = fract( coord.t * ( size.y / 2.0 ) );","noise = vec2( 0.25, 0.75 ) * vec2( ff ) + vec2( 0.75, 0.25 ) * gg;","}","return ( noise * 2.0 - 1.0 ) * noiseAmount;","}","float readDepth( const in vec2 coord ) {","float cameraFarPlusNear = cameraFar + cameraNear;","float cameraFarMinusNear = cameraFar - cameraNear;","float cameraCoef = 2.0 * cameraNear;","#ifdef USE_LOGDEPTHBUF","float logz = unpackRGBAToDepth( texture2D( tDepth, coord ) );","float w = pow(2.0, (logz / logDepthBufFC)) - 1.0;","float z = (logz / w) + 1.0;","#else","float z = unpackRGBAToDepth( texture2D( tDepth, coord ) );","#endif","return cameraCoef / ( cameraFarPlusNear - z * cameraFarMinusNear );","}","float compareDepths( const in float depth1, const in float depth2, inout int far ) {","float garea = 8.0;","float diff = ( depth1 - depth2 ) * 100.0;","if ( diff < gDisplace ) {","garea = diffArea;","} else {","far = 1;","}","float dd = diff - gDisplace;","float gauss = pow( EULER, -2.0 * ( dd * dd ) / ( garea * garea ) );","return gauss;","}","float calcAO( float depth, float dw, float dh ) {","vec2 vv = vec2( dw, dh );","vec2 coord1 = vUv + radius * vv;","vec2 coord2 = vUv - radius * vv;","float temp1 = 0.0;","float temp2 = 0.0;","int far = 0;","temp1 = compareDepths( depth, readDepth( coord1 ), far );","if ( far > 0 ) {","temp2 = compareDepths( readDepth( coord2 ), depth, far );","temp1 += ( 1.0 - temp1 ) * temp2;","}","return temp1;","}","void main() {","vec2 noise = rand( vUv );","float depth = readDepth( vUv );","float tt = clamp( depth, aoClamp, 1.0 );","float w = ( 1.0 / size.x ) / tt + ( noise.x * ( 1.0 - noise.x ) );","float h = ( 1.0 / size.y ) / tt + ( noise.y * ( 1.0 - noise.y ) );","float ao = 0.0;","float dz = 1.0 / float( samples );","float l = 0.0;","float z = 1.0 - dz / 2.0;","for ( int i = 0; i <= samples; i ++ ) {","float r = sqrt( 1.0 - z );","float pw = cos( l ) * r;","float ph = sin( l ) * r;","ao += calcAO( depth, pw * w, ph * h );","z = z - dz;","l = l + DL;","}","ao /= float( samples );","ao = 1.0 - ao;","vec3 color = texture2D( tDiffuse, vUv ).rgb;","vec3 lumcoeff = vec3( 0.299, 0.587, 0.114 );","float lum = dot( color.rgb, lumcoeff );","vec3 luminance = vec3( lum );","vec3 final = vec3( color * mix( vec3( ao ), vec3( 1.0 ), luminance * lumInfluence ) );","if ( onlyAO ) {","final = vec3( mix( vec3( ao ), vec3( 1.0 ), luminance * lumInfluence ) );","}","gl_FragColor = vec4( final, 1.0 );","}"].join("\n")}})); \ No newline at end of file diff --git a/js/scripts/three.min.js b/js/scripts/three.min.js new file mode 100644 index 00000000000..ca9b61105a7 --- /dev/null +++ b/js/scripts/three.min.js @@ -0,0 +1,966 @@ +// threejs.org/license +(function(l,ia){"object"===typeof exports&&"undefined"!==typeof module?ia(exports):"function"===typeof define&&define.amd?define(["exports"],ia):ia(l.THREE={})})(this,function(l){function ia(){}function A(a,b){this.x=a||0;this.y=b||0}function P(){this.elements=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1];0<arguments.length&&console.error("THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.")}function ja(a,b,c,d){this._x=a||0;this._y=b||0;this._z=c||0;this._w=void 0!==d?d:1}function p(a, +b,c){this.x=a||0;this.y=b||0;this.z=c||0}function oa(){this.elements=[1,0,0,0,1,0,0,0,1];0<arguments.length&&console.error("THREE.Matrix3: the constructor no longer reads arguments. use .set() instead.")}function Q(a,b,c,d,e,f,g,h,k,m){Object.defineProperty(this,"id",{value:Gf++});this.uuid=S.generateUUID();this.name="";this.image=void 0!==a?a:Q.DEFAULT_IMAGE;this.mipmaps=[];this.mapping=void 0!==b?b:Q.DEFAULT_MAPPING;this.wrapS=void 0!==c?c:1001;this.wrapT=void 0!==d?d:1001;this.magFilter=void 0!== +e?e:1006;this.minFilter=void 0!==f?f:1008;this.anisotropy=void 0!==k?k:1;this.format=void 0!==g?g:1023;this.type=void 0!==h?h:1009;this.offset=new A(0,0);this.repeat=new A(1,1);this.center=new A(0,0);this.rotation=0;this.matrixAutoUpdate=!0;this.matrix=new oa;this.generateMipmaps=!0;this.premultiplyAlpha=!1;this.flipY=!0;this.unpackAlignment=4;this.encoding=void 0!==m?m:3E3;this.version=0;this.onUpdate=null}function Z(a,b,c,d){this.x=a||0;this.y=b||0;this.z=c||0;this.w=void 0!==d?d:1}function ib(a, +b,c){this.width=a;this.height=b;this.scissor=new Z(0,0,a,b);this.scissorTest=!1;this.viewport=new Z(0,0,a,b);c=c||{};void 0===c.minFilter&&(c.minFilter=1006);this.texture=new Q(void 0,void 0,c.wrapS,c.wrapT,c.magFilter,c.minFilter,c.format,c.type,c.anisotropy,c.encoding);this.texture.generateMipmaps=void 0!==c.generateMipmaps?c.generateMipmaps:!0;this.depthBuffer=void 0!==c.depthBuffer?c.depthBuffer:!0;this.stencilBuffer=void 0!==c.stencilBuffer?c.stencilBuffer:!0;this.depthTexture=void 0!==c.depthTexture? +c.depthTexture:null}function Jb(a,b,c){ib.call(this,a,b,c);this.activeMipMapLevel=this.activeCubeFace=0}function jb(a,b,c,d,e,f,g,h,k,m,r,n){Q.call(this,null,f,g,h,k,m,d,e,r,n);this.image={data:a,width:b,height:c};this.magFilter=void 0!==k?k:1003;this.minFilter=void 0!==m?m:1003;this.flipY=this.generateMipmaps=!1;this.unpackAlignment=1}function Wa(a,b){this.min=void 0!==a?a:new p(Infinity,Infinity,Infinity);this.max=void 0!==b?b:new p(-Infinity,-Infinity,-Infinity)}function Fa(a,b){this.center=void 0!== +a?a:new p;this.radius=void 0!==b?b:0}function Pa(a,b){this.normal=void 0!==a?a:new p(1,0,0);this.constant=void 0!==b?b:0}function rd(a,b,c,d,e,f){this.planes=[void 0!==a?a:new Pa,void 0!==b?b:new Pa,void 0!==c?c:new Pa,void 0!==d?d:new Pa,void 0!==e?e:new Pa,void 0!==f?f:new Pa]}function G(a,b,c){return void 0===b&&void 0===c?this.set(a):this.setRGB(a,b,c)}function Wd(){function a(e,f){!1!==c&&(d(e,f),b.requestAnimationFrame(a))}var b=null,c=!1,d=null;return{start:function(){!0!==c&&null!==d&&(b.requestAnimationFrame(a), +c=!0)},stop:function(){c=!1},setAnimationLoop:function(a){d=a},setContext:function(a){b=a}}}function Hf(a){function b(b,c){var d=b.array,e=b.dynamic?a.DYNAMIC_DRAW:a.STATIC_DRAW,h=a.createBuffer();a.bindBuffer(c,h);a.bufferData(c,d,e);b.onUploadCallback();c=a.FLOAT;d instanceof Float32Array?c=a.FLOAT:d instanceof Float64Array?console.warn("THREE.WebGLAttributes: Unsupported data buffer format: Float64Array."):d instanceof Uint16Array?c=a.UNSIGNED_SHORT:d instanceof Int16Array?c=a.SHORT:d instanceof +Uint32Array?c=a.UNSIGNED_INT:d instanceof Int32Array?c=a.INT:d instanceof Int8Array?c=a.BYTE:d instanceof Uint8Array&&(c=a.UNSIGNED_BYTE);return{buffer:h,type:c,bytesPerElement:d.BYTES_PER_ELEMENT,version:b.version}}var c=new WeakMap;return{get:function(a){a.isInterleavedBufferAttribute&&(a=a.data);return c.get(a)},remove:function(b){b.isInterleavedBufferAttribute&&(b=b.data);var d=c.get(b);d&&(a.deleteBuffer(d.buffer),c.delete(b))},update:function(d,e){d.isInterleavedBufferAttribute&&(d=d.data); +var f=c.get(d);if(void 0===f)c.set(d,b(d,e));else if(f.version<d.version){var g=d,h=g.array,k=g.updateRange;a.bindBuffer(e,f.buffer);!1===g.dynamic?a.bufferData(e,h,a.STATIC_DRAW):-1===k.count?a.bufferSubData(e,0,h):0===k.count?console.error("THREE.WebGLObjects.updateBuffer: dynamic THREE.BufferAttribute marked as needsUpdate but updateRange.count is 0, ensure you are using set methods or updating manually."):(a.bufferSubData(e,k.offset*h.BYTES_PER_ELEMENT,h.subarray(k.offset,k.offset+k.count)),k.count= +-1);f.version=d.version}}}}function Xa(a,b,c,d,e,f){this.a=a;this.b=b;this.c=c;this.normal=d&&d.isVector3?d:new p;this.vertexNormals=Array.isArray(d)?d:[];this.color=e&&e.isColor?e:new G;this.vertexColors=Array.isArray(e)?e:[];this.materialIndex=void 0!==f?f:0}function kb(a,b,c,d){this._x=a||0;this._y=b||0;this._z=c||0;this._order=d||kb.DefaultOrder}function Xd(){this.mask=1}function C(){Object.defineProperty(this,"id",{value:If++});this.uuid=S.generateUUID();this.name="";this.type="Object3D";this.parent= +null;this.children=[];this.up=C.DefaultUp.clone();var a=new p,b=new kb,c=new ja,d=new p(1,1,1);b.onChange(function(){c.setFromEuler(b,!1)});c.onChange(function(){b.setFromQuaternion(c,void 0,!1)});Object.defineProperties(this,{position:{enumerable:!0,value:a},rotation:{enumerable:!0,value:b},quaternion:{enumerable:!0,value:c},scale:{enumerable:!0,value:d},modelViewMatrix:{value:new P},normalMatrix:{value:new oa}});this.matrix=new P;this.matrixWorld=new P;this.matrixAutoUpdate=C.DefaultMatrixAutoUpdate; +this.matrixWorldNeedsUpdate=!1;this.layers=new Xd;this.visible=!0;this.receiveShadow=this.castShadow=!1;this.frustumCulled=!0;this.renderOrder=0;this.userData={}}function M(){Object.defineProperty(this,"id",{value:Jf+=2});this.uuid=S.generateUUID();this.name="";this.type="Geometry";this.vertices=[];this.colors=[];this.faces=[];this.faceVertexUvs=[[]];this.morphTargets=[];this.morphNormals=[];this.skinWeights=[];this.skinIndices=[];this.lineDistances=[];this.boundingSphere=this.boundingBox=null;this.groupsNeedUpdate= +this.lineDistancesNeedUpdate=this.colorsNeedUpdate=this.normalsNeedUpdate=this.uvsNeedUpdate=this.verticesNeedUpdate=this.elementsNeedUpdate=!1}function I(a,b,c){if(Array.isArray(a))throw new TypeError("THREE.BufferAttribute: array should be a Typed Array.");this.name="";this.array=a;this.itemSize=b;this.count=void 0!==a?a.length/b:0;this.normalized=!0===c;this.dynamic=!1;this.updateRange={offset:0,count:-1};this.version=0}function sc(a,b,c){I.call(this,new Int8Array(a),b,c)}function tc(a,b,c){I.call(this, +new Uint8Array(a),b,c)}function uc(a,b,c){I.call(this,new Uint8ClampedArray(a),b,c)}function vc(a,b,c){I.call(this,new Int16Array(a),b,c)}function lb(a,b,c){I.call(this,new Uint16Array(a),b,c)}function wc(a,b,c){I.call(this,new Int32Array(a),b,c)}function mb(a,b,c){I.call(this,new Uint32Array(a),b,c)}function z(a,b,c){I.call(this,new Float32Array(a),b,c)}function xc(a,b,c){I.call(this,new Float64Array(a),b,c)}function Ge(){this.vertices=[];this.normals=[];this.colors=[];this.uvs=[];this.uvs2=[];this.groups= +[];this.morphTargets={};this.skinWeights=[];this.skinIndices=[];this.boundingSphere=this.boundingBox=null;this.groupsNeedUpdate=this.uvsNeedUpdate=this.colorsNeedUpdate=this.normalsNeedUpdate=this.verticesNeedUpdate=!1}function He(a){if(0===a.length)return-Infinity;for(var b=a[0],c=1,d=a.length;c<d;++c)a[c]>b&&(b=a[c]);return b}function F(){Object.defineProperty(this,"id",{value:Kf+=2});this.uuid=S.generateUUID();this.name="";this.type="BufferGeometry";this.index=null;this.attributes={};this.morphAttributes= +{};this.groups=[];this.boundingSphere=this.boundingBox=null;this.drawRange={start:0,count:Infinity};this.userData={}}function Kb(a,b,c,d,e,f){M.call(this);this.type="BoxGeometry";this.parameters={width:a,height:b,depth:c,widthSegments:d,heightSegments:e,depthSegments:f};this.fromBufferGeometry(new nb(a,b,c,d,e,f));this.mergeVertices()}function nb(a,b,c,d,e,f){function g(a,b,c,d,e,f,g,l,X,B,Lb){var t=f/X,u=g/B,y=f/2,w=g/2,x=l/2;g=X+1;var R=B+1,J=f=0,D,A,z=new p;for(A=0;A<R;A++){var C=A*u-w;for(D=0;D< +g;D++)z[a]=(D*t-y)*d,z[b]=C*e,z[c]=x,m.push(z.x,z.y,z.z),z[a]=0,z[b]=0,z[c]=0<l?1:-1,r.push(z.x,z.y,z.z),n.push(D/X),n.push(1-A/B),f+=1}for(A=0;A<B;A++)for(D=0;D<X;D++)a=q+D+g*(A+1),b=q+(D+1)+g*(A+1),c=q+(D+1)+g*A,k.push(q+D+g*A,a,c),k.push(a,b,c),J+=6;h.addGroup(v,J,Lb);v+=J;q+=f}F.call(this);this.type="BoxBufferGeometry";this.parameters={width:a,height:b,depth:c,widthSegments:d,heightSegments:e,depthSegments:f};var h=this;a=a||1;b=b||1;c=c||1;d=Math.floor(d)||1;e=Math.floor(e)||1;f=Math.floor(f)|| +1;var k=[],m=[],r=[],n=[],q=0,v=0;g("z","y","x",-1,-1,c,b,a,f,e,0);g("z","y","x",1,-1,c,b,-a,f,e,1);g("x","z","y",1,1,a,c,b,d,f,2);g("x","z","y",1,-1,a,c,-b,d,f,3);g("x","y","z",1,-1,a,b,c,d,e,4);g("x","y","z",-1,-1,a,b,-c,d,e,5);this.setIndex(k);this.addAttribute("position",new z(m,3));this.addAttribute("normal",new z(r,3));this.addAttribute("uv",new z(n,2))}function yc(a,b,c,d){M.call(this);this.type="PlaneGeometry";this.parameters={width:a,height:b,widthSegments:c,heightSegments:d};this.fromBufferGeometry(new ob(a, +b,c,d));this.mergeVertices()}function ob(a,b,c,d){F.call(this);this.type="PlaneBufferGeometry";this.parameters={width:a,height:b,widthSegments:c,heightSegments:d};a=a||1;b=b||1;var e=a/2,f=b/2;c=Math.floor(c)||1;d=Math.floor(d)||1;var g=c+1,h=d+1,k=a/c,m=b/d,r=[],n=[],q=[],v=[];for(a=0;a<h;a++){var t=a*m-f;for(b=0;b<g;b++)n.push(b*k-e,-t,0),q.push(0,0,1),v.push(b/c),v.push(1-a/d)}for(a=0;a<d;a++)for(b=0;b<c;b++)e=b+g*(a+1),f=b+1+g*(a+1),h=b+1+g*a,r.push(b+g*a,e,h),r.push(e,f,h);this.setIndex(r);this.addAttribute("position", +new z(n,3));this.addAttribute("normal",new z(q,3));this.addAttribute("uv",new z(v,2))}function L(){Object.defineProperty(this,"id",{value:Lf++});this.uuid=S.generateUUID();this.name="";this.type="Material";this.lights=this.fog=!0;this.blending=1;this.side=0;this.flatShading=!1;this.vertexColors=0;this.opacity=1;this.transparent=!1;this.blendSrc=204;this.blendDst=205;this.blendEquation=100;this.blendEquationAlpha=this.blendDstAlpha=this.blendSrcAlpha=null;this.depthFunc=3;this.depthWrite=this.depthTest= +!0;this.clippingPlanes=null;this.clipShadows=this.clipIntersection=!1;this.shadowSide=null;this.colorWrite=!0;this.precision=null;this.polygonOffset=!1;this.polygonOffsetUnits=this.polygonOffsetFactor=0;this.dithering=!1;this.alphaTest=0;this.premultipliedAlpha=!1;this.overdraw=0;this.visible=!0;this.userData={};this.needsUpdate=!0}function ka(a){L.call(this);this.type="ShaderMaterial";this.defines={};this.uniforms={};this.vertexShader="void main() {\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}"; +this.fragmentShader="void main() {\n\tgl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );\n}";this.linewidth=1;this.wireframe=!1;this.wireframeLinewidth=1;this.morphNormals=this.morphTargets=this.skinning=this.clipping=this.lights=this.fog=!1;this.extensions={derivatives:!1,fragDepth:!1,drawBuffers:!1,shaderTextureLOD:!1};this.defaultAttributeValues={color:[1,1,1],uv:[0,0],uv2:[0,0]};this.index0AttributeName=void 0;this.uniformsNeedUpdate=!1;void 0!==a&&(void 0!==a.attributes&&console.error("THREE.ShaderMaterial: attributes should now be defined in THREE.BufferGeometry instead."), +this.setValues(a))}function pb(a,b){this.origin=void 0!==a?a:new p;this.direction=void 0!==b?b:new p}function da(a,b,c){this.a=void 0!==a?a:new p;this.b=void 0!==b?b:new p;this.c=void 0!==c?c:new p}function wa(a){L.call(this);this.type="MeshBasicMaterial";this.color=new G(16777215);this.lightMap=this.map=null;this.lightMapIntensity=1;this.aoMap=null;this.aoMapIntensity=1;this.envMap=this.alphaMap=this.specularMap=null;this.combine=0;this.reflectivity=1;this.refractionRatio=.98;this.wireframe=!1;this.wireframeLinewidth= +1;this.wireframeLinejoin=this.wireframeLinecap="round";this.lights=this.morphTargets=this.skinning=!1;this.setValues(a)}function ua(a,b){C.call(this);this.type="Mesh";this.geometry=void 0!==a?a:new F;this.material=void 0!==b?b:new wa({color:16777215*Math.random()});this.drawMode=0;this.updateMorphTargets()}function Mf(a,b,c,d){function e(a,c){b.buffers.color.setClear(a.r,a.g,a.b,c,d)}var f=new G(0),g=0,h,k;return{getClearColor:function(){return f},setClearColor:function(a,b){f.set(a);g=void 0!==b? +b:1;e(f,g)},getClearAlpha:function(){return g},setClearAlpha:function(a){g=a;e(f,g)},render:function(b,d,n,q){d=d.background;null===d?e(f,g):d&&d.isColor&&(e(d,1),q=!0);(a.autoClear||q)&&a.clear(a.autoClearColor,a.autoClearDepth,a.autoClearStencil);d&&d.isCubeTexture?(void 0===k&&(k=new ua(new nb(1,1,1),new ka({uniforms:va.clone(Qa.cube.uniforms),vertexShader:Qa.cube.vertexShader,fragmentShader:Qa.cube.fragmentShader,side:1,depthTest:!0,depthWrite:!1,fog:!1})),k.geometry.removeAttribute("normal"), +k.geometry.removeAttribute("uv"),k.onBeforeRender=function(a,b,c){this.matrixWorld.copyPosition(c.matrixWorld)},c.update(k)),k.material.uniforms.tCube.value=d,b.push(k,k.geometry,k.material,0,null)):d&&d.isTexture&&(void 0===h&&(h=new ua(new ob(2,2),new ka({uniforms:va.clone(Qa.background.uniforms),vertexShader:Qa.background.vertexShader,fragmentShader:Qa.background.fragmentShader,side:0,depthTest:!0,depthWrite:!1,fog:!1})),h.geometry.removeAttribute("normal"),c.update(h)),h.material.uniforms.t2D.value= +d,b.push(h,h.geometry,h.material,0,null))}}}function Nf(a,b,c,d){var e;this.setMode=function(a){e=a};this.render=function(b,d){a.drawArrays(e,b,d);c.update(d,e)};this.renderInstances=function(f,g,h){if(d.isWebGL2)var k=a;else if(k=b.get("ANGLE_instanced_arrays"),null===k){console.error("THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.");return}k[d.isWebGL2?"drawArraysInstanced":"drawArraysInstancedANGLE"](e,g,h,f.maxInstancedCount); +c.update(h,e,f.maxInstancedCount)}}function Of(a,b,c){function d(b){if("highp"===b){if(0<a.getShaderPrecisionFormat(a.VERTEX_SHADER,a.HIGH_FLOAT).precision&&0<a.getShaderPrecisionFormat(a.FRAGMENT_SHADER,a.HIGH_FLOAT).precision)return"highp";b="mediump"}return"mediump"===b&&0<a.getShaderPrecisionFormat(a.VERTEX_SHADER,a.MEDIUM_FLOAT).precision&&0<a.getShaderPrecisionFormat(a.FRAGMENT_SHADER,a.MEDIUM_FLOAT).precision?"mediump":"lowp"}var e,f="undefined"!==typeof WebGL2RenderingContext&&a instanceof +WebGL2RenderingContext,g=void 0!==c.precision?c.precision:"highp",h=d(g);h!==g&&(console.warn("THREE.WebGLRenderer:",g,"not supported, using",h,"instead."),g=h);c=!0===c.logarithmicDepthBuffer;h=a.getParameter(a.MAX_TEXTURE_IMAGE_UNITS);var k=a.getParameter(a.MAX_VERTEX_TEXTURE_IMAGE_UNITS),m=a.getParameter(a.MAX_TEXTURE_SIZE),r=a.getParameter(a.MAX_CUBE_MAP_TEXTURE_SIZE),n=a.getParameter(a.MAX_VERTEX_ATTRIBS),q=a.getParameter(a.MAX_VERTEX_UNIFORM_VECTORS),v=a.getParameter(a.MAX_VARYING_VECTORS), +t=a.getParameter(a.MAX_FRAGMENT_UNIFORM_VECTORS),l=0<k,y=f||!!b.get("OES_texture_float");return{isWebGL2:f,getMaxAnisotropy:function(){if(void 0!==e)return e;var c=b.get("EXT_texture_filter_anisotropic");return e=null!==c?a.getParameter(c.MAX_TEXTURE_MAX_ANISOTROPY_EXT):0},getMaxPrecision:d,precision:g,logarithmicDepthBuffer:c,maxTextures:h,maxVertexTextures:k,maxTextureSize:m,maxCubemapSize:r,maxAttributes:n,maxVertexUniforms:q,maxVaryings:v,maxFragmentUniforms:t,vertexTextures:l,floatFragmentTextures:y, +floatVertexTextures:l&&y}}function Pf(){function a(){m.value!==d&&(m.value=d,m.needsUpdate=0<e);c.numPlanes=e;c.numIntersection=0}function b(a,b,d,e){var f=null!==a?a.length:0,g=null;if(0!==f){g=m.value;if(!0!==e||null===g){e=d+4*f;b=b.matrixWorldInverse;k.getNormalMatrix(b);if(null===g||g.length<e)g=new Float32Array(e);for(e=0;e!==f;++e,d+=4)h.copy(a[e]).applyMatrix4(b,k),h.normal.toArray(g,d),g[d+3]=h.constant}m.value=g;m.needsUpdate=!0}c.numPlanes=f;return g}var c=this,d=null,e=0,f=!1,g=!1,h=new Pa, +k=new oa,m={value:null,needsUpdate:!1};this.uniform=m;this.numIntersection=this.numPlanes=0;this.init=function(a,c,g){var h=0!==a.length||c||0!==e||f;f=c;d=b(a,g,0);e=a.length;return h};this.beginShadows=function(){g=!0;b(null)};this.endShadows=function(){g=!1;a()};this.setState=function(c,h,k,v,t,l){if(!f||null===c||0===c.length||g&&!k)g?b(null):a();else{k=g?0:e;var n=4*k,r=t.clippingState||null;m.value=r;r=b(c,v,n,l);for(c=0;c!==n;++c)r[c]=d[c];t.clippingState=r;this.numIntersection=h?this.numPlanes: +0;this.numPlanes+=k}}}function Qf(a){var b={};return{get:function(c){if(void 0!==b[c])return b[c];switch(c){case "WEBGL_depth_texture":var d=a.getExtension("WEBGL_depth_texture")||a.getExtension("MOZ_WEBGL_depth_texture")||a.getExtension("WEBKIT_WEBGL_depth_texture");break;case "EXT_texture_filter_anisotropic":d=a.getExtension("EXT_texture_filter_anisotropic")||a.getExtension("MOZ_EXT_texture_filter_anisotropic")||a.getExtension("WEBKIT_EXT_texture_filter_anisotropic");break;case "WEBGL_compressed_texture_s3tc":d= +a.getExtension("WEBGL_compressed_texture_s3tc")||a.getExtension("MOZ_WEBGL_compressed_texture_s3tc")||a.getExtension("WEBKIT_WEBGL_compressed_texture_s3tc");break;case "WEBGL_compressed_texture_pvrtc":d=a.getExtension("WEBGL_compressed_texture_pvrtc")||a.getExtension("WEBKIT_WEBGL_compressed_texture_pvrtc");break;default:d=a.getExtension(c)}null===d&&console.warn("THREE.WebGLRenderer: "+c+" extension not supported.");return b[c]=d}}}function Rf(a,b,c){function d(a){var h=a.target;a=e[h.id];null!== +a.index&&b.remove(a.index);for(var g in a.attributes)b.remove(a.attributes[g]);h.removeEventListener("dispose",d);delete e[h.id];if(g=f[a.id])b.remove(g),delete f[a.id];c.memory.geometries--}var e={},f={};return{get:function(a,b){var f=e[b.id];if(f)return f;b.addEventListener("dispose",d);b.isBufferGeometry?f=b:b.isGeometry&&(void 0===b._bufferGeometry&&(b._bufferGeometry=(new F).setFromObject(a)),f=b._bufferGeometry);e[b.id]=f;c.memory.geometries++;return f},update:function(c){var d=c.index,e=c.attributes; +null!==d&&b.update(d,a.ELEMENT_ARRAY_BUFFER);for(var f in e)b.update(e[f],a.ARRAY_BUFFER);c=c.morphAttributes;for(f in c){d=c[f];e=0;for(var g=d.length;e<g;e++)b.update(d[e],a.ARRAY_BUFFER)}},getWireframeAttribute:function(c){var d=f[c.id];if(d)return d;d=[];var e=c.index,g=c.attributes;if(null!==e){e=e.array;g=0;for(var r=e.length;g<r;g+=3){var n=e[g+0],q=e[g+1],v=e[g+2];d.push(n,q,q,v,v,n)}}else for(e=g.position.array,g=0,r=e.length/3-1;g<r;g+=3)n=g+0,q=g+1,v=g+2,d.push(n,q,q,v,v,n);d=new (65535< +He(d)?mb:lb)(d,1);b.update(d,a.ELEMENT_ARRAY_BUFFER);return f[c.id]=d}}}function Sf(a,b,c,d){var e,f,g;this.setMode=function(a){e=a};this.setIndex=function(a){f=a.type;g=a.bytesPerElement};this.render=function(b,d){a.drawElements(e,d,f,b*g);c.update(d,e)};this.renderInstances=function(h,k,m){if(d.isWebGL2)var r=a;else if(r=b.get("ANGLE_instanced_arrays"),null===r){console.error("THREE.WebGLIndexedBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays."); +return}r[d.isWebGL2?"drawElementsInstanced":"drawElementsInstancedANGLE"](e,m,f,k*g,h.maxInstancedCount);c.update(m,e,h.maxInstancedCount)}}function Tf(a){var b={frame:0,calls:0,triangles:0,points:0,lines:0};return{memory:{geometries:0,textures:0},render:b,programs:null,autoReset:!0,reset:function(){b.frame++;b.calls=0;b.triangles=0;b.points=0;b.lines=0},update:function(c,d,e){e=e||1;b.calls++;switch(d){case a.TRIANGLES:b.triangles+=c/3*e;break;case a.TRIANGLE_STRIP:case a.TRIANGLE_FAN:b.triangles+= +e*(c-2);break;case a.LINES:b.lines+=c/2*e;break;case a.LINE_STRIP:b.lines+=e*(c-1);break;case a.LINE_LOOP:b.lines+=e*c;break;case a.POINTS:b.points+=e*c;break;default:console.error("THREE.WebGLInfo: Unknown draw mode:",d)}}}}function Uf(a,b){return Math.abs(b[1])-Math.abs(a[1])}function Vf(a){var b={},c=new Float32Array(8);return{update:function(d,e,f,g){var h=d.morphTargetInfluences,k=h.length;d=b[e.id];if(void 0===d){d=[];for(var m=0;m<k;m++)d[m]=[m,0];b[e.id]=d}var r=f.morphTargets&&e.morphAttributes.position; +f=f.morphNormals&&e.morphAttributes.normal;for(m=0;m<k;m++){var n=d[m];0!==n[1]&&(r&&e.removeAttribute("morphTarget"+m),f&&e.removeAttribute("morphNormal"+m))}for(m=0;m<k;m++)n=d[m],n[0]=m,n[1]=h[m];d.sort(Uf);for(m=0;8>m;m++){if(n=d[m])if(h=n[0],k=n[1]){r&&e.addAttribute("morphTarget"+m,r[h]);f&&e.addAttribute("morphNormal"+m,f[h]);c[m]=k;continue}c[m]=0}g.getUniforms().setValue(a,"morphTargetInfluences",c)}}}function Wf(a,b){var c={};return{update:function(d){var e=b.render.frame,f=d.geometry,g= +a.get(d,f);c[g.id]!==e&&(f.isGeometry&&g.updateFromObject(d),a.update(g),c[g.id]=e);return g},dispose:function(){c={}}}}function Ya(a,b,c,d,e,f,g,h,k,m){a=void 0!==a?a:[];Q.call(this,a,void 0!==b?b:301,c,d,e,f,g,h,k,m);this.flipY=!1}function Mb(a,b,c,d){Q.call(this,null);this.image={data:a,width:b,height:c,depth:d};this.minFilter=this.magFilter=1003;this.flipY=this.generateMipmaps=!1}function Nb(a,b,c){var d=a[0];if(0>=d||0<d)return a;var e=b*c,f=Ie[e];void 0===f&&(f=new Float32Array(e),Ie[e]=f); +if(0!==b)for(d.toArray(f,0),d=1,e=0;d!==b;++d)e+=c,a[d].toArray(f,e);return f}function ea(a,b){if(a.length!==b.length)return!1;for(var c=0,d=a.length;c<d;c++)if(a[c]!==b[c])return!1;return!0}function sa(a,b){for(var c=0,d=b.length;c<d;c++)a[c]=b[c]}function Je(a,b){var c=Ke[b];void 0===c&&(c=new Int32Array(b),Ke[b]=c);for(var d=0;d!==b;++d)c[d]=a.allocTextureUnit();return c}function Xf(a,b){var c=this.cache;c[0]!==b&&(a.uniform1f(this.addr,b),c[0]=b)}function Yf(a,b){var c=this.cache;c[0]!==b&&(a.uniform1i(this.addr, +b),c[0]=b)}function Zf(a,b){var c=this.cache;if(void 0!==b.x){if(c[0]!==b.x||c[1]!==b.y)a.uniform2f(this.addr,b.x,b.y),c[0]=b.x,c[1]=b.y}else ea(c,b)||(a.uniform2fv(this.addr,b),sa(c,b))}function $f(a,b){var c=this.cache;if(void 0!==b.x){if(c[0]!==b.x||c[1]!==b.y||c[2]!==b.z)a.uniform3f(this.addr,b.x,b.y,b.z),c[0]=b.x,c[1]=b.y,c[2]=b.z}else if(void 0!==b.r){if(c[0]!==b.r||c[1]!==b.g||c[2]!==b.b)a.uniform3f(this.addr,b.r,b.g,b.b),c[0]=b.r,c[1]=b.g,c[2]=b.b}else ea(c,b)||(a.uniform3fv(this.addr,b), +sa(c,b))}function ag(a,b){var c=this.cache;if(void 0!==b.x){if(c[0]!==b.x||c[1]!==b.y||c[2]!==b.z||c[3]!==b.w)a.uniform4f(this.addr,b.x,b.y,b.z,b.w),c[0]=b.x,c[1]=b.y,c[2]=b.z,c[3]=b.w}else ea(c,b)||(a.uniform4fv(this.addr,b),sa(c,b))}function bg(a,b){var c=this.cache,d=b.elements;void 0===d?ea(c,b)||(a.uniformMatrix2fv(this.addr,!1,b),sa(c,b)):ea(c,d)||(Le.set(d),a.uniformMatrix2fv(this.addr,!1,Le),sa(c,d))}function cg(a,b){var c=this.cache,d=b.elements;void 0===d?ea(c,b)||(a.uniformMatrix3fv(this.addr, +!1,b),sa(c,b)):ea(c,d)||(Me.set(d),a.uniformMatrix3fv(this.addr,!1,Me),sa(c,d))}function dg(a,b){var c=this.cache,d=b.elements;void 0===d?ea(c,b)||(a.uniformMatrix4fv(this.addr,!1,b),sa(c,b)):ea(c,d)||(Ne.set(d),a.uniformMatrix4fv(this.addr,!1,Ne),sa(c,d))}function eg(a,b,c){var d=this.cache,e=c.allocTextureUnit();d[0]!==e&&(a.uniform1i(this.addr,e),d[0]=e);c.setTexture2D(b||Oe,e)}function fg(a,b,c){var d=this.cache,e=c.allocTextureUnit();d[0]!==e&&(a.uniform1i(this.addr,e),d[0]=e);c.setTexture3D(b|| +gg,e)}function hg(a,b,c){var d=this.cache,e=c.allocTextureUnit();d[0]!==e&&(a.uniform1i(this.addr,e),d[0]=e);c.setTextureCube(b||Pe,e)}function Qe(a,b){var c=this.cache;ea(c,b)||(a.uniform2iv(this.addr,b),sa(c,b))}function Re(a,b){var c=this.cache;ea(c,b)||(a.uniform3iv(this.addr,b),sa(c,b))}function Se(a,b){var c=this.cache;ea(c,b)||(a.uniform4iv(this.addr,b),sa(c,b))}function ig(a){switch(a){case 5126:return Xf;case 35664:return Zf;case 35665:return $f;case 35666:return ag;case 35674:return bg; +case 35675:return cg;case 35676:return dg;case 35678:case 36198:return eg;case 35679:return fg;case 35680:return hg;case 5124:case 35670:return Yf;case 35667:case 35671:return Qe;case 35668:case 35672:return Re;case 35669:case 35673:return Se}}function jg(a,b){var c=this.cache;ea(c,b)||(a.uniform1fv(this.addr,b),sa(c,b))}function kg(a,b){var c=this.cache;ea(c,b)||(a.uniform1iv(this.addr,b),sa(c,b))}function lg(a,b){var c=this.cache;b=Nb(b,this.size,2);ea(c,b)||(a.uniform2fv(this.addr,b),this.updateCache(b))} +function mg(a,b){var c=this.cache;b=Nb(b,this.size,3);ea(c,b)||(a.uniform3fv(this.addr,b),this.updateCache(b))}function ng(a,b){var c=this.cache;b=Nb(b,this.size,4);ea(c,b)||(a.uniform4fv(this.addr,b),this.updateCache(b))}function og(a,b){var c=this.cache;b=Nb(b,this.size,4);ea(c,b)||(a.uniformMatrix2fv(this.addr,!1,b),this.updateCache(b))}function pg(a,b){var c=this.cache;b=Nb(b,this.size,9);ea(c,b)||(a.uniformMatrix3fv(this.addr,!1,b),this.updateCache(b))}function qg(a,b){var c=this.cache;b=Nb(b, +this.size,16);ea(c,b)||(a.uniformMatrix4fv(this.addr,!1,b),this.updateCache(b))}function rg(a,b,c){var d=this.cache,e=b.length,f=Je(c,e);!1===ea(d,f)&&(a.uniform1iv(this.addr,f),sa(d,f));for(a=0;a!==e;++a)c.setTexture2D(b[a]||Oe,f[a])}function sg(a,b,c){var d=this.cache,e=b.length,f=Je(c,e);!1===ea(d,f)&&(a.uniform1iv(this.addr,f),sa(d,f));for(a=0;a!==e;++a)c.setTextureCube(b[a]||Pe,f[a])}function tg(a){switch(a){case 5126:return jg;case 35664:return lg;case 35665:return mg;case 35666:return ng;case 35674:return og; +case 35675:return pg;case 35676:return qg;case 35678:return rg;case 35680:return sg;case 5124:case 35670:return kg;case 35667:case 35671:return Qe;case 35668:case 35672:return Re;case 35669:case 35673:return Se}}function ug(a,b,c){this.id=a;this.addr=c;this.cache=[];this.setValue=ig(b.type)}function Te(a,b,c){this.id=a;this.addr=c;this.cache=[];this.size=b.size;this.setValue=tg(b.type)}function Ue(a){this.id=a;this.seq=[];this.map={}}function bb(a,b,c){this.seq=[];this.map={};this.renderer=c;c=a.getProgramParameter(b, +a.ACTIVE_UNIFORMS);for(var d=0;d<c;++d){var e=a.getActiveUniform(b,d),f=a.getUniformLocation(b,e.name),g=this,h=e.name,k=h.length;for(Zd.lastIndex=0;;){var m=Zd.exec(h),r=Zd.lastIndex,n=m[1],q=m[3];"]"===m[2]&&(n|=0);if(void 0===q||"["===q&&r+2===k){h=g;e=void 0===q?new ug(n,e,f):new Te(n,e,f);h.seq.push(e);h.map[e.id]=e;break}else q=g.map[n],void 0===q&&(q=new Ue(n),n=g,g=q,n.seq.push(g),n.map[g.id]=g),g=q}}}function vg(a){a=a.split("\n");for(var b=0;b<a.length;b++)a[b]=b+1+": "+a[b];return a.join("\n")} +function Ve(a,b,c){var d=a.createShader(b);a.shaderSource(d,c);a.compileShader(d);!1===a.getShaderParameter(d,a.COMPILE_STATUS)&&console.error("THREE.WebGLShader: Shader couldn't compile.");""!==a.getShaderInfoLog(d)&&console.warn("THREE.WebGLShader: gl.getShaderInfoLog()",b===a.VERTEX_SHADER?"vertex":"fragment",a.getShaderInfoLog(d),vg(c));return d}function We(a){switch(a){case 3E3:return["Linear","( value )"];case 3001:return["sRGB","( value )"];case 3002:return["RGBE","( value )"];case 3004:return["RGBM", +"( value, 7.0 )"];case 3005:return["RGBM","( value, 16.0 )"];case 3006:return["RGBD","( value, 256.0 )"];case 3007:return["Gamma","( value, float( GAMMA_FACTOR ) )"];default:throw Error("unsupported encoding: "+a);}}function td(a,b){b=We(b);return"vec4 "+a+"( vec4 value ) { return "+b[0]+"ToLinear"+b[1]+"; }"}function wg(a,b){b=We(b);return"vec4 "+a+"( vec4 value ) { return LinearTo"+b[0]+b[1]+"; }"}function xg(a,b){switch(b){case 1:b="Linear";break;case 2:b="Reinhard";break;case 3:b="Uncharted2"; +break;case 4:b="OptimizedCineon";break;default:throw Error("unsupported toneMapping: "+b);}return"vec3 "+a+"( vec3 color ) { return "+b+"ToneMapping( color ); }"}function yg(a,b,c){a=a||{};return[a.derivatives||b.envMapCubeUV||b.bumpMap||b.normalMap&&!b.objectSpaceNormalMap||b.flatShading?"#extension GL_OES_standard_derivatives : enable":"",(a.fragDepth||b.logarithmicDepthBuffer)&&c.get("EXT_frag_depth")?"#extension GL_EXT_frag_depth : enable":"",a.drawBuffers&&c.get("WEBGL_draw_buffers")?"#extension GL_EXT_draw_buffers : require": +"",(a.shaderTextureLOD||b.envMap)&&c.get("EXT_shader_texture_lod")?"#extension GL_EXT_shader_texture_lod : enable":""].filter(zc).join("\n")}function zg(a){var b=[],c;for(c in a){var d=a[c];!1!==d&&b.push("#define "+c+" "+d)}return b.join("\n")}function zc(a){return""!==a}function Xe(a,b){return a.replace(/NUM_DIR_LIGHTS/g,b.numDirLights).replace(/NUM_SPOT_LIGHTS/g,b.numSpotLights).replace(/NUM_RECT_AREA_LIGHTS/g,b.numRectAreaLights).replace(/NUM_POINT_LIGHTS/g,b.numPointLights).replace(/NUM_HEMI_LIGHTS/g, +b.numHemiLights)}function Ye(a,b){return a.replace(/NUM_CLIPPING_PLANES/g,b.numClippingPlanes).replace(/UNION_CLIPPING_PLANES/g,b.numClippingPlanes-b.numClipIntersection)}function $d(a){return a.replace(/^[ \t]*#include +<([\w\d./]+)>/gm,function(a,c){a=K[c];if(void 0===a)throw Error("Can not resolve #include <"+c+">");return $d(a)})}function Ze(a){return a.replace(/#pragma unroll_loop[\s]+?for \( int i = (\d+); i < (\d+); i \+\+ \) \{([\s\S]+?)(?=\})\}/g,function(a,c,d,e){a="";for(c=parseInt(c);c< +parseInt(d);c++)a+=e.replace(/\[ i \]/g,"[ "+c+" ]");return a})}function Ag(a,b,c,d,e,f,g){var h=a.context,k=d.defines,m=e.vertexShader,r=e.fragmentShader,n="SHADOWMAP_TYPE_BASIC";1===f.shadowMapType?n="SHADOWMAP_TYPE_PCF":2===f.shadowMapType&&(n="SHADOWMAP_TYPE_PCF_SOFT");var q="ENVMAP_TYPE_CUBE",v="ENVMAP_MODE_REFLECTION",t="ENVMAP_BLENDING_MULTIPLY";if(f.envMap){switch(d.envMap.mapping){case 301:case 302:q="ENVMAP_TYPE_CUBE";break;case 306:case 307:q="ENVMAP_TYPE_CUBE_UV";break;case 303:case 304:q= +"ENVMAP_TYPE_EQUIREC";break;case 305:q="ENVMAP_TYPE_SPHERE"}switch(d.envMap.mapping){case 302:case 304:v="ENVMAP_MODE_REFRACTION"}switch(d.combine){case 0:t="ENVMAP_BLENDING_MULTIPLY";break;case 1:t="ENVMAP_BLENDING_MIX";break;case 2:t="ENVMAP_BLENDING_ADD"}}var l=0<a.gammaFactor?a.gammaFactor:1,y=g.isWebGL2?"":yg(d.extensions,f,b),p=zg(k),w=h.createProgram();d.isRawShaderMaterial?(k=[p].filter(zc).join("\n"),0<k.length&&(k+="\n"),b=[y,p].filter(zc).join("\n"),0<b.length&&(b+="\n")):(k=["precision "+ +f.precision+" float;","precision "+f.precision+" int;","#define SHADER_NAME "+e.name,p,f.supportsVertexTextures?"#define VERTEX_TEXTURES":"","#define GAMMA_FACTOR "+l,"#define MAX_BONES "+f.maxBones,f.useFog&&f.fog?"#define USE_FOG":"",f.useFog&&f.fogExp?"#define FOG_EXP2":"",f.map?"#define USE_MAP":"",f.envMap?"#define USE_ENVMAP":"",f.envMap?"#define "+v:"",f.lightMap?"#define USE_LIGHTMAP":"",f.aoMap?"#define USE_AOMAP":"",f.emissiveMap?"#define USE_EMISSIVEMAP":"",f.bumpMap?"#define USE_BUMPMAP": +"",f.normalMap?"#define USE_NORMALMAP":"",f.normalMap&&f.objectSpaceNormalMap?"#define OBJECTSPACE_NORMALMAP":"",f.displacementMap&&f.supportsVertexTextures?"#define USE_DISPLACEMENTMAP":"",f.specularMap?"#define USE_SPECULARMAP":"",f.roughnessMap?"#define USE_ROUGHNESSMAP":"",f.metalnessMap?"#define USE_METALNESSMAP":"",f.alphaMap?"#define USE_ALPHAMAP":"",f.vertexColors?"#define USE_COLOR":"",f.flatShading?"#define FLAT_SHADED":"",f.skinning?"#define USE_SKINNING":"",f.useVertexTexture?"#define BONE_TEXTURE": +"",f.morphTargets?"#define USE_MORPHTARGETS":"",f.morphNormals&&!1===f.flatShading?"#define USE_MORPHNORMALS":"",f.doubleSided?"#define DOUBLE_SIDED":"",f.flipSided?"#define FLIP_SIDED":"",f.shadowMapEnabled?"#define USE_SHADOWMAP":"",f.shadowMapEnabled?"#define "+n:"",f.sizeAttenuation?"#define USE_SIZEATTENUATION":"",f.logarithmicDepthBuffer?"#define USE_LOGDEPTHBUF":"",f.logarithmicDepthBuffer&&(g.isWebGL2||b.get("EXT_frag_depth"))?"#define USE_LOGDEPTHBUF_EXT":"","uniform mat4 modelMatrix;","uniform mat4 modelViewMatrix;", +"uniform mat4 projectionMatrix;","uniform mat4 viewMatrix;","uniform mat3 normalMatrix;","uniform vec3 cameraPosition;","attribute vec3 position;","attribute vec3 normal;","attribute vec2 uv;","#ifdef USE_COLOR","\tattribute vec3 color;","#endif","#ifdef USE_MORPHTARGETS","\tattribute vec3 morphTarget0;","\tattribute vec3 morphTarget1;","\tattribute vec3 morphTarget2;","\tattribute vec3 morphTarget3;","\t#ifdef USE_MORPHNORMALS","\t\tattribute vec3 morphNormal0;","\t\tattribute vec3 morphNormal1;", +"\t\tattribute vec3 morphNormal2;","\t\tattribute vec3 morphNormal3;","\t#else","\t\tattribute vec3 morphTarget4;","\t\tattribute vec3 morphTarget5;","\t\tattribute vec3 morphTarget6;","\t\tattribute vec3 morphTarget7;","\t#endif","#endif","#ifdef USE_SKINNING","\tattribute vec4 skinIndex;","\tattribute vec4 skinWeight;","#endif","\n"].filter(zc).join("\n"),b=[y,"precision "+f.precision+" float;","precision "+f.precision+" int;","#define SHADER_NAME "+e.name,p,f.alphaTest?"#define ALPHATEST "+f.alphaTest+ +(f.alphaTest%1?"":".0"):"","#define GAMMA_FACTOR "+l,f.useFog&&f.fog?"#define USE_FOG":"",f.useFog&&f.fogExp?"#define FOG_EXP2":"",f.map?"#define USE_MAP":"",f.envMap?"#define USE_ENVMAP":"",f.envMap?"#define "+q:"",f.envMap?"#define "+v:"",f.envMap?"#define "+t:"",f.lightMap?"#define USE_LIGHTMAP":"",f.aoMap?"#define USE_AOMAP":"",f.emissiveMap?"#define USE_EMISSIVEMAP":"",f.bumpMap?"#define USE_BUMPMAP":"",f.normalMap?"#define USE_NORMALMAP":"",f.normalMap&&f.objectSpaceNormalMap?"#define OBJECTSPACE_NORMALMAP": +"",f.specularMap?"#define USE_SPECULARMAP":"",f.roughnessMap?"#define USE_ROUGHNESSMAP":"",f.metalnessMap?"#define USE_METALNESSMAP":"",f.alphaMap?"#define USE_ALPHAMAP":"",f.vertexColors?"#define USE_COLOR":"",f.gradientMap?"#define USE_GRADIENTMAP":"",f.flatShading?"#define FLAT_SHADED":"",f.doubleSided?"#define DOUBLE_SIDED":"",f.flipSided?"#define FLIP_SIDED":"",f.shadowMapEnabled?"#define USE_SHADOWMAP":"",f.shadowMapEnabled?"#define "+n:"",f.premultipliedAlpha?"#define PREMULTIPLIED_ALPHA": +"",f.physicallyCorrectLights?"#define PHYSICALLY_CORRECT_LIGHTS":"",f.logarithmicDepthBuffer?"#define USE_LOGDEPTHBUF":"",f.logarithmicDepthBuffer&&(g.isWebGL2||b.get("EXT_frag_depth"))?"#define USE_LOGDEPTHBUF_EXT":"",f.envMap&&(g.isWebGL2||b.get("EXT_shader_texture_lod"))?"#define TEXTURE_LOD_EXT":"","uniform mat4 viewMatrix;","uniform vec3 cameraPosition;",0!==f.toneMapping?"#define TONE_MAPPING":"",0!==f.toneMapping?K.tonemapping_pars_fragment:"",0!==f.toneMapping?xg("toneMapping",f.toneMapping): +"",f.dithering?"#define DITHERING":"",f.outputEncoding||f.mapEncoding||f.matcapEncoding||f.envMapEncoding||f.emissiveMapEncoding?K.encodings_pars_fragment:"",f.mapEncoding?td("mapTexelToLinear",f.mapEncoding):"",f.matcapEncoding?td("matcapTexelToLinear",f.matcapEncoding):"",f.envMapEncoding?td("envMapTexelToLinear",f.envMapEncoding):"",f.emissiveMapEncoding?td("emissiveMapTexelToLinear",f.emissiveMapEncoding):"",f.outputEncoding?wg("linearToOutputTexel",f.outputEncoding):"",f.depthPacking?"#define DEPTH_PACKING "+ +d.depthPacking:"","\n"].filter(zc).join("\n"));m=$d(m);m=Xe(m,f);m=Ye(m,f);r=$d(r);r=Xe(r,f);r=Ye(r,f);m=Ze(m);r=Ze(r);g.isWebGL2&&!d.isRawShaderMaterial&&(g=!1,n=/^\s*#version\s+300\s+es\s*\n/,d.isShaderMaterial&&null!==m.match(n)&&null!==r.match(n)&&(g=!0,m=m.replace(n,""),r=r.replace(n,"")),k="#version 300 es\n\n#define attribute in\n#define varying out\n#define texture2D texture\n"+k,b=["#version 300 es\n\n#define varying in",g?"":"out highp vec4 pc_fragColor;",g?"":"#define gl_FragColor pc_fragColor", +"#define gl_FragDepthEXT gl_FragDepth\n#define texture2D texture\n#define textureCube texture\n#define texture2DProj textureProj\n#define texture2DLodEXT textureLod\n#define texture2DProjLodEXT textureProjLod\n#define textureCubeLodEXT textureLod\n#define texture2DGradEXT textureGrad\n#define texture2DProjGradEXT textureProjGrad\n#define textureCubeGradEXT textureGrad"].join("\n")+"\n"+b);r=b+r;m=Ve(h,h.VERTEX_SHADER,k+m);r=Ve(h,h.FRAGMENT_SHADER,r);h.attachShader(w,m);h.attachShader(w,r);void 0!== +d.index0AttributeName?h.bindAttribLocation(w,0,d.index0AttributeName):!0===f.morphTargets&&h.bindAttribLocation(w,0,"position");h.linkProgram(w);f=h.getProgramInfoLog(w).trim();g=h.getShaderInfoLog(m).trim();n=h.getShaderInfoLog(r).trim();v=q=!0;if(!1===h.getProgramParameter(w,h.LINK_STATUS))q=!1,console.error("THREE.WebGLProgram: shader error: ",h.getError(),"gl.VALIDATE_STATUS",h.getProgramParameter(w,h.VALIDATE_STATUS),"gl.getProgramInfoLog",f,g,n);else if(""!==f)console.warn("THREE.WebGLProgram: gl.getProgramInfoLog()", +f);else if(""===g||""===n)v=!1;v&&(this.diagnostics={runnable:q,material:d,programLog:f,vertexShader:{log:g,prefix:k},fragmentShader:{log:n,prefix:b}});h.deleteShader(m);h.deleteShader(r);var D;this.getUniforms=function(){void 0===D&&(D=new bb(h,w,a));return D};var J;this.getAttributes=function(){if(void 0===J){for(var a={},b=h.getProgramParameter(w,h.ACTIVE_ATTRIBUTES),c=0;c<b;c++){var d=h.getActiveAttrib(w,c).name;a[d]=h.getAttribLocation(w,d)}J=a}return J};this.destroy=function(){h.deleteProgram(w); +this.program=void 0};Object.defineProperties(this,{uniforms:{get:function(){console.warn("THREE.WebGLProgram: .uniforms is now .getUniforms().");return this.getUniforms()}},attributes:{get:function(){console.warn("THREE.WebGLProgram: .attributes is now .getAttributes().");return this.getAttributes()}}});this.name=e.name;this.id=Bg++;this.code=c;this.usedTimes=1;this.program=w;this.vertexShader=m;this.fragmentShader=r;return this}function Cg(a,b,c){function d(a,b){if(a)a.isTexture?c=a.encoding:a.isWebGLRenderTarget&& +(console.warn("THREE.WebGLPrograms.getTextureEncodingFromMap: don't use render targets as textures. Use their .texture property instead."),c=a.texture.encoding);else var c=3E3;3E3===c&&b&&(c=3007);return c}var e=[],f={MeshDepthMaterial:"depth",MeshDistanceMaterial:"distanceRGBA",MeshNormalMaterial:"normal",MeshBasicMaterial:"basic",MeshLambertMaterial:"lambert",MeshPhongMaterial:"phong",MeshToonMaterial:"phong",MeshStandardMaterial:"physical",MeshPhysicalMaterial:"physical",MeshMatcapMaterial:"matcap", +LineBasicMaterial:"basic",LineDashedMaterial:"dashed",PointsMaterial:"points",ShadowMaterial:"shadow",SpriteMaterial:"sprite"},g="precision supportsVertexTextures map mapEncoding matcapEncoding envMap envMapMode envMapEncoding lightMap aoMap emissiveMap emissiveMapEncoding bumpMap normalMap objectSpaceNormalMap displacementMap specularMap roughnessMap metalnessMap gradientMap alphaMap combine vertexColors fog useFog fogExp flatShading sizeAttenuation logarithmicDepthBuffer skinning maxBones useVertexTexture morphTargets morphNormals maxMorphTargets maxMorphNormals premultipliedAlpha numDirLights numPointLights numSpotLights numHemiLights numRectAreaLights shadowMapEnabled shadowMapType toneMapping physicallyCorrectLights alphaTest doubleSided flipSided numClippingPlanes numClipIntersection depthPacking dithering".split(" "); +this.getParameters=function(b,e,g,r,n,q,v){var h=f[b.type];if(v.isSkinnedMesh){var k=v.skeleton.bones;if(c.floatVertexTextures)k=1024;else{var m=Math.min(Math.floor((c.maxVertexUniforms-20)/4),k.length);m<k.length?(console.warn("THREE.WebGLRenderer: Skeleton has "+k.length+" bones. This GPU supports "+m+"."),k=0):k=m}}else k=0;m=c.precision;null!==b.precision&&(m=c.getMaxPrecision(b.precision),m!==b.precision&&console.warn("THREE.WebGLProgram.getParameters:",b.precision,"not supported, using",m,"instead.")); +var l=a.getRenderTarget();return{shaderID:h,precision:m,supportsVertexTextures:c.vertexTextures,outputEncoding:d(l?l.texture:null,a.gammaOutput),map:!!b.map,mapEncoding:d(b.map,a.gammaInput),matcap:!!b.matcap,matcapEncoding:d(b.matcap,a.gammaInput),envMap:!!b.envMap,envMapMode:b.envMap&&b.envMap.mapping,envMapEncoding:d(b.envMap,a.gammaInput),envMapCubeUV:!!b.envMap&&(306===b.envMap.mapping||307===b.envMap.mapping),lightMap:!!b.lightMap,aoMap:!!b.aoMap,emissiveMap:!!b.emissiveMap,emissiveMapEncoding:d(b.emissiveMap, +a.gammaInput),bumpMap:!!b.bumpMap,normalMap:!!b.normalMap,objectSpaceNormalMap:1===b.normalMapType,displacementMap:!!b.displacementMap,roughnessMap:!!b.roughnessMap,metalnessMap:!!b.metalnessMap,specularMap:!!b.specularMap,alphaMap:!!b.alphaMap,gradientMap:!!b.gradientMap,combine:b.combine,vertexColors:b.vertexColors,fog:!!r,useFog:b.fog,fogExp:r&&r.isFogExp2,flatShading:b.flatShading,sizeAttenuation:b.sizeAttenuation,logarithmicDepthBuffer:c.logarithmicDepthBuffer,skinning:b.skinning&&0<k,maxBones:k, +useVertexTexture:c.floatVertexTextures,morphTargets:b.morphTargets,morphNormals:b.morphNormals,maxMorphTargets:a.maxMorphTargets,maxMorphNormals:a.maxMorphNormals,numDirLights:e.directional.length,numPointLights:e.point.length,numSpotLights:e.spot.length,numRectAreaLights:e.rectArea.length,numHemiLights:e.hemi.length,numClippingPlanes:n,numClipIntersection:q,dithering:b.dithering,shadowMapEnabled:a.shadowMap.enabled&&v.receiveShadow&&0<g.length,shadowMapType:a.shadowMap.type,toneMapping:a.toneMapping, +physicallyCorrectLights:a.physicallyCorrectLights,premultipliedAlpha:b.premultipliedAlpha,alphaTest:b.alphaTest,doubleSided:2===b.side,flipSided:1===b.side,depthPacking:void 0!==b.depthPacking?b.depthPacking:!1}};this.getProgramCode=function(b,c){var d=[];c.shaderID?d.push(c.shaderID):(d.push(b.fragmentShader),d.push(b.vertexShader));if(void 0!==b.defines)for(var e in b.defines)d.push(e),d.push(b.defines[e]);for(e=0;e<g.length;e++)d.push(c[g[e]]);d.push(b.onBeforeCompile.toString());d.push(a.gammaOutput); +return d.join()};this.acquireProgram=function(d,f,g,r){for(var h,k=0,m=e.length;k<m;k++){var l=e[k];if(l.code===r){h=l;++h.usedTimes;break}}void 0===h&&(h=new Ag(a,b,r,d,f,g,c),e.push(h));return h};this.releaseProgram=function(a){if(0===--a.usedTimes){var b=e.indexOf(a);e[b]=e[e.length-1];e.pop();a.destroy()}};this.programs=e}function Dg(){var a=new WeakMap;return{get:function(b){var c=a.get(b);void 0===c&&(c={},a.set(b,c));return c},remove:function(b){a.delete(b)},update:function(b,c,d){a.get(b)[c]= +d},dispose:function(){a=new WeakMap}}}function Eg(a,b){return a.renderOrder!==b.renderOrder?a.renderOrder-b.renderOrder:a.program&&b.program&&a.program!==b.program?a.program.id-b.program.id:a.material.id!==b.material.id?a.material.id-b.material.id:a.z!==b.z?a.z-b.z:a.id-b.id}function Fg(a,b){return a.renderOrder!==b.renderOrder?a.renderOrder-b.renderOrder:a.z!==b.z?b.z-a.z:a.id-b.id}function Gg(){var a=[],b=0,c=[],d=[];return{opaque:c,transparent:d,init:function(){b=0;c.length=0;d.length=0},push:function(e, +f,g,h,k){var m=a[b];void 0===m?(m={id:e.id,object:e,geometry:f,material:g,program:g.program,renderOrder:e.renderOrder,z:h,group:k},a[b]=m):(m.id=e.id,m.object=e,m.geometry=f,m.material=g,m.program=g.program,m.renderOrder=e.renderOrder,m.z=h,m.group=k);(!0===g.transparent?d:c).push(m);b++},sort:function(){1<c.length&&c.sort(Eg);1<d.length&&d.sort(Fg)}}}function Hg(){var a={};return{get:function(b,c){b=b.id+","+c.id;c=a[b];void 0===c&&(c=new Gg,a[b]=c);return c},dispose:function(){a={}}}}function Ig(){var a= +{};return{get:function(b){if(void 0!==a[b.id])return a[b.id];switch(b.type){case "DirectionalLight":var c={direction:new p,color:new G,shadow:!1,shadowBias:0,shadowRadius:1,shadowMapSize:new A};break;case "SpotLight":c={position:new p,direction:new p,color:new G,distance:0,coneCos:0,penumbraCos:0,decay:0,shadow:!1,shadowBias:0,shadowRadius:1,shadowMapSize:new A};break;case "PointLight":c={position:new p,color:new G,distance:0,decay:0,shadow:!1,shadowBias:0,shadowRadius:1,shadowMapSize:new A,shadowCameraNear:1, +shadowCameraFar:1E3};break;case "HemisphereLight":c={direction:new p,skyColor:new G,groundColor:new G};break;case "RectAreaLight":c={color:new G,position:new p,halfWidth:new p,halfHeight:new p}}return a[b.id]=c}}}function Jg(){var a=new Ig,b={id:Kg++,hash:{stateID:-1,directionalLength:-1,pointLength:-1,spotLength:-1,rectAreaLength:-1,hemiLength:-1,shadowsLength:-1},ambient:[0,0,0],directional:[],directionalShadowMap:[],directionalShadowMatrix:[],spot:[],spotShadowMap:[],spotShadowMatrix:[],rectArea:[], +point:[],pointShadowMap:[],pointShadowMatrix:[],hemi:[]},c=new p,d=new P,e=new P;return{setup:function(f,g,h){var k=0,m=0,r=0,n=0,q=0,v=0,l=0,u=0;h=h.matrixWorldInverse;for(var y=0,p=f.length;y<p;y++){var w=f[y],D=w.color,J=w.intensity,R=w.distance,X=w.shadow&&w.shadow.map?w.shadow.map.texture:null;if(w.isAmbientLight)k+=D.r*J,m+=D.g*J,r+=D.b*J;else if(w.isDirectionalLight){var B=a.get(w);B.color.copy(w.color).multiplyScalar(w.intensity);B.direction.setFromMatrixPosition(w.matrixWorld);c.setFromMatrixPosition(w.target.matrixWorld); +B.direction.sub(c);B.direction.transformDirection(h);if(B.shadow=w.castShadow)D=w.shadow,B.shadowBias=D.bias,B.shadowRadius=D.radius,B.shadowMapSize=D.mapSize;b.directionalShadowMap[n]=X;b.directionalShadowMatrix[n]=w.shadow.matrix;b.directional[n]=B;n++}else if(w.isSpotLight){B=a.get(w);B.position.setFromMatrixPosition(w.matrixWorld);B.position.applyMatrix4(h);B.color.copy(D).multiplyScalar(J);B.distance=R;B.direction.setFromMatrixPosition(w.matrixWorld);c.setFromMatrixPosition(w.target.matrixWorld); +B.direction.sub(c);B.direction.transformDirection(h);B.coneCos=Math.cos(w.angle);B.penumbraCos=Math.cos(w.angle*(1-w.penumbra));B.decay=w.decay;if(B.shadow=w.castShadow)D=w.shadow,B.shadowBias=D.bias,B.shadowRadius=D.radius,B.shadowMapSize=D.mapSize;b.spotShadowMap[v]=X;b.spotShadowMatrix[v]=w.shadow.matrix;b.spot[v]=B;v++}else if(w.isRectAreaLight)B=a.get(w),B.color.copy(D).multiplyScalar(J),B.position.setFromMatrixPosition(w.matrixWorld),B.position.applyMatrix4(h),e.identity(),d.copy(w.matrixWorld), +d.premultiply(h),e.extractRotation(d),B.halfWidth.set(.5*w.width,0,0),B.halfHeight.set(0,.5*w.height,0),B.halfWidth.applyMatrix4(e),B.halfHeight.applyMatrix4(e),b.rectArea[l]=B,l++;else if(w.isPointLight){B=a.get(w);B.position.setFromMatrixPosition(w.matrixWorld);B.position.applyMatrix4(h);B.color.copy(w.color).multiplyScalar(w.intensity);B.distance=w.distance;B.decay=w.decay;if(B.shadow=w.castShadow)D=w.shadow,B.shadowBias=D.bias,B.shadowRadius=D.radius,B.shadowMapSize=D.mapSize,B.shadowCameraNear= +D.camera.near,B.shadowCameraFar=D.camera.far;b.pointShadowMap[q]=X;b.pointShadowMatrix[q]=w.shadow.matrix;b.point[q]=B;q++}else w.isHemisphereLight&&(B=a.get(w),B.direction.setFromMatrixPosition(w.matrixWorld),B.direction.transformDirection(h),B.direction.normalize(),B.skyColor.copy(w.color).multiplyScalar(J),B.groundColor.copy(w.groundColor).multiplyScalar(J),b.hemi[u]=B,u++)}b.ambient[0]=k;b.ambient[1]=m;b.ambient[2]=r;b.directional.length=n;b.spot.length=v;b.rectArea.length=l;b.point.length=q; +b.hemi.length=u;b.hash.stateID=b.id;b.hash.directionalLength=n;b.hash.pointLength=q;b.hash.spotLength=v;b.hash.rectAreaLength=l;b.hash.hemiLength=u;b.hash.shadowsLength=g.length},state:b}}function $e(){var a=new Jg,b=[],c=[];return{init:function(){b.length=0;c.length=0},state:{lightsArray:b,shadowsArray:c,lights:a},setupLights:function(d){a.setup(b,c,d)},pushLight:function(a){b.push(a)},pushShadow:function(a){c.push(a)}}}function Lg(){var a={};return{get:function(b,c){if(void 0===a[b.id]){var d=new $e; +a[b.id]={};a[b.id][c.id]=d}else void 0===a[b.id][c.id]?(d=new $e,a[b.id][c.id]=d):d=a[b.id][c.id];return d},dispose:function(){a={}}}}function cb(a){L.call(this);this.type="MeshDepthMaterial";this.depthPacking=3200;this.morphTargets=this.skinning=!1;this.displacementMap=this.alphaMap=this.map=null;this.displacementScale=1;this.displacementBias=0;this.wireframe=!1;this.wireframeLinewidth=1;this.lights=this.fog=!1;this.setValues(a)}function db(a){L.call(this);this.type="MeshDistanceMaterial";this.referencePosition= +new p;this.nearDistance=1;this.farDistance=1E3;this.morphTargets=this.skinning=!1;this.displacementMap=this.alphaMap=this.map=null;this.displacementScale=1;this.displacementBias=0;this.lights=this.fog=!1;this.setValues(a)}function af(a,b,c){function d(b,c,d,e,f,g){var h=b.geometry;var k=n;var m=b.customDepthMaterial;d&&(k=q,m=b.customDistanceMaterial);m?k=m:(m=!1,c.morphTargets&&(h&&h.isBufferGeometry?m=h.morphAttributes&&h.morphAttributes.position&&0<h.morphAttributes.position.length:h&&h.isGeometry&& +(m=h.morphTargets&&0<h.morphTargets.length)),b.isSkinnedMesh&&!1===c.skinning&&console.warn("THREE.WebGLShadowMap: THREE.SkinnedMesh with material.skinning set to false:",b),b=b.isSkinnedMesh&&c.skinning,h=0,m&&(h|=1),b&&(h|=2),k=k[h]);a.localClippingEnabled&&!0===c.clipShadows&&0!==c.clippingPlanes.length&&(h=k.uuid,m=c.uuid,b=v[h],void 0===b&&(b={},v[h]=b),h=b[m],void 0===h&&(h=k.clone(),b[m]=h),k=h);k.visible=c.visible;k.wireframe=c.wireframe;k.side=null!=c.shadowSide?c.shadowSide:l[c.side];k.clipShadows= +c.clipShadows;k.clippingPlanes=c.clippingPlanes;k.clipIntersection=c.clipIntersection;k.wireframeLinewidth=c.wireframeLinewidth;k.linewidth=c.linewidth;d&&k.isMeshDistanceMaterial&&(k.referencePosition.copy(e),k.nearDistance=f,k.farDistance=g);return k}function e(c,g,h,k){if(!1!==c.visible){if(c.layers.test(g.layers)&&(c.isMesh||c.isLine||c.isPoints)&&c.castShadow&&(!c.frustumCulled||f.intersectsObject(c))){c.modelViewMatrix.multiplyMatrices(h.matrixWorldInverse,c.matrixWorld);var m=b.update(c),n= +c.material;if(Array.isArray(n))for(var q=m.groups,v=0,l=q.length;v<l;v++){var t=q[v],u=n[t.materialIndex];u&&u.visible&&(u=d(c,u,k,r,h.near,h.far),a.renderBufferDirect(h,null,m,u,c,t))}else n.visible&&(u=d(c,n,k,r,h.near,h.far),a.renderBufferDirect(h,null,m,u,c,null))}c=c.children;m=0;for(n=c.length;m<n;m++)e(c[m],g,h,k)}}var f=new rd,g=new P,h=new A,k=new A(c,c),m=new p,r=new p,n=Array(4),q=Array(4),v={},l={0:1,1:0,2:2},u=[new p(1,0,0),new p(-1,0,0),new p(0,0,1),new p(0,0,-1),new p(0,1,0),new p(0, +-1,0)],y=[new p(0,1,0),new p(0,1,0),new p(0,1,0),new p(0,1,0),new p(0,0,1),new p(0,0,-1)],x=[new Z,new Z,new Z,new Z,new Z,new Z];for(c=0;4!==c;++c){var w=0!==(c&1),D=0!==(c&2),J=new cb({depthPacking:3201,morphTargets:w,skinning:D});n[c]=J;w=new db({morphTargets:w,skinning:D});q[c]=w}var R=this;this.enabled=!1;this.autoUpdate=!0;this.needsUpdate=!1;this.type=1;this.render=function(b,c,d){if(!1!==R.enabled&&(!1!==R.autoUpdate||!1!==R.needsUpdate)&&0!==b.length){var n=a.state;n.disable(a.context.BLEND); +n.buffers.color.setClear(1,1,1,1);n.buffers.depth.setTest(!0);n.setScissorTest(!1);for(var q,v=0,l=b.length;v<l;v++){var t=b[v];q=t.shadow;var X=t&&t.isPointLight;if(void 0===q)console.warn("THREE.WebGLShadowMap:",t,"has no shadow.");else{var w=q.camera;h.copy(q.mapSize);h.min(k);if(X){var p=h.x,B=h.y;x[0].set(2*p,B,p,B);x[1].set(0,B,p,B);x[2].set(3*p,B,p,B);x[3].set(p,B,p,B);x[4].set(3*p,0,p,B);x[5].set(p,0,p,B);h.x*=4;h.y*=2}null===q.map&&(q.map=new ib(h.x,h.y,{minFilter:1003,magFilter:1003,format:1023}), +q.map.texture.name=t.name+".shadowMap",w.updateProjectionMatrix());q.isSpotLightShadow&&q.update(t);p=q.map;B=q.matrix;r.setFromMatrixPosition(t.matrixWorld);w.position.copy(r);X?(q=6,B.makeTranslation(-r.x,-r.y,-r.z)):(q=1,m.setFromMatrixPosition(t.target.matrixWorld),w.lookAt(m),w.updateMatrixWorld(),B.set(.5,0,0,.5,0,.5,0,.5,0,0,.5,.5,0,0,0,1),B.multiply(w.projectionMatrix),B.multiply(w.matrixWorldInverse));a.setRenderTarget(p);a.clear();for(t=0;t<q;t++)X&&(m.copy(w.position),m.add(u[t]),w.up.copy(y[t]), +w.lookAt(m),w.updateMatrixWorld(),n.viewport(x[t])),g.multiplyMatrices(w.projectionMatrix,w.matrixWorldInverse),f.setFromMatrix(g),e(c,d,w,X)}}R.needsUpdate=!1}}}function Mg(a,b,c,d){function e(b,c,d){var e=new Uint8Array(4),f=a.createTexture();a.bindTexture(b,f);a.texParameteri(b,a.TEXTURE_MIN_FILTER,a.NEAREST);a.texParameteri(b,a.TEXTURE_MAG_FILTER,a.NEAREST);for(b=0;b<d;b++)a.texImage2D(c+b,0,a.RGBA,1,1,0,a.RGBA,a.UNSIGNED_BYTE,e);return f}function f(c,e){x[c]=1;0===w[c]&&(a.enableVertexAttribArray(c), +w[c]=1);D[c]!==e&&((d.isWebGL2?a:b.get("ANGLE_instanced_arrays"))[d.isWebGL2?"vertexAttribDivisor":"vertexAttribDivisorANGLE"](c,e),D[c]=e)}function g(b){!0!==J[b]&&(a.enable(b),J[b]=!0)}function h(b){!1!==J[b]&&(a.disable(b),J[b]=!1)}function k(b,d,e,f,k,m,n,r){if(0===b)B&&(h(a.BLEND),B=!1);else if(B||(g(a.BLEND),B=!0),5!==b){if(b!==Lb||r!==H){if(100!==A||100!==z)a.blendEquation(a.FUNC_ADD),z=A=100;if(r)switch(b){case 1:a.blendFuncSeparate(a.ONE,a.ONE_MINUS_SRC_ALPHA,a.ONE,a.ONE_MINUS_SRC_ALPHA); +break;case 2:a.blendFunc(a.ONE,a.ONE);break;case 3:a.blendFuncSeparate(a.ZERO,a.ZERO,a.ONE_MINUS_SRC_COLOR,a.ONE_MINUS_SRC_ALPHA);break;case 4:a.blendFuncSeparate(a.ZERO,a.SRC_COLOR,a.ZERO,a.SRC_ALPHA);break;default:console.error("THREE.WebGLState: Invalid blending: ",b)}else switch(b){case 1:a.blendFuncSeparate(a.SRC_ALPHA,a.ONE_MINUS_SRC_ALPHA,a.ONE,a.ONE_MINUS_SRC_ALPHA);break;case 2:a.blendFunc(a.SRC_ALPHA,a.ONE);break;case 3:a.blendFunc(a.ZERO,a.ONE_MINUS_SRC_COLOR);break;case 4:a.blendFunc(a.ZERO, +a.SRC_COLOR);break;default:console.error("THREE.WebGLState: Invalid blending: ",b)}F=C=Y=Yd=null;Lb=b;H=r}}else{k=k||d;m=m||e;n=n||f;if(d!==A||k!==z)a.blendEquationSeparate(c.convert(d),c.convert(k)),A=d,z=k;if(e!==Yd||f!==Y||m!==C||n!==F)a.blendFuncSeparate(c.convert(e),c.convert(f),c.convert(m),c.convert(n)),Yd=e,Y=f,C=m,F=n;Lb=b;H=null}}function m(b){G!==b&&(b?a.frontFace(a.CW):a.frontFace(a.CCW),G=b)}function r(b){0!==b?(g(a.CULL_FACE),b!==N&&(1===b?a.cullFace(a.BACK):2===b?a.cullFace(a.FRONT): +a.cullFace(a.FRONT_AND_BACK))):h(a.CULL_FACE);N=b}function n(b,c,d){if(b){if(g(a.POLYGON_OFFSET_FILL),M!==c||L!==d)a.polygonOffset(c,d),M=c,L=d}else h(a.POLYGON_OFFSET_FILL)}function q(b){void 0===b&&(b=a.TEXTURE0+S-1);K!==b&&(a.activeTexture(b),K=b)}var v=new function(){var b=!1,c=new Z,d=null,e=new Z(0,0,0,0);return{setMask:function(c){d===c||b||(a.colorMask(c,c,c,c),d=c)},setLocked:function(a){b=a},setClear:function(b,d,f,g,h){!0===h&&(b*=g,d*=g,f*=g);c.set(b,d,f,g);!1===e.equals(c)&&(a.clearColor(b, +d,f,g),e.copy(c))},reset:function(){b=!1;d=null;e.set(-1,0,0,0)}}},l=new function(){var b=!1,c=null,d=null,e=null;return{setTest:function(b){b?g(a.DEPTH_TEST):h(a.DEPTH_TEST)},setMask:function(d){c===d||b||(a.depthMask(d),c=d)},setFunc:function(b){if(d!==b){if(b)switch(b){case 0:a.depthFunc(a.NEVER);break;case 1:a.depthFunc(a.ALWAYS);break;case 2:a.depthFunc(a.LESS);break;case 3:a.depthFunc(a.LEQUAL);break;case 4:a.depthFunc(a.EQUAL);break;case 5:a.depthFunc(a.GEQUAL);break;case 6:a.depthFunc(a.GREATER); +break;case 7:a.depthFunc(a.NOTEQUAL);break;default:a.depthFunc(a.LEQUAL)}else a.depthFunc(a.LEQUAL);d=b}},setLocked:function(a){b=a},setClear:function(b){e!==b&&(a.clearDepth(b),e=b)},reset:function(){b=!1;e=d=c=null}}},u=new function(){var b=!1,c=null,d=null,e=null,f=null,k=null,m=null,n=null,r=null;return{setTest:function(b){b?g(a.STENCIL_TEST):h(a.STENCIL_TEST)},setMask:function(d){c===d||b||(a.stencilMask(d),c=d)},setFunc:function(b,c,g){if(d!==b||e!==c||f!==g)a.stencilFunc(b,c,g),d=b,e=c,f=g}, +setOp:function(b,c,d){if(k!==b||m!==c||n!==d)a.stencilOp(b,c,d),k=b,m=c,n=d},setLocked:function(a){b=a},setClear:function(b){r!==b&&(a.clearStencil(b),r=b)},reset:function(){b=!1;r=n=m=k=f=e=d=c=null}}},p=a.getParameter(a.MAX_VERTEX_ATTRIBS),x=new Uint8Array(p),w=new Uint8Array(p),D=new Uint8Array(p),J={},R=null,X=null,B=null,Lb=null,A=null,Yd=null,Y=null,z=null,C=null,F=null,H=!1,G=null,N=null,P=null,M=null,L=null,S=a.getParameter(a.MAX_COMBINED_TEXTURE_IMAGE_UNITS),I=!1;p=0;p=a.getParameter(a.VERSION); +-1!==p.indexOf("WebGL")?(p=parseFloat(/^WebGL ([0-9])/.exec(p)[1]),I=1<=p):-1!==p.indexOf("OpenGL ES")&&(p=parseFloat(/^OpenGL ES ([0-9])/.exec(p)[1]),I=2<=p);var K=null,T={},Q=new Z,O=new Z,U={};U[a.TEXTURE_2D]=e(a.TEXTURE_2D,a.TEXTURE_2D,1);U[a.TEXTURE_CUBE_MAP]=e(a.TEXTURE_CUBE_MAP,a.TEXTURE_CUBE_MAP_POSITIVE_X,6);v.setClear(0,0,0,1);l.setClear(1);u.setClear(0);g(a.DEPTH_TEST);l.setFunc(3);m(!1);r(1);g(a.CULL_FACE);k(0);return{buffers:{color:v,depth:l,stencil:u},initAttributes:function(){for(var a= +0,b=x.length;a<b;a++)x[a]=0},enableAttribute:function(a){f(a,0)},enableAttributeAndDivisor:f,disableUnusedAttributes:function(){for(var b=0,c=w.length;b!==c;++b)w[b]!==x[b]&&(a.disableVertexAttribArray(b),w[b]=0)},enable:g,disable:h,getCompressedTextureFormats:function(){if(null===R&&(R=[],b.get("WEBGL_compressed_texture_pvrtc")||b.get("WEBGL_compressed_texture_s3tc")||b.get("WEBGL_compressed_texture_etc1")||b.get("WEBGL_compressed_texture_astc")))for(var c=a.getParameter(a.COMPRESSED_TEXTURE_FORMATS), +d=0;d<c.length;d++)R.push(c[d]);return R},useProgram:function(b){return X!==b?(a.useProgram(b),X=b,!0):!1},setBlending:k,setMaterial:function(b,c){2===b.side?h(a.CULL_FACE):g(a.CULL_FACE);var d=1===b.side;c&&(d=!d);m(d);1===b.blending&&!1===b.transparent?k(0):k(b.blending,b.blendEquation,b.blendSrc,b.blendDst,b.blendEquationAlpha,b.blendSrcAlpha,b.blendDstAlpha,b.premultipliedAlpha);l.setFunc(b.depthFunc);l.setTest(b.depthTest);l.setMask(b.depthWrite);v.setMask(b.colorWrite);n(b.polygonOffset,b.polygonOffsetFactor, +b.polygonOffsetUnits)},setFlipSided:m,setCullFace:r,setLineWidth:function(b){b!==P&&(I&&a.lineWidth(b),P=b)},setPolygonOffset:n,setScissorTest:function(b){b?g(a.SCISSOR_TEST):h(a.SCISSOR_TEST)},activeTexture:q,bindTexture:function(b,c){null===K&&q();var d=T[K];void 0===d&&(d={type:void 0,texture:void 0},T[K]=d);if(d.type!==b||d.texture!==c)a.bindTexture(b,c||U[b]),d.type=b,d.texture=c},compressedTexImage2D:function(){try{a.compressedTexImage2D.apply(a,arguments)}catch(fa){console.error("THREE.WebGLState:", +fa)}},texImage2D:function(){try{a.texImage2D.apply(a,arguments)}catch(fa){console.error("THREE.WebGLState:",fa)}},texImage3D:function(){try{a.texImage3D.apply(a,arguments)}catch(fa){console.error("THREE.WebGLState:",fa)}},scissor:function(b){!1===Q.equals(b)&&(a.scissor(b.x,b.y,b.z,b.w),Q.copy(b))},viewport:function(b){!1===O.equals(b)&&(a.viewport(b.x,b.y,b.z,b.w),O.copy(b))},reset:function(){for(var b=0;b<w.length;b++)1===w[b]&&(a.disableVertexAttribArray(b),w[b]=0);J={};K=R=null;T={};N=G=Lb=X= +null;v.reset();l.reset();u.reset()}}}function Ng(a,b,c,d,e,f,g){function h(a,b){if(a.width>b||a.height>b){if("data"in a){console.warn("THREE.WebGLRenderer: image in DataTexture is too big ("+a.width+"x"+a.height+").");return}b/=Math.max(a.width,a.height);var c=document.createElementNS("http://www.w3.org/1999/xhtml","canvas");c.width=Math.floor(a.width*b);c.height=Math.floor(a.height*b);c.getContext("2d").drawImage(a,0,0,a.width,a.height,0,0,c.width,c.height);console.warn("THREE.WebGLRenderer: image is too big ("+ +a.width+"x"+a.height+"). Resized to "+c.width+"x"+c.height);return c}return a}function k(a){return S.isPowerOfTwo(a.width)&&S.isPowerOfTwo(a.height)}function m(a,b){return a.generateMipmaps&&b&&1003!==a.minFilter&&1006!==a.minFilter}function r(b,c,e,f){a.generateMipmap(b);d.get(c).__maxMipLevel=Math.log(Math.max(e,f))*Math.LOG2E}function n(b,c){if(!e.isWebGL2)return b;if(b===a.RED){if(c===a.FLOAT)return a.R32F;if(c===a.HALF_FLOAT)return a.R16F;if(c===a.UNSIGNED_BYTE)return a.R8}if(b===a.RGB){if(c=== +a.FLOAT)return a.RGB32F;if(c===a.HALF_FLOAT)return a.RGB16F;if(c===a.UNSIGNED_BYTE)return a.RGB8}if(b===a.RGBA){if(c===a.FLOAT)return a.RGBA32F;if(c===a.HALF_FLOAT)return a.RGBA16F;if(c===a.UNSIGNED_BYTE)return a.RGBA8}return b}function q(b){return 1003===b||1004===b||1005===b?a.NEAREST:a.LINEAR}function v(b){b=b.target;b.removeEventListener("dispose",v);a:{var c=d.get(b);if(b.image&&c.__image__webglTextureCube)a.deleteTexture(c.__image__webglTextureCube);else{if(void 0===c.__webglInit)break a;a.deleteTexture(c.__webglTexture)}d.remove(b)}b.isVideoTexture&& +delete J[b.id];g.memory.textures--}function l(b){b=b.target;b.removeEventListener("dispose",l);var c=d.get(b),e=d.get(b.texture);if(b){void 0!==e.__webglTexture&&a.deleteTexture(e.__webglTexture);b.depthTexture&&b.depthTexture.dispose();if(b.isWebGLRenderTargetCube)for(e=0;6>e;e++)a.deleteFramebuffer(c.__webglFramebuffer[e]),c.__webglDepthbuffer&&a.deleteRenderbuffer(c.__webglDepthbuffer[e]);else a.deleteFramebuffer(c.__webglFramebuffer),c.__webglDepthbuffer&&a.deleteRenderbuffer(c.__webglDepthbuffer); +d.remove(b.texture);d.remove(b)}g.memory.textures--}function u(b,e){var f=d.get(b);if(b.isVideoTexture){var h=b.id,k=g.render.frame;J[h]!==k&&(J[h]=k,b.update())}if(0<b.version&&f.__version!==b.version)if(h=b.image,void 0===h)console.warn("THREE.WebGLRenderer: Texture marked for update but image is undefined");else if(!1===h.complete)console.warn("THREE.WebGLRenderer: Texture marked for update but image is incomplete");else{x(f,b,e);return}c.activeTexture(a.TEXTURE0+e);c.bindTexture(a.TEXTURE_2D, +f.__webglTexture)}function p(c,g,h){h?(a.texParameteri(c,a.TEXTURE_WRAP_S,f.convert(g.wrapS)),a.texParameteri(c,a.TEXTURE_WRAP_T,f.convert(g.wrapT)),a.texParameteri(c,a.TEXTURE_MAG_FILTER,f.convert(g.magFilter)),a.texParameteri(c,a.TEXTURE_MIN_FILTER,f.convert(g.minFilter))):(a.texParameteri(c,a.TEXTURE_WRAP_S,a.CLAMP_TO_EDGE),a.texParameteri(c,a.TEXTURE_WRAP_T,a.CLAMP_TO_EDGE),1001===g.wrapS&&1001===g.wrapT||console.warn("THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping."), +a.texParameteri(c,a.TEXTURE_MAG_FILTER,q(g.magFilter)),a.texParameteri(c,a.TEXTURE_MIN_FILTER,q(g.minFilter)),1003!==g.minFilter&&1006!==g.minFilter&&console.warn("THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter."));!(h=b.get("EXT_texture_filter_anisotropic"))||1015===g.type&&null===b.get("OES_texture_float_linear")||1016===g.type&&null===(e.isWebGL2||b.get("OES_texture_half_float_linear"))||!(1<g.anisotropy||d.get(g).__currentAnisotropy)|| +(a.texParameterf(c,h.TEXTURE_MAX_ANISOTROPY_EXT,Math.min(g.anisotropy,e.getMaxAnisotropy())),d.get(g).__currentAnisotropy=g.anisotropy)}function x(b,d,q){var l=d.isDataTexture3D?a.TEXTURE_3D:a.TEXTURE_2D;void 0===b.__webglInit&&(b.__webglInit=!0,d.addEventListener("dispose",v),b.__webglTexture=a.createTexture(),g.memory.textures++);c.activeTexture(a.TEXTURE0+q);c.bindTexture(l,b.__webglTexture);a.pixelStorei(a.UNPACK_FLIP_Y_WEBGL,d.flipY);a.pixelStorei(a.UNPACK_PREMULTIPLY_ALPHA_WEBGL,d.premultiplyAlpha); +a.pixelStorei(a.UNPACK_ALIGNMENT,d.unpackAlignment);q=h(d.image,e.maxTextureSize);var t=e.isWebGL2?!1:1001!==d.wrapS||1001!==d.wrapT||1003!==d.minFilter&&1006!==d.minFilter;t&&!1===k(q)&&(q instanceof HTMLImageElement||q instanceof HTMLCanvasElement||q instanceof ImageBitmap)&&(void 0===R&&(R=document.createElementNS("http://www.w3.org/1999/xhtml","canvas")),R.width=S.floorPowerOfTwo(q.width),R.height=S.floorPowerOfTwo(q.height),R.getContext("2d").drawImage(q,0,0,R.width,R.height),console.warn("THREE.WebGLRenderer: image is not power of two ("+ +q.width+"x"+q.height+"). Resized to "+R.width+"x"+R.height),q=R);t=k(q);var u=f.convert(d.format),w=f.convert(d.type),y=n(u,w);p(l,d,t);var X=d.mipmaps;if(d.isDepthTexture){y=a.DEPTH_COMPONENT;if(1015===d.type){if(!e.isWebGL2)throw Error("Float Depth Texture only supported in WebGL2.0");y=a.DEPTH_COMPONENT32F}else e.isWebGL2&&(y=a.DEPTH_COMPONENT16);1026===d.format&&y===a.DEPTH_COMPONENT&&1012!==d.type&&1014!==d.type&&(console.warn("THREE.WebGLRenderer: Use UnsignedShortType or UnsignedIntType for DepthFormat DepthTexture."), +d.type=1012,w=f.convert(d.type));1027===d.format&&(y=a.DEPTH_STENCIL,1020!==d.type&&(console.warn("THREE.WebGLRenderer: Use UnsignedInt248Type for DepthStencilFormat DepthTexture."),d.type=1020,w=f.convert(d.type)));c.texImage2D(a.TEXTURE_2D,0,y,q.width,q.height,0,u,w,null)}else if(d.isDataTexture)if(0<X.length&&t){for(var B=0,D=X.length;B<D;B++)l=X[B],c.texImage2D(a.TEXTURE_2D,B,y,l.width,l.height,0,u,w,l.data);d.generateMipmaps=!1;b.__maxMipLevel=X.length-1}else c.texImage2D(a.TEXTURE_2D,0,y,q.width, +q.height,0,u,w,q.data),b.__maxMipLevel=0;else if(d.isCompressedTexture){B=0;for(D=X.length;B<D;B++)l=X[B],1023!==d.format&&1022!==d.format?-1<c.getCompressedTextureFormats().indexOf(u)?c.compressedTexImage2D(a.TEXTURE_2D,B,y,l.width,l.height,0,l.data):console.warn("THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()"):c.texImage2D(a.TEXTURE_2D,B,y,l.width,l.height,0,u,w,l.data);b.__maxMipLevel=X.length-1}else if(d.isDataTexture3D)c.texImage3D(a.TEXTURE_3D, +0,y,q.width,q.height,q.depth,0,u,w,q.data),b.__maxMipLevel=0;else if(0<X.length&&t){B=0;for(D=X.length;B<D;B++)l=X[B],c.texImage2D(a.TEXTURE_2D,B,y,u,w,l);d.generateMipmaps=!1;b.__maxMipLevel=X.length-1}else c.texImage2D(a.TEXTURE_2D,0,y,u,w,q),b.__maxMipLevel=0;m(d,t)&&r(a.TEXTURE_2D,d,q.width,q.height);b.__version=d.version;if(d.onUpdate)d.onUpdate(d)}function w(b,e,g,h){var k=f.convert(e.texture.format),m=f.convert(e.texture.type),r=n(k,m);c.texImage2D(h,0,r,e.width,e.height,0,k,m,null);a.bindFramebuffer(a.FRAMEBUFFER, +b);a.framebufferTexture2D(a.FRAMEBUFFER,g,h,d.get(e.texture).__webglTexture,0);a.bindFramebuffer(a.FRAMEBUFFER,null)}function D(b,c){a.bindRenderbuffer(a.RENDERBUFFER,b);c.depthBuffer&&!c.stencilBuffer?(a.renderbufferStorage(a.RENDERBUFFER,a.DEPTH_COMPONENT16,c.width,c.height),a.framebufferRenderbuffer(a.FRAMEBUFFER,a.DEPTH_ATTACHMENT,a.RENDERBUFFER,b)):c.depthBuffer&&c.stencilBuffer?(a.renderbufferStorage(a.RENDERBUFFER,a.DEPTH_STENCIL,c.width,c.height),a.framebufferRenderbuffer(a.FRAMEBUFFER,a.DEPTH_STENCIL_ATTACHMENT, +a.RENDERBUFFER,b)):a.renderbufferStorage(a.RENDERBUFFER,a.RGBA4,c.width,c.height);a.bindRenderbuffer(a.RENDERBUFFER,null)}var J={},R;this.setTexture2D=u;this.setTexture3D=function(b,e){var f=d.get(b);0<b.version&&f.__version!==b.version?x(f,b,e):(c.activeTexture(a.TEXTURE0+e),c.bindTexture(a.TEXTURE_3D,f.__webglTexture))};this.setTextureCube=function(b,q){var l=d.get(b);if(6===b.image.length)if(0<b.version&&l.__version!==b.version){l.__image__webglTextureCube||(b.addEventListener("dispose",v),l.__image__webglTextureCube= +a.createTexture(),g.memory.textures++);c.activeTexture(a.TEXTURE0+q);c.bindTexture(a.TEXTURE_CUBE_MAP,l.__image__webglTextureCube);a.pixelStorei(a.UNPACK_FLIP_Y_WEBGL,b.flipY);q=b&&b.isCompressedTexture;for(var t=b.image[0]&&b.image[0].isDataTexture,u=[],w=0;6>w;w++)u[w]=q||t?t?b.image[w].image:b.image[w]:h(b.image[w],e.maxCubemapSize);var y=u[0],D=k(y),R=f.convert(b.format),X=f.convert(b.type),B=n(R,X);p(a.TEXTURE_CUBE_MAP,b,D);for(w=0;6>w;w++)if(q)for(var x,J=u[w].mipmaps,A=0,z=J.length;A<z;A++)x= +J[A],1023!==b.format&&1022!==b.format?-1<c.getCompressedTextureFormats().indexOf(R)?c.compressedTexImage2D(a.TEXTURE_CUBE_MAP_POSITIVE_X+w,A,B,x.width,x.height,0,x.data):console.warn("THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setTextureCube()"):c.texImage2D(a.TEXTURE_CUBE_MAP_POSITIVE_X+w,A,B,x.width,x.height,0,R,X,x.data);else t?c.texImage2D(a.TEXTURE_CUBE_MAP_POSITIVE_X+w,0,B,u[w].width,u[w].height,0,R,X,u[w].data):c.texImage2D(a.TEXTURE_CUBE_MAP_POSITIVE_X+ +w,0,B,R,X,u[w]);l.__maxMipLevel=q?J.length-1:0;m(b,D)&&r(a.TEXTURE_CUBE_MAP,b,y.width,y.height);l.__version=b.version;if(b.onUpdate)b.onUpdate(b)}else c.activeTexture(a.TEXTURE0+q),c.bindTexture(a.TEXTURE_CUBE_MAP,l.__image__webglTextureCube)};this.setTextureCubeDynamic=function(b,e){c.activeTexture(a.TEXTURE0+e);c.bindTexture(a.TEXTURE_CUBE_MAP,d.get(b).__webglTexture)};this.setupRenderTarget=function(b){var e=d.get(b),f=d.get(b.texture);b.addEventListener("dispose",l);f.__webglTexture=a.createTexture(); +g.memory.textures++;var h=!0===b.isWebGLRenderTargetCube,n=k(b);if(h){e.__webglFramebuffer=[];for(var q=0;6>q;q++)e.__webglFramebuffer[q]=a.createFramebuffer()}else e.__webglFramebuffer=a.createFramebuffer();if(h){c.bindTexture(a.TEXTURE_CUBE_MAP,f.__webglTexture);p(a.TEXTURE_CUBE_MAP,b.texture,n);for(q=0;6>q;q++)w(e.__webglFramebuffer[q],b,a.COLOR_ATTACHMENT0,a.TEXTURE_CUBE_MAP_POSITIVE_X+q);m(b.texture,n)&&r(a.TEXTURE_CUBE_MAP,b.texture,b.width,b.height);c.bindTexture(a.TEXTURE_CUBE_MAP,null)}else c.bindTexture(a.TEXTURE_2D, +f.__webglTexture),p(a.TEXTURE_2D,b.texture,n),w(e.__webglFramebuffer,b,a.COLOR_ATTACHMENT0,a.TEXTURE_2D),m(b.texture,n)&&r(a.TEXTURE_2D,b.texture,b.width,b.height),c.bindTexture(a.TEXTURE_2D,null);if(b.depthBuffer){e=d.get(b);f=!0===b.isWebGLRenderTargetCube;if(b.depthTexture){if(f)throw Error("target.depthTexture not supported in Cube render targets");if(b&&b.isWebGLRenderTargetCube)throw Error("Depth Texture with cube render targets is not supported");a.bindFramebuffer(a.FRAMEBUFFER,e.__webglFramebuffer); +if(!b.depthTexture||!b.depthTexture.isDepthTexture)throw Error("renderTarget.depthTexture must be an instance of THREE.DepthTexture");d.get(b.depthTexture).__webglTexture&&b.depthTexture.image.width===b.width&&b.depthTexture.image.height===b.height||(b.depthTexture.image.width=b.width,b.depthTexture.image.height=b.height,b.depthTexture.needsUpdate=!0);u(b.depthTexture,0);e=d.get(b.depthTexture).__webglTexture;if(1026===b.depthTexture.format)a.framebufferTexture2D(a.FRAMEBUFFER,a.DEPTH_ATTACHMENT, +a.TEXTURE_2D,e,0);else if(1027===b.depthTexture.format)a.framebufferTexture2D(a.FRAMEBUFFER,a.DEPTH_STENCIL_ATTACHMENT,a.TEXTURE_2D,e,0);else throw Error("Unknown depthTexture format");}else if(f)for(e.__webglDepthbuffer=[],f=0;6>f;f++)a.bindFramebuffer(a.FRAMEBUFFER,e.__webglFramebuffer[f]),e.__webglDepthbuffer[f]=a.createRenderbuffer(),D(e.__webglDepthbuffer[f],b);else a.bindFramebuffer(a.FRAMEBUFFER,e.__webglFramebuffer),e.__webglDepthbuffer=a.createRenderbuffer(),D(e.__webglDepthbuffer,b);a.bindFramebuffer(a.FRAMEBUFFER, +null)}};this.updateRenderTargetMipmap=function(b){var e=b.texture,f=k(b);if(m(e,f)){f=b.isWebGLRenderTargetCube?a.TEXTURE_CUBE_MAP:a.TEXTURE_2D;var g=d.get(e).__webglTexture;c.bindTexture(f,g);r(f,e,b.width,b.height);c.bindTexture(f,null)}}}function bf(a,b,c){return{convert:function(d){if(1E3===d)return a.REPEAT;if(1001===d)return a.CLAMP_TO_EDGE;if(1002===d)return a.MIRRORED_REPEAT;if(1003===d)return a.NEAREST;if(1004===d)return a.NEAREST_MIPMAP_NEAREST;if(1005===d)return a.NEAREST_MIPMAP_LINEAR; +if(1006===d)return a.LINEAR;if(1007===d)return a.LINEAR_MIPMAP_NEAREST;if(1008===d)return a.LINEAR_MIPMAP_LINEAR;if(1009===d)return a.UNSIGNED_BYTE;if(1017===d)return a.UNSIGNED_SHORT_4_4_4_4;if(1018===d)return a.UNSIGNED_SHORT_5_5_5_1;if(1019===d)return a.UNSIGNED_SHORT_5_6_5;if(1010===d)return a.BYTE;if(1011===d)return a.SHORT;if(1012===d)return a.UNSIGNED_SHORT;if(1013===d)return a.INT;if(1014===d)return a.UNSIGNED_INT;if(1015===d)return a.FLOAT;if(1016===d){if(c.isWebGL2)return a.HALF_FLOAT;var e= +b.get("OES_texture_half_float");if(null!==e)return e.HALF_FLOAT_OES}if(1021===d)return a.ALPHA;if(1022===d)return a.RGB;if(1023===d)return a.RGBA;if(1024===d)return a.LUMINANCE;if(1025===d)return a.LUMINANCE_ALPHA;if(1026===d)return a.DEPTH_COMPONENT;if(1027===d)return a.DEPTH_STENCIL;if(1028===d)return a.RED;if(100===d)return a.FUNC_ADD;if(101===d)return a.FUNC_SUBTRACT;if(102===d)return a.FUNC_REVERSE_SUBTRACT;if(200===d)return a.ZERO;if(201===d)return a.ONE;if(202===d)return a.SRC_COLOR;if(203=== +d)return a.ONE_MINUS_SRC_COLOR;if(204===d)return a.SRC_ALPHA;if(205===d)return a.ONE_MINUS_SRC_ALPHA;if(206===d)return a.DST_ALPHA;if(207===d)return a.ONE_MINUS_DST_ALPHA;if(208===d)return a.DST_COLOR;if(209===d)return a.ONE_MINUS_DST_COLOR;if(210===d)return a.SRC_ALPHA_SATURATE;if(33776===d||33777===d||33778===d||33779===d)if(e=b.get("WEBGL_compressed_texture_s3tc"),null!==e){if(33776===d)return e.COMPRESSED_RGB_S3TC_DXT1_EXT;if(33777===d)return e.COMPRESSED_RGBA_S3TC_DXT1_EXT;if(33778===d)return e.COMPRESSED_RGBA_S3TC_DXT3_EXT; +if(33779===d)return e.COMPRESSED_RGBA_S3TC_DXT5_EXT}if(35840===d||35841===d||35842===d||35843===d)if(e=b.get("WEBGL_compressed_texture_pvrtc"),null!==e){if(35840===d)return e.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;if(35841===d)return e.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;if(35842===d)return e.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;if(35843===d)return e.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG}if(36196===d&&(e=b.get("WEBGL_compressed_texture_etc1"),null!==e))return e.COMPRESSED_RGB_ETC1_WEBGL;if(37808===d||37809===d||37810=== +d||37811===d||37812===d||37813===d||37814===d||37815===d||37816===d||37817===d||37818===d||37819===d||37820===d||37821===d)if(e=b.get("WEBGL_compressed_texture_astc"),null!==e)return d;if(103===d||104===d){if(c.isWebGL2){if(103===d)return a.MIN;if(104===d)return a.MAX}e=b.get("EXT_blend_minmax");if(null!==e){if(103===d)return e.MIN_EXT;if(104===d)return e.MAX_EXT}}if(1020===d){if(c.isWebGL2)return a.UNSIGNED_INT_24_8;e=b.get("WEBGL_depth_texture");if(null!==e)return e.UNSIGNED_INT_24_8_WEBGL}return 0}}} +function Ob(){C.call(this);this.type="Group"}function Ra(){C.call(this);this.type="Camera";this.matrixWorldInverse=new P;this.projectionMatrix=new P;this.projectionMatrixInverse=new P}function V(a,b,c,d){Ra.call(this);this.type="PerspectiveCamera";this.fov=void 0!==a?a:50;this.zoom=1;this.near=void 0!==c?c:.1;this.far=void 0!==d?d:2E3;this.focus=10;this.aspect=void 0!==b?b:1;this.view=null;this.filmGauge=35;this.filmOffset=0;this.updateProjectionMatrix()}function Cc(a){V.call(this);this.cameras=a|| +[]}function cf(a){function b(){return null!==e&&!0===e.isPresenting}function c(){if(b()){var c=e.getEyeParameters("left"),f=c.renderWidth;c=c.renderHeight;w=a.getPixelRatio();x=a.getSize();a.setDrawingBufferSize(2*f,c,1);J.start()}else d.enabled&&a.setDrawingBufferSize(x.width,x.height,w),J.stop()}var d=this,e=null,f=null,g=null,h=[],k=new P,m=new P,r="stage";"undefined"!==typeof window&&"VRFrameData"in window&&(f=new window.VRFrameData,window.addEventListener("vrdisplaypresentchange",c,!1));var n= +new P,q=new ja,v=new p,l=new V;l.bounds=new Z(0,0,.5,1);l.layers.enable(1);var u=new V;u.bounds=new Z(.5,0,.5,1);u.layers.enable(2);var y=new Cc([l,u]);y.layers.enable(1);y.layers.enable(2);var x,w,D=[];this.enabled=!1;this.getController=function(a){var b=h[a];void 0===b&&(b=new Ob,b.matrixAutoUpdate=!1,b.visible=!1,h[a]=b);return b};this.getDevice=function(){return e};this.setDevice=function(a){void 0!==a&&(e=a);J.setContext(a)};this.setFrameOfReferenceType=function(a){r=a};this.setPoseTarget=function(a){void 0!== +a&&(g=a)};this.getCamera=function(a){var b="stage"===r?1.6:0;if(null===e)return a.position.set(0,b,0),a;e.depthNear=a.near;e.depthFar=a.far;e.getFrameData(f);if("stage"===r){var c=e.stageParameters;c?k.fromArray(c.sittingToStandingTransform):k.makeTranslation(0,b,0)}b=f.pose;c=null!==g?g:a;c.matrix.copy(k);c.matrix.decompose(c.position,c.quaternion,c.scale);null!==b.orientation&&(q.fromArray(b.orientation),c.quaternion.multiply(q));null!==b.position&&(q.setFromRotationMatrix(k),v.fromArray(b.position), +v.applyQuaternion(q),c.position.add(v));c.updateMatrixWorld();if(!1===e.isPresenting)return a;l.near=a.near;u.near=a.near;l.far=a.far;u.far=a.far;y.matrixWorld.copy(a.matrixWorld);y.matrixWorldInverse.copy(a.matrixWorldInverse);l.matrixWorldInverse.fromArray(f.leftViewMatrix);u.matrixWorldInverse.fromArray(f.rightViewMatrix);m.getInverse(k);"stage"===r&&(l.matrixWorldInverse.multiply(m),u.matrixWorldInverse.multiply(m));a=c.parent;null!==a&&(n.getInverse(a.matrixWorld),l.matrixWorldInverse.multiply(n), +u.matrixWorldInverse.multiply(n));l.matrixWorld.getInverse(l.matrixWorldInverse);u.matrixWorld.getInverse(u.matrixWorldInverse);l.projectionMatrix.fromArray(f.leftProjectionMatrix);u.projectionMatrix.fromArray(f.rightProjectionMatrix);y.projectionMatrix.copy(l.projectionMatrix);a=e.getLayers();a.length&&(a=a[0],null!==a.leftBounds&&4===a.leftBounds.length&&l.bounds.fromArray(a.leftBounds),null!==a.rightBounds&&4===a.rightBounds.length&&u.bounds.fromArray(a.rightBounds));a:for(a=0;a<h.length;a++){b= +h[a];b:{c=a;for(var d=navigator.getGamepads&&navigator.getGamepads(),t=0,w=0,p=d.length;t<p;t++){var x=d[t];if(x&&("Daydream Controller"===x.id||"Gear VR Controller"===x.id||"Oculus Go Controller"===x.id||"OpenVR Gamepad"===x.id||x.id.startsWith("Oculus Touch")||x.id.startsWith("Spatial Controller"))){if(w===c){c=x;break b}w++}}c=void 0}if(void 0!==c&&void 0!==c.pose){if(null===c.pose)break a;d=c.pose;!1===d.hasPosition&&b.position.set(.2,-.6,-.05);null!==d.position&&b.position.fromArray(d.position); +null!==d.orientation&&b.quaternion.fromArray(d.orientation);b.matrix.compose(b.position,b.quaternion,b.scale);b.matrix.premultiply(k);b.matrix.decompose(b.position,b.quaternion,b.scale);b.matrixWorldNeedsUpdate=!0;b.visible=!0;d="Daydream Controller"===c.id?0:1;D[a]!==c.buttons[d].pressed&&(D[a]=c.buttons[d].pressed,!0===D[a]?b.dispatchEvent({type:"selectstart"}):(b.dispatchEvent({type:"selectend"}),b.dispatchEvent({type:"select"})))}else b.visible=!1}return y};this.getStandingMatrix=function(){return k}; +this.isPresenting=b;var J=new Wd;this.setAnimationLoop=function(a){J.setAnimationLoop(a)};this.submitFrame=function(){b()&&e.submitFrame()};this.dispose=function(){"undefined"!==typeof window&&window.removeEventListener("vrdisplaypresentchange",c)}}function Og(a){function b(){return null!==h&&null!==k}function c(a){var b=n[q.indexOf(a.inputSource)];b&&b.dispatchEvent({type:a.type})}function d(){a.setFramebuffer(null);x.stop()}function e(a,b){null===b?a.matrixWorld.copy(a.matrix):a.matrixWorld.multiplyMatrices(b.matrixWorld, +a.matrix);a.matrixWorldInverse.getInverse(a.matrixWorld)}var f=a.context,g=null,h=null,k=null,m="stage",r=null,n=[],q=[],l=new V;l.layers.enable(1);l.viewport=new Z;var t=new V;t.layers.enable(2);t.viewport=new Z;var u=new Cc([l,t]);u.layers.enable(1);u.layers.enable(2);this.enabled=!1;this.getController=function(a){var b=n[a];void 0===b&&(b=new Ob,b.matrixAutoUpdate=!1,b.visible=!1,n[a]=b);return b};this.getDevice=function(){return g};this.setDevice=function(a){void 0!==a&&(g=a);a instanceof XRDevice&& +f.setCompatibleXRDevice(a)};this.setFrameOfReferenceType=function(a){m=a};this.setSession=function(b){h=b;null!==h&&(h.addEventListener("select",c),h.addEventListener("selectstart",c),h.addEventListener("selectend",c),h.addEventListener("end",d),h.baseLayer=new XRWebGLLayer(h,f),h.requestFrameOfReference(m).then(function(b){k=b;a.setFramebuffer(h.baseLayer.framebuffer);x.setContext(h);x.start()}),q=h.getInputSources(),h.addEventListener("inputsourceschange",function(){q=h.getInputSources();console.log(q)}))}; +this.getCamera=function(a){if(b()){var c=a.parent,d=u.cameras;e(u,c);for(var f=0;f<d.length;f++)e(d[f],c);a.matrixWorld.copy(u.matrixWorld);a=a.children;f=0;for(c=a.length;f<c;f++)a[f].updateMatrixWorld(!0);return u}return a};this.isPresenting=b;var p=null,x=new Wd;x.setAnimationLoop(function(a,b){r=b.getDevicePose(k);if(null!==r)for(var c=h.baseLayer,d=b.views,e=0;e<d.length;e++){var f=d[e],g=c.getViewport(f),m=r.getViewMatrix(f),l=u.cameras[e];l.matrix.fromArray(m).getInverse(l.matrix);l.projectionMatrix.fromArray(f.projectionMatrix); +l.viewport.set(g.x,g.y,g.width,g.height);0===e&&(u.matrix.copy(l.matrix),u.projectionMatrix.copy(l.projectionMatrix))}for(e=0;e<n.length;e++){c=n[e];if(d=q[e])if(d=b.getInputPose(d,k),null!==d){"targetRay"in d?c.matrix.elements=d.targetRay.transformMatrix:"pointerMatrix"in d&&(c.matrix.elements=d.pointerMatrix);c.matrix.decompose(c.position,c.rotation,c.scale);c.visible=!0;continue}c.visible=!1}p&&p(a)});this.setAnimationLoop=function(a){p=a};this.dispose=function(){};this.getStandingMatrix=function(){console.warn("THREE.WebXRManager: getStandingMatrix() is no longer needed."); +return new THREE.Matrix4};this.submitFrame=function(){}}function be(a){var b;function c(){la=new Qf(E);xa=new Of(E,la,a);xa.isWebGL2||(la.get("WEBGL_depth_texture"),la.get("OES_texture_float"),la.get("OES_texture_half_float"),la.get("OES_texture_half_float_linear"),la.get("OES_standard_derivatives"),la.get("OES_element_index_uint"),la.get("ANGLE_instanced_arrays"));la.get("OES_texture_float_linear");ia=new bf(E,la,xa);ba=new Mg(E,la,ia,xa);ba.scissor(Bc.copy(ja).multiplyScalar(U));ba.viewport(W.copy(fa).multiplyScalar(U)); +da=new Tf(E);Da=new Dg;ha=new Ng(E,la,ba,Da,xa,ia,da);ra=new Hf(E);ta=new Rf(E,ra,da);oa=new Wf(ta,da);ya=new Vf(E);na=new Cg(Y,la,xa);ua=new Hg;pa=new Lg;ma=new Mf(Y,ba,oa,A);za=new Nf(E,la,da,xa);Ba=new Sf(E,la,da,xa);da.programs=na.programs;Y.context=E;Y.capabilities=xa;Y.extensions=la;Y.properties=Da;Y.renderLists=ua;Y.state=ba;Y.info=da}function d(a){a.preventDefault();console.log("THREE.WebGLRenderer: Context Lost.");G=!0}function e(){console.log("THREE.WebGLRenderer: Context Restored.");G= +!1;c()}function f(a){a=a.target;a.removeEventListener("dispose",f);g(a);Da.remove(a)}function g(a){var b=Da.get(a).program;a.program=void 0;void 0!==b&&na.releaseProgram(b)}function h(a,b){a.render(function(a){Y.renderBufferImmediate(a,b)})}function k(a,b,c){if(!1!==a.visible){if(a.layers.test(b.layers))if(a.isLight)F.pushLight(a),a.castShadow&&F.pushShadow(a);else if(a.isSprite){if(!a.frustumCulled||qa.intersectsSprite(a)){c&&eb.setFromMatrixPosition(a.matrixWorld).applyMatrix4(Ac);var d=oa.update(a), +e=a.material;C.push(a,d,e,eb.z,null)}}else if(a.isImmediateRenderObject)c&&eb.setFromMatrixPosition(a.matrixWorld).applyMatrix4(Ac),C.push(a,null,a.material,eb.z,null);else if(a.isMesh||a.isLine||a.isPoints)if(a.isSkinnedMesh&&a.skeleton.update(),!a.frustumCulled||qa.intersectsObject(a))if(c&&eb.setFromMatrixPosition(a.matrixWorld).applyMatrix4(Ac),d=oa.update(a),e=a.material,Array.isArray(e))for(var f=d.groups,g=0,h=f.length;g<h;g++){var m=f[g],n=e[m.materialIndex];n&&n.visible&&C.push(a,d,n,eb.z, +m)}else e.visible&&C.push(a,d,e,eb.z,null);a=a.children;g=0;for(h=a.length;g<h;g++)k(a[g],b,c)}}function m(a,b,c,d){for(var e=0,f=a.length;e<f;e++){var g=a[e],h=g.object,k=g.geometry,m=void 0===d?g.material:d;g=g.group;if(c.isArrayCamera){Q=c;for(var n=c.cameras,q=0,l=n.length;q<l;q++){var v=n[q];if(h.layers.test(v.layers)){if("viewport"in v)ba.viewport(W.copy(v.viewport));else{var t=v.bounds;ba.viewport(W.set(t.x*V,t.y*O,t.z*V,t.w*O).multiplyScalar(U))}F.setupLights(v);r(h,b,v,k,m,g)}}}else Q=null, +r(h,b,c,k,m,g)}}function r(a,c,d,e,f,g){a.onBeforeRender(Y,c,d,e,f,g);F=pa.get(c,Q||d);a.modelViewMatrix.multiplyMatrices(d.matrixWorldInverse,a.matrixWorld);a.normalMatrix.getNormalMatrix(a.modelViewMatrix);if(a.isImmediateRenderObject){ba.setMaterial(f);var k=q(d,c.fog,f,a);K=b=null;sd=!1;h(a,k)}else Y.renderBufferDirect(d,c.fog,e,f,a,g);a.onAfterRender(Y,c,d,e,f,g);F=pa.get(c,Q||d)}function n(a,b,c){var d=Da.get(a),e=F.state.lights,h=d.lightsHash,k=e.state.hash;c=na.getParameters(a,e.state,F.state.shadowsArray, +b,aa.numPlanes,aa.numIntersection,c);var m=na.getProgramCode(a,c),n=d.program,r=!0;if(void 0===n)a.addEventListener("dispose",f);else if(n.code!==m)g(a);else{if(h.stateID!==k.stateID||h.directionalLength!==k.directionalLength||h.pointLength!==k.pointLength||h.spotLength!==k.spotLength||h.rectAreaLength!==k.rectAreaLength||h.hemiLength!==k.hemiLength||h.shadowsLength!==k.shadowsLength)h.stateID=k.stateID,h.directionalLength=k.directionalLength,h.pointLength=k.pointLength,h.spotLength=k.spotLength, +h.rectAreaLength=k.rectAreaLength,h.hemiLength=k.hemiLength,h.shadowsLength=k.shadowsLength;else if(void 0!==c.shaderID)return;r=!1}r&&(c.shaderID?(m=Qa[c.shaderID],d.shader={name:a.type,uniforms:va.clone(m.uniforms),vertexShader:m.vertexShader,fragmentShader:m.fragmentShader}):d.shader={name:a.type,uniforms:a.uniforms,vertexShader:a.vertexShader,fragmentShader:a.fragmentShader},a.onBeforeCompile(d.shader,Y),m=na.getProgramCode(a,c),n=na.acquireProgram(a,d.shader,c,m),d.program=n,a.program=n);c=n.getAttributes(); +if(a.morphTargets)for(m=a.numSupportedMorphTargets=0;m<Y.maxMorphTargets;m++)0<=c["morphTarget"+m]&&a.numSupportedMorphTargets++;if(a.morphNormals)for(m=a.numSupportedMorphNormals=0;m<Y.maxMorphNormals;m++)0<=c["morphNormal"+m]&&a.numSupportedMorphNormals++;c=d.shader.uniforms;if(!a.isShaderMaterial&&!a.isRawShaderMaterial||!0===a.clipping)d.numClippingPlanes=aa.numPlanes,d.numIntersection=aa.numIntersection,c.clippingPlanes=aa.uniform;d.fog=b;void 0===h&&(d.lightsHash=h={});h.stateID=k.stateID;h.directionalLength= +k.directionalLength;h.pointLength=k.pointLength;h.spotLength=k.spotLength;h.rectAreaLength=k.rectAreaLength;h.hemiLength=k.hemiLength;h.shadowsLength=k.shadowsLength;a.lights&&(c.ambientLightColor.value=e.state.ambient,c.directionalLights.value=e.state.directional,c.spotLights.value=e.state.spot,c.rectAreaLights.value=e.state.rectArea,c.pointLights.value=e.state.point,c.hemisphereLights.value=e.state.hemi,c.directionalShadowMap.value=e.state.directionalShadowMap,c.directionalShadowMatrix.value=e.state.directionalShadowMatrix, +c.spotShadowMap.value=e.state.spotShadowMap,c.spotShadowMatrix.value=e.state.spotShadowMatrix,c.pointShadowMap.value=e.state.pointShadowMap,c.pointShadowMatrix.value=e.state.pointShadowMatrix);a=d.program.getUniforms();a=bb.seqWithValue(a.seq,c);d.uniformsList=a}function q(a,b,c,d){ca=0;var e=Da.get(c),f=e.lightsHash,g=F.state.lights.state.hash;ud&&(ae||a!==T)&&aa.setState(c.clippingPlanes,c.clipIntersection,c.clipShadows,a,e,a===T&&c.id===I);!1===c.needsUpdate&&(void 0===e.program?c.needsUpdate= +!0:c.fog&&e.fog!==b?c.needsUpdate=!0:!c.lights||f.stateID===g.stateID&&f.directionalLength===g.directionalLength&&f.pointLength===g.pointLength&&f.spotLength===g.spotLength&&f.rectAreaLength===g.rectAreaLength&&f.hemiLength===g.hemiLength&&f.shadowsLength===g.shadowsLength?void 0===e.numClippingPlanes||e.numClippingPlanes===aa.numPlanes&&e.numIntersection===aa.numIntersection||(c.needsUpdate=!0):c.needsUpdate=!0);c.needsUpdate&&(n(c,b,d),c.needsUpdate=!1);var h=!1,k=!1,m=!1;f=e.program;g=f.getUniforms(); +var r=e.shader.uniforms;ba.useProgram(f.program)&&(m=k=h=!0);c.id!==I&&(I=c.id,k=!0);if(h||T!==a){g.setValue(E,"projectionMatrix",a.projectionMatrix);xa.logarithmicDepthBuffer&&g.setValue(E,"logDepthBufFC",2/(Math.log(a.far+1)/Math.LN2));T!==a&&(T=a,m=k=!0);if(c.isShaderMaterial||c.isMeshPhongMaterial||c.isMeshStandardMaterial||c.envMap)h=g.map.cameraPosition,void 0!==h&&h.setValue(E,eb.setFromMatrixPosition(a.matrixWorld));(c.isMeshPhongMaterial||c.isMeshLambertMaterial||c.isMeshBasicMaterial||c.isMeshStandardMaterial|| +c.isShaderMaterial||c.skinning)&&g.setValue(E,"viewMatrix",a.matrixWorldInverse)}if(c.skinning&&(g.setOptional(E,d,"bindMatrix"),g.setOptional(E,d,"bindMatrixInverse"),a=d.skeleton))if(h=a.bones,xa.floatVertexTextures){if(void 0===a.boneTexture){h=Math.sqrt(4*h.length);h=S.ceilPowerOfTwo(h);h=Math.max(h,4);var q=new Float32Array(h*h*4);q.set(a.boneMatrices);var v=new jb(q,h,h,1023,1015);v.needsUpdate=!0;a.boneMatrices=q;a.boneTexture=v;a.boneTextureSize=h}g.setValue(E,"boneTexture",a.boneTexture); +g.setValue(E,"boneTextureSize",a.boneTextureSize)}else g.setOptional(E,a,"boneMatrices");k&&(g.setValue(E,"toneMappingExposure",Y.toneMappingExposure),g.setValue(E,"toneMappingWhitePoint",Y.toneMappingWhitePoint),c.lights&&(k=m,r.ambientLightColor.needsUpdate=k,r.directionalLights.needsUpdate=k,r.pointLights.needsUpdate=k,r.spotLights.needsUpdate=k,r.rectAreaLights.needsUpdate=k,r.hemisphereLights.needsUpdate=k),b&&c.fog&&(r.fogColor.value=b.color,b.isFog?(r.fogNear.value=b.near,r.fogFar.value=b.far): +b.isFogExp2&&(r.fogDensity.value=b.density)),c.isMeshBasicMaterial?l(r,c):c.isMeshLambertMaterial?(l(r,c),c.emissiveMap&&(r.emissiveMap.value=c.emissiveMap)):c.isMeshPhongMaterial?(l(r,c),c.isMeshToonMaterial?(t(r,c),c.gradientMap&&(r.gradientMap.value=c.gradientMap)):t(r,c)):c.isMeshStandardMaterial?(l(r,c),c.isMeshPhysicalMaterial?(u(r,c),r.reflectivity.value=c.reflectivity,r.clearCoat.value=c.clearCoat,r.clearCoatRoughness.value=c.clearCoatRoughness):u(r,c)):c.isMeshMatcapMaterial?(l(r,c),c.matcap&& +(r.matcap.value=c.matcap),c.bumpMap&&(r.bumpMap.value=c.bumpMap,r.bumpScale.value=c.bumpScale,1===c.side&&(r.bumpScale.value*=-1)),c.normalMap&&(r.normalMap.value=c.normalMap,r.normalScale.value.copy(c.normalScale),1===c.side&&r.normalScale.value.negate()),c.displacementMap&&(r.displacementMap.value=c.displacementMap,r.displacementScale.value=c.displacementScale,r.displacementBias.value=c.displacementBias)):c.isMeshDepthMaterial?(l(r,c),c.displacementMap&&(r.displacementMap.value=c.displacementMap, +r.displacementScale.value=c.displacementScale,r.displacementBias.value=c.displacementBias)):c.isMeshDistanceMaterial?(l(r,c),c.displacementMap&&(r.displacementMap.value=c.displacementMap,r.displacementScale.value=c.displacementScale,r.displacementBias.value=c.displacementBias),r.referencePosition.value.copy(c.referencePosition),r.nearDistance.value=c.nearDistance,r.farDistance.value=c.farDistance):c.isMeshNormalMaterial?(l(r,c),c.bumpMap&&(r.bumpMap.value=c.bumpMap,r.bumpScale.value=c.bumpScale,1=== +c.side&&(r.bumpScale.value*=-1)),c.normalMap&&(r.normalMap.value=c.normalMap,r.normalScale.value.copy(c.normalScale),1===c.side&&r.normalScale.value.negate()),c.displacementMap&&(r.displacementMap.value=c.displacementMap,r.displacementScale.value=c.displacementScale,r.displacementBias.value=c.displacementBias)):c.isLineBasicMaterial?(r.diffuse.value=c.color,r.opacity.value=c.opacity,c.isLineDashedMaterial&&(r.dashSize.value=c.dashSize,r.totalSize.value=c.dashSize+c.gapSize,r.scale.value=c.scale)): +c.isPointsMaterial?(r.diffuse.value=c.color,r.opacity.value=c.opacity,r.size.value=c.size*U,r.scale.value=.5*O,r.map.value=c.map,null!==c.map&&(!0===c.map.matrixAutoUpdate&&c.map.updateMatrix(),r.uvTransform.value.copy(c.map.matrix))):c.isSpriteMaterial?(r.diffuse.value=c.color,r.opacity.value=c.opacity,r.rotation.value=c.rotation,r.map.value=c.map,null!==c.map&&(!0===c.map.matrixAutoUpdate&&c.map.updateMatrix(),r.uvTransform.value.copy(c.map.matrix))):c.isShadowMaterial&&(r.color.value=c.color,r.opacity.value= +c.opacity),void 0!==r.ltc_1&&(r.ltc_1.value=H.LTC_1),void 0!==r.ltc_2&&(r.ltc_2.value=H.LTC_2),bb.upload(E,e.uniformsList,r,Y));c.isShaderMaterial&&!0===c.uniformsNeedUpdate&&(bb.upload(E,e.uniformsList,r,Y),c.uniformsNeedUpdate=!1);c.isSpriteMaterial&&g.setValue(E,"center",d.center);g.setValue(E,"modelViewMatrix",d.modelViewMatrix);g.setValue(E,"normalMatrix",d.normalMatrix);g.setValue(E,"modelMatrix",d.matrixWorld);return f}function l(a,b){a.opacity.value=b.opacity;b.color&&(a.diffuse.value=b.color); +b.emissive&&a.emissive.value.copy(b.emissive).multiplyScalar(b.emissiveIntensity);b.map&&(a.map.value=b.map);b.alphaMap&&(a.alphaMap.value=b.alphaMap);b.specularMap&&(a.specularMap.value=b.specularMap);b.envMap&&(a.envMap.value=b.envMap,a.flipEnvMap.value=b.envMap&&b.envMap.isCubeTexture?-1:1,a.reflectivity.value=b.reflectivity,a.refractionRatio.value=b.refractionRatio,a.maxMipLevel.value=Da.get(b.envMap).__maxMipLevel);b.lightMap&&(a.lightMap.value=b.lightMap,a.lightMapIntensity.value=b.lightMapIntensity); +b.aoMap&&(a.aoMap.value=b.aoMap,a.aoMapIntensity.value=b.aoMapIntensity);if(b.map)var c=b.map;else b.specularMap?c=b.specularMap:b.displacementMap?c=b.displacementMap:b.normalMap?c=b.normalMap:b.bumpMap?c=b.bumpMap:b.roughnessMap?c=b.roughnessMap:b.metalnessMap?c=b.metalnessMap:b.alphaMap?c=b.alphaMap:b.emissiveMap&&(c=b.emissiveMap);void 0!==c&&(c.isWebGLRenderTarget&&(c=c.texture),!0===c.matrixAutoUpdate&&c.updateMatrix(),a.uvTransform.value.copy(c.matrix))}function t(a,b){a.specular.value=b.specular; +a.shininess.value=Math.max(b.shininess,1E-4);b.emissiveMap&&(a.emissiveMap.value=b.emissiveMap);b.bumpMap&&(a.bumpMap.value=b.bumpMap,a.bumpScale.value=b.bumpScale,1===b.side&&(a.bumpScale.value*=-1));b.normalMap&&(a.normalMap.value=b.normalMap,a.normalScale.value.copy(b.normalScale),1===b.side&&a.normalScale.value.negate());b.displacementMap&&(a.displacementMap.value=b.displacementMap,a.displacementScale.value=b.displacementScale,a.displacementBias.value=b.displacementBias)}function u(a,b){a.roughness.value= +b.roughness;a.metalness.value=b.metalness;b.roughnessMap&&(a.roughnessMap.value=b.roughnessMap);b.metalnessMap&&(a.metalnessMap.value=b.metalnessMap);b.emissiveMap&&(a.emissiveMap.value=b.emissiveMap);b.bumpMap&&(a.bumpMap.value=b.bumpMap,a.bumpScale.value=b.bumpScale,1===b.side&&(a.bumpScale.value*=-1));b.normalMap&&(a.normalMap.value=b.normalMap,a.normalScale.value.copy(b.normalScale),1===b.side&&a.normalScale.value.negate());b.displacementMap&&(a.displacementMap.value=b.displacementMap,a.displacementScale.value= +b.displacementScale,a.displacementBias.value=b.displacementBias);b.envMap&&(a.envMapIntensity.value=b.envMapIntensity)}console.log("THREE.WebGLRenderer","97");a=a||{};var y=void 0!==a.canvas?a.canvas:document.createElementNS("http://www.w3.org/1999/xhtml","canvas"),x=void 0!==a.context?a.context:null,w=void 0!==a.alpha?a.alpha:!1,D=void 0!==a.depth?a.depth:!0,J=void 0!==a.stencil?a.stencil:!0,R=void 0!==a.antialias?a.antialias:!1,A=void 0!==a.premultipliedAlpha?a.premultipliedAlpha:!0,B=void 0!== +a.preserveDrawingBuffer?a.preserveDrawingBuffer:!1,z=void 0!==a.powerPreference?a.powerPreference:"default",C=null,F=null;this.domElement=y;this.context=null;this.sortObjects=this.autoClearStencil=this.autoClearDepth=this.autoClearColor=this.autoClear=!0;this.clippingPlanes=[];this.localClippingEnabled=!1;this.gammaFactor=2;this.physicallyCorrectLights=this.gammaOutput=this.gammaInput=!1;this.toneMappingWhitePoint=this.toneMappingExposure=this.toneMapping=1;this.maxMorphTargets=8;this.maxMorphNormals= +4;var Y=this,G=!1,N=null,M=null,L=null,I=-1;var K=b=null;var sd=!1;var T=null,Q=null,W=new Z,Bc=new Z,ea=null,ca=0,V=y.width,O=y.height,U=1,fa=new Z(0,0,V,O),ja=new Z(0,0,V,O),sa=!1,qa=new rd,aa=new Pf,ud=!1,ae=!1,Ac=new P,eb=new p;try{w={alpha:w,depth:D,stencil:J,antialias:R,premultipliedAlpha:A,preserveDrawingBuffer:B,powerPreference:z};y.addEventListener("webglcontextlost",d,!1);y.addEventListener("webglcontextrestored",e,!1);var E=x||y.getContext("webgl",w)||y.getContext("experimental-webgl", +w);if(null===E){if(null!==y.getContext("webgl"))throw Error("Error creating WebGL context with your selected attributes.");throw Error("Error creating WebGL context.");}void 0===E.getShaderPrecisionFormat&&(E.getShaderPrecisionFormat=function(){return{rangeMin:1,rangeMax:1,precision:1}})}catch(Pg){console.error("THREE.WebGLRenderer: "+Pg.message)}var la,xa,ba,da,Da,ha,ra,ta,oa,na,ua,pa,ma,ya,za,Ba,ia;c();var ka=null;"undefined"!==typeof navigator&&(ka="xr"in navigator?new Og(Y):new cf(Y));this.vr= +ka;var Ca=new af(Y,oa,xa.maxTextureSize);this.shadowMap=Ca;this.getContext=function(){return E};this.getContextAttributes=function(){return E.getContextAttributes()};this.forceContextLoss=function(){var a=la.get("WEBGL_lose_context");a&&a.loseContext()};this.forceContextRestore=function(){var a=la.get("WEBGL_lose_context");a&&a.restoreContext()};this.getPixelRatio=function(){return U};this.setPixelRatio=function(a){void 0!==a&&(U=a,this.setSize(V,O,!1))};this.getSize=function(){return{width:V,height:O}}; +this.setSize=function(a,b,c){ka.isPresenting()?console.warn("THREE.WebGLRenderer: Can't change size while VR device is presenting."):(V=a,O=b,y.width=a*U,y.height=b*U,!1!==c&&(y.style.width=a+"px",y.style.height=b+"px"),this.setViewport(0,0,a,b))};this.getDrawingBufferSize=function(){return{width:V*U,height:O*U}};this.setDrawingBufferSize=function(a,b,c){V=a;O=b;U=c;y.width=a*c;y.height=b*c;this.setViewport(0,0,a,b)};this.getCurrentViewport=function(){return W};this.setViewport=function(a,b,c,d){fa.set(a, +O-b-d,c,d);ba.viewport(W.copy(fa).multiplyScalar(U))};this.setScissor=function(a,b,c,d){ja.set(a,O-b-d,c,d);ba.scissor(Bc.copy(ja).multiplyScalar(U))};this.setScissorTest=function(a){ba.setScissorTest(sa=a)};this.getClearColor=function(){return ma.getClearColor()};this.setClearColor=function(){ma.setClearColor.apply(ma,arguments)};this.getClearAlpha=function(){return ma.getClearAlpha()};this.setClearAlpha=function(){ma.setClearAlpha.apply(ma,arguments)};this.clear=function(a,b,c){var d=0;if(void 0=== +a||a)d|=E.COLOR_BUFFER_BIT;if(void 0===b||b)d|=E.DEPTH_BUFFER_BIT;if(void 0===c||c)d|=E.STENCIL_BUFFER_BIT;E.clear(d)};this.clearColor=function(){this.clear(!0,!1,!1)};this.clearDepth=function(){this.clear(!1,!0,!1)};this.clearStencil=function(){this.clear(!1,!1,!0)};this.dispose=function(){y.removeEventListener("webglcontextlost",d,!1);y.removeEventListener("webglcontextrestored",e,!1);ua.dispose();pa.dispose();Da.dispose();oa.dispose();ka.dispose();wa.stop()};this.renderBufferImmediate=function(a, +b){ba.initAttributes();var c=Da.get(a);a.hasPositions&&!c.position&&(c.position=E.createBuffer());a.hasNormals&&!c.normal&&(c.normal=E.createBuffer());a.hasUvs&&!c.uv&&(c.uv=E.createBuffer());a.hasColors&&!c.color&&(c.color=E.createBuffer());b=b.getAttributes();a.hasPositions&&(E.bindBuffer(E.ARRAY_BUFFER,c.position),E.bufferData(E.ARRAY_BUFFER,a.positionArray,E.DYNAMIC_DRAW),ba.enableAttribute(b.position),E.vertexAttribPointer(b.position,3,E.FLOAT,!1,0,0));a.hasNormals&&(E.bindBuffer(E.ARRAY_BUFFER, +c.normal),E.bufferData(E.ARRAY_BUFFER,a.normalArray,E.DYNAMIC_DRAW),ba.enableAttribute(b.normal),E.vertexAttribPointer(b.normal,3,E.FLOAT,!1,0,0));a.hasUvs&&(E.bindBuffer(E.ARRAY_BUFFER,c.uv),E.bufferData(E.ARRAY_BUFFER,a.uvArray,E.DYNAMIC_DRAW),ba.enableAttribute(b.uv),E.vertexAttribPointer(b.uv,2,E.FLOAT,!1,0,0));a.hasColors&&(E.bindBuffer(E.ARRAY_BUFFER,c.color),E.bufferData(E.ARRAY_BUFFER,a.colorArray,E.DYNAMIC_DRAW),ba.enableAttribute(b.color),E.vertexAttribPointer(b.color,3,E.FLOAT,!1,0,0)); +ba.disableUnusedAttributes();E.drawArrays(E.TRIANGLES,0,a.count);a.count=0};this.renderBufferDirect=function(a,c,d,e,f,g){var h=f.isMesh&&0>f.normalMatrix.determinant();ba.setMaterial(e,h);var k=q(a,c,e,f),m=!1;if(b!==d.id||K!==k.id||sd!==(!0===e.wireframe))b=d.id,K=k.id,sd=!0===e.wireframe,m=!0;f.morphTargetInfluences&&(ya.update(f,d,e,k),m=!0);h=d.index;var r=d.attributes.position;c=1;!0===e.wireframe&&(h=ta.getWireframeAttribute(d),c=2);a=za;if(null!==h){var n=ra.get(h);a=Ba;a.setIndex(n)}if(m){if(d&& +d.isInstancedBufferGeometry&!xa.isWebGL2&&null===la.get("ANGLE_instanced_arrays"))console.error("THREE.WebGLRenderer.setupVertexAttributes: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.");else{ba.initAttributes();m=d.attributes;k=k.getAttributes();var l=e.defaultAttributeValues;for(B in k){var v=k[B];if(0<=v){var t=m[B];if(void 0!==t){var u=t.normalized,p=t.itemSize,w=ra.get(t);if(void 0!==w){var y=w.buffer,x=w.type;w=w.bytesPerElement;if(t.isInterleavedBufferAttribute){var J= +t.data,D=J.stride;t=t.offset;J&&J.isInstancedInterleavedBuffer?(ba.enableAttributeAndDivisor(v,J.meshPerAttribute),void 0===d.maxInstancedCount&&(d.maxInstancedCount=J.meshPerAttribute*J.count)):ba.enableAttribute(v);E.bindBuffer(E.ARRAY_BUFFER,y);E.vertexAttribPointer(v,p,x,u,D*w,t*w)}else t.isInstancedBufferAttribute?(ba.enableAttributeAndDivisor(v,t.meshPerAttribute),void 0===d.maxInstancedCount&&(d.maxInstancedCount=t.meshPerAttribute*t.count)):ba.enableAttribute(v),E.bindBuffer(E.ARRAY_BUFFER, +y),E.vertexAttribPointer(v,p,x,u,0,0)}}else if(void 0!==l&&(u=l[B],void 0!==u))switch(u.length){case 2:E.vertexAttrib2fv(v,u);break;case 3:E.vertexAttrib3fv(v,u);break;case 4:E.vertexAttrib4fv(v,u);break;default:E.vertexAttrib1fv(v,u)}}}ba.disableUnusedAttributes()}null!==h&&E.bindBuffer(E.ELEMENT_ARRAY_BUFFER,n.buffer)}n=Infinity;null!==h?n=h.count:void 0!==r&&(n=r.count);h=d.drawRange.start*c;r=null!==g?g.start*c:0;var B=Math.max(h,r);g=Math.max(0,Math.min(n,h+d.drawRange.count*c,r+(null!==g?g.count* +c:Infinity))-1-B+1);if(0!==g){if(f.isMesh)if(!0===e.wireframe)ba.setLineWidth(e.wireframeLinewidth*(null===M?U:1)),a.setMode(E.LINES);else switch(f.drawMode){case 0:a.setMode(E.TRIANGLES);break;case 1:a.setMode(E.TRIANGLE_STRIP);break;case 2:a.setMode(E.TRIANGLE_FAN)}else f.isLine?(e=e.linewidth,void 0===e&&(e=1),ba.setLineWidth(e*(null===M?U:1)),f.isLineSegments?a.setMode(E.LINES):f.isLineLoop?a.setMode(E.LINE_LOOP):a.setMode(E.LINE_STRIP)):f.isPoints?a.setMode(E.POINTS):f.isSprite&&a.setMode(E.TRIANGLES); +d&&d.isInstancedBufferGeometry?0<d.maxInstancedCount&&a.renderInstances(d,B,g):a.render(B,g)}};this.compile=function(a,b){F=pa.get(a,b);F.init();a.traverse(function(a){a.isLight&&(F.pushLight(a),a.castShadow&&F.pushShadow(a))});F.setupLights(b);a.traverse(function(b){if(b.material)if(Array.isArray(b.material))for(var c=0;c<b.material.length;c++)n(b.material[c],a.fog,b);else n(b.material,a.fog,b)})};var Aa=null,wa=new Wd;wa.setAnimationLoop(function(a){ka.isPresenting()||Aa&&Aa(a)});"undefined"!== +typeof window&&wa.setContext(window);this.setAnimationLoop=function(a){Aa=a;ka.setAnimationLoop(a);wa.start()};this.render=function(a,c,d,e){if(!c||!c.isCamera)console.error("THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.");else if(!G){K=b=null;sd=!1;I=-1;T=null;!0===a.autoUpdate&&a.updateMatrixWorld();null===c.parent&&c.updateMatrixWorld();ka.enabled&&(c=ka.getCamera(c));F=pa.get(a,c);F.init();a.onBeforeRender(Y,a,c,d);Ac.multiplyMatrices(c.projectionMatrix,c.matrixWorldInverse); +qa.setFromMatrix(Ac);ae=this.localClippingEnabled;ud=aa.init(this.clippingPlanes,ae,c);C=ua.get(a,c);C.init();k(a,c,Y.sortObjects);!0===Y.sortObjects&&C.sort();ud&&aa.beginShadows();Ca.render(F.state.shadowsArray,a,c);F.setupLights(c);ud&&aa.endShadows();this.info.autoReset&&this.info.reset();void 0===d&&(d=null);this.setRenderTarget(d);ma.render(C,a,c,e);e=C.opaque;var f=C.transparent;if(a.overrideMaterial){var g=a.overrideMaterial;e.length&&m(e,a,c,g);f.length&&m(f,a,c,g)}else e.length&&m(e,a,c), +f.length&&m(f,a,c);d&&ha.updateRenderTargetMipmap(d);ba.buffers.depth.setTest(!0);ba.buffers.depth.setMask(!0);ba.buffers.color.setMask(!0);ba.setPolygonOffset(!1);a.onAfterRender(Y,a,c);ka.enabled&&ka.submitFrame();F=C=null}};this.allocTextureUnit=function(){var a=ca;a>=xa.maxTextures&&console.warn("THREE.WebGLRenderer: Trying to use "+a+" texture units while this GPU supports only "+xa.maxTextures);ca+=1;return a};this.setTexture2D=function(){var a=!1;return function(b,c){b&&b.isWebGLRenderTarget&& +(a||(console.warn("THREE.WebGLRenderer.setTexture2D: don't use render targets as textures. Use their .texture property instead."),a=!0),b=b.texture);ha.setTexture2D(b,c)}}();this.setTexture3D=function(){return function(a,b){ha.setTexture3D(a,b)}}();this.setTexture=function(){var a=!1;return function(b,c){a||(console.warn("THREE.WebGLRenderer: .setTexture is deprecated, use setTexture2D instead."),a=!0);ha.setTexture2D(b,c)}}();this.setTextureCube=function(){var a=!1;return function(b,c){b&&b.isWebGLRenderTargetCube&& +(a||(console.warn("THREE.WebGLRenderer.setTextureCube: don't use cube render targets as textures. Use their .texture property instead."),a=!0),b=b.texture);b&&b.isCubeTexture||Array.isArray(b.image)&&6===b.image.length?ha.setTextureCube(b,c):ha.setTextureCubeDynamic(b,c)}}();this.setFramebuffer=function(a){N=a};this.getRenderTarget=function(){return M};this.setRenderTarget=function(a){(M=a)&&void 0===Da.get(a).__webglFramebuffer&&ha.setupRenderTarget(a);var b=N,c=!1;a?(b=Da.get(a).__webglFramebuffer, +a.isWebGLRenderTargetCube&&(b=b[a.activeCubeFace],c=!0),W.copy(a.viewport),Bc.copy(a.scissor),ea=a.scissorTest):(W.copy(fa).multiplyScalar(U),Bc.copy(ja).multiplyScalar(U),ea=sa);L!==b&&(E.bindFramebuffer(E.FRAMEBUFFER,b),L=b);ba.viewport(W);ba.scissor(Bc);ba.setScissorTest(ea);c&&(c=Da.get(a.texture),E.framebufferTexture2D(E.FRAMEBUFFER,E.COLOR_ATTACHMENT0,E.TEXTURE_CUBE_MAP_POSITIVE_X+a.activeCubeFace,c.__webglTexture,a.activeMipMapLevel))};this.readRenderTargetPixels=function(a,b,c,d,e,f){if(a&& +a.isWebGLRenderTarget){var g=Da.get(a).__webglFramebuffer;if(g){var h=!1;g!==L&&(E.bindFramebuffer(E.FRAMEBUFFER,g),h=!0);try{var k=a.texture,m=k.format,r=k.type;1023!==m&&ia.convert(m)!==E.getParameter(E.IMPLEMENTATION_COLOR_READ_FORMAT)?console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format."):1009===r||ia.convert(r)===E.getParameter(E.IMPLEMENTATION_COLOR_READ_TYPE)||1015===r&&(xa.isWebGL2||la.get("OES_texture_float")||la.get("WEBGL_color_buffer_float"))|| +1016===r&&(xa.isWebGL2?la.get("EXT_color_buffer_float"):la.get("EXT_color_buffer_half_float"))?E.checkFramebufferStatus(E.FRAMEBUFFER)===E.FRAMEBUFFER_COMPLETE?0<=b&&b<=a.width-d&&0<=c&&c<=a.height-e&&E.readPixels(b,c,d,e,ia.convert(m),ia.convert(r),f):console.error("THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete."):console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.")}finally{h&& +E.bindFramebuffer(E.FRAMEBUFFER,L)}}}else console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.")};this.copyFramebufferToTexture=function(a,b,c){var d=b.image.width,e=b.image.height,f=ia.convert(b.format);this.setTexture2D(b,0);E.copyTexImage2D(E.TEXTURE_2D,c||0,f,a.x,a.y,d,e,0)};this.copyTextureToTexture=function(a,b,c,d){var e=b.image.width,f=b.image.height,g=ia.convert(c.format),h=ia.convert(c.type);this.setTexture2D(c,0);b.isDataTexture?E.texSubImage2D(E.TEXTURE_2D, +d||0,a.x,a.y,e,f,g,h,b.image.data):E.texSubImage2D(E.TEXTURE_2D,d||0,a.x,a.y,g,h,b.image)}}function Pb(a,b){this.name="";this.color=new G(a);this.density=void 0!==b?b:2.5E-4}function Qb(a,b,c){this.name="";this.color=new G(a);this.near=void 0!==b?b:1;this.far=void 0!==c?c:1E3}function vd(){C.call(this);this.type="Scene";this.overrideMaterial=this.fog=this.background=null;this.autoUpdate=!0}function qb(a,b){this.array=a;this.stride=b;this.count=void 0!==a?a.length/b:0;this.dynamic=!1;this.updateRange= +{offset:0,count:-1};this.version=0}function Dc(a,b,c,d){this.data=a;this.itemSize=b;this.offset=c;this.normalized=!0===d}function fb(a){L.call(this);this.type="SpriteMaterial";this.color=new G(16777215);this.map=null;this.rotation=0;this.sizeAttenuation=!0;this.lights=!1;this.transparent=!0;this.setValues(a)}function Ec(a){C.call(this);this.type="Sprite";if(void 0===Rb){Rb=new F;var b=new Float32Array([-.5,-.5,0,0,0,.5,-.5,0,1,0,.5,.5,0,1,1,-.5,.5,0,0,1]);b=new qb(b,5);Rb.setIndex([0,1,2,0,2,3]); +Rb.addAttribute("position",new Dc(b,3,0,!1));Rb.addAttribute("uv",new Dc(b,2,3,!1))}this.geometry=Rb;this.material=void 0!==a?a:new fb;this.center=new A(.5,.5)}function Fc(){C.call(this);this.type="LOD";Object.defineProperties(this,{levels:{enumerable:!0,value:[]}})}function Gc(a,b){a=a||[];this.bones=a.slice(0);this.boneMatrices=new Float32Array(16*this.bones.length);if(void 0===b)this.calculateInverses();else if(this.bones.length===b.length)this.boneInverses=b.slice(0);else for(console.warn("THREE.Skeleton boneInverses is the wrong length."), +this.boneInverses=[],a=0,b=this.bones.length;a<b;a++)this.boneInverses.push(new P)}function wd(){C.call(this);this.type="Bone"}function xd(a,b){ua.call(this,a,b);this.type="SkinnedMesh";this.bindMode="attached";this.bindMatrix=new P;this.bindMatrixInverse=new P;a=this.initBones();a=new Gc(a);this.bind(a,this.matrixWorld);this.normalizeSkinWeights()}function T(a){L.call(this);this.type="LineBasicMaterial";this.color=new G(16777215);this.linewidth=1;this.linejoin=this.linecap="round";this.lights=!1; +this.setValues(a)}function pa(a,b,c){1===c&&console.error("THREE.Line: parameter THREE.LinePieces no longer supported. Use THREE.LineSegments instead.");C.call(this);this.type="Line";this.geometry=void 0!==a?a:new F;this.material=void 0!==b?b:new T({color:16777215*Math.random()})}function W(a,b){pa.call(this,a,b);this.type="LineSegments"}function yd(a,b){pa.call(this,a,b);this.type="LineLoop"}function Ga(a){L.call(this);this.type="PointsMaterial";this.color=new G(16777215);this.map=null;this.size= +1;this.sizeAttenuation=!0;this.lights=this.morphTargets=!1;this.setValues(a)}function Sb(a,b){C.call(this);this.type="Points";this.geometry=void 0!==a?a:new F;this.material=void 0!==b?b:new Ga({color:16777215*Math.random()})}function ce(a,b,c,d,e,f,g,h,k){Q.call(this,a,b,c,d,e,f,g,h,k);this.generateMipmaps=!1}function Tb(a,b,c,d,e,f,g,h,k,m,r,n){Q.call(this,null,f,g,h,k,m,d,e,r,n);this.image={width:b,height:c};this.mipmaps=a;this.generateMipmaps=this.flipY=!1}function Hc(a,b,c,d,e,f,g,h,k){Q.call(this, +a,b,c,d,e,f,g,h,k);this.needsUpdate=!0}function Ic(a,b,c,d,e,f,g,h,k,m){m=void 0!==m?m:1026;if(1026!==m&&1027!==m)throw Error("DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat");void 0===c&&1026===m&&(c=1012);void 0===c&&1027===m&&(c=1020);Q.call(this,null,d,e,f,g,h,m,c,k);this.image={width:a,height:b};this.magFilter=void 0!==g?g:1003;this.minFilter=void 0!==h?h:1003;this.generateMipmaps=this.flipY=!1}function Ub(a){F.call(this);this.type="WireframeGeometry";var b= +[],c,d,e,f=[0,0],g={},h=["a","b","c"];if(a&&a.isGeometry){var k=a.faces;var m=0;for(d=k.length;m<d;m++){var r=k[m];for(c=0;3>c;c++){var n=r[h[c]];var q=r[h[(c+1)%3]];f[0]=Math.min(n,q);f[1]=Math.max(n,q);n=f[0]+","+f[1];void 0===g[n]&&(g[n]={index1:f[0],index2:f[1]})}}for(n in g)m=g[n],h=a.vertices[m.index1],b.push(h.x,h.y,h.z),h=a.vertices[m.index2],b.push(h.x,h.y,h.z)}else if(a&&a.isBufferGeometry)if(h=new p,null!==a.index){k=a.attributes.position;r=a.index;var l=a.groups;0===l.length&&(l=[{start:0, +count:r.count,materialIndex:0}]);a=0;for(e=l.length;a<e;++a)for(m=l[a],c=m.start,d=m.count,m=c,d=c+d;m<d;m+=3)for(c=0;3>c;c++)n=r.getX(m+c),q=r.getX(m+(c+1)%3),f[0]=Math.min(n,q),f[1]=Math.max(n,q),n=f[0]+","+f[1],void 0===g[n]&&(g[n]={index1:f[0],index2:f[1]});for(n in g)m=g[n],h.fromBufferAttribute(k,m.index1),b.push(h.x,h.y,h.z),h.fromBufferAttribute(k,m.index2),b.push(h.x,h.y,h.z)}else for(k=a.attributes.position,m=0,d=k.count/3;m<d;m++)for(c=0;3>c;c++)g=3*m+c,h.fromBufferAttribute(k,g),b.push(h.x, +h.y,h.z),g=3*m+(c+1)%3,h.fromBufferAttribute(k,g),b.push(h.x,h.y,h.z);this.addAttribute("position",new z(b,3))}function Jc(a,b,c){M.call(this);this.type="ParametricGeometry";this.parameters={func:a,slices:b,stacks:c};this.fromBufferGeometry(new Vb(a,b,c));this.mergeVertices()}function Vb(a,b,c){F.call(this);this.type="ParametricBufferGeometry";this.parameters={func:a,slices:b,stacks:c};var d=[],e=[],f=[],g=[],h=new p,k=new p,m=new p,r=new p,n=new p,q,l;3>a.length&&console.error("THREE.ParametricGeometry: Function must now modify a Vector3 as third parameter."); +var t=b+1;for(q=0;q<=c;q++){var u=q/c;for(l=0;l<=b;l++){var y=l/b;a(y,u,k);e.push(k.x,k.y,k.z);0<=y-1E-5?(a(y-1E-5,u,m),r.subVectors(k,m)):(a(y+1E-5,u,m),r.subVectors(m,k));0<=u-1E-5?(a(y,u-1E-5,m),n.subVectors(k,m)):(a(y,u+1E-5,m),n.subVectors(m,k));h.crossVectors(r,n).normalize();f.push(h.x,h.y,h.z);g.push(y,u)}}for(q=0;q<c;q++)for(l=0;l<b;l++)a=q*t+l+1,h=(q+1)*t+l+1,k=(q+1)*t+l,d.push(q*t+l,a,k),d.push(a,h,k);this.setIndex(d);this.addAttribute("position",new z(e,3));this.addAttribute("normal", +new z(f,3));this.addAttribute("uv",new z(g,2))}function Kc(a,b,c,d){M.call(this);this.type="PolyhedronGeometry";this.parameters={vertices:a,indices:b,radius:c,detail:d};this.fromBufferGeometry(new ma(a,b,c,d));this.mergeVertices()}function ma(a,b,c,d){function e(a){h.push(a.x,a.y,a.z)}function f(b,c){b*=3;c.x=a[b+0];c.y=a[b+1];c.z=a[b+2]}function g(a,b,c,d){0>d&&1===a.x&&(k[b]=a.x-1);0===c.x&&0===c.z&&(k[b]=d/2/Math.PI+.5)}F.call(this);this.type="PolyhedronBufferGeometry";this.parameters={vertices:a, +indices:b,radius:c,detail:d};c=c||1;d=d||0;var h=[],k=[];(function(a){for(var c=new p,d=new p,g=new p,h=0;h<b.length;h+=3){f(b[h+0],c);f(b[h+1],d);f(b[h+2],g);var k,m,l=c,x=d,w=g,D=Math.pow(2,a),J=[];for(m=0;m<=D;m++){J[m]=[];var R=l.clone().lerp(w,m/D),A=x.clone().lerp(w,m/D),B=D-m;for(k=0;k<=B;k++)J[m][k]=0===k&&m===D?R:R.clone().lerp(A,k/B)}for(m=0;m<D;m++)for(k=0;k<2*(D-m)-1;k++)l=Math.floor(k/2),0===k%2?(e(J[m][l+1]),e(J[m+1][l]),e(J[m][l])):(e(J[m][l+1]),e(J[m+1][l+1]),e(J[m+1][l]))}})(d);(function(a){for(var b= +new p,c=0;c<h.length;c+=3)b.x=h[c+0],b.y=h[c+1],b.z=h[c+2],b.normalize().multiplyScalar(a),h[c+0]=b.x,h[c+1]=b.y,h[c+2]=b.z})(c);(function(){for(var a=new p,b=0;b<h.length;b+=3)a.x=h[b+0],a.y=h[b+1],a.z=h[b+2],k.push(Math.atan2(a.z,-a.x)/2/Math.PI+.5,1-(Math.atan2(-a.y,Math.sqrt(a.x*a.x+a.z*a.z))/Math.PI+.5));a=new p;b=new p;for(var c=new p,d=new p,e=new A,f=new A,l=new A,y=0,x=0;y<h.length;y+=9,x+=6){a.set(h[y+0],h[y+1],h[y+2]);b.set(h[y+3],h[y+4],h[y+5]);c.set(h[y+6],h[y+7],h[y+8]);e.set(k[x+0], +k[x+1]);f.set(k[x+2],k[x+3]);l.set(k[x+4],k[x+5]);d.copy(a).add(b).add(c).divideScalar(3);var w=Math.atan2(d.z,-d.x);g(e,x+0,a,w);g(f,x+2,b,w);g(l,x+4,c,w)}for(a=0;a<k.length;a+=6)b=k[a+0],c=k[a+2],d=k[a+4],e=Math.min(b,c,d),.9<Math.max(b,c,d)&&.1>e&&(.2>b&&(k[a+0]+=1),.2>c&&(k[a+2]+=1),.2>d&&(k[a+4]+=1))})();this.addAttribute("position",new z(h,3));this.addAttribute("normal",new z(h.slice(),3));this.addAttribute("uv",new z(k,2));0===d?this.computeVertexNormals():this.normalizeNormals()}function Lc(a, +b){M.call(this);this.type="TetrahedronGeometry";this.parameters={radius:a,detail:b};this.fromBufferGeometry(new Wb(a,b));this.mergeVertices()}function Wb(a,b){ma.call(this,[1,1,1,-1,-1,1,-1,1,-1,1,-1,-1],[2,1,0,0,3,2,1,3,0,2,3,1],a,b);this.type="TetrahedronBufferGeometry";this.parameters={radius:a,detail:b}}function Mc(a,b){M.call(this);this.type="OctahedronGeometry";this.parameters={radius:a,detail:b};this.fromBufferGeometry(new rb(a,b));this.mergeVertices()}function rb(a,b){ma.call(this,[1,0,0, +-1,0,0,0,1,0,0,-1,0,0,0,1,0,0,-1],[0,2,4,0,4,3,0,3,5,0,5,2,1,2,5,1,5,3,1,3,4,1,4,2],a,b);this.type="OctahedronBufferGeometry";this.parameters={radius:a,detail:b}}function Nc(a,b){M.call(this);this.type="IcosahedronGeometry";this.parameters={radius:a,detail:b};this.fromBufferGeometry(new Xb(a,b));this.mergeVertices()}function Xb(a,b){var c=(1+Math.sqrt(5))/2;ma.call(this,[-1,c,0,1,c,0,-1,-c,0,1,-c,0,0,-1,c,0,1,c,0,-1,-c,0,1,-c,c,0,-1,c,0,1,-c,0,-1,-c,0,1],[0,11,5,0,5,1,0,1,7,0,7,10,0,10,11,1,5,9,5, +11,4,11,10,2,10,7,6,7,1,8,3,9,4,3,4,2,3,2,6,3,6,8,3,8,9,4,9,5,2,4,11,6,2,10,8,6,7,9,8,1],a,b);this.type="IcosahedronBufferGeometry";this.parameters={radius:a,detail:b}}function Oc(a,b){M.call(this);this.type="DodecahedronGeometry";this.parameters={radius:a,detail:b};this.fromBufferGeometry(new Yb(a,b));this.mergeVertices()}function Yb(a,b){var c=(1+Math.sqrt(5))/2,d=1/c;ma.call(this,[-1,-1,-1,-1,-1,1,-1,1,-1,-1,1,1,1,-1,-1,1,-1,1,1,1,-1,1,1,1,0,-d,-c,0,-d,c,0,d,-c,0,d,c,-d,-c,0,-d,c,0,d,-c,0,d,c, +0,-c,0,-d,c,0,-d,-c,0,d,c,0,d],[3,11,7,3,7,15,3,15,13,7,19,17,7,17,6,7,6,15,17,4,8,17,8,10,17,10,6,8,0,16,8,16,2,8,2,10,0,12,1,0,1,18,0,18,16,6,10,2,6,2,13,6,13,15,2,16,18,2,18,3,2,3,13,18,1,9,18,9,11,18,11,3,4,14,12,4,12,0,4,0,8,11,9,5,11,5,19,11,19,7,19,5,14,19,14,4,19,4,17,1,12,14,1,14,5,1,5,9],a,b);this.type="DodecahedronBufferGeometry";this.parameters={radius:a,detail:b}}function Pc(a,b,c,d,e,f){M.call(this);this.type="TubeGeometry";this.parameters={path:a,tubularSegments:b,radius:c,radialSegments:d, +closed:e};void 0!==f&&console.warn("THREE.TubeGeometry: taper has been removed.");a=new Zb(a,b,c,d,e);this.tangents=a.tangents;this.normals=a.normals;this.binormals=a.binormals;this.fromBufferGeometry(a);this.mergeVertices()}function Zb(a,b,c,d,e){function f(e){r=a.getPointAt(e/b,r);var f=g.normals[e];e=g.binormals[e];for(q=0;q<=d;q++){var m=q/d*Math.PI*2,n=Math.sin(m);m=-Math.cos(m);k.x=m*f.x+n*e.x;k.y=m*f.y+n*e.y;k.z=m*f.z+n*e.z;k.normalize();t.push(k.x,k.y,k.z);h.x=r.x+c*k.x;h.y=r.y+c*k.y;h.z= +r.z+c*k.z;l.push(h.x,h.y,h.z)}}F.call(this);this.type="TubeBufferGeometry";this.parameters={path:a,tubularSegments:b,radius:c,radialSegments:d,closed:e};b=b||64;c=c||1;d=d||8;e=e||!1;var g=a.computeFrenetFrames(b,e);this.tangents=g.tangents;this.normals=g.normals;this.binormals=g.binormals;var h=new p,k=new p,m=new A,r=new p,n,q,l=[],t=[],u=[],y=[];for(n=0;n<b;n++)f(n);f(!1===e?b:0);for(n=0;n<=b;n++)for(q=0;q<=d;q++)m.x=n/b,m.y=q/d,u.push(m.x,m.y);(function(){for(q=1;q<=b;q++)for(n=1;n<=d;n++){var a= +(d+1)*q+(n-1),c=(d+1)*q+n,e=(d+1)*(q-1)+n;y.push((d+1)*(q-1)+(n-1),a,e);y.push(a,c,e)}})();this.setIndex(y);this.addAttribute("position",new z(l,3));this.addAttribute("normal",new z(t,3));this.addAttribute("uv",new z(u,2))}function Qc(a,b,c,d,e,f,g){M.call(this);this.type="TorusKnotGeometry";this.parameters={radius:a,tube:b,tubularSegments:c,radialSegments:d,p:e,q:f};void 0!==g&&console.warn("THREE.TorusKnotGeometry: heightScale has been deprecated. Use .scale( x, y, z ) instead.");this.fromBufferGeometry(new $b(a, +b,c,d,e,f));this.mergeVertices()}function $b(a,b,c,d,e,f){function g(a,b,c,d,e){var f=Math.sin(a);b=c/b*a;c=Math.cos(b);e.x=d*(2+c)*.5*Math.cos(a);e.y=d*(2+c)*f*.5;e.z=d*Math.sin(b)*.5}F.call(this);this.type="TorusKnotBufferGeometry";this.parameters={radius:a,tube:b,tubularSegments:c,radialSegments:d,p:e,q:f};a=a||1;b=b||.4;c=Math.floor(c)||64;d=Math.floor(d)||8;e=e||2;f=f||3;var h=[],k=[],m=[],r=[],n,q=new p,l=new p,t=new p,u=new p,y=new p,x=new p,w=new p;for(n=0;n<=c;++n){var D=n/c*e*Math.PI*2; +g(D,e,f,a,t);g(D+.01,e,f,a,u);x.subVectors(u,t);w.addVectors(u,t);y.crossVectors(x,w);w.crossVectors(y,x);y.normalize();w.normalize();for(D=0;D<=d;++D){var J=D/d*Math.PI*2,R=-b*Math.cos(J);J=b*Math.sin(J);q.x=t.x+(R*w.x+J*y.x);q.y=t.y+(R*w.y+J*y.y);q.z=t.z+(R*w.z+J*y.z);k.push(q.x,q.y,q.z);l.subVectors(q,t).normalize();m.push(l.x,l.y,l.z);r.push(n/c);r.push(D/d)}}for(D=1;D<=c;D++)for(n=1;n<=d;n++)a=(d+1)*D+(n-1),b=(d+1)*D+n,e=(d+1)*(D-1)+n,h.push((d+1)*(D-1)+(n-1),a,e),h.push(a,b,e);this.setIndex(h); +this.addAttribute("position",new z(k,3));this.addAttribute("normal",new z(m,3));this.addAttribute("uv",new z(r,2))}function Rc(a,b,c,d,e){M.call(this);this.type="TorusGeometry";this.parameters={radius:a,tube:b,radialSegments:c,tubularSegments:d,arc:e};this.fromBufferGeometry(new ac(a,b,c,d,e));this.mergeVertices()}function ac(a,b,c,d,e){F.call(this);this.type="TorusBufferGeometry";this.parameters={radius:a,tube:b,radialSegments:c,tubularSegments:d,arc:e};a=a||1;b=b||.4;c=Math.floor(c)||8;d=Math.floor(d)|| +6;e=e||2*Math.PI;var f=[],g=[],h=[],k=[],m=new p,r=new p,n=new p,q,l;for(q=0;q<=c;q++)for(l=0;l<=d;l++){var t=l/d*e,u=q/c*Math.PI*2;r.x=(a+b*Math.cos(u))*Math.cos(t);r.y=(a+b*Math.cos(u))*Math.sin(t);r.z=b*Math.sin(u);g.push(r.x,r.y,r.z);m.x=a*Math.cos(t);m.y=a*Math.sin(t);n.subVectors(r,m).normalize();h.push(n.x,n.y,n.z);k.push(l/d);k.push(q/c)}for(q=1;q<=c;q++)for(l=1;l<=d;l++)a=(d+1)*(q-1)+l-1,b=(d+1)*(q-1)+l,e=(d+1)*q+l,f.push((d+1)*q+l-1,a,e),f.push(a,b,e);this.setIndex(f);this.addAttribute("position", +new z(g,3));this.addAttribute("normal",new z(h,3));this.addAttribute("uv",new z(k,2))}function df(a,b,c,d,e){for(var f,g=0,h=b,k=c-d;h<c;h+=d)g+=(a[k]-a[h])*(a[h+1]+a[k+1]),k=h;if(e===0<g)for(e=b;e<c;e+=d)f=ef(e,a[e],a[e+1],f);else for(e=c-d;e>=b;e-=d)f=ef(e,a[e],a[e+1],f);f&&sb(f,f.next)&&(Sc(f),f=f.next);return f}function Tc(a,b){if(!a)return a;b||(b=a);do{var c=!1;if(a.steiner||!sb(a,a.next)&&0!==na(a.prev,a,a.next))a=a.next;else{Sc(a);a=b=a.prev;if(a===a.next)break;c=!0}}while(c||a!==b);return b} +function Uc(a,b,c,d,e,f,g){if(a){if(!g&&f){var h=a,k=h;do null===k.z&&(k.z=de(k.x,k.y,d,e,f)),k.prevZ=k.prev,k=k.nextZ=k.next;while(k!==h);k.prevZ.nextZ=null;k.prevZ=null;h=k;var m,r,n,l,v=1;do{k=h;var t=h=null;for(r=0;k;){r++;var u=k;for(m=n=0;m<v&&(n++,u=u.nextZ,u);m++);for(l=v;0<n||0<l&&u;)0!==n&&(0===l||!u||k.z<=u.z)?(m=k,k=k.nextZ,n--):(m=u,u=u.nextZ,l--),t?t.nextZ=m:h=m,m.prevZ=t,t=m;k=u}t.nextZ=null;v*=2}while(1<r)}for(h=a;a.prev!==a.next;){k=a.prev;u=a.next;if(f)a:{t=a;l=d;var p=e,x=f;r=t.prev; +n=t;v=t.next;if(0<=na(r,n,v))t=!1;else{var w=r.x>n.x?r.x>v.x?r.x:v.x:n.x>v.x?n.x:v.x,D=r.y>n.y?r.y>v.y?r.y:v.y:n.y>v.y?n.y:v.y;m=de(r.x<n.x?r.x<v.x?r.x:v.x:n.x<v.x?n.x:v.x,r.y<n.y?r.y<v.y?r.y:v.y:n.y<v.y?n.y:v.y,l,p,x);l=de(w,D,l,p,x);for(p=t.nextZ;p&&p.z<=l;){if(p!==t.prev&&p!==t.next&&zd(r.x,r.y,n.x,n.y,v.x,v.y,p.x,p.y)&&0<=na(p.prev,p,p.next)){t=!1;break a}p=p.nextZ}for(p=t.prevZ;p&&p.z>=m;){if(p!==t.prev&&p!==t.next&&zd(r.x,r.y,n.x,n.y,v.x,v.y,p.x,p.y)&&0<=na(p.prev,p,p.next)){t=!1;break a}p= +p.prevZ}t=!0}}else a:if(t=a,r=t.prev,n=t,v=t.next,0<=na(r,n,v))t=!1;else{for(m=t.next.next;m!==t.prev;){if(zd(r.x,r.y,n.x,n.y,v.x,v.y,m.x,m.y)&&0<=na(m.prev,m,m.next)){t=!1;break a}m=m.next}t=!0}if(t)b.push(k.i/c),b.push(a.i/c),b.push(u.i/c),Sc(a),h=a=u.next;else if(a=u,a===h){if(!g)Uc(Tc(a),b,c,d,e,f,1);else if(1===g){g=b;h=c;k=a;do u=k.prev,t=k.next.next,!sb(u,t)&&ff(u,k,k.next,t)&&Vc(u,t)&&Vc(t,u)&&(g.push(u.i/h),g.push(k.i/h),g.push(t.i/h),Sc(k),Sc(k.next),k=a=t),k=k.next;while(k!==a);a=k;Uc(a, +b,c,d,e,f,2)}else if(2===g)a:{g=a;do{for(h=g.next.next;h!==g.prev;){if(k=g.i!==h.i){k=g;u=h;if(t=k.next.i!==u.i&&k.prev.i!==u.i){b:{t=k;do{if(t.i!==k.i&&t.next.i!==k.i&&t.i!==u.i&&t.next.i!==u.i&&ff(t,t.next,k,u)){t=!0;break b}t=t.next}while(t!==k);t=!1}t=!t}if(t=t&&Vc(k,u)&&Vc(u,k)){t=k;r=!1;n=(k.x+u.x)/2;u=(k.y+u.y)/2;do t.y>u!==t.next.y>u&&t.next.y!==t.y&&n<(t.next.x-t.x)*(u-t.y)/(t.next.y-t.y)+t.x&&(r=!r),t=t.next;while(t!==k);t=r}k=t}if(k){a=gf(g,h);g=Tc(g,g.next);a=Tc(a,a.next);Uc(g,b,c,d,e, +f);Uc(a,b,c,d,e,f);break a}h=h.next}g=g.next}while(g!==a)}break}}}}function Qg(a,b){return a.x-b.x}function Rg(a,b){var c=b,d=a.x,e=a.y,f=-Infinity;do{if(e<=c.y&&e>=c.next.y&&c.next.y!==c.y){var g=c.x+(e-c.y)*(c.next.x-c.x)/(c.next.y-c.y);if(g<=d&&g>f){f=g;if(g===d){if(e===c.y)return c;if(e===c.next.y)return c.next}var h=c.x<c.next.x?c:c.next}}c=c.next}while(c!==b);if(!h)return null;if(d===f)return h.prev;b=h;g=h.x;var k=h.y,m=Infinity;for(c=h.next;c!==b;){if(d>=c.x&&c.x>=g&&d!==c.x&&zd(e<k?d:f,e, +g,k,e<k?f:d,e,c.x,c.y)){var r=Math.abs(e-c.y)/(d-c.x);(r<m||r===m&&c.x>h.x)&&Vc(c,a)&&(h=c,m=r)}c=c.next}return h}function de(a,b,c,d,e){a=32767*(a-c)*e;b=32767*(b-d)*e;a=(a|a<<8)&16711935;a=(a|a<<4)&252645135;a=(a|a<<2)&858993459;b=(b|b<<8)&16711935;b=(b|b<<4)&252645135;b=(b|b<<2)&858993459;return(a|a<<1)&1431655765|((b|b<<1)&1431655765)<<1}function Sg(a){var b=a,c=a;do b.x<c.x&&(c=b),b=b.next;while(b!==a);return c}function zd(a,b,c,d,e,f,g,h){return 0<=(e-g)*(b-h)-(a-g)*(f-h)&&0<=(a-g)*(d-h)-(c- +g)*(b-h)&&0<=(c-g)*(f-h)-(e-g)*(d-h)}function na(a,b,c){return(b.y-a.y)*(c.x-b.x)-(b.x-a.x)*(c.y-b.y)}function sb(a,b){return a.x===b.x&&a.y===b.y}function ff(a,b,c,d){return sb(a,b)&&sb(c,d)||sb(a,d)&&sb(c,b)?!0:0<na(a,b,c)!==0<na(a,b,d)&&0<na(c,d,a)!==0<na(c,d,b)}function Vc(a,b){return 0>na(a.prev,a,a.next)?0<=na(a,b,a.next)&&0<=na(a,a.prev,b):0>na(a,b,a.prev)||0>na(a,a.next,b)}function gf(a,b){var c=new ee(a.i,a.x,a.y),d=new ee(b.i,b.x,b.y),e=a.next,f=b.prev;a.next=b;b.prev=a;c.next=e;e.prev= +c;d.next=c;c.prev=d;f.next=d;d.prev=f;return d}function ef(a,b,c,d){a=new ee(a,b,c);d?(a.next=d.next,a.prev=d,d.next.prev=a,d.next=a):(a.prev=a,a.next=a);return a}function Sc(a){a.next.prev=a.prev;a.prev.next=a.next;a.prevZ&&(a.prevZ.nextZ=a.nextZ);a.nextZ&&(a.nextZ.prevZ=a.prevZ)}function ee(a,b,c){this.i=a;this.x=b;this.y=c;this.nextZ=this.prevZ=this.z=this.next=this.prev=null;this.steiner=!1}function hf(a){var b=a.length;2<b&&a[b-1].equals(a[0])&&a.pop()}function jf(a,b){for(var c=0;c<b.length;c++)a.push(b[c].x), +a.push(b[c].y)}function tb(a,b){M.call(this);this.type="ExtrudeGeometry";this.parameters={shapes:a,options:b};this.fromBufferGeometry(new Sa(a,b));this.mergeVertices()}function Sa(a,b){function c(a){function c(a,b,c){b||console.error("THREE.ExtrudeGeometry: vec does not exist");return b.clone().multiplyScalar(c).add(a)}function g(a,b,c){var d=a.x-b.x;var e=a.y-b.y;var f=c.x-a.x;var g=c.y-a.y,h=d*d+e*e;if(Math.abs(d*g-e*f)>Number.EPSILON){var k=Math.sqrt(h),m=Math.sqrt(f*f+g*g);h=b.x-e/k;b=b.y+d/k; +g=((c.x-g/m-h)*g-(c.y+f/m-b)*f)/(d*g-e*f);f=h+d*g-a.x;d=b+e*g-a.y;e=f*f+d*d;if(2>=e)return new A(f,d);e=Math.sqrt(e/2)}else a=!1,d>Number.EPSILON?f>Number.EPSILON&&(a=!0):d<-Number.EPSILON?f<-Number.EPSILON&&(a=!0):Math.sign(e)===Math.sign(g)&&(a=!0),a?(f=-e,e=Math.sqrt(h)):(f=d,d=e,e=Math.sqrt(h/2));return new A(f/e,d/e)}function h(a,b){for(O=a.length;0<=--O;){var c=O;var f=O-1;0>f&&(f=a.length-1);var g,h=w+2*B;for(g=0;g<h;g++){var k=W*g,m=W*(g+1),r=b+f+k,n=b+f+m;m=b+c+m;t(b+c+k);t(r);t(m);t(r); +t(n);t(m);k=e.length/3;k=C.generateSideWallUV(d,e,k-6,k-3,k-2,k-1);u(k[0]);u(k[1]);u(k[3]);u(k[1]);u(k[2]);u(k[3])}}}function k(a,b,c){y.push(a);y.push(b);y.push(c)}function l(a,b,c){t(a);t(b);t(c);a=e.length/3;a=C.generateTopUV(d,e,a-3,a-2,a-1);u(a[0]);u(a[1]);u(a[2])}function t(a){e.push(y[3*a]);e.push(y[3*a+1]);e.push(y[3*a+2])}function u(a){f.push(a.x);f.push(a.y)}var y=[],x=void 0!==b.curveSegments?b.curveSegments:12,w=void 0!==b.steps?b.steps:1,D=void 0!==b.depth?b.depth:100,J=void 0!==b.bevelEnabled? +b.bevelEnabled:!0,R=void 0!==b.bevelThickness?b.bevelThickness:6,X=void 0!==b.bevelSize?b.bevelSize:R-2,B=void 0!==b.bevelSegments?b.bevelSegments:3,z=b.extrudePath,C=void 0!==b.UVGenerator?b.UVGenerator:Tg;void 0!==b.amount&&(console.warn("THREE.ExtrudeBufferGeometry: amount has been renamed to depth."),D=b.amount);var F=!1;if(z){var Y=z.getSpacedPoints(w);F=!0;J=!1;var G=z.computeFrenetFrames(w,!1);var H=new p;var N=new p;var M=new p}J||(X=R=B=0);var P;x=a.extractPoints(x);a=x.shape;var L=x.holes; +if(!Za.isClockWise(a)){a=a.reverse();var I=0;for(P=L.length;I<P;I++){var K=L[I];Za.isClockWise(K)&&(L[I]=K.reverse())}}var S=Za.triangulateShape(a,L),T=a;I=0;for(P=L.length;I<P;I++)K=L[I],a=a.concat(K);var Q,W=a.length,V,Z=S.length;x=[];var O=0;var U=T.length;var fa=U-1;for(Q=O+1;O<U;O++,fa++,Q++)fa===U&&(fa=0),Q===U&&(Q=0),x[O]=g(T[O],T[fa],T[Q]);z=[];var ea=x.concat();I=0;for(P=L.length;I<P;I++){K=L[I];var ca=[];O=0;U=K.length;fa=U-1;for(Q=O+1;O<U;O++,fa++,Q++)fa===U&&(fa=0),Q===U&&(Q=0),ca[O]= +g(K[O],K[fa],K[Q]);z.push(ca);ea=ea.concat(ca)}for(fa=0;fa<B;fa++){U=fa/B;var da=R*Math.cos(U*Math.PI/2);Q=X*Math.sin(U*Math.PI/2);O=0;for(U=T.length;O<U;O++){var aa=c(T[O],x[O],Q);k(aa.x,aa.y,-da)}I=0;for(P=L.length;I<P;I++)for(K=L[I],ca=z[I],O=0,U=K.length;O<U;O++)aa=c(K[O],ca[O],Q),k(aa.x,aa.y,-da)}Q=X;for(O=0;O<W;O++)aa=J?c(a[O],ea[O],Q):a[O],F?(N.copy(G.normals[0]).multiplyScalar(aa.x),H.copy(G.binormals[0]).multiplyScalar(aa.y),M.copy(Y[0]).add(N).add(H),k(M.x,M.y,M.z)):k(aa.x,aa.y,0);for(U= +1;U<=w;U++)for(O=0;O<W;O++)aa=J?c(a[O],ea[O],Q):a[O],F?(N.copy(G.normals[U]).multiplyScalar(aa.x),H.copy(G.binormals[U]).multiplyScalar(aa.y),M.copy(Y[U]).add(N).add(H),k(M.x,M.y,M.z)):k(aa.x,aa.y,D/w*U);for(fa=B-1;0<=fa;fa--){U=fa/B;da=R*Math.cos(U*Math.PI/2);Q=X*Math.sin(U*Math.PI/2);O=0;for(U=T.length;O<U;O++)aa=c(T[O],x[O],Q),k(aa.x,aa.y,D+da);I=0;for(P=L.length;I<P;I++)for(K=L[I],ca=z[I],O=0,U=K.length;O<U;O++)aa=c(K[O],ca[O],Q),F?k(aa.x,aa.y+Y[w-1].y,Y[w-1].x+da):k(aa.x,aa.y,D+da)}(function(){var a= +e.length/3;if(J){var b=0*W;for(O=0;O<Z;O++)V=S[O],l(V[2]+b,V[1]+b,V[0]+b);b=W*(w+2*B);for(O=0;O<Z;O++)V=S[O],l(V[0]+b,V[1]+b,V[2]+b)}else{for(O=0;O<Z;O++)V=S[O],l(V[2],V[1],V[0]);for(O=0;O<Z;O++)V=S[O],l(V[0]+W*w,V[1]+W*w,V[2]+W*w)}d.addGroup(a,e.length/3-a,0)})();(function(){var a=e.length/3,b=0;h(T,b);b+=T.length;I=0;for(P=L.length;I<P;I++)K=L[I],h(K,b),b+=K.length;d.addGroup(a,e.length/3-a,1)})()}F.call(this);this.type="ExtrudeBufferGeometry";this.parameters={shapes:a,options:b};a=Array.isArray(a)? +a:[a];for(var d=this,e=[],f=[],g=0,h=a.length;g<h;g++)c(a[g]);this.addAttribute("position",new z(e,3));this.addAttribute("uv",new z(f,2));this.computeVertexNormals()}function kf(a,b,c){c.shapes=[];if(Array.isArray(a))for(var d=0,e=a.length;d<e;d++)c.shapes.push(a[d].uuid);else c.shapes.push(a.uuid);void 0!==b.extrudePath&&(c.options.extrudePath=b.extrudePath.toJSON());return c}function Wc(a,b){M.call(this);this.type="TextGeometry";this.parameters={text:a,parameters:b};this.fromBufferGeometry(new bc(a, +b));this.mergeVertices()}function bc(a,b){b=b||{};var c=b.font;if(!c||!c.isFont)return console.error("THREE.TextGeometry: font parameter is not an instance of THREE.Font."),new M;a=c.generateShapes(a,b.size);b.depth=void 0!==b.height?b.height:50;void 0===b.bevelThickness&&(b.bevelThickness=10);void 0===b.bevelSize&&(b.bevelSize=8);void 0===b.bevelEnabled&&(b.bevelEnabled=!1);Sa.call(this,a,b);this.type="TextBufferGeometry"}function Xc(a,b,c,d,e,f,g){M.call(this);this.type="SphereGeometry";this.parameters= +{radius:a,widthSegments:b,heightSegments:c,phiStart:d,phiLength:e,thetaStart:f,thetaLength:g};this.fromBufferGeometry(new ub(a,b,c,d,e,f,g));this.mergeVertices()}function ub(a,b,c,d,e,f,g){F.call(this);this.type="SphereBufferGeometry";this.parameters={radius:a,widthSegments:b,heightSegments:c,phiStart:d,phiLength:e,thetaStart:f,thetaLength:g};a=a||1;b=Math.max(3,Math.floor(b)||8);c=Math.max(2,Math.floor(c)||6);d=void 0!==d?d:0;e=void 0!==e?e:2*Math.PI;f=void 0!==f?f:0;g=void 0!==g?g:Math.PI;var h= +f+g,k,m,r=0,n=[],l=new p,v=new p,t=[],u=[],y=[],x=[];for(m=0;m<=c;m++){var w=[],D=m/c;for(k=0;k<=b;k++){var J=k/b;l.x=-a*Math.cos(d+J*e)*Math.sin(f+D*g);l.y=a*Math.cos(f+D*g);l.z=a*Math.sin(d+J*e)*Math.sin(f+D*g);u.push(l.x,l.y,l.z);v.set(l.x,l.y,l.z).normalize();y.push(v.x,v.y,v.z);x.push(J,1-D);w.push(r++)}n.push(w)}for(m=0;m<c;m++)for(k=0;k<b;k++)a=n[m][k+1],d=n[m][k],e=n[m+1][k],g=n[m+1][k+1],(0!==m||0<f)&&t.push(a,d,g),(m!==c-1||h<Math.PI)&&t.push(d,e,g);this.setIndex(t);this.addAttribute("position", +new z(u,3));this.addAttribute("normal",new z(y,3));this.addAttribute("uv",new z(x,2))}function Yc(a,b,c,d,e,f){M.call(this);this.type="RingGeometry";this.parameters={innerRadius:a,outerRadius:b,thetaSegments:c,phiSegments:d,thetaStart:e,thetaLength:f};this.fromBufferGeometry(new cc(a,b,c,d,e,f));this.mergeVertices()}function cc(a,b,c,d,e,f){F.call(this);this.type="RingBufferGeometry";this.parameters={innerRadius:a,outerRadius:b,thetaSegments:c,phiSegments:d,thetaStart:e,thetaLength:f};a=a||.5;b=b|| +1;e=void 0!==e?e:0;f=void 0!==f?f:2*Math.PI;c=void 0!==c?Math.max(3,c):8;d=void 0!==d?Math.max(1,d):1;var g=[],h=[],k=[],m=[],r=a,n=(b-a)/d,l=new p,v=new A,t,u;for(t=0;t<=d;t++){for(u=0;u<=c;u++)a=e+u/c*f,l.x=r*Math.cos(a),l.y=r*Math.sin(a),h.push(l.x,l.y,l.z),k.push(0,0,1),v.x=(l.x/b+1)/2,v.y=(l.y/b+1)/2,m.push(v.x,v.y);r+=n}for(t=0;t<d;t++)for(b=t*(c+1),u=0;u<c;u++)a=u+b,e=a+c+1,f=a+c+2,r=a+1,g.push(a,e,r),g.push(e,f,r);this.setIndex(g);this.addAttribute("position",new z(h,3));this.addAttribute("normal", +new z(k,3));this.addAttribute("uv",new z(m,2))}function Zc(a,b,c,d){M.call(this);this.type="LatheGeometry";this.parameters={points:a,segments:b,phiStart:c,phiLength:d};this.fromBufferGeometry(new dc(a,b,c,d));this.mergeVertices()}function dc(a,b,c,d){F.call(this);this.type="LatheBufferGeometry";this.parameters={points:a,segments:b,phiStart:c,phiLength:d};b=Math.floor(b)||12;c=c||0;d=d||2*Math.PI;d=S.clamp(d,0,2*Math.PI);var e=[],f=[],g=[],h=1/b,k=new p,m=new A,r;for(r=0;r<=b;r++){var n=c+r*h*d;var l= +Math.sin(n),v=Math.cos(n);for(n=0;n<=a.length-1;n++)k.x=a[n].x*l,k.y=a[n].y,k.z=a[n].x*v,f.push(k.x,k.y,k.z),m.x=r/b,m.y=n/(a.length-1),g.push(m.x,m.y)}for(r=0;r<b;r++)for(n=0;n<a.length-1;n++)c=n+r*a.length,h=c+a.length,k=c+a.length+1,m=c+1,e.push(c,h,m),e.push(h,k,m);this.setIndex(e);this.addAttribute("position",new z(f,3));this.addAttribute("uv",new z(g,2));this.computeVertexNormals();if(d===2*Math.PI)for(d=this.attributes.normal.array,e=new p,f=new p,g=new p,c=b*a.length*3,n=r=0;r<a.length;r++, +n+=3)e.x=d[n+0],e.y=d[n+1],e.z=d[n+2],f.x=d[c+n+0],f.y=d[c+n+1],f.z=d[c+n+2],g.addVectors(e,f).normalize(),d[n+0]=d[c+n+0]=g.x,d[n+1]=d[c+n+1]=g.y,d[n+2]=d[c+n+2]=g.z}function vb(a,b){M.call(this);this.type="ShapeGeometry";"object"===typeof b&&(console.warn("THREE.ShapeGeometry: Options parameter has been removed."),b=b.curveSegments);this.parameters={shapes:a,curveSegments:b};this.fromBufferGeometry(new wb(a,b));this.mergeVertices()}function wb(a,b){function c(a){var c,h=e.length/3;a=a.extractPoints(b); +var m=a.shape,r=a.holes;if(!1===Za.isClockWise(m))for(m=m.reverse(),a=0,c=r.length;a<c;a++){var l=r[a];!0===Za.isClockWise(l)&&(r[a]=l.reverse())}var p=Za.triangulateShape(m,r);a=0;for(c=r.length;a<c;a++)l=r[a],m=m.concat(l);a=0;for(c=m.length;a<c;a++)l=m[a],e.push(l.x,l.y,0),f.push(0,0,1),g.push(l.x,l.y);a=0;for(c=p.length;a<c;a++)m=p[a],d.push(m[0]+h,m[1]+h,m[2]+h),k+=3}F.call(this);this.type="ShapeBufferGeometry";this.parameters={shapes:a,curveSegments:b};b=b||12;var d=[],e=[],f=[],g=[],h=0,k= +0;if(!1===Array.isArray(a))c(a);else for(var m=0;m<a.length;m++)c(a[m]),this.addGroup(h,k,m),h+=k,k=0;this.setIndex(d);this.addAttribute("position",new z(e,3));this.addAttribute("normal",new z(f,3));this.addAttribute("uv",new z(g,2))}function lf(a,b){b.shapes=[];if(Array.isArray(a))for(var c=0,d=a.length;c<d;c++)b.shapes.push(a[c].uuid);else b.shapes.push(a.uuid);return b}function ec(a,b){F.call(this);this.type="EdgesGeometry";this.parameters={thresholdAngle:b};var c=[];b=Math.cos(S.DEG2RAD*(void 0!== +b?b:1));var d=[0,0],e={},f=["a","b","c"];if(a.isBufferGeometry){var g=new M;g.fromBufferGeometry(a)}else g=a.clone();g.mergeVertices();g.computeFaceNormals();a=g.vertices;g=g.faces;for(var h=0,k=g.length;h<k;h++)for(var m=g[h],r=0;3>r;r++){var n=m[f[r]];var l=m[f[(r+1)%3]];d[0]=Math.min(n,l);d[1]=Math.max(n,l);n=d[0]+","+d[1];void 0===e[n]?e[n]={index1:d[0],index2:d[1],face1:h,face2:void 0}:e[n].face2=h}for(n in e)if(d=e[n],void 0===d.face2||g[d.face1].normal.dot(g[d.face2].normal)<=b)f=a[d.index1], +c.push(f.x,f.y,f.z),f=a[d.index2],c.push(f.x,f.y,f.z);this.addAttribute("position",new z(c,3))}function xb(a,b,c,d,e,f,g,h){M.call(this);this.type="CylinderGeometry";this.parameters={radiusTop:a,radiusBottom:b,height:c,radialSegments:d,heightSegments:e,openEnded:f,thetaStart:g,thetaLength:h};this.fromBufferGeometry(new $a(a,b,c,d,e,f,g,h));this.mergeVertices()}function $a(a,b,c,d,e,f,g,h){function k(c){var e,f=new A,k=new p,q=0,u=!0===c?a:b,w=!0===c?1:-1;var z=t;for(e=1;e<=d;e++)n.push(0,y*w,0),l.push(0, +w,0),v.push(.5,.5),t++;var F=t;for(e=0;e<=d;e++){var C=e/d*h+g,I=Math.cos(C);C=Math.sin(C);k.x=u*C;k.y=y*w;k.z=u*I;n.push(k.x,k.y,k.z);l.push(0,w,0);f.x=.5*I+.5;f.y=.5*C*w+.5;v.push(f.x,f.y);t++}for(e=0;e<d;e++)f=z+e,k=F+e,!0===c?r.push(k,k+1,f):r.push(k+1,k,f),q+=3;m.addGroup(x,q,!0===c?1:2);x+=q}F.call(this);this.type="CylinderBufferGeometry";this.parameters={radiusTop:a,radiusBottom:b,height:c,radialSegments:d,heightSegments:e,openEnded:f,thetaStart:g,thetaLength:h};var m=this;a=void 0!==a?a:1; +b=void 0!==b?b:1;c=c||1;d=Math.floor(d)||8;e=Math.floor(e)||1;f=void 0!==f?f:!1;g=void 0!==g?g:0;h=void 0!==h?h:2*Math.PI;var r=[],n=[],l=[],v=[],t=0,u=[],y=c/2,x=0;(function(){var f,k,q=new p,R=new p,A=0,B=(b-a)/c;for(k=0;k<=e;k++){var z=[],C=k/e,F=C*(b-a)+a;for(f=0;f<=d;f++){var I=f/d,G=I*h+g,H=Math.sin(G);G=Math.cos(G);R.x=F*H;R.y=-C*c+y;R.z=F*G;n.push(R.x,R.y,R.z);q.set(H,B,G).normalize();l.push(q.x,q.y,q.z);v.push(I,1-C);z.push(t++)}u.push(z)}for(f=0;f<d;f++)for(k=0;k<e;k++)q=u[k+1][f],R=u[k+ +1][f+1],B=u[k][f+1],r.push(u[k][f],q,B),r.push(q,R,B),A+=6;m.addGroup(x,A,0);x+=A})();!1===f&&(0<a&&k(!0),0<b&&k(!1));this.setIndex(r);this.addAttribute("position",new z(n,3));this.addAttribute("normal",new z(l,3));this.addAttribute("uv",new z(v,2))}function $c(a,b,c,d,e,f,g){xb.call(this,0,a,b,c,d,e,f,g);this.type="ConeGeometry";this.parameters={radius:a,height:b,radialSegments:c,heightSegments:d,openEnded:e,thetaStart:f,thetaLength:g}}function ad(a,b,c,d,e,f,g){$a.call(this,0,a,b,c,d,e,f,g);this.type= +"ConeBufferGeometry";this.parameters={radius:a,height:b,radialSegments:c,heightSegments:d,openEnded:e,thetaStart:f,thetaLength:g}}function bd(a,b,c,d){M.call(this);this.type="CircleGeometry";this.parameters={radius:a,segments:b,thetaStart:c,thetaLength:d};this.fromBufferGeometry(new fc(a,b,c,d));this.mergeVertices()}function fc(a,b,c,d){F.call(this);this.type="CircleBufferGeometry";this.parameters={radius:a,segments:b,thetaStart:c,thetaLength:d};a=a||1;b=void 0!==b?Math.max(3,b):8;c=void 0!==c?c: +0;d=void 0!==d?d:2*Math.PI;var e=[],f=[],g=[],h=[],k,m=new p,r=new A;f.push(0,0,0);g.push(0,0,1);h.push(.5,.5);var n=0;for(k=3;n<=b;n++,k+=3){var l=c+n/b*d;m.x=a*Math.cos(l);m.y=a*Math.sin(l);f.push(m.x,m.y,m.z);g.push(0,0,1);r.x=(f[k]/a+1)/2;r.y=(f[k+1]/a+1)/2;h.push(r.x,r.y)}for(k=1;k<=b;k++)e.push(k,k+1,0);this.setIndex(e);this.addAttribute("position",new z(f,3));this.addAttribute("normal",new z(g,3));this.addAttribute("uv",new z(h,2))}function yb(a){L.call(this);this.type="ShadowMaterial";this.color= +new G(0);this.transparent=!0;this.setValues(a)}function gc(a){ka.call(this,a);this.type="RawShaderMaterial"}function Ta(a){L.call(this);this.defines={STANDARD:""};this.type="MeshStandardMaterial";this.color=new G(16777215);this.metalness=this.roughness=.5;this.lightMap=this.map=null;this.lightMapIntensity=1;this.aoMap=null;this.aoMapIntensity=1;this.emissive=new G(0);this.emissiveIntensity=1;this.bumpMap=this.emissiveMap=null;this.bumpScale=1;this.normalMap=null;this.normalMapType=0;this.normalScale= +new A(1,1);this.displacementMap=null;this.displacementScale=1;this.displacementBias=0;this.envMap=this.alphaMap=this.metalnessMap=this.roughnessMap=null;this.envMapIntensity=1;this.refractionRatio=.98;this.wireframe=!1;this.wireframeLinewidth=1;this.wireframeLinejoin=this.wireframeLinecap="round";this.morphNormals=this.morphTargets=this.skinning=!1;this.setValues(a)}function zb(a){Ta.call(this);this.defines={PHYSICAL:""};this.type="MeshPhysicalMaterial";this.reflectivity=.5;this.clearCoatRoughness= +this.clearCoat=0;this.setValues(a)}function Ha(a){L.call(this);this.type="MeshPhongMaterial";this.color=new G(16777215);this.specular=new G(1118481);this.shininess=30;this.lightMap=this.map=null;this.lightMapIntensity=1;this.aoMap=null;this.aoMapIntensity=1;this.emissive=new G(0);this.emissiveIntensity=1;this.bumpMap=this.emissiveMap=null;this.bumpScale=1;this.normalMap=null;this.normalMapType=0;this.normalScale=new A(1,1);this.displacementMap=null;this.displacementScale=1;this.displacementBias=0; +this.envMap=this.alphaMap=this.specularMap=null;this.combine=0;this.reflectivity=1;this.refractionRatio=.98;this.wireframe=!1;this.wireframeLinewidth=1;this.wireframeLinejoin=this.wireframeLinecap="round";this.morphNormals=this.morphTargets=this.skinning=!1;this.setValues(a)}function Ab(a){Ha.call(this);this.defines={TOON:""};this.type="MeshToonMaterial";this.gradientMap=null;this.setValues(a)}function Bb(a){L.call(this);this.type="MeshNormalMaterial";this.bumpMap=null;this.bumpScale=1;this.normalMap= +null;this.normalMapType=0;this.normalScale=new A(1,1);this.displacementMap=null;this.displacementScale=1;this.displacementBias=0;this.wireframe=!1;this.wireframeLinewidth=1;this.morphNormals=this.morphTargets=this.skinning=this.lights=this.fog=!1;this.setValues(a)}function Cb(a){L.call(this);this.type="MeshLambertMaterial";this.color=new G(16777215);this.lightMap=this.map=null;this.lightMapIntensity=1;this.aoMap=null;this.aoMapIntensity=1;this.emissive=new G(0);this.emissiveIntensity=1;this.envMap= +this.alphaMap=this.specularMap=this.emissiveMap=null;this.combine=0;this.reflectivity=1;this.refractionRatio=.98;this.wireframe=!1;this.wireframeLinewidth=1;this.wireframeLinejoin=this.wireframeLinecap="round";this.morphNormals=this.morphTargets=this.skinning=!1;this.setValues(a)}function Db(a){L.call(this);this.defines={MATCAP:""};this.type="MeshMatcapMaterial";this.color=new G(16777215);this.bumpMap=this.map=this.matcap=null;this.bumpScale=1;this.normalMap=null;this.normalMapType=0;this.normalScale= +new A(1,1);this.displacementMap=null;this.displacementScale=1;this.displacementBias=0;this.alphaMap=null;this.lights=this.morphNormals=this.morphTargets=this.skinning=!1;this.setValues(a);if(null===this.matcap){a=document.createElement("canvas");a.width=1;a.height=1;var b=a.getContext("2d");b.fillStyle="#fff";b.fillRect(0,0,1,1);this.matcap=new THREE.CanvasTexture(a)}}function Eb(a){T.call(this);this.type="LineDashedMaterial";this.scale=1;this.dashSize=3;this.gapSize=1;this.setValues(a)}function fe(a, +b,c){var d=this,e=!1,f=0,g=0,h=void 0;this.onStart=void 0;this.onLoad=a;this.onProgress=b;this.onError=c;this.itemStart=function(a){g++;if(!1===e&&void 0!==d.onStart)d.onStart(a,f,g);e=!0};this.itemEnd=function(a){f++;if(void 0!==d.onProgress)d.onProgress(a,f,g);if(f===g&&(e=!1,void 0!==d.onLoad))d.onLoad()};this.itemError=function(a){if(void 0!==d.onError)d.onError(a)};this.resolveURL=function(a){return h?h(a):a};this.setURLModifier=function(a){h=a;return this}}function Ia(a){this.manager=void 0!== +a?a:ya}function mf(a){this.manager=void 0!==a?a:ya;this._parser=null}function ge(a){this.manager=void 0!==a?a:ya;this._parser=null}function cd(a){this.manager=void 0!==a?a:ya}function he(a){this.manager=void 0!==a?a:ya}function Ad(a){this.manager=void 0!==a?a:ya}function N(){this.type="Curve";this.arcLengthDivisions=200}function Ca(a,b,c,d,e,f,g,h){N.call(this);this.type="EllipseCurve";this.aX=a||0;this.aY=b||0;this.xRadius=c||1;this.yRadius=d||1;this.aStartAngle=e||0;this.aEndAngle=f||2*Math.PI; +this.aClockwise=g||!1;this.aRotation=h||0}function hc(a,b,c,d,e,f){Ca.call(this,a,b,c,c,d,e,f);this.type="ArcCurve"}function ie(){var a=0,b=0,c=0,d=0;return{initCatmullRom:function(e,f,g,h,k){e=k*(g-e);h=k*(h-f);a=f;b=e;c=-3*f+3*g-2*e-h;d=2*f-2*g+e+h},initNonuniformCatmullRom:function(e,f,g,h,k,m,r){e=((f-e)/k-(g-e)/(k+m)+(g-f)/m)*m;h=((g-f)/m-(h-f)/(m+r)+(h-g)/r)*m;a=f;b=e;c=-3*f+3*g-2*e-h;d=2*f-2*g+e+h},calc:function(e){var f=e*e;return a+b*e+c*f+d*f*e}}}function ha(a,b,c,d){N.call(this);this.type= +"CatmullRomCurve3";this.points=a||[];this.closed=b||!1;this.curveType=c||"centripetal";this.tension=d||.5}function nf(a,b,c,d,e){b=.5*(d-b);e=.5*(e-c);var f=a*a;return(2*c-2*d+b+e)*a*f+(-3*c+3*d-2*b-e)*f+b*a+c}function dd(a,b,c,d){var e=1-a;return e*e*b+2*(1-a)*a*c+a*a*d}function ed(a,b,c,d,e){var f=1-a,g=1-a;return f*f*f*b+3*g*g*a*c+3*(1-a)*a*a*d+a*a*a*e}function Ja(a,b,c,d){N.call(this);this.type="CubicBezierCurve";this.v0=a||new A;this.v1=b||new A;this.v2=c||new A;this.v3=d||new A}function Ua(a, +b,c,d){N.call(this);this.type="CubicBezierCurve3";this.v0=a||new p;this.v1=b||new p;this.v2=c||new p;this.v3=d||new p}function za(a,b){N.call(this);this.type="LineCurve";this.v1=a||new A;this.v2=b||new A}function Ka(a,b){N.call(this);this.type="LineCurve3";this.v1=a||new p;this.v2=b||new p}function La(a,b,c){N.call(this);this.type="QuadraticBezierCurve";this.v0=a||new A;this.v1=b||new A;this.v2=c||new A}function Va(a,b,c){N.call(this);this.type="QuadraticBezierCurve3";this.v0=a||new p;this.v1=b|| +new p;this.v2=c||new p}function Ma(a){N.call(this);this.type="SplineCurve";this.points=a||[]}function ab(){N.call(this);this.type="CurvePath";this.curves=[];this.autoClose=!1}function Na(a){ab.call(this);this.type="Path";this.currentPoint=new A;a&&this.setFromPoints(a)}function gb(a){Na.call(this,a);this.uuid=S.generateUUID();this.type="Shape";this.holes=[]}function ca(a,b){C.call(this);this.type="Light";this.color=new G(a);this.intensity=void 0!==b?b:1;this.receiveShadow=void 0}function Bd(a,b,c){ca.call(this, +a,c);this.type="HemisphereLight";this.castShadow=void 0;this.position.copy(C.DefaultUp);this.updateMatrix();this.groundColor=new G(b)}function Fb(a){this.camera=a;this.bias=0;this.radius=1;this.mapSize=new A(512,512);this.map=null;this.matrix=new P}function Cd(){Fb.call(this,new V(50,1,.5,500))}function Dd(a,b,c,d,e,f){ca.call(this,a,b);this.type="SpotLight";this.position.copy(C.DefaultUp);this.updateMatrix();this.target=new C;Object.defineProperty(this,"power",{get:function(){return this.intensity* +Math.PI},set:function(a){this.intensity=a/Math.PI}});this.distance=void 0!==c?c:0;this.angle=void 0!==d?d:Math.PI/3;this.penumbra=void 0!==e?e:0;this.decay=void 0!==f?f:1;this.shadow=new Cd}function Ed(a,b,c,d){ca.call(this,a,b);this.type="PointLight";Object.defineProperty(this,"power",{get:function(){return 4*this.intensity*Math.PI},set:function(a){this.intensity=a/(4*Math.PI)}});this.distance=void 0!==c?c:0;this.decay=void 0!==d?d:1;this.shadow=new Fb(new V(90,1,.5,500))}function fd(a,b,c,d,e,f){Ra.call(this); +this.type="OrthographicCamera";this.zoom=1;this.view=null;this.left=a;this.right=b;this.top=c;this.bottom=d;this.near=void 0!==e?e:.1;this.far=void 0!==f?f:2E3;this.updateProjectionMatrix()}function Fd(){Fb.call(this,new fd(-5,5,5,-5,.5,500))}function Gd(a,b){ca.call(this,a,b);this.type="DirectionalLight";this.position.copy(C.DefaultUp);this.updateMatrix();this.target=new C;this.shadow=new Fd}function Hd(a,b){ca.call(this,a,b);this.type="AmbientLight";this.castShadow=void 0}function Id(a,b,c,d){ca.call(this, +a,b);this.type="RectAreaLight";this.width=void 0!==c?c:10;this.height=void 0!==d?d:10}function Aa(a,b,c,d){this.parameterPositions=a;this._cachedIndex=0;this.resultBuffer=void 0!==d?d:new b.constructor(c);this.sampleValues=b;this.valueSize=c}function Jd(a,b,c,d){Aa.call(this,a,b,c,d);this._offsetNext=this._weightNext=this._offsetPrev=this._weightPrev=-0}function gd(a,b,c,d){Aa.call(this,a,b,c,d)}function Kd(a,b,c,d){Aa.call(this,a,b,c,d)}function qa(a,b,c,d){if(void 0===a)throw Error("THREE.KeyframeTrack: track name is undefined"); +if(void 0===b||0===b.length)throw Error("THREE.KeyframeTrack: no keyframes in track named "+a);this.name=a;this.times=ra.convertArray(b,this.TimeBufferType);this.values=ra.convertArray(c,this.ValueBufferType);this.setInterpolation(d||this.DefaultInterpolation)}function Ld(a,b,c){qa.call(this,a,b,c)}function Md(a,b,c,d){qa.call(this,a,b,c,d)}function ic(a,b,c,d){qa.call(this,a,b,c,d)}function Nd(a,b,c,d){Aa.call(this,a,b,c,d)}function hd(a,b,c,d){qa.call(this,a,b,c,d)}function Od(a,b,c,d){qa.call(this, +a,b,c,d)}function jc(a,b,c,d){qa.call(this,a,b,c,d)}function Ea(a,b,c){this.name=a;this.tracks=c;this.duration=void 0!==b?b:-1;this.uuid=S.generateUUID();0>this.duration&&this.resetDuration()}function Ug(a){switch(a.toLowerCase()){case "scalar":case "double":case "float":case "number":case "integer":return ic;case "vector":case "vector2":case "vector3":case "vector4":return jc;case "color":return Md;case "quaternion":return hd;case "bool":case "boolean":return Ld;case "string":return Od}throw Error("THREE.KeyframeTrack: Unsupported typeName: "+ +a);}function Vg(a){if(void 0===a.type)throw Error("THREE.KeyframeTrack: track type undefined, can not parse");var b=Ug(a.type);if(void 0===a.times){var c=[],d=[];ra.flattenJSON(a.keys,c,d,"value");a.times=c;a.values=d}return void 0!==b.parse?b.parse(a):new b(a.name,a.times,a.values,a.interpolation)}function Pd(a){this.manager=void 0!==a?a:ya;this.textures={}}function je(a){this.manager=void 0!==a?a:ya}function kc(){}function Qd(a){"boolean"===typeof a&&(console.warn("THREE.JSONLoader: showStatus parameter has been removed from constructor."), +a=void 0);this.manager=void 0!==a?a:ya;this.withCredentials=!1}function of(a){this.manager=void 0!==a?a:ya;this.texturePath=""}function ke(a){"undefined"===typeof createImageBitmap&&console.warn("THREE.ImageBitmapLoader: createImageBitmap() not supported.");"undefined"===typeof fetch&&console.warn("THREE.ImageBitmapLoader: fetch() not supported.");this.manager=void 0!==a?a:ya;this.options=void 0}function le(){this.type="ShapePath";this.color=new G;this.subPaths=[];this.currentPath=null}function me(a){this.type= +"Font";this.data=a}function pf(a){this.manager=void 0!==a?a:ya}function ne(a){this.manager=void 0!==a?a:ya}function qf(){this.type="StereoCamera";this.aspect=1;this.eyeSep=.064;this.cameraL=new V;this.cameraL.layers.enable(1);this.cameraL.matrixAutoUpdate=!1;this.cameraR=new V;this.cameraR.layers.enable(2);this.cameraR.matrixAutoUpdate=!1}function id(a,b,c){C.call(this);this.type="CubeCamera";var d=new V(90,1,a,b);d.up.set(0,-1,0);d.lookAt(new p(1,0,0));this.add(d);var e=new V(90,1,a,b);e.up.set(0, +-1,0);e.lookAt(new p(-1,0,0));this.add(e);var f=new V(90,1,a,b);f.up.set(0,0,1);f.lookAt(new p(0,1,0));this.add(f);var g=new V(90,1,a,b);g.up.set(0,0,-1);g.lookAt(new p(0,-1,0));this.add(g);var h=new V(90,1,a,b);h.up.set(0,-1,0);h.lookAt(new p(0,0,1));this.add(h);var k=new V(90,1,a,b);k.up.set(0,-1,0);k.lookAt(new p(0,0,-1));this.add(k);this.renderTarget=new Jb(c,c,{format:1022,magFilter:1006,minFilter:1006});this.renderTarget.texture.name="CubeCamera";this.update=function(a,b){null===this.parent&& +this.updateMatrixWorld();var c=this.renderTarget,m=c.texture.generateMipmaps;c.texture.generateMipmaps=!1;c.activeCubeFace=0;a.render(b,d,c);c.activeCubeFace=1;a.render(b,e,c);c.activeCubeFace=2;a.render(b,f,c);c.activeCubeFace=3;a.render(b,g,c);c.activeCubeFace=4;a.render(b,h,c);c.texture.generateMipmaps=m;c.activeCubeFace=5;a.render(b,k,c);a.setRenderTarget(null)};this.clear=function(a,b,c,d){for(var e=this.renderTarget,f=0;6>f;f++)e.activeCubeFace=f,a.setRenderTarget(e),a.clear(b,c,d);a.setRenderTarget(null)}} +function oe(){C.call(this);this.type="AudioListener";this.context=pe.getContext();this.gain=this.context.createGain();this.gain.connect(this.context.destination);this.filter=null}function lc(a){C.call(this);this.type="Audio";this.context=a.context;this.gain=this.context.createGain();this.gain.connect(a.getInput());this.autoplay=!1;this.buffer=null;this.loop=!1;this.offset=this.startTime=0;this.playbackRate=1;this.isPlaying=!1;this.hasPlaybackControl=!0;this.sourceType="empty";this.filters=[]}function qe(a){lc.call(this, +a);this.panner=this.context.createPanner();this.panner.connect(this.gain)}function re(a,b){this.analyser=a.context.createAnalyser();this.analyser.fftSize=void 0!==b?b:2048;this.data=new Uint8Array(this.analyser.frequencyBinCount);a.getOutput().connect(this.analyser)}function se(a,b,c){this.binding=a;this.valueSize=c;a=Float64Array;switch(b){case "quaternion":b=this._slerp;break;case "string":case "bool":a=Array;b=this._select;break;default:b=this._lerp}this.buffer=new a(4*c);this._mixBufferRegion= +b;this.referenceCount=this.useCount=this.cumulativeWeight=0}function rf(a,b,c){c=c||ta.parseTrackName(b);this._targetGroup=a;this._bindings=a.subscribe_(b,c)}function ta(a,b,c){this.path=b;this.parsedPath=c||ta.parseTrackName(b);this.node=ta.findNode(a,this.parsedPath.nodeName)||a;this.rootNode=a}function sf(){this.uuid=S.generateUUID();this._objects=Array.prototype.slice.call(arguments);this.nCachedObjects_=0;var a={};this._indicesByUUID=a;for(var b=0,c=arguments.length;b!==c;++b)a[arguments[b].uuid]= +b;this._paths=[];this._parsedPaths=[];this._bindings=[];this._bindingsIndicesByPath={};var d=this;this.stats={objects:{get total(){return d._objects.length},get inUse(){return this.total-d.nCachedObjects_}},get bindingsPerObject(){return d._bindings.length}}}function tf(a,b,c){this._mixer=a;this._clip=b;this._localRoot=c||null;a=b.tracks;b=a.length;c=Array(b);for(var d={endingStart:2400,endingEnd:2400},e=0;e!==b;++e){var f=a[e].createInterpolant(null);c[e]=f;f.settings=d}this._interpolantSettings= +d;this._interpolants=c;this._propertyBindings=Array(b);this._weightInterpolant=this._timeScaleInterpolant=this._byClipCacheIndex=this._cacheIndex=null;this.loop=2201;this._loopCount=-1;this._startTime=null;this.time=0;this._effectiveWeight=this.weight=this._effectiveTimeScale=this.timeScale=1;this.repetitions=Infinity;this.paused=!1;this.enabled=!0;this.clampWhenFinished=!1;this.zeroSlopeAtEnd=this.zeroSlopeAtStart=!0}function te(a){this._root=a;this._initMemoryManager();this.time=this._accuIndex= +0;this.timeScale=1}function Rd(a,b){"string"===typeof a&&(console.warn("THREE.Uniform: Type parameter is no longer needed."),a=b);this.value=a}function ue(){F.call(this);this.type="InstancedBufferGeometry";this.maxInstancedCount=void 0}function ve(a,b,c){qb.call(this,a,b);this.meshPerAttribute=c||1}function we(a,b,c,d){"number"===typeof c&&(d=c,c=!1,console.error("THREE.InstancedBufferAttribute: The constructor now expects normalized as the third argument."));I.call(this,a,b,c);this.meshPerAttribute= +d||1}function uf(a,b,c,d){this.ray=new pb(a,b);this.near=c||0;this.far=d||Infinity;this.params={Mesh:{},Line:{},LOD:{},Points:{threshold:1},Sprite:{}};Object.defineProperties(this.params,{PointCloud:{get:function(){console.warn("THREE.Raycaster: params.PointCloud has been renamed to params.Points.");return this.Points}}})}function vf(a,b){return a.distance-b.distance}function xe(a,b,c,d){if(!1!==a.visible&&(a.raycast(b,c),!0===d)){a=a.children;d=0;for(var e=a.length;d<e;d++)xe(a[d],b,c,!0)}}function wf(a){this.autoStart= +void 0!==a?a:!0;this.elapsedTime=this.oldTime=this.startTime=0;this.running=!1}function xf(a,b,c){this.radius=void 0!==a?a:1;this.phi=void 0!==b?b:0;this.theta=void 0!==c?c:0;return this}function yf(a,b,c){this.radius=void 0!==a?a:1;this.theta=void 0!==b?b:0;this.y=void 0!==c?c:0;return this}function ye(a,b){this.min=void 0!==a?a:new A(Infinity,Infinity);this.max=void 0!==b?b:new A(-Infinity,-Infinity)}function ze(a,b){this.start=void 0!==a?a:new p;this.end=void 0!==b?b:new p}function jd(a){C.call(this); +this.material=a;this.render=function(){}}function kd(a,b,c,d){this.object=a;this.size=void 0!==b?b:1;a=void 0!==c?c:16711680;d=void 0!==d?d:1;b=0;(c=this.object.geometry)&&c.isGeometry?b=3*c.faces.length:c&&c.isBufferGeometry&&(b=c.attributes.normal.count);c=new F;b=new z(6*b,3);c.addAttribute("position",b);W.call(this,c,new T({color:a,linewidth:d}));this.matrixAutoUpdate=!1;this.update()}function mc(a,b){C.call(this);this.light=a;this.light.updateMatrixWorld();this.matrix=a.matrixWorld;this.matrixAutoUpdate= +!1;this.color=b;a=new F;b=[0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,-1,0,1,0,0,0,0,1,1,0,0,0,0,-1,1];for(var c=0,d=1;32>c;c++,d++){var e=c/32*Math.PI*2,f=d/32*Math.PI*2;b.push(Math.cos(e),Math.sin(e),1,Math.cos(f),Math.sin(f),1)}a.addAttribute("position",new z(b,3));b=new T({fog:!1});this.cone=new W(a,b);this.add(this.cone);this.update()}function zf(a){var b=[];a&&a.isBone&&b.push(a);for(var c=0;c<a.children.length;c++)b.push.apply(b,zf(a.children[c]));return b}function nc(a){for(var b=zf(a),c=new F,d=[],e= +[],f=new G(0,0,1),g=new G(0,1,0),h=0;h<b.length;h++){var k=b[h];k.parent&&k.parent.isBone&&(d.push(0,0,0),d.push(0,0,0),e.push(f.r,f.g,f.b),e.push(g.r,g.g,g.b))}c.addAttribute("position",new z(d,3));c.addAttribute("color",new z(e,3));d=new T({vertexColors:2,depthTest:!1,depthWrite:!1,transparent:!0});W.call(this,c,d);this.root=a;this.bones=b;this.matrix=a.matrixWorld;this.matrixAutoUpdate=!1}function oc(a,b,c){this.light=a;this.light.updateMatrixWorld();this.color=c;a=new ub(b,4,2);b=new wa({wireframe:!0, +fog:!1});ua.call(this,a,b);this.matrix=this.light.matrixWorld;this.matrixAutoUpdate=!1;this.update()}function pc(a,b){C.call(this);this.light=a;this.light.updateMatrixWorld();this.matrix=a.matrixWorld;this.matrixAutoUpdate=!1;this.color=b;a=new T({fog:!1});b=new F;b.addAttribute("position",new I(new Float32Array(15),3));this.line=new pa(b,a);this.add(this.line);this.update()}function qc(a,b,c){C.call(this);this.light=a;this.light.updateMatrixWorld();this.matrix=a.matrixWorld;this.matrixAutoUpdate= +!1;this.color=c;a=new rb(b);a.rotateY(.5*Math.PI);this.material=new wa({wireframe:!0,fog:!1});void 0===this.color&&(this.material.vertexColors=2);b=a.getAttribute("position");b=new Float32Array(3*b.count);a.addAttribute("color",new I(b,3));this.add(new ua(a,this.material));this.update()}function ld(a,b,c,d){a=a||10;b=b||10;c=new G(void 0!==c?c:4473924);d=new G(void 0!==d?d:8947848);var e=b/2,f=a/b,g=a/2;a=[];for(var h=[],k=0,m=0,r=-g;k<=b;k++,r+=f){a.push(-g,0,r,g,0,r);a.push(r,0,-g,r,0,g);var n= +k===e?c:d;n.toArray(h,m);m+=3;n.toArray(h,m);m+=3;n.toArray(h,m);m+=3;n.toArray(h,m);m+=3}b=new F;b.addAttribute("position",new z(a,3));b.addAttribute("color",new z(h,3));c=new T({vertexColors:2});W.call(this,b,c)}function Sd(a,b,c,d,e,f){a=a||10;b=b||16;c=c||8;d=d||64;e=new G(void 0!==e?e:4473924);f=new G(void 0!==f?f:8947848);var g=[],h=[],k;for(k=0;k<=b;k++){var m=k/b*2*Math.PI;var r=Math.sin(m)*a;m=Math.cos(m)*a;g.push(0,0,0);g.push(r,0,m);var n=k&1?e:f;h.push(n.r,n.g,n.b);h.push(n.r,n.g,n.b)}for(k= +0;k<=c;k++){n=k&1?e:f;var l=a-a/c*k;for(b=0;b<d;b++)m=b/d*2*Math.PI,r=Math.sin(m)*l,m=Math.cos(m)*l,g.push(r,0,m),h.push(n.r,n.g,n.b),m=(b+1)/d*2*Math.PI,r=Math.sin(m)*l,m=Math.cos(m)*l,g.push(r,0,m),h.push(n.r,n.g,n.b)}a=new F;a.addAttribute("position",new z(g,3));a.addAttribute("color",new z(h,3));g=new T({vertexColors:2});W.call(this,a,g)}function md(a,b,c,d){this.object=a;this.size=void 0!==b?b:1;a=void 0!==c?c:16776960;d=void 0!==d?d:1;b=0;(c=this.object.geometry)&&c.isGeometry?b=c.faces.length: +console.warn("THREE.FaceNormalsHelper: only THREE.Geometry is supported. Use THREE.VertexNormalsHelper, instead.");c=new F;b=new z(6*b,3);c.addAttribute("position",b);W.call(this,c,new T({color:a,linewidth:d}));this.matrixAutoUpdate=!1;this.update()}function rc(a,b,c){C.call(this);this.light=a;this.light.updateMatrixWorld();this.matrix=a.matrixWorld;this.matrixAutoUpdate=!1;this.color=c;void 0===b&&(b=1);a=new F;a.addAttribute("position",new z([-b,b,0,b,b,0,b,-b,0,-b,-b,0,-b,b,0],3));b=new T({fog:!1}); +this.lightPlane=new pa(a,b);this.add(this.lightPlane);a=new F;a.addAttribute("position",new z([0,0,0,0,0,1],3));this.targetLine=new pa(a,b);this.add(this.targetLine);this.update()}function nd(a){function b(a,b,d){c(a,d);c(b,d)}function c(a,b){f.push(0,0,0);g.push(b.r,b.g,b.b);void 0===h[a]&&(h[a]=[]);h[a].push(f.length/3-1)}var d=new F,e=new T({color:16777215,vertexColors:1}),f=[],g=[],h={},k=new G(16755200),m=new G(16711680),r=new G(43775),n=new G(16777215),l=new G(3355443);b("n1","n2",k);b("n2", +"n4",k);b("n4","n3",k);b("n3","n1",k);b("f1","f2",k);b("f2","f4",k);b("f4","f3",k);b("f3","f1",k);b("n1","f1",k);b("n2","f2",k);b("n3","f3",k);b("n4","f4",k);b("p","n1",m);b("p","n2",m);b("p","n3",m);b("p","n4",m);b("u1","u2",r);b("u2","u3",r);b("u3","u1",r);b("c","t",n);b("p","c",l);b("cn1","cn2",l);b("cn3","cn4",l);b("cf1","cf2",l);b("cf3","cf4",l);d.addAttribute("position",new z(f,3));d.addAttribute("color",new z(g,3));W.call(this,d,e);this.camera=a;this.camera.updateProjectionMatrix&&this.camera.updateProjectionMatrix(); +this.matrix=a.matrixWorld;this.matrixAutoUpdate=!1;this.pointMap=h;this.update()}function Gb(a,b){this.object=a;void 0===b&&(b=16776960);a=new Uint16Array([0,1,1,2,2,3,3,0,4,5,5,6,6,7,7,4,0,4,1,5,2,6,3,7]);var c=new Float32Array(24),d=new F;d.setIndex(new I(a,1));d.addAttribute("position",new I(c,3));W.call(this,d,new T({color:b}));this.matrixAutoUpdate=!1;this.update()}function od(a,b){this.type="Box3Helper";this.box=a;a=void 0!==b?b:16776960;b=new Uint16Array([0,1,1,2,2,3,3,0,4,5,5,6,6,7,7,4,0, +4,1,5,2,6,3,7]);var c=new F;c.setIndex(new I(b,1));c.addAttribute("position",new z([1,1,1,-1,1,1,-1,-1,1,1,-1,1,1,1,-1,-1,1,-1,-1,-1,-1,1,-1,-1],3));W.call(this,c,new T({color:a}));this.geometry.computeBoundingSphere()}function pd(a,b,c){this.type="PlaneHelper";this.plane=a;this.size=void 0===b?1:b;a=void 0!==c?c:16776960;b=new F;b.addAttribute("position",new z([1,-1,1,-1,1,1,-1,-1,1,1,1,1,-1,1,1,-1,-1,1,1,-1,1,1,1,1,0,0,1,0,0,0],3));b.computeBoundingSphere();pa.call(this,b,new T({color:a}));b=new F; +b.addAttribute("position",new z([1,1,1,-1,1,1,-1,-1,1,1,1,1,-1,-1,1,1,-1,1],3));b.computeBoundingSphere();this.add(new ua(b,new wa({color:a,opacity:.2,transparent:!0,depthWrite:!1})))}function Hb(a,b,c,d,e,f){C.call(this);void 0===d&&(d=16776960);void 0===c&&(c=1);void 0===e&&(e=.2*c);void 0===f&&(f=.2*e);void 0===Td&&(Td=new F,Td.addAttribute("position",new z([0,0,0,0,1,0],3)),Ae=new $a(0,.5,1,5,1),Ae.translate(0,-.5,0));this.position.copy(b);this.line=new pa(Td,new T({color:d}));this.line.matrixAutoUpdate= +!1;this.add(this.line);this.cone=new ua(Ae,new wa({color:d}));this.cone.matrixAutoUpdate=!1;this.add(this.cone);this.setDirection(a);this.setLength(c,e,f)}function qd(a){a=a||1;var b=[0,0,0,a,0,0,0,0,0,0,a,0,0,0,0,0,0,a];a=new F;a.addAttribute("position",new z(b,3));a.addAttribute("color",new z([1,0,0,1,.6,0,0,1,0,.6,1,0,0,0,1,0,.6,1],3));b=new T({vertexColors:2});W.call(this,a,b)}function Af(a){console.warn("THREE.ClosedSplineCurve3 has been deprecated. Use THREE.CatmullRomCurve3 instead.");ha.call(this, +a);this.type="catmullrom";this.closed=!0}function Bf(a){console.warn("THREE.SplineCurve3 has been deprecated. Use THREE.CatmullRomCurve3 instead.");ha.call(this,a);this.type="catmullrom"}function Be(a){console.warn("THREE.Spline has been removed. Use THREE.CatmullRomCurve3 instead.");ha.call(this,a);this.type="catmullrom"}void 0===Number.EPSILON&&(Number.EPSILON=Math.pow(2,-52));void 0===Number.isInteger&&(Number.isInteger=function(a){return"number"===typeof a&&isFinite(a)&&Math.floor(a)===a});void 0=== +Math.sign&&(Math.sign=function(a){return 0>a?-1:0<a?1:+a});!1==="name"in Function.prototype&&Object.defineProperty(Function.prototype,"name",{get:function(){return this.toString().match(/^\s*function\s*([^\(\s]*)/)[1]}});void 0===Object.assign&&function(){Object.assign=function(a){if(void 0===a||null===a)throw new TypeError("Cannot convert undefined or null to object");for(var b=Object(a),c=1;c<arguments.length;c++){var d=arguments[c];if(void 0!==d&&null!==d)for(var e in d)Object.prototype.hasOwnProperty.call(d, +e)&&(b[e]=d[e])}return b}}();Object.assign(ia.prototype,{addEventListener:function(a,b){void 0===this._listeners&&(this._listeners={});var c=this._listeners;void 0===c[a]&&(c[a]=[]);-1===c[a].indexOf(b)&&c[a].push(b)},hasEventListener:function(a,b){if(void 0===this._listeners)return!1;var c=this._listeners;return void 0!==c[a]&&-1!==c[a].indexOf(b)},removeEventListener:function(a,b){void 0!==this._listeners&&(a=this._listeners[a],void 0!==a&&(b=a.indexOf(b),-1!==b&&a.splice(b,1)))},dispatchEvent:function(a){if(void 0!== +this._listeners){var b=this._listeners[a.type];if(void 0!==b){a.target=this;b=b.slice(0);for(var c=0,d=b.length;c<d;c++)b[c].call(this,a)}}}});var S={DEG2RAD:Math.PI/180,RAD2DEG:180/Math.PI,generateUUID:function(){for(var a=[],b=0;256>b;b++)a[b]=(16>b?"0":"")+b.toString(16);return function(){var b=4294967295*Math.random()|0,d=4294967295*Math.random()|0,e=4294967295*Math.random()|0,f=4294967295*Math.random()|0;return(a[b&255]+a[b>>8&255]+a[b>>16&255]+a[b>>24&255]+"-"+a[d&255]+a[d>>8&255]+"-"+a[d>> +16&15|64]+a[d>>24&255]+"-"+a[e&63|128]+a[e>>8&255]+"-"+a[e>>16&255]+a[e>>24&255]+a[f&255]+a[f>>8&255]+a[f>>16&255]+a[f>>24&255]).toUpperCase()}}(),clamp:function(a,b,c){return Math.max(b,Math.min(c,a))},euclideanModulo:function(a,b){return(a%b+b)%b},mapLinear:function(a,b,c,d,e){return d+(a-b)*(e-d)/(c-b)},lerp:function(a,b,c){return(1-c)*a+c*b},smoothstep:function(a,b,c){if(a<=b)return 0;if(a>=c)return 1;a=(a-b)/(c-b);return a*a*(3-2*a)},smootherstep:function(a,b,c){if(a<=b)return 0;if(a>=c)return 1; +a=(a-b)/(c-b);return a*a*a*(a*(6*a-15)+10)},randInt:function(a,b){return a+Math.floor(Math.random()*(b-a+1))},randFloat:function(a,b){return a+Math.random()*(b-a)},randFloatSpread:function(a){return a*(.5-Math.random())},degToRad:function(a){return a*S.DEG2RAD},radToDeg:function(a){return a*S.RAD2DEG},isPowerOfTwo:function(a){return 0===(a&a-1)&&0!==a},ceilPowerOfTwo:function(a){return Math.pow(2,Math.ceil(Math.log(a)/Math.LN2))},floorPowerOfTwo:function(a){return Math.pow(2,Math.floor(Math.log(a)/ +Math.LN2))}};Object.defineProperties(A.prototype,{width:{get:function(){return this.x},set:function(a){this.x=a}},height:{get:function(){return this.y},set:function(a){this.y=a}}});Object.assign(A.prototype,{isVector2:!0,set:function(a,b){this.x=a;this.y=b;return this},setScalar:function(a){this.y=this.x=a;return this},setX:function(a){this.x=a;return this},setY:function(a){this.y=a;return this},setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b;break;default:throw Error("index is out of range: "+ +a);}return this},getComponent:function(a){switch(a){case 0:return this.x;case 1:return this.y;default:throw Error("index is out of range: "+a);}},clone:function(){return new this.constructor(this.x,this.y)},copy:function(a){this.x=a.x;this.y=a.y;return this},add:function(a,b){if(void 0!==b)return console.warn("THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b);this.x+=a.x;this.y+=a.y;return this},addScalar:function(a){this.x+=a;this.y+=a;return this}, +addVectors:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;return this},addScaledVector:function(a,b){this.x+=a.x*b;this.y+=a.y*b;return this},sub:function(a,b){if(void 0!==b)return console.warn("THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(a,b);this.x-=a.x;this.y-=a.y;return this},subScalar:function(a){this.x-=a;this.y-=a;return this},subVectors:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;return this},multiply:function(a){this.x*=a.x;this.y*= +a.y;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;return this},divide:function(a){this.x/=a.x;this.y/=a.y;return this},divideScalar:function(a){return this.multiplyScalar(1/a)},applyMatrix3:function(a){var b=this.x,c=this.y;a=a.elements;this.x=a[0]*b+a[3]*c+a[6];this.y=a[1]*b+a[4]*c+a[7];return this},min:function(a){this.x=Math.min(this.x,a.x);this.y=Math.min(this.y,a.y);return this},max:function(a){this.x=Math.max(this.x,a.x);this.y=Math.max(this.y,a.y);return this},clamp:function(a, +b){this.x=Math.max(a.x,Math.min(b.x,this.x));this.y=Math.max(a.y,Math.min(b.y,this.y));return this},clampScalar:function(){var a=new A,b=new A;return function(c,d){a.set(c,c);b.set(d,d);return this.clamp(a,b)}}(),clampLength:function(a,b){var c=this.length();return this.divideScalar(c||1).multiplyScalar(Math.max(a,Math.min(b,c)))},floor:function(){this.x=Math.floor(this.x);this.y=Math.floor(this.y);return this},ceil:function(){this.x=Math.ceil(this.x);this.y=Math.ceil(this.y);return this},round:function(){this.x= +Math.round(this.x);this.y=Math.round(this.y);return this},roundToZero:function(){this.x=0>this.x?Math.ceil(this.x):Math.floor(this.x);this.y=0>this.y?Math.ceil(this.y):Math.floor(this.y);return this},negate:function(){this.x=-this.x;this.y=-this.y;return this},dot:function(a){return this.x*a.x+this.y*a.y},cross:function(a){return this.x*a.y-this.y*a.x},lengthSq:function(){return this.x*this.x+this.y*this.y},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y)},manhattanLength:function(){return Math.abs(this.x)+ +Math.abs(this.y)},normalize:function(){return this.divideScalar(this.length()||1)},angle:function(){var a=Math.atan2(this.y,this.x);0>a&&(a+=2*Math.PI);return a},distanceTo:function(a){return Math.sqrt(this.distanceToSquared(a))},distanceToSquared:function(a){var b=this.x-a.x;a=this.y-a.y;return b*b+a*a},manhattanDistanceTo:function(a){return Math.abs(this.x-a.x)+Math.abs(this.y-a.y)},setLength:function(a){return this.normalize().multiplyScalar(a)},lerp:function(a,b){this.x+=(a.x-this.x)*b;this.y+= +(a.y-this.y)*b;return this},lerpVectors:function(a,b,c){return this.subVectors(b,a).multiplyScalar(c).add(a)},equals:function(a){return a.x===this.x&&a.y===this.y},fromArray:function(a,b){void 0===b&&(b=0);this.x=a[b];this.y=a[b+1];return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this.x;a[b+1]=this.y;return a},fromBufferAttribute:function(a,b,c){void 0!==c&&console.warn("THREE.Vector2: offset has been removed from .fromBufferAttribute().");this.x=a.getX(b);this.y=a.getY(b); +return this},rotateAround:function(a,b){var c=Math.cos(b);b=Math.sin(b);var d=this.x-a.x,e=this.y-a.y;this.x=d*c-e*b+a.x;this.y=d*b+e*c+a.y;return this}});Object.assign(P.prototype,{isMatrix4:!0,set:function(a,b,c,d,e,f,g,h,k,m,r,n,l,v,t,p){var q=this.elements;q[0]=a;q[4]=b;q[8]=c;q[12]=d;q[1]=e;q[5]=f;q[9]=g;q[13]=h;q[2]=k;q[6]=m;q[10]=r;q[14]=n;q[3]=l;q[7]=v;q[11]=t;q[15]=p;return this},identity:function(){this.set(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1);return this},clone:function(){return(new P).fromArray(this.elements)}, +copy:function(a){var b=this.elements;a=a.elements;b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3];b[4]=a[4];b[5]=a[5];b[6]=a[6];b[7]=a[7];b[8]=a[8];b[9]=a[9];b[10]=a[10];b[11]=a[11];b[12]=a[12];b[13]=a[13];b[14]=a[14];b[15]=a[15];return this},copyPosition:function(a){var b=this.elements;a=a.elements;b[12]=a[12];b[13]=a[13];b[14]=a[14];return this},extractBasis:function(a,b,c){a.setFromMatrixColumn(this,0);b.setFromMatrixColumn(this,1);c.setFromMatrixColumn(this,2);return this},makeBasis:function(a,b,c){this.set(a.x, +b.x,c.x,0,a.y,b.y,c.y,0,a.z,b.z,c.z,0,0,0,0,1);return this},extractRotation:function(){var a=new p;return function(b){var c=this.elements,d=b.elements,e=1/a.setFromMatrixColumn(b,0).length(),f=1/a.setFromMatrixColumn(b,1).length();b=1/a.setFromMatrixColumn(b,2).length();c[0]=d[0]*e;c[1]=d[1]*e;c[2]=d[2]*e;c[3]=0;c[4]=d[4]*f;c[5]=d[5]*f;c[6]=d[6]*f;c[7]=0;c[8]=d[8]*b;c[9]=d[9]*b;c[10]=d[10]*b;c[11]=0;c[12]=0;c[13]=0;c[14]=0;c[15]=1;return this}}(),makeRotationFromEuler:function(a){a&&a.isEuler||console.error("THREE.Matrix4: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order."); +var b=this.elements,c=a.x,d=a.y,e=a.z,f=Math.cos(c);c=Math.sin(c);var g=Math.cos(d);d=Math.sin(d);var h=Math.cos(e);e=Math.sin(e);if("XYZ"===a.order){a=f*h;var k=f*e,m=c*h,r=c*e;b[0]=g*h;b[4]=-g*e;b[8]=d;b[1]=k+m*d;b[5]=a-r*d;b[9]=-c*g;b[2]=r-a*d;b[6]=m+k*d;b[10]=f*g}else"YXZ"===a.order?(a=g*h,k=g*e,m=d*h,r=d*e,b[0]=a+r*c,b[4]=m*c-k,b[8]=f*d,b[1]=f*e,b[5]=f*h,b[9]=-c,b[2]=k*c-m,b[6]=r+a*c,b[10]=f*g):"ZXY"===a.order?(a=g*h,k=g*e,m=d*h,r=d*e,b[0]=a-r*c,b[4]=-f*e,b[8]=m+k*c,b[1]=k+m*c,b[5]=f*h,b[9]= +r-a*c,b[2]=-f*d,b[6]=c,b[10]=f*g):"ZYX"===a.order?(a=f*h,k=f*e,m=c*h,r=c*e,b[0]=g*h,b[4]=m*d-k,b[8]=a*d+r,b[1]=g*e,b[5]=r*d+a,b[9]=k*d-m,b[2]=-d,b[6]=c*g,b[10]=f*g):"YZX"===a.order?(a=f*g,k=f*d,m=c*g,r=c*d,b[0]=g*h,b[4]=r-a*e,b[8]=m*e+k,b[1]=e,b[5]=f*h,b[9]=-c*h,b[2]=-d*h,b[6]=k*e+m,b[10]=a-r*e):"XZY"===a.order&&(a=f*g,k=f*d,m=c*g,r=c*d,b[0]=g*h,b[4]=-e,b[8]=d*h,b[1]=a*e+r,b[5]=f*h,b[9]=k*e-m,b[2]=m*e-k,b[6]=c*h,b[10]=r*e+a);b[3]=0;b[7]=0;b[11]=0;b[12]=0;b[13]=0;b[14]=0;b[15]=1;return this},makeRotationFromQuaternion:function(){var a= +new p(0,0,0),b=new p(1,1,1);return function(c){return this.compose(a,c,b)}}(),lookAt:function(){var a=new p,b=new p,c=new p;return function(d,e,f){var g=this.elements;c.subVectors(d,e);0===c.lengthSq()&&(c.z=1);c.normalize();a.crossVectors(f,c);0===a.lengthSq()&&(1===Math.abs(f.z)?c.x+=1E-4:c.z+=1E-4,c.normalize(),a.crossVectors(f,c));a.normalize();b.crossVectors(c,a);g[0]=a.x;g[4]=b.x;g[8]=c.x;g[1]=a.y;g[5]=b.y;g[9]=c.y;g[2]=a.z;g[6]=b.z;g[10]=c.z;return this}}(),multiply:function(a,b){return void 0!== +b?(console.warn("THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead."),this.multiplyMatrices(a,b)):this.multiplyMatrices(this,a)},premultiply:function(a){return this.multiplyMatrices(a,this)},multiplyMatrices:function(a,b){var c=a.elements,d=b.elements;b=this.elements;a=c[0];var e=c[4],f=c[8],g=c[12],h=c[1],k=c[5],m=c[9],r=c[13],n=c[2],l=c[6],v=c[10],t=c[14],p=c[3],y=c[7],x=c[11];c=c[15];var w=d[0],D=d[4],J=d[8],R=d[12],A=d[1],B=d[5],z=d[9],C=d[13],F=d[2], +I=d[6],G=d[10],H=d[14],L=d[3],M=d[7],K=d[11];d=d[15];b[0]=a*w+e*A+f*F+g*L;b[4]=a*D+e*B+f*I+g*M;b[8]=a*J+e*z+f*G+g*K;b[12]=a*R+e*C+f*H+g*d;b[1]=h*w+k*A+m*F+r*L;b[5]=h*D+k*B+m*I+r*M;b[9]=h*J+k*z+m*G+r*K;b[13]=h*R+k*C+m*H+r*d;b[2]=n*w+l*A+v*F+t*L;b[6]=n*D+l*B+v*I+t*M;b[10]=n*J+l*z+v*G+t*K;b[14]=n*R+l*C+v*H+t*d;b[3]=p*w+y*A+x*F+c*L;b[7]=p*D+y*B+x*I+c*M;b[11]=p*J+y*z+x*G+c*K;b[15]=p*R+y*C+x*H+c*d;return this},multiplyScalar:function(a){var b=this.elements;b[0]*=a;b[4]*=a;b[8]*=a;b[12]*=a;b[1]*=a;b[5]*= +a;b[9]*=a;b[13]*=a;b[2]*=a;b[6]*=a;b[10]*=a;b[14]*=a;b[3]*=a;b[7]*=a;b[11]*=a;b[15]*=a;return this},applyToBufferAttribute:function(){var a=new p;return function(b){for(var c=0,d=b.count;c<d;c++)a.x=b.getX(c),a.y=b.getY(c),a.z=b.getZ(c),a.applyMatrix4(this),b.setXYZ(c,a.x,a.y,a.z);return b}}(),determinant:function(){var a=this.elements,b=a[0],c=a[4],d=a[8],e=a[12],f=a[1],g=a[5],h=a[9],k=a[13],m=a[2],r=a[6],l=a[10],q=a[14];return a[3]*(+e*h*r-d*k*r-e*g*l+c*k*l+d*g*q-c*h*q)+a[7]*(+b*h*q-b*k*l+e*f*l- +d*f*q+d*k*m-e*h*m)+a[11]*(+b*k*r-b*g*q-e*f*r+c*f*q+e*g*m-c*k*m)+a[15]*(-d*g*m-b*h*r+b*g*l+d*f*r-c*f*l+c*h*m)},transpose:function(){var a=this.elements;var b=a[1];a[1]=a[4];a[4]=b;b=a[2];a[2]=a[8];a[8]=b;b=a[6];a[6]=a[9];a[9]=b;b=a[3];a[3]=a[12];a[12]=b;b=a[7];a[7]=a[13];a[13]=b;b=a[11];a[11]=a[14];a[14]=b;return this},setPosition:function(a){var b=this.elements;b[12]=a.x;b[13]=a.y;b[14]=a.z;return this},getInverse:function(a,b){var c=this.elements,d=a.elements;a=d[0];var e=d[1],f=d[2],g=d[3],h=d[4], +k=d[5],m=d[6],l=d[7],n=d[8],q=d[9],v=d[10],t=d[11],p=d[12],y=d[13],x=d[14];d=d[15];var w=q*x*l-y*v*l+y*m*t-k*x*t-q*m*d+k*v*d,D=p*v*l-n*x*l-p*m*t+h*x*t+n*m*d-h*v*d,J=n*y*l-p*q*l+p*k*t-h*y*t-n*k*d+h*q*d,A=p*q*m-n*y*m-p*k*v+h*y*v+n*k*x-h*q*x,z=a*w+e*D+f*J+g*A;if(0===z){if(!0===b)throw Error("THREE.Matrix4: .getInverse() can't invert matrix, determinant is 0");console.warn("THREE.Matrix4: .getInverse() can't invert matrix, determinant is 0");return this.identity()}b=1/z;c[0]=w*b;c[1]=(y*v*g-q*x*g-y*f* +t+e*x*t+q*f*d-e*v*d)*b;c[2]=(k*x*g-y*m*g+y*f*l-e*x*l-k*f*d+e*m*d)*b;c[3]=(q*m*g-k*v*g-q*f*l+e*v*l+k*f*t-e*m*t)*b;c[4]=D*b;c[5]=(n*x*g-p*v*g+p*f*t-a*x*t-n*f*d+a*v*d)*b;c[6]=(p*m*g-h*x*g-p*f*l+a*x*l+h*f*d-a*m*d)*b;c[7]=(h*v*g-n*m*g+n*f*l-a*v*l-h*f*t+a*m*t)*b;c[8]=J*b;c[9]=(p*q*g-n*y*g-p*e*t+a*y*t+n*e*d-a*q*d)*b;c[10]=(h*y*g-p*k*g+p*e*l-a*y*l-h*e*d+a*k*d)*b;c[11]=(n*k*g-h*q*g-n*e*l+a*q*l+h*e*t-a*k*t)*b;c[12]=A*b;c[13]=(n*y*f-p*q*f+p*e*v-a*y*v-n*e*x+a*q*x)*b;c[14]=(p*k*f-h*y*f-p*e*m+a*y*m+h*e*x-a*k*x)* +b;c[15]=(h*q*f-n*k*f+n*e*m-a*q*m-h*e*v+a*k*v)*b;return this},scale:function(a){var b=this.elements,c=a.x,d=a.y;a=a.z;b[0]*=c;b[4]*=d;b[8]*=a;b[1]*=c;b[5]*=d;b[9]*=a;b[2]*=c;b[6]*=d;b[10]*=a;b[3]*=c;b[7]*=d;b[11]*=a;return this},getMaxScaleOnAxis:function(){var a=this.elements;return Math.sqrt(Math.max(a[0]*a[0]+a[1]*a[1]+a[2]*a[2],a[4]*a[4]+a[5]*a[5]+a[6]*a[6],a[8]*a[8]+a[9]*a[9]+a[10]*a[10]))},makeTranslation:function(a,b,c){this.set(1,0,0,a,0,1,0,b,0,0,1,c,0,0,0,1);return this},makeRotationX:function(a){var b= +Math.cos(a);a=Math.sin(a);this.set(1,0,0,0,0,b,-a,0,0,a,b,0,0,0,0,1);return this},makeRotationY:function(a){var b=Math.cos(a);a=Math.sin(a);this.set(b,0,a,0,0,1,0,0,-a,0,b,0,0,0,0,1);return this},makeRotationZ:function(a){var b=Math.cos(a);a=Math.sin(a);this.set(b,-a,0,0,a,b,0,0,0,0,1,0,0,0,0,1);return this},makeRotationAxis:function(a,b){var c=Math.cos(b);b=Math.sin(b);var d=1-c,e=a.x,f=a.y;a=a.z;var g=d*e,h=d*f;this.set(g*e+c,g*f-b*a,g*a+b*f,0,g*f+b*a,h*f+c,h*a-b*e,0,g*a-b*f,h*a+b*e,d*a*a+c,0,0, +0,0,1);return this},makeScale:function(a,b,c){this.set(a,0,0,0,0,b,0,0,0,0,c,0,0,0,0,1);return this},makeShear:function(a,b,c){this.set(1,b,c,0,a,1,c,0,a,b,1,0,0,0,0,1);return this},compose:function(a,b,c){var d=this.elements,e=b._x,f=b._y,g=b._z,h=b._w,k=e+e,m=f+f,l=g+g;b=e*k;var n=e*m;e*=l;var q=f*m;f*=l;g*=l;k*=h;m*=h;h*=l;l=c.x;var v=c.y;c=c.z;d[0]=(1-(q+g))*l;d[1]=(n+h)*l;d[2]=(e-m)*l;d[3]=0;d[4]=(n-h)*v;d[5]=(1-(b+g))*v;d[6]=(f+k)*v;d[7]=0;d[8]=(e+m)*c;d[9]=(f-k)*c;d[10]=(1-(b+q))*c;d[11]=0; +d[12]=a.x;d[13]=a.y;d[14]=a.z;d[15]=1;return this},decompose:function(){var a=new p,b=new P;return function(c,d,e){var f=this.elements,g=a.set(f[0],f[1],f[2]).length(),h=a.set(f[4],f[5],f[6]).length(),k=a.set(f[8],f[9],f[10]).length();0>this.determinant()&&(g=-g);c.x=f[12];c.y=f[13];c.z=f[14];b.copy(this);c=1/g;f=1/h;var m=1/k;b.elements[0]*=c;b.elements[1]*=c;b.elements[2]*=c;b.elements[4]*=f;b.elements[5]*=f;b.elements[6]*=f;b.elements[8]*=m;b.elements[9]*=m;b.elements[10]*=m;d.setFromRotationMatrix(b); +e.x=g;e.y=h;e.z=k;return this}}(),makePerspective:function(a,b,c,d,e,f){void 0===f&&console.warn("THREE.Matrix4: .makePerspective() has been redefined and has a new signature. Please check the docs.");var g=this.elements;g[0]=2*e/(b-a);g[4]=0;g[8]=(b+a)/(b-a);g[12]=0;g[1]=0;g[5]=2*e/(c-d);g[9]=(c+d)/(c-d);g[13]=0;g[2]=0;g[6]=0;g[10]=-(f+e)/(f-e);g[14]=-2*f*e/(f-e);g[3]=0;g[7]=0;g[11]=-1;g[15]=0;return this},makeOrthographic:function(a,b,c,d,e,f){var g=this.elements,h=1/(b-a),k=1/(c-d),m=1/(f-e);g[0]= +2*h;g[4]=0;g[8]=0;g[12]=-((b+a)*h);g[1]=0;g[5]=2*k;g[9]=0;g[13]=-((c+d)*k);g[2]=0;g[6]=0;g[10]=-2*m;g[14]=-((f+e)*m);g[3]=0;g[7]=0;g[11]=0;g[15]=1;return this},equals:function(a){var b=this.elements;a=a.elements;for(var c=0;16>c;c++)if(b[c]!==a[c])return!1;return!0},fromArray:function(a,b){void 0===b&&(b=0);for(var c=0;16>c;c++)this.elements[c]=a[c+b];return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);var c=this.elements;a[b]=c[0];a[b+1]=c[1];a[b+2]=c[2];a[b+3]=c[3];a[b+4]=c[4]; +a[b+5]=c[5];a[b+6]=c[6];a[b+7]=c[7];a[b+8]=c[8];a[b+9]=c[9];a[b+10]=c[10];a[b+11]=c[11];a[b+12]=c[12];a[b+13]=c[13];a[b+14]=c[14];a[b+15]=c[15];return a}});Object.assign(ja,{slerp:function(a,b,c,d){return c.copy(a).slerp(b,d)},slerpFlat:function(a,b,c,d,e,f,g){var h=c[d+0],k=c[d+1],m=c[d+2];c=c[d+3];d=e[f+0];var l=e[f+1],n=e[f+2];e=e[f+3];if(c!==e||h!==d||k!==l||m!==n){f=1-g;var q=h*d+k*l+m*n+c*e,v=0<=q?1:-1,p=1-q*q;p>Number.EPSILON&&(p=Math.sqrt(p),q=Math.atan2(p,q*v),f=Math.sin(f*q)/p,g=Math.sin(g* +q)/p);v*=g;h=h*f+d*v;k=k*f+l*v;m=m*f+n*v;c=c*f+e*v;f===1-g&&(g=1/Math.sqrt(h*h+k*k+m*m+c*c),h*=g,k*=g,m*=g,c*=g)}a[b]=h;a[b+1]=k;a[b+2]=m;a[b+3]=c}});Object.defineProperties(ja.prototype,{x:{get:function(){return this._x},set:function(a){this._x=a;this.onChangeCallback()}},y:{get:function(){return this._y},set:function(a){this._y=a;this.onChangeCallback()}},z:{get:function(){return this._z},set:function(a){this._z=a;this.onChangeCallback()}},w:{get:function(){return this._w},set:function(a){this._w= +a;this.onChangeCallback()}}});Object.assign(ja.prototype,{isQuaternion:!0,set:function(a,b,c,d){this._x=a;this._y=b;this._z=c;this._w=d;this.onChangeCallback();return this},clone:function(){return new this.constructor(this._x,this._y,this._z,this._w)},copy:function(a){this._x=a.x;this._y=a.y;this._z=a.z;this._w=a.w;this.onChangeCallback();return this},setFromEuler:function(a,b){if(!a||!a.isEuler)throw Error("THREE.Quaternion: .setFromEuler() now expects an Euler rotation rather than a Vector3 and order."); +var c=a._x,d=a._y,e=a._z;a=a.order;var f=Math.cos,g=Math.sin,h=f(c/2),k=f(d/2);f=f(e/2);c=g(c/2);d=g(d/2);e=g(e/2);"XYZ"===a?(this._x=c*k*f+h*d*e,this._y=h*d*f-c*k*e,this._z=h*k*e+c*d*f,this._w=h*k*f-c*d*e):"YXZ"===a?(this._x=c*k*f+h*d*e,this._y=h*d*f-c*k*e,this._z=h*k*e-c*d*f,this._w=h*k*f+c*d*e):"ZXY"===a?(this._x=c*k*f-h*d*e,this._y=h*d*f+c*k*e,this._z=h*k*e+c*d*f,this._w=h*k*f-c*d*e):"ZYX"===a?(this._x=c*k*f-h*d*e,this._y=h*d*f+c*k*e,this._z=h*k*e-c*d*f,this._w=h*k*f+c*d*e):"YZX"===a?(this._x= +c*k*f+h*d*e,this._y=h*d*f+c*k*e,this._z=h*k*e-c*d*f,this._w=h*k*f-c*d*e):"XZY"===a&&(this._x=c*k*f-h*d*e,this._y=h*d*f-c*k*e,this._z=h*k*e+c*d*f,this._w=h*k*f+c*d*e);if(!1!==b)this.onChangeCallback();return this},setFromAxisAngle:function(a,b){b/=2;var c=Math.sin(b);this._x=a.x*c;this._y=a.y*c;this._z=a.z*c;this._w=Math.cos(b);this.onChangeCallback();return this},setFromRotationMatrix:function(a){var b=a.elements,c=b[0];a=b[4];var d=b[8],e=b[1],f=b[5],g=b[9],h=b[2],k=b[6];b=b[10];var m=c+f+b;0<m? +(c=.5/Math.sqrt(m+1),this._w=.25/c,this._x=(k-g)*c,this._y=(d-h)*c,this._z=(e-a)*c):c>f&&c>b?(c=2*Math.sqrt(1+c-f-b),this._w=(k-g)/c,this._x=.25*c,this._y=(a+e)/c,this._z=(d+h)/c):f>b?(c=2*Math.sqrt(1+f-c-b),this._w=(d-h)/c,this._x=(a+e)/c,this._y=.25*c,this._z=(g+k)/c):(c=2*Math.sqrt(1+b-c-f),this._w=(e-a)/c,this._x=(d+h)/c,this._y=(g+k)/c,this._z=.25*c);this.onChangeCallback();return this},setFromUnitVectors:function(){var a=new p,b;return function(c,d){void 0===a&&(a=new p);b=c.dot(d)+1;1E-6>b? +(b=0,Math.abs(c.x)>Math.abs(c.z)?a.set(-c.y,c.x,0):a.set(0,-c.z,c.y)):a.crossVectors(c,d);this._x=a.x;this._y=a.y;this._z=a.z;this._w=b;return this.normalize()}}(),angleTo:function(a){return 2*Math.acos(Math.abs(S.clamp(this.dot(a),-1,1)))},rotateTowards:function(a,b){var c=this.angleTo(a);if(0===c)return this;this.slerp(a,Math.min(1,b/c));return this},inverse:function(){return this.conjugate()},conjugate:function(){this._x*=-1;this._y*=-1;this._z*=-1;this.onChangeCallback();return this},dot:function(a){return this._x* +a._x+this._y*a._y+this._z*a._z+this._w*a._w},lengthSq:function(){return this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w},length:function(){return Math.sqrt(this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w)},normalize:function(){var a=this.length();0===a?(this._z=this._y=this._x=0,this._w=1):(a=1/a,this._x*=a,this._y*=a,this._z*=a,this._w*=a);this.onChangeCallback();return this},multiply:function(a,b){return void 0!==b?(console.warn("THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead."), +this.multiplyQuaternions(a,b)):this.multiplyQuaternions(this,a)},premultiply:function(a){return this.multiplyQuaternions(a,this)},multiplyQuaternions:function(a,b){var c=a._x,d=a._y,e=a._z;a=a._w;var f=b._x,g=b._y,h=b._z;b=b._w;this._x=c*b+a*f+d*h-e*g;this._y=d*b+a*g+e*f-c*h;this._z=e*b+a*h+c*g-d*f;this._w=a*b-c*f-d*g-e*h;this.onChangeCallback();return this},slerp:function(a,b){if(0===b)return this;if(1===b)return this.copy(a);var c=this._x,d=this._y,e=this._z,f=this._w,g=f*a._w+c*a._x+d*a._y+e*a._z; +0>g?(this._w=-a._w,this._x=-a._x,this._y=-a._y,this._z=-a._z,g=-g):this.copy(a);if(1<=g)return this._w=f,this._x=c,this._y=d,this._z=e,this;a=1-g*g;if(a<=Number.EPSILON)return g=1-b,this._w=g*f+b*this._w,this._x=g*c+b*this._x,this._y=g*d+b*this._y,this._z=g*e+b*this._z,this.normalize();a=Math.sqrt(a);var h=Math.atan2(a,g);g=Math.sin((1-b)*h)/a;b=Math.sin(b*h)/a;this._w=f*g+this._w*b;this._x=c*g+this._x*b;this._y=d*g+this._y*b;this._z=e*g+this._z*b;this.onChangeCallback();return this},equals:function(a){return a._x=== +this._x&&a._y===this._y&&a._z===this._z&&a._w===this._w},fromArray:function(a,b){void 0===b&&(b=0);this._x=a[b];this._y=a[b+1];this._z=a[b+2];this._w=a[b+3];this.onChangeCallback();return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this._x;a[b+1]=this._y;a[b+2]=this._z;a[b+3]=this._w;return a},onChange:function(a){this.onChangeCallback=a;return this},onChangeCallback:function(){}});Object.assign(p.prototype,{isVector3:!0,set:function(a,b,c){this.x=a;this.y=b;this.z=c;return this}, +setScalar:function(a){this.z=this.y=this.x=a;return this},setX:function(a){this.x=a;return this},setY:function(a){this.y=a;return this},setZ:function(a){this.z=a;return this},setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b;break;case 2:this.z=b;break;default:throw Error("index is out of range: "+a);}return this},getComponent:function(a){switch(a){case 0:return this.x;case 1:return this.y;case 2:return this.z;default:throw Error("index is out of range: "+a);}},clone:function(){return new this.constructor(this.x, +this.y,this.z)},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;return this},add:function(a,b){if(void 0!==b)return console.warn("THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b);this.x+=a.x;this.y+=a.y;this.z+=a.z;return this},addScalar:function(a){this.x+=a;this.y+=a;this.z+=a;return this},addVectors:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;this.z=a.z+b.z;return this},addScaledVector:function(a,b){this.x+=a.x*b;this.y+=a.y*b;this.z+= +a.z*b;return this},sub:function(a,b){if(void 0!==b)return console.warn("THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(a,b);this.x-=a.x;this.y-=a.y;this.z-=a.z;return this},subScalar:function(a){this.x-=a;this.y-=a;this.z-=a;return this},subVectors:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;this.z=a.z-b.z;return this},multiply:function(a,b){if(void 0!==b)return console.warn("THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead."), +this.multiplyVectors(a,b);this.x*=a.x;this.y*=a.y;this.z*=a.z;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;this.z*=a;return this},multiplyVectors:function(a,b){this.x=a.x*b.x;this.y=a.y*b.y;this.z=a.z*b.z;return this},applyEuler:function(){var a=new ja;return function(b){b&&b.isEuler||console.error("THREE.Vector3: .applyEuler() now expects an Euler rotation rather than a Vector3 and order.");return this.applyQuaternion(a.setFromEuler(b))}}(),applyAxisAngle:function(){var a=new ja;return function(b, +c){return this.applyQuaternion(a.setFromAxisAngle(b,c))}}(),applyMatrix3:function(a){var b=this.x,c=this.y,d=this.z;a=a.elements;this.x=a[0]*b+a[3]*c+a[6]*d;this.y=a[1]*b+a[4]*c+a[7]*d;this.z=a[2]*b+a[5]*c+a[8]*d;return this},applyMatrix4:function(a){var b=this.x,c=this.y,d=this.z;a=a.elements;var e=1/(a[3]*b+a[7]*c+a[11]*d+a[15]);this.x=(a[0]*b+a[4]*c+a[8]*d+a[12])*e;this.y=(a[1]*b+a[5]*c+a[9]*d+a[13])*e;this.z=(a[2]*b+a[6]*c+a[10]*d+a[14])*e;return this},applyQuaternion:function(a){var b=this.x, +c=this.y,d=this.z,e=a.x,f=a.y,g=a.z;a=a.w;var h=a*b+f*d-g*c,k=a*c+g*b-e*d,m=a*d+e*c-f*b;b=-e*b-f*c-g*d;this.x=h*a+b*-e+k*-g-m*-f;this.y=k*a+b*-f+m*-e-h*-g;this.z=m*a+b*-g+h*-f-k*-e;return this},project:function(a){return this.applyMatrix4(a.matrixWorldInverse).applyMatrix4(a.projectionMatrix)},unproject:function(){var a=new P;return function(b){return this.applyMatrix4(a.getInverse(b.projectionMatrix)).applyMatrix4(b.matrixWorld)}}(),transformDirection:function(a){var b=this.x,c=this.y,d=this.z;a= +a.elements;this.x=a[0]*b+a[4]*c+a[8]*d;this.y=a[1]*b+a[5]*c+a[9]*d;this.z=a[2]*b+a[6]*c+a[10]*d;return this.normalize()},divide:function(a){this.x/=a.x;this.y/=a.y;this.z/=a.z;return this},divideScalar:function(a){return this.multiplyScalar(1/a)},min:function(a){this.x=Math.min(this.x,a.x);this.y=Math.min(this.y,a.y);this.z=Math.min(this.z,a.z);return this},max:function(a){this.x=Math.max(this.x,a.x);this.y=Math.max(this.y,a.y);this.z=Math.max(this.z,a.z);return this},clamp:function(a,b){this.x=Math.max(a.x, +Math.min(b.x,this.x));this.y=Math.max(a.y,Math.min(b.y,this.y));this.z=Math.max(a.z,Math.min(b.z,this.z));return this},clampScalar:function(){var a=new p,b=new p;return function(c,d){a.set(c,c,c);b.set(d,d,d);return this.clamp(a,b)}}(),clampLength:function(a,b){var c=this.length();return this.divideScalar(c||1).multiplyScalar(Math.max(a,Math.min(b,c)))},floor:function(){this.x=Math.floor(this.x);this.y=Math.floor(this.y);this.z=Math.floor(this.z);return this},ceil:function(){this.x=Math.ceil(this.x); +this.y=Math.ceil(this.y);this.z=Math.ceil(this.z);return this},round:function(){this.x=Math.round(this.x);this.y=Math.round(this.y);this.z=Math.round(this.z);return this},roundToZero:function(){this.x=0>this.x?Math.ceil(this.x):Math.floor(this.x);this.y=0>this.y?Math.ceil(this.y):Math.floor(this.y);this.z=0>this.z?Math.ceil(this.z):Math.floor(this.z);return this},negate:function(){this.x=-this.x;this.y=-this.y;this.z=-this.z;return this},dot:function(a){return this.x*a.x+this.y*a.y+this.z*a.z},lengthSq:function(){return this.x* +this.x+this.y*this.y+this.z*this.z},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z)},manhattanLength:function(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)},normalize:function(){return this.divideScalar(this.length()||1)},setLength:function(a){return this.normalize().multiplyScalar(a)},lerp:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;this.z+=(a.z-this.z)*b;return this},lerpVectors:function(a,b,c){return this.subVectors(b,a).multiplyScalar(c).add(a)}, +cross:function(a,b){return void 0!==b?(console.warn("THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead."),this.crossVectors(a,b)):this.crossVectors(this,a)},crossVectors:function(a,b){var c=a.x,d=a.y;a=a.z;var e=b.x,f=b.y;b=b.z;this.x=d*b-a*f;this.y=a*e-c*b;this.z=c*f-d*e;return this},projectOnVector:function(a){var b=a.dot(this)/a.lengthSq();return this.copy(a).multiplyScalar(b)},projectOnPlane:function(){var a=new p;return function(b){a.copy(this).projectOnVector(b); +return this.sub(a)}}(),reflect:function(){var a=new p;return function(b){return this.sub(a.copy(b).multiplyScalar(2*this.dot(b)))}}(),angleTo:function(a){a=this.dot(a)/Math.sqrt(this.lengthSq()*a.lengthSq());return Math.acos(S.clamp(a,-1,1))},distanceTo:function(a){return Math.sqrt(this.distanceToSquared(a))},distanceToSquared:function(a){var b=this.x-a.x,c=this.y-a.y;a=this.z-a.z;return b*b+c*c+a*a},manhattanDistanceTo:function(a){return Math.abs(this.x-a.x)+Math.abs(this.y-a.y)+Math.abs(this.z- +a.z)},setFromSpherical:function(a){return this.setFromSphericalCoords(a.radius,a.phi,a.theta)},setFromSphericalCoords:function(a,b,c){var d=Math.sin(b)*a;this.x=d*Math.sin(c);this.y=Math.cos(b)*a;this.z=d*Math.cos(c);return this},setFromCylindrical:function(a){return this.setFromCylindricalCoords(a.radius,a.theta,a.y)},setFromCylindricalCoords:function(a,b,c){this.x=a*Math.sin(b);this.y=c;this.z=a*Math.cos(b);return this},setFromMatrixPosition:function(a){a=a.elements;this.x=a[12];this.y=a[13];this.z= +a[14];return this},setFromMatrixScale:function(a){var b=this.setFromMatrixColumn(a,0).length(),c=this.setFromMatrixColumn(a,1).length();a=this.setFromMatrixColumn(a,2).length();this.x=b;this.y=c;this.z=a;return this},setFromMatrixColumn:function(a,b){return this.fromArray(a.elements,4*b)},equals:function(a){return a.x===this.x&&a.y===this.y&&a.z===this.z},fromArray:function(a,b){void 0===b&&(b=0);this.x=a[b];this.y=a[b+1];this.z=a[b+2];return this},toArray:function(a,b){void 0===a&&(a=[]);void 0=== +b&&(b=0);a[b]=this.x;a[b+1]=this.y;a[b+2]=this.z;return a},fromBufferAttribute:function(a,b,c){void 0!==c&&console.warn("THREE.Vector3: offset has been removed from .fromBufferAttribute().");this.x=a.getX(b);this.y=a.getY(b);this.z=a.getZ(b);return this}});Object.assign(oa.prototype,{isMatrix3:!0,set:function(a,b,c,d,e,f,g,h,k){var m=this.elements;m[0]=a;m[1]=d;m[2]=g;m[3]=b;m[4]=e;m[5]=h;m[6]=c;m[7]=f;m[8]=k;return this},identity:function(){this.set(1,0,0,0,1,0,0,0,1);return this},clone:function(){return(new this.constructor).fromArray(this.elements)}, +copy:function(a){var b=this.elements;a=a.elements;b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3];b[4]=a[4];b[5]=a[5];b[6]=a[6];b[7]=a[7];b[8]=a[8];return this},setFromMatrix4:function(a){a=a.elements;this.set(a[0],a[4],a[8],a[1],a[5],a[9],a[2],a[6],a[10]);return this},applyToBufferAttribute:function(){var a=new p;return function(b){for(var c=0,d=b.count;c<d;c++)a.x=b.getX(c),a.y=b.getY(c),a.z=b.getZ(c),a.applyMatrix3(this),b.setXYZ(c,a.x,a.y,a.z);return b}}(),multiply:function(a){return this.multiplyMatrices(this, +a)},premultiply:function(a){return this.multiplyMatrices(a,this)},multiplyMatrices:function(a,b){var c=a.elements,d=b.elements;b=this.elements;a=c[0];var e=c[3],f=c[6],g=c[1],h=c[4],k=c[7],m=c[2],l=c[5];c=c[8];var n=d[0],q=d[3],p=d[6],t=d[1],u=d[4],y=d[7],x=d[2],w=d[5];d=d[8];b[0]=a*n+e*t+f*x;b[3]=a*q+e*u+f*w;b[6]=a*p+e*y+f*d;b[1]=g*n+h*t+k*x;b[4]=g*q+h*u+k*w;b[7]=g*p+h*y+k*d;b[2]=m*n+l*t+c*x;b[5]=m*q+l*u+c*w;b[8]=m*p+l*y+c*d;return this},multiplyScalar:function(a){var b=this.elements;b[0]*=a;b[3]*= +a;b[6]*=a;b[1]*=a;b[4]*=a;b[7]*=a;b[2]*=a;b[5]*=a;b[8]*=a;return this},determinant:function(){var a=this.elements,b=a[0],c=a[1],d=a[2],e=a[3],f=a[4],g=a[5],h=a[6],k=a[7];a=a[8];return b*f*a-b*g*k-c*e*a+c*g*h+d*e*k-d*f*h},getInverse:function(a,b){a&&a.isMatrix4&&console.error("THREE.Matrix3: .getInverse() no longer takes a Matrix4 argument.");var c=a.elements;a=this.elements;var d=c[0],e=c[1],f=c[2],g=c[3],h=c[4],k=c[5],m=c[6],l=c[7];c=c[8];var n=c*h-k*l,q=k*m-c*g,p=l*g-h*m,t=d*n+e*q+f*p;if(0===t){if(!0=== +b)throw Error("THREE.Matrix3: .getInverse() can't invert matrix, determinant is 0");console.warn("THREE.Matrix3: .getInverse() can't invert matrix, determinant is 0");return this.identity()}b=1/t;a[0]=n*b;a[1]=(f*l-c*e)*b;a[2]=(k*e-f*h)*b;a[3]=q*b;a[4]=(c*d-f*m)*b;a[5]=(f*g-k*d)*b;a[6]=p*b;a[7]=(e*m-l*d)*b;a[8]=(h*d-e*g)*b;return this},transpose:function(){var a=this.elements;var b=a[1];a[1]=a[3];a[3]=b;b=a[2];a[2]=a[6];a[6]=b;b=a[5];a[5]=a[7];a[7]=b;return this},getNormalMatrix:function(a){return this.setFromMatrix4(a).getInverse(this).transpose()}, +transposeIntoArray:function(a){var b=this.elements;a[0]=b[0];a[1]=b[3];a[2]=b[6];a[3]=b[1];a[4]=b[4];a[5]=b[7];a[6]=b[2];a[7]=b[5];a[8]=b[8];return this},setUvTransform:function(a,b,c,d,e,f,g){var h=Math.cos(e);e=Math.sin(e);this.set(c*h,c*e,-c*(h*f+e*g)+f+a,-d*e,d*h,-d*(-e*f+h*g)+g+b,0,0,1)},scale:function(a,b){var c=this.elements;c[0]*=a;c[3]*=a;c[6]*=a;c[1]*=b;c[4]*=b;c[7]*=b;return this},rotate:function(a){var b=Math.cos(a);a=Math.sin(a);var c=this.elements,d=c[0],e=c[3],f=c[6],g=c[1],h=c[4], +k=c[7];c[0]=b*d+a*g;c[3]=b*e+a*h;c[6]=b*f+a*k;c[1]=-a*d+b*g;c[4]=-a*e+b*h;c[7]=-a*f+b*k;return this},translate:function(a,b){var c=this.elements;c[0]+=a*c[2];c[3]+=a*c[5];c[6]+=a*c[8];c[1]+=b*c[2];c[4]+=b*c[5];c[7]+=b*c[8];return this},equals:function(a){var b=this.elements;a=a.elements;for(var c=0;9>c;c++)if(b[c]!==a[c])return!1;return!0},fromArray:function(a,b){void 0===b&&(b=0);for(var c=0;9>c;c++)this.elements[c]=a[c+b];return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);var c= +this.elements;a[b]=c[0];a[b+1]=c[1];a[b+2]=c[2];a[b+3]=c[3];a[b+4]=c[4];a[b+5]=c[5];a[b+6]=c[6];a[b+7]=c[7];a[b+8]=c[8];return a}});var hb={getDataURL:function(a){if(a instanceof HTMLCanvasElement)var b=a;else{b=document.createElementNS("http://www.w3.org/1999/xhtml","canvas");b.width=a.width;b.height=a.height;var c=b.getContext("2d");a instanceof ImageData?c.putImageData(a,0,0):c.drawImage(a,0,0,a.width,a.height)}return 2048<b.width||2048<b.height?b.toDataURL("image/jpeg",.6):b.toDataURL("image/png")}}, +Gf=0;Q.DEFAULT_IMAGE=void 0;Q.DEFAULT_MAPPING=300;Q.prototype=Object.assign(Object.create(ia.prototype),{constructor:Q,isTexture:!0,updateMatrix:function(){this.matrix.setUvTransform(this.offset.x,this.offset.y,this.repeat.x,this.repeat.y,this.rotation,this.center.x,this.center.y)},clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.name=a.name;this.image=a.image;this.mipmaps=a.mipmaps.slice(0);this.mapping=a.mapping;this.wrapS=a.wrapS;this.wrapT=a.wrapT;this.magFilter= +a.magFilter;this.minFilter=a.minFilter;this.anisotropy=a.anisotropy;this.format=a.format;this.type=a.type;this.offset.copy(a.offset);this.repeat.copy(a.repeat);this.center.copy(a.center);this.rotation=a.rotation;this.matrixAutoUpdate=a.matrixAutoUpdate;this.matrix.copy(a.matrix);this.generateMipmaps=a.generateMipmaps;this.premultiplyAlpha=a.premultiplyAlpha;this.flipY=a.flipY;this.unpackAlignment=a.unpackAlignment;this.encoding=a.encoding;return this},toJSON:function(a){var b=void 0===a||"string"=== +typeof a;if(!b&&void 0!==a.textures[this.uuid])return a.textures[this.uuid];var c={metadata:{version:4.5,type:"Texture",generator:"Texture.toJSON"},uuid:this.uuid,name:this.name,mapping:this.mapping,repeat:[this.repeat.x,this.repeat.y],offset:[this.offset.x,this.offset.y],center:[this.center.x,this.center.y],rotation:this.rotation,wrap:[this.wrapS,this.wrapT],format:this.format,minFilter:this.minFilter,magFilter:this.magFilter,anisotropy:this.anisotropy,flipY:this.flipY};if(void 0!==this.image){var d= +this.image;void 0===d.uuid&&(d.uuid=S.generateUUID());if(!b&&void 0===a.images[d.uuid]){if(Array.isArray(d)){var e=[];for(var f=0,g=d.length;f<g;f++)e.push(hb.getDataURL(d[f]))}else e=hb.getDataURL(d);a.images[d.uuid]={uuid:d.uuid,url:e}}c.image=d.uuid}b||(a.textures[this.uuid]=c);return c},dispose:function(){this.dispatchEvent({type:"dispose"})},transformUv:function(a){if(300!==this.mapping)return a;a.applyMatrix3(this.matrix);if(0>a.x||1<a.x)switch(this.wrapS){case 1E3:a.x-=Math.floor(a.x);break; +case 1001:a.x=0>a.x?0:1;break;case 1002:a.x=1===Math.abs(Math.floor(a.x)%2)?Math.ceil(a.x)-a.x:a.x-Math.floor(a.x)}if(0>a.y||1<a.y)switch(this.wrapT){case 1E3:a.y-=Math.floor(a.y);break;case 1001:a.y=0>a.y?0:1;break;case 1002:a.y=1===Math.abs(Math.floor(a.y)%2)?Math.ceil(a.y)-a.y:a.y-Math.floor(a.y)}this.flipY&&(a.y=1-a.y);return a}});Object.defineProperty(Q.prototype,"needsUpdate",{set:function(a){!0===a&&this.version++}});Object.assign(Z.prototype,{isVector4:!0,set:function(a,b,c,d){this.x=a;this.y= +b;this.z=c;this.w=d;return this},setScalar:function(a){this.w=this.z=this.y=this.x=a;return this},setX:function(a){this.x=a;return this},setY:function(a){this.y=a;return this},setZ:function(a){this.z=a;return this},setW:function(a){this.w=a;return this},setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b;break;case 2:this.z=b;break;case 3:this.w=b;break;default:throw Error("index is out of range: "+a);}return this},getComponent:function(a){switch(a){case 0:return this.x;case 1:return this.y; +case 2:return this.z;case 3:return this.w;default:throw Error("index is out of range: "+a);}},clone:function(){return new this.constructor(this.x,this.y,this.z,this.w)},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;this.w=void 0!==a.w?a.w:1;return this},add:function(a,b){if(void 0!==b)return console.warn("THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b);this.x+=a.x;this.y+=a.y;this.z+=a.z;this.w+=a.w;return this},addScalar:function(a){this.x+= +a;this.y+=a;this.z+=a;this.w+=a;return this},addVectors:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;this.z=a.z+b.z;this.w=a.w+b.w;return this},addScaledVector:function(a,b){this.x+=a.x*b;this.y+=a.y*b;this.z+=a.z*b;this.w+=a.w*b;return this},sub:function(a,b){if(void 0!==b)return console.warn("THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(a,b);this.x-=a.x;this.y-=a.y;this.z-=a.z;this.w-=a.w;return this},subScalar:function(a){this.x-=a;this.y-= +a;this.z-=a;this.w-=a;return this},subVectors:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;this.z=a.z-b.z;this.w=a.w-b.w;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;this.z*=a;this.w*=a;return this},applyMatrix4:function(a){var b=this.x,c=this.y,d=this.z,e=this.w;a=a.elements;this.x=a[0]*b+a[4]*c+a[8]*d+a[12]*e;this.y=a[1]*b+a[5]*c+a[9]*d+a[13]*e;this.z=a[2]*b+a[6]*c+a[10]*d+a[14]*e;this.w=a[3]*b+a[7]*c+a[11]*d+a[15]*e;return this},divideScalar:function(a){return this.multiplyScalar(1/ +a)},setAxisAngleFromQuaternion:function(a){this.w=2*Math.acos(a.w);var b=Math.sqrt(1-a.w*a.w);1E-4>b?(this.x=1,this.z=this.y=0):(this.x=a.x/b,this.y=a.y/b,this.z=a.z/b);return this},setAxisAngleFromRotationMatrix:function(a){a=a.elements;var b=a[0];var c=a[4];var d=a[8],e=a[1],f=a[5],g=a[9];var h=a[2];var k=a[6];var m=a[10];if(.01>Math.abs(c-e)&&.01>Math.abs(d-h)&&.01>Math.abs(g-k)){if(.1>Math.abs(c+e)&&.1>Math.abs(d+h)&&.1>Math.abs(g+k)&&.1>Math.abs(b+f+m-3))return this.set(1,0,0,0),this;a=Math.PI; +b=(b+1)/2;f=(f+1)/2;m=(m+1)/2;c=(c+e)/4;d=(d+h)/4;g=(g+k)/4;b>f&&b>m?.01>b?(k=0,c=h=.707106781):(k=Math.sqrt(b),h=c/k,c=d/k):f>m?.01>f?(k=.707106781,h=0,c=.707106781):(h=Math.sqrt(f),k=c/h,c=g/h):.01>m?(h=k=.707106781,c=0):(c=Math.sqrt(m),k=d/c,h=g/c);this.set(k,h,c,a);return this}a=Math.sqrt((k-g)*(k-g)+(d-h)*(d-h)+(e-c)*(e-c));.001>Math.abs(a)&&(a=1);this.x=(k-g)/a;this.y=(d-h)/a;this.z=(e-c)/a;this.w=Math.acos((b+f+m-1)/2);return this},min:function(a){this.x=Math.min(this.x,a.x);this.y=Math.min(this.y, +a.y);this.z=Math.min(this.z,a.z);this.w=Math.min(this.w,a.w);return this},max:function(a){this.x=Math.max(this.x,a.x);this.y=Math.max(this.y,a.y);this.z=Math.max(this.z,a.z);this.w=Math.max(this.w,a.w);return this},clamp:function(a,b){this.x=Math.max(a.x,Math.min(b.x,this.x));this.y=Math.max(a.y,Math.min(b.y,this.y));this.z=Math.max(a.z,Math.min(b.z,this.z));this.w=Math.max(a.w,Math.min(b.w,this.w));return this},clampScalar:function(){var a,b;return function(c,d){void 0===a&&(a=new Z,b=new Z);a.set(c, +c,c,c);b.set(d,d,d,d);return this.clamp(a,b)}}(),clampLength:function(a,b){var c=this.length();return this.divideScalar(c||1).multiplyScalar(Math.max(a,Math.min(b,c)))},floor:function(){this.x=Math.floor(this.x);this.y=Math.floor(this.y);this.z=Math.floor(this.z);this.w=Math.floor(this.w);return this},ceil:function(){this.x=Math.ceil(this.x);this.y=Math.ceil(this.y);this.z=Math.ceil(this.z);this.w=Math.ceil(this.w);return this},round:function(){this.x=Math.round(this.x);this.y=Math.round(this.y); +this.z=Math.round(this.z);this.w=Math.round(this.w);return this},roundToZero:function(){this.x=0>this.x?Math.ceil(this.x):Math.floor(this.x);this.y=0>this.y?Math.ceil(this.y):Math.floor(this.y);this.z=0>this.z?Math.ceil(this.z):Math.floor(this.z);this.w=0>this.w?Math.ceil(this.w):Math.floor(this.w);return this},negate:function(){this.x=-this.x;this.y=-this.y;this.z=-this.z;this.w=-this.w;return this},dot:function(a){return this.x*a.x+this.y*a.y+this.z*a.z+this.w*a.w},lengthSq:function(){return this.x* +this.x+this.y*this.y+this.z*this.z+this.w*this.w},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w)},manhattanLength:function(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)+Math.abs(this.w)},normalize:function(){return this.divideScalar(this.length()||1)},setLength:function(a){return this.normalize().multiplyScalar(a)},lerp:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;this.z+=(a.z-this.z)*b;this.w+=(a.w-this.w)*b;return this},lerpVectors:function(a, +b,c){return this.subVectors(b,a).multiplyScalar(c).add(a)},equals:function(a){return a.x===this.x&&a.y===this.y&&a.z===this.z&&a.w===this.w},fromArray:function(a,b){void 0===b&&(b=0);this.x=a[b];this.y=a[b+1];this.z=a[b+2];this.w=a[b+3];return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this.x;a[b+1]=this.y;a[b+2]=this.z;a[b+3]=this.w;return a},fromBufferAttribute:function(a,b,c){void 0!==c&&console.warn("THREE.Vector4: offset has been removed from .fromBufferAttribute()."); +this.x=a.getX(b);this.y=a.getY(b);this.z=a.getZ(b);this.w=a.getW(b);return this}});ib.prototype=Object.assign(Object.create(ia.prototype),{constructor:ib,isWebGLRenderTarget:!0,setSize:function(a,b){if(this.width!==a||this.height!==b)this.width=a,this.height=b,this.dispose();this.viewport.set(0,0,a,b);this.scissor.set(0,0,a,b)},clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.width=a.width;this.height=a.height;this.viewport.copy(a.viewport);this.texture=a.texture.clone(); +this.depthBuffer=a.depthBuffer;this.stencilBuffer=a.stencilBuffer;this.depthTexture=a.depthTexture;return this},dispose:function(){this.dispatchEvent({type:"dispose"})}});Jb.prototype=Object.create(ib.prototype);Jb.prototype.constructor=Jb;Jb.prototype.isWebGLRenderTargetCube=!0;jb.prototype=Object.create(Q.prototype);jb.prototype.constructor=jb;jb.prototype.isDataTexture=!0;Object.assign(Wa.prototype,{isBox3:!0,set:function(a,b){this.min.copy(a);this.max.copy(b);return this},setFromArray:function(a){for(var b= +Infinity,c=Infinity,d=Infinity,e=-Infinity,f=-Infinity,g=-Infinity,h=0,k=a.length;h<k;h+=3){var m=a[h],l=a[h+1],n=a[h+2];m<b&&(b=m);l<c&&(c=l);n<d&&(d=n);m>e&&(e=m);l>f&&(f=l);n>g&&(g=n)}this.min.set(b,c,d);this.max.set(e,f,g);return this},setFromBufferAttribute:function(a){for(var b=Infinity,c=Infinity,d=Infinity,e=-Infinity,f=-Infinity,g=-Infinity,h=0,k=a.count;h<k;h++){var m=a.getX(h),l=a.getY(h),n=a.getZ(h);m<b&&(b=m);l<c&&(c=l);n<d&&(d=n);m>e&&(e=m);l>f&&(f=l);n>g&&(g=n)}this.min.set(b,c,d); +this.max.set(e,f,g);return this},setFromPoints:function(a){this.makeEmpty();for(var b=0,c=a.length;b<c;b++)this.expandByPoint(a[b]);return this},setFromCenterAndSize:function(){var a=new p;return function(b,c){c=a.copy(c).multiplyScalar(.5);this.min.copy(b).sub(c);this.max.copy(b).add(c);return this}}(),setFromObject:function(a){this.makeEmpty();return this.expandByObject(a)},clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.min.copy(a.min);this.max.copy(a.max);return this}, +makeEmpty:function(){this.min.x=this.min.y=this.min.z=Infinity;this.max.x=this.max.y=this.max.z=-Infinity;return this},isEmpty:function(){return this.max.x<this.min.x||this.max.y<this.min.y||this.max.z<this.min.z},getCenter:function(a){void 0===a&&(console.warn("THREE.Box3: .getCenter() target is now required"),a=new p);return this.isEmpty()?a.set(0,0,0):a.addVectors(this.min,this.max).multiplyScalar(.5)},getSize:function(a){void 0===a&&(console.warn("THREE.Box3: .getSize() target is now required"), +a=new p);return this.isEmpty()?a.set(0,0,0):a.subVectors(this.max,this.min)},expandByPoint:function(a){this.min.min(a);this.max.max(a);return this},expandByVector:function(a){this.min.sub(a);this.max.add(a);return this},expandByScalar:function(a){this.min.addScalar(-a);this.max.addScalar(a);return this},expandByObject:function(){function a(a){var f=a.geometry;if(void 0!==f)if(f.isGeometry)for(f=f.vertices,c=0,d=f.length;c<d;c++)e.copy(f[c]),e.applyMatrix4(a.matrixWorld),b.expandByPoint(e);else if(f.isBufferGeometry&& +(f=f.attributes.position,void 0!==f))for(c=0,d=f.count;c<d;c++)e.fromBufferAttribute(f,c).applyMatrix4(a.matrixWorld),b.expandByPoint(e)}var b,c,d,e=new p;return function(c){b=this;c.updateMatrixWorld(!0);c.traverse(a);return this}}(),containsPoint:function(a){return a.x<this.min.x||a.x>this.max.x||a.y<this.min.y||a.y>this.max.y||a.z<this.min.z||a.z>this.max.z?!1:!0},containsBox:function(a){return this.min.x<=a.min.x&&a.max.x<=this.max.x&&this.min.y<=a.min.y&&a.max.y<=this.max.y&&this.min.z<=a.min.z&& +a.max.z<=this.max.z},getParameter:function(a,b){void 0===b&&(console.warn("THREE.Box3: .getParameter() target is now required"),b=new p);return b.set((a.x-this.min.x)/(this.max.x-this.min.x),(a.y-this.min.y)/(this.max.y-this.min.y),(a.z-this.min.z)/(this.max.z-this.min.z))},intersectsBox:function(a){return a.max.x<this.min.x||a.min.x>this.max.x||a.max.y<this.min.y||a.min.y>this.max.y||a.max.z<this.min.z||a.min.z>this.max.z?!1:!0},intersectsSphere:function(){var a=new p;return function(b){this.clampPoint(b.center, +a);return a.distanceToSquared(b.center)<=b.radius*b.radius}}(),intersectsPlane:function(a){if(0<a.normal.x){var b=a.normal.x*this.min.x;var c=a.normal.x*this.max.x}else b=a.normal.x*this.max.x,c=a.normal.x*this.min.x;0<a.normal.y?(b+=a.normal.y*this.min.y,c+=a.normal.y*this.max.y):(b+=a.normal.y*this.max.y,c+=a.normal.y*this.min.y);0<a.normal.z?(b+=a.normal.z*this.min.z,c+=a.normal.z*this.max.z):(b+=a.normal.z*this.max.z,c+=a.normal.z*this.min.z);return b<=-a.constant&&c>=-a.constant},intersectsTriangle:function(){function a(a){var e; +var f=0;for(e=a.length-3;f<=e;f+=3){h.fromArray(a,f);var g=m.x*Math.abs(h.x)+m.y*Math.abs(h.y)+m.z*Math.abs(h.z),k=b.dot(h),l=c.dot(h),n=d.dot(h);if(Math.max(-Math.max(k,l,n),Math.min(k,l,n))>g)return!1}return!0}var b=new p,c=new p,d=new p,e=new p,f=new p,g=new p,h=new p,k=new p,m=new p,l=new p;return function(h){if(this.isEmpty())return!1;this.getCenter(k);m.subVectors(this.max,k);b.subVectors(h.a,k);c.subVectors(h.b,k);d.subVectors(h.c,k);e.subVectors(c,b);f.subVectors(d,c);g.subVectors(b,d);h= +[0,-e.z,e.y,0,-f.z,f.y,0,-g.z,g.y,e.z,0,-e.x,f.z,0,-f.x,g.z,0,-g.x,-e.y,e.x,0,-f.y,f.x,0,-g.y,g.x,0];if(!a(h))return!1;h=[1,0,0,0,1,0,0,0,1];if(!a(h))return!1;l.crossVectors(e,f);h=[l.x,l.y,l.z];return a(h)}}(),clampPoint:function(a,b){void 0===b&&(console.warn("THREE.Box3: .clampPoint() target is now required"),b=new p);return b.copy(a).clamp(this.min,this.max)},distanceToPoint:function(){var a=new p;return function(b){return a.copy(b).clamp(this.min,this.max).sub(b).length()}}(),getBoundingSphere:function(){var a= +new p;return function(b){void 0===b&&(console.warn("THREE.Box3: .getBoundingSphere() target is now required"),b=new Fa);this.getCenter(b.center);b.radius=.5*this.getSize(a).length();return b}}(),intersect:function(a){this.min.max(a.min);this.max.min(a.max);this.isEmpty()&&this.makeEmpty();return this},union:function(a){this.min.min(a.min);this.max.max(a.max);return this},applyMatrix4:function(){var a=[new p,new p,new p,new p,new p,new p,new p,new p];return function(b){if(this.isEmpty())return this; +a[0].set(this.min.x,this.min.y,this.min.z).applyMatrix4(b);a[1].set(this.min.x,this.min.y,this.max.z).applyMatrix4(b);a[2].set(this.min.x,this.max.y,this.min.z).applyMatrix4(b);a[3].set(this.min.x,this.max.y,this.max.z).applyMatrix4(b);a[4].set(this.max.x,this.min.y,this.min.z).applyMatrix4(b);a[5].set(this.max.x,this.min.y,this.max.z).applyMatrix4(b);a[6].set(this.max.x,this.max.y,this.min.z).applyMatrix4(b);a[7].set(this.max.x,this.max.y,this.max.z).applyMatrix4(b);this.setFromPoints(a);return this}}(), +translate:function(a){this.min.add(a);this.max.add(a);return this},equals:function(a){return a.min.equals(this.min)&&a.max.equals(this.max)}});Object.assign(Fa.prototype,{set:function(a,b){this.center.copy(a);this.radius=b;return this},setFromPoints:function(){var a=new Wa;return function(b,c){var d=this.center;void 0!==c?d.copy(c):a.setFromPoints(b).getCenter(d);for(var e=c=0,f=b.length;e<f;e++)c=Math.max(c,d.distanceToSquared(b[e]));this.radius=Math.sqrt(c);return this}}(),clone:function(){return(new this.constructor).copy(this)}, +copy:function(a){this.center.copy(a.center);this.radius=a.radius;return this},empty:function(){return 0>=this.radius},containsPoint:function(a){return a.distanceToSquared(this.center)<=this.radius*this.radius},distanceToPoint:function(a){return a.distanceTo(this.center)-this.radius},intersectsSphere:function(a){var b=this.radius+a.radius;return a.center.distanceToSquared(this.center)<=b*b},intersectsBox:function(a){return a.intersectsSphere(this)},intersectsPlane:function(a){return Math.abs(a.distanceToPoint(this.center))<= +this.radius},clampPoint:function(a,b){var c=this.center.distanceToSquared(a);void 0===b&&(console.warn("THREE.Sphere: .clampPoint() target is now required"),b=new p);b.copy(a);c>this.radius*this.radius&&(b.sub(this.center).normalize(),b.multiplyScalar(this.radius).add(this.center));return b},getBoundingBox:function(a){void 0===a&&(console.warn("THREE.Sphere: .getBoundingBox() target is now required"),a=new Wa);a.set(this.center,this.center);a.expandByScalar(this.radius);return a},applyMatrix4:function(a){this.center.applyMatrix4(a); +this.radius*=a.getMaxScaleOnAxis();return this},translate:function(a){this.center.add(a);return this},equals:function(a){return a.center.equals(this.center)&&a.radius===this.radius}});Object.assign(Pa.prototype,{set:function(a,b){this.normal.copy(a);this.constant=b;return this},setComponents:function(a,b,c,d){this.normal.set(a,b,c);this.constant=d;return this},setFromNormalAndCoplanarPoint:function(a,b){this.normal.copy(a);this.constant=-b.dot(this.normal);return this},setFromCoplanarPoints:function(){var a= +new p,b=new p;return function(c,d,e){d=a.subVectors(e,d).cross(b.subVectors(c,d)).normalize();this.setFromNormalAndCoplanarPoint(d,c);return this}}(),clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.normal.copy(a.normal);this.constant=a.constant;return this},normalize:function(){var a=1/this.normal.length();this.normal.multiplyScalar(a);this.constant*=a;return this},negate:function(){this.constant*=-1;this.normal.negate();return this},distanceToPoint:function(a){return this.normal.dot(a)+ +this.constant},distanceToSphere:function(a){return this.distanceToPoint(a.center)-a.radius},projectPoint:function(a,b){void 0===b&&(console.warn("THREE.Plane: .projectPoint() target is now required"),b=new p);return b.copy(this.normal).multiplyScalar(-this.distanceToPoint(a)).add(a)},intersectLine:function(){var a=new p;return function(b,c){void 0===c&&(console.warn("THREE.Plane: .intersectLine() target is now required"),c=new p);var d=b.delta(a),e=this.normal.dot(d);if(0===e){if(0===this.distanceToPoint(b.start))return c.copy(b.start)}else if(e= +-(b.start.dot(this.normal)+this.constant)/e,!(0>e||1<e))return c.copy(d).multiplyScalar(e).add(b.start)}}(),intersectsLine:function(a){var b=this.distanceToPoint(a.start);a=this.distanceToPoint(a.end);return 0>b&&0<a||0>a&&0<b},intersectsBox:function(a){return a.intersectsPlane(this)},intersectsSphere:function(a){return a.intersectsPlane(this)},coplanarPoint:function(a){void 0===a&&(console.warn("THREE.Plane: .coplanarPoint() target is now required"),a=new p);return a.copy(this.normal).multiplyScalar(-this.constant)}, +applyMatrix4:function(){var a=new p,b=new oa;return function(c,d){d=d||b.getNormalMatrix(c);c=this.coplanarPoint(a).applyMatrix4(c);d=this.normal.applyMatrix3(d).normalize();this.constant=-c.dot(d);return this}}(),translate:function(a){this.constant-=a.dot(this.normal);return this},equals:function(a){return a.normal.equals(this.normal)&&a.constant===this.constant}});Object.assign(rd.prototype,{set:function(a,b,c,d,e,f){var g=this.planes;g[0].copy(a);g[1].copy(b);g[2].copy(c);g[3].copy(d);g[4].copy(e); +g[5].copy(f);return this},clone:function(){return(new this.constructor).copy(this)},copy:function(a){for(var b=this.planes,c=0;6>c;c++)b[c].copy(a.planes[c]);return this},setFromMatrix:function(a){var b=this.planes,c=a.elements;a=c[0];var d=c[1],e=c[2],f=c[3],g=c[4],h=c[5],k=c[6],m=c[7],l=c[8],n=c[9],q=c[10],p=c[11],t=c[12],u=c[13],y=c[14];c=c[15];b[0].setComponents(f-a,m-g,p-l,c-t).normalize();b[1].setComponents(f+a,m+g,p+l,c+t).normalize();b[2].setComponents(f+d,m+h,p+n,c+u).normalize();b[3].setComponents(f- +d,m-h,p-n,c-u).normalize();b[4].setComponents(f-e,m-k,p-q,c-y).normalize();b[5].setComponents(f+e,m+k,p+q,c+y).normalize();return this},intersectsObject:function(){var a=new Fa;return function(b){var c=b.geometry;null===c.boundingSphere&&c.computeBoundingSphere();a.copy(c.boundingSphere).applyMatrix4(b.matrixWorld);return this.intersectsSphere(a)}}(),intersectsSprite:function(){var a=new Fa;return function(b){a.center.set(0,0,0);a.radius=.7071067811865476;a.applyMatrix4(b.matrixWorld);return this.intersectsSphere(a)}}(), +intersectsSphere:function(a){var b=this.planes,c=a.center;a=-a.radius;for(var d=0;6>d;d++)if(b[d].distanceToPoint(c)<a)return!1;return!0},intersectsBox:function(){var a=new p;return function(b){for(var c=this.planes,d=0;6>d;d++){var e=c[d];a.x=0<e.normal.x?b.max.x:b.min.x;a.y=0<e.normal.y?b.max.y:b.min.y;a.z=0<e.normal.z?b.max.z:b.min.z;if(0>e.distanceToPoint(a))return!1}return!0}}(),containsPoint:function(a){for(var b=this.planes,c=0;6>c;c++)if(0>b[c].distanceToPoint(a))return!1;return!0}});var K= +{alphamap_fragment:"#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vUv ).g;\n#endif\n",alphamap_pars_fragment:"#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif\n",alphatest_fragment:"#ifdef ALPHATEST\n\tif ( diffuseColor.a < ALPHATEST ) discard;\n#endif\n",aomap_fragment:"#ifdef USE_AOMAP\n\tfloat ambientOcclusion = ( texture2D( aoMap, vUv2 ).r - 1.0 ) * aoMapIntensity + 1.0;\n\treflectedLight.indirectDiffuse *= ambientOcclusion;\n\t#if defined( USE_ENVMAP ) && defined( PHYSICAL )\n\t\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\t\treflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.specularRoughness );\n\t#endif\n#endif\n", +aomap_pars_fragment:"#ifdef USE_AOMAP\n\tuniform sampler2D aoMap;\n\tuniform float aoMapIntensity;\n#endif",begin_vertex:"\nvec3 transformed = vec3( position );\n",beginnormal_vertex:"\nvec3 objectNormal = vec3( normal );\n",bsdfs:"float punctualLightIntensityToIrradianceFactor( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\n#if defined ( PHYSICALLY_CORRECT_LIGHTS )\n\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\tif( cutoffDistance > 0.0 ) {\n\t\tdistanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t}\n\treturn distanceFalloff;\n#else\n\tif( cutoffDistance > 0.0 ) {\n\t\treturn pow( saturate( -lightDistance / cutoffDistance + 1.0 ), decayExponent );\n\t}\n\treturn 1.0;\n#endif\n}\nvec3 BRDF_Diffuse_Lambert( const in vec3 diffuseColor ) {\n\treturn RECIPROCAL_PI * diffuseColor;\n}\nvec3 F_Schlick( const in vec3 specularColor, const in float dotLH ) {\n\tfloat fresnel = exp2( ( -5.55473 * dotLH - 6.98316 ) * dotLH );\n\treturn ( 1.0 - specularColor ) * fresnel + specularColor;\n}\nfloat G_GGX_Smith( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gl = dotNL + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\tfloat gv = dotNV + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\treturn 1.0 / ( gl * gv );\n}\nfloat G_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\treturn 0.5 / max( gv + gl, EPSILON );\n}\nfloat D_GGX( const in float alpha, const in float dotNH ) {\n\tfloat a2 = pow2( alpha );\n\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;\n\treturn RECIPROCAL_PI * a2 / pow2( denom );\n}\nvec3 BRDF_Specular_GGX( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) {\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\n\tfloat dotNL = saturate( dot( geometry.normal, incidentLight.direction ) );\n\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\tfloat G = G_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\tfloat D = D_GGX( alpha, dotNH );\n\treturn F * ( G * D );\n}\nvec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) {\n\tconst float LUT_SIZE = 64.0;\n\tconst float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE;\n\tconst float LUT_BIAS = 0.5 / LUT_SIZE;\n\tfloat dotNV = saturate( dot( N, V ) );\n\tvec2 uv = vec2( roughness, sqrt( 1.0 - dotNV ) );\n\tuv = uv * LUT_SCALE + LUT_BIAS;\n\treturn uv;\n}\nfloat LTC_ClippedSphereFormFactor( const in vec3 f ) {\n\tfloat l = length( f );\n\treturn max( ( l * l + f.z ) / ( l + 1.0 ), 0.0 );\n}\nvec3 LTC_EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) {\n\tfloat x = dot( v1, v2 );\n\tfloat y = abs( x );\n\tfloat a = 0.8543985 + ( 0.4965155 + 0.0145206 * y ) * y;\n\tfloat b = 3.4175940 + ( 4.1616724 + y ) * y;\n\tfloat v = a / b;\n\tfloat theta_sintheta = ( x > 0.0 ) ? v : 0.5 * inversesqrt( max( 1.0 - x * x, 1e-7 ) ) - v;\n\treturn cross( v1, v2 ) * theta_sintheta;\n}\nvec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) {\n\tvec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ];\n\tvec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ];\n\tvec3 lightNormal = cross( v1, v2 );\n\tif( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 );\n\tvec3 T1, T2;\n\tT1 = normalize( V - N * dot( V, N ) );\n\tT2 = - cross( N, T1 );\n\tmat3 mat = mInv * transposeMat3( mat3( T1, T2, N ) );\n\tvec3 coords[ 4 ];\n\tcoords[ 0 ] = mat * ( rectCoords[ 0 ] - P );\n\tcoords[ 1 ] = mat * ( rectCoords[ 1 ] - P );\n\tcoords[ 2 ] = mat * ( rectCoords[ 2 ] - P );\n\tcoords[ 3 ] = mat * ( rectCoords[ 3 ] - P );\n\tcoords[ 0 ] = normalize( coords[ 0 ] );\n\tcoords[ 1 ] = normalize( coords[ 1 ] );\n\tcoords[ 2 ] = normalize( coords[ 2 ] );\n\tcoords[ 3 ] = normalize( coords[ 3 ] );\n\tvec3 vectorFormFactor = vec3( 0.0 );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] );\n\tfloat result = LTC_ClippedSphereFormFactor( vectorFormFactor );\n\treturn vec3( result );\n}\nvec3 BRDF_Specular_GGX_Environment( const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) {\n\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\tconst vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );\n\tconst vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 );\n\tvec4 r = roughness * c0 + c1;\n\tfloat a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y;\n\tvec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;\n\treturn specularColor * AB.x + AB.y;\n}\nfloat G_BlinnPhong_Implicit( ) {\n\treturn 0.25;\n}\nfloat D_BlinnPhong( const in float shininess, const in float dotNH ) {\n\treturn RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );\n}\nvec3 BRDF_Specular_BlinnPhong( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float shininess ) {\n\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\n\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\tfloat G = G_BlinnPhong_Implicit( );\n\tfloat D = D_BlinnPhong( shininess, dotNH );\n\treturn F * ( G * D );\n}\nfloat GGXRoughnessToBlinnExponent( const in float ggxRoughness ) {\n\treturn ( 2.0 / pow2( ggxRoughness + 0.0001 ) - 2.0 );\n}\nfloat BlinnExponentToGGXRoughness( const in float blinnExponent ) {\n\treturn sqrt( 2.0 / ( blinnExponent + 2.0 ) );\n}\n", +bumpmap_pars_fragment:"#ifdef USE_BUMPMAP\n\tuniform sampler2D bumpMap;\n\tuniform float bumpScale;\n\tvec2 dHdxy_fwd() {\n\t\tvec2 dSTdx = dFdx( vUv );\n\t\tvec2 dSTdy = dFdy( vUv );\n\t\tfloat Hll = bumpScale * texture2D( bumpMap, vUv ).x;\n\t\tfloat dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;\n\t\tfloat dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;\n\t\treturn vec2( dBx, dBy );\n\t}\n\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {\n\t\tvec3 vSigmaX = vec3( dFdx( surf_pos.x ), dFdx( surf_pos.y ), dFdx( surf_pos.z ) );\n\t\tvec3 vSigmaY = vec3( dFdy( surf_pos.x ), dFdy( surf_pos.y ), dFdy( surf_pos.z ) );\n\t\tvec3 vN = surf_norm;\n\t\tvec3 R1 = cross( vSigmaY, vN );\n\t\tvec3 R2 = cross( vN, vSigmaX );\n\t\tfloat fDet = dot( vSigmaX, R1 );\n\t\tfDet *= ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n\t\treturn normalize( abs( fDet ) * surf_norm - vGrad );\n\t}\n#endif\n", +clipping_planes_fragment:"#if NUM_CLIPPING_PLANES > 0\n\tvec4 plane;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) {\n\t\tplane = clippingPlanes[ i ];\n\t\tif ( dot( vViewPosition, plane.xyz ) > plane.w ) discard;\n\t}\n\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\tbool clipped = true;\n\t\t#pragma unroll_loop\n\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) {\n\t\t\tplane = clippingPlanes[ i ];\n\t\t\tclipped = ( dot( vViewPosition, plane.xyz ) > plane.w ) && clipped;\n\t\t}\n\t\tif ( clipped ) discard;\n\t#endif\n#endif\n", +clipping_planes_pars_fragment:"#if NUM_CLIPPING_PLANES > 0\n\t#if ! defined( PHYSICAL ) && ! defined( PHONG ) && ! defined( MATCAP )\n\t\tvarying vec3 vViewPosition;\n\t#endif\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\n#endif\n",clipping_planes_pars_vertex:"#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG ) && ! defined( MATCAP )\n\tvarying vec3 vViewPosition;\n#endif\n",clipping_planes_vertex:"#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG ) && ! defined( MATCAP )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n", +color_fragment:"#ifdef USE_COLOR\n\tdiffuseColor.rgb *= vColor;\n#endif",color_pars_fragment:"#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif\n",color_pars_vertex:"#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif",color_vertex:"#ifdef USE_COLOR\n\tvColor.xyz = color.xyz;\n#endif",common:"#define PI 3.14159265359\n#define PI2 6.28318530718\n#define PI_HALF 1.5707963267949\n#define RECIPROCAL_PI 0.31830988618\n#define RECIPROCAL_PI2 0.15915494\n#define LOG2 1.442695\n#define EPSILON 1e-6\n#define saturate(a) clamp( a, 0.0, 1.0 )\n#define whiteCompliment(a) ( 1.0 - saturate( a ) )\nfloat pow2( const in float x ) { return x*x; }\nfloat pow3( const in float x ) { return x*x*x; }\nfloat pow4( const in float x ) { float x2 = x*x; return x2*x2; }\nfloat average( const in vec3 color ) { return dot( color, vec3( 0.3333 ) ); }\nhighp float rand( const in vec2 uv ) {\n\tconst highp float a = 12.9898, b = 78.233, c = 43758.5453;\n\thighp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );\n\treturn fract(sin(sn) * c);\n}\nstruct IncidentLight {\n\tvec3 color;\n\tvec3 direction;\n\tbool visible;\n};\nstruct ReflectedLight {\n\tvec3 directDiffuse;\n\tvec3 directSpecular;\n\tvec3 indirectDiffuse;\n\tvec3 indirectSpecular;\n};\nstruct GeometricContext {\n\tvec3 position;\n\tvec3 normal;\n\tvec3 viewDir;\n};\nvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n}\nvec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );\n}\nvec3 projectOnPlane(in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\tfloat distance = dot( planeNormal, point - pointOnPlane );\n\treturn - distance * planeNormal + point;\n}\nfloat sideOfPlane( in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\treturn sign( dot( point - pointOnPlane, planeNormal ) );\n}\nvec3 linePlaneIntersect( in vec3 pointOnLine, in vec3 lineDirection, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\treturn lineDirection * ( dot( planeNormal, pointOnPlane - pointOnLine ) / dot( planeNormal, lineDirection ) ) + pointOnLine;\n}\nmat3 transposeMat3( const in mat3 m ) {\n\tmat3 tmp;\n\ttmp[ 0 ] = vec3( m[ 0 ].x, m[ 1 ].x, m[ 2 ].x );\n\ttmp[ 1 ] = vec3( m[ 0 ].y, m[ 1 ].y, m[ 2 ].y );\n\ttmp[ 2 ] = vec3( m[ 0 ].z, m[ 1 ].z, m[ 2 ].z );\n\treturn tmp;\n}\nfloat linearToRelativeLuminance( const in vec3 color ) {\n\tvec3 weights = vec3( 0.2126, 0.7152, 0.0722 );\n\treturn dot( weights, color.rgb );\n}\n", +cube_uv_reflection_fragment:"#ifdef ENVMAP_TYPE_CUBE_UV\n#define cubeUV_textureSize (1024.0)\nint getFaceFromDirection(vec3 direction) {\n\tvec3 absDirection = abs(direction);\n\tint face = -1;\n\tif( absDirection.x > absDirection.z ) {\n\t\tif(absDirection.x > absDirection.y )\n\t\t\tface = direction.x > 0.0 ? 0 : 3;\n\t\telse\n\t\t\tface = direction.y > 0.0 ? 1 : 4;\n\t}\n\telse {\n\t\tif(absDirection.z > absDirection.y )\n\t\t\tface = direction.z > 0.0 ? 2 : 5;\n\t\telse\n\t\t\tface = direction.y > 0.0 ? 1 : 4;\n\t}\n\treturn face;\n}\n#define cubeUV_maxLods1 (log2(cubeUV_textureSize*0.25) - 1.0)\n#define cubeUV_rangeClamp (exp2((6.0 - 1.0) * 2.0))\nvec2 MipLevelInfo( vec3 vec, float roughnessLevel, float roughness ) {\n\tfloat scale = exp2(cubeUV_maxLods1 - roughnessLevel);\n\tfloat dxRoughness = dFdx(roughness);\n\tfloat dyRoughness = dFdy(roughness);\n\tvec3 dx = dFdx( vec * scale * dxRoughness );\n\tvec3 dy = dFdy( vec * scale * dyRoughness );\n\tfloat d = max( dot( dx, dx ), dot( dy, dy ) );\n\td = clamp(d, 1.0, cubeUV_rangeClamp);\n\tfloat mipLevel = 0.5 * log2(d);\n\treturn vec2(floor(mipLevel), fract(mipLevel));\n}\n#define cubeUV_maxLods2 (log2(cubeUV_textureSize*0.25) - 2.0)\n#define cubeUV_rcpTextureSize (1.0 / cubeUV_textureSize)\nvec2 getCubeUV(vec3 direction, float roughnessLevel, float mipLevel) {\n\tmipLevel = roughnessLevel > cubeUV_maxLods2 - 3.0 ? 0.0 : mipLevel;\n\tfloat a = 16.0 * cubeUV_rcpTextureSize;\n\tvec2 exp2_packed = exp2( vec2( roughnessLevel, mipLevel ) );\n\tvec2 rcp_exp2_packed = vec2( 1.0 ) / exp2_packed;\n\tfloat powScale = exp2_packed.x * exp2_packed.y;\n\tfloat scale = rcp_exp2_packed.x * rcp_exp2_packed.y * 0.25;\n\tfloat mipOffset = 0.75*(1.0 - rcp_exp2_packed.y) * rcp_exp2_packed.x;\n\tbool bRes = mipLevel == 0.0;\n\tscale = bRes && (scale < a) ? a : scale;\n\tvec3 r;\n\tvec2 offset;\n\tint face = getFaceFromDirection(direction);\n\tfloat rcpPowScale = 1.0 / powScale;\n\tif( face == 0) {\n\t\tr = vec3(direction.x, -direction.z, direction.y);\n\t\toffset = vec2(0.0+mipOffset,0.75 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\n\t}\n\telse if( face == 1) {\n\t\tr = vec3(direction.y, direction.x, direction.z);\n\t\toffset = vec2(scale+mipOffset, 0.75 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\n\t}\n\telse if( face == 2) {\n\t\tr = vec3(direction.z, direction.x, direction.y);\n\t\toffset = vec2(2.0*scale+mipOffset, 0.75 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\n\t}\n\telse if( face == 3) {\n\t\tr = vec3(direction.x, direction.z, direction.y);\n\t\toffset = vec2(0.0+mipOffset,0.5 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\n\t}\n\telse if( face == 4) {\n\t\tr = vec3(direction.y, direction.x, -direction.z);\n\t\toffset = vec2(scale+mipOffset, 0.5 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\n\t}\n\telse {\n\t\tr = vec3(direction.z, -direction.x, direction.y);\n\t\toffset = vec2(2.0*scale+mipOffset, 0.5 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\n\t}\n\tr = normalize(r);\n\tfloat texelOffset = 0.5 * cubeUV_rcpTextureSize;\n\tvec2 s = ( r.yz / abs( r.x ) + vec2( 1.0 ) ) * 0.5;\n\tvec2 base = offset + vec2( texelOffset );\n\treturn base + s * ( scale - 2.0 * texelOffset );\n}\n#define cubeUV_maxLods3 (log2(cubeUV_textureSize*0.25) - 3.0)\nvec4 textureCubeUV( sampler2D envMap, vec3 reflectedDirection, float roughness ) {\n\tfloat roughnessVal = roughness* cubeUV_maxLods3;\n\tfloat r1 = floor(roughnessVal);\n\tfloat r2 = r1 + 1.0;\n\tfloat t = fract(roughnessVal);\n\tvec2 mipInfo = MipLevelInfo(reflectedDirection, r1, roughness);\n\tfloat s = mipInfo.y;\n\tfloat level0 = mipInfo.x;\n\tfloat level1 = level0 + 1.0;\n\tlevel1 = level1 > 5.0 ? 5.0 : level1;\n\tlevel0 += min( floor( s + 0.5 ), 5.0 );\n\tvec2 uv_10 = getCubeUV(reflectedDirection, r1, level0);\n\tvec4 color10 = envMapTexelToLinear(texture2D(envMap, uv_10));\n\tvec2 uv_20 = getCubeUV(reflectedDirection, r2, level0);\n\tvec4 color20 = envMapTexelToLinear(texture2D(envMap, uv_20));\n\tvec4 result = mix(color10, color20, t);\n\treturn vec4(result.rgb, 1.0);\n}\n#endif\n", +defaultnormal_vertex:"vec3 transformedNormal = normalMatrix * objectNormal;\n#ifdef FLIP_SIDED\n\ttransformedNormal = - transformedNormal;\n#endif\n",displacementmap_pars_vertex:"#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif\n",displacementmap_vertex:"#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, uv ).x * displacementScale + displacementBias );\n#endif\n", +emissivemap_fragment:"#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vUv );\n\temissiveColor.rgb = emissiveMapTexelToLinear( emissiveColor ).rgb;\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif\n",emissivemap_pars_fragment:"#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif\n",encodings_fragment:" gl_FragColor = linearToOutputTexel( gl_FragColor );\n",encodings_pars_fragment:"\nvec4 LinearToLinear( in vec4 value ) {\n\treturn value;\n}\nvec4 GammaToLinear( in vec4 value, in float gammaFactor ) {\n\treturn vec4( pow( value.rgb, vec3( gammaFactor ) ), value.a );\n}\nvec4 LinearToGamma( in vec4 value, in float gammaFactor ) {\n\treturn vec4( pow( value.rgb, vec3( 1.0 / gammaFactor ) ), value.a );\n}\nvec4 sRGBToLinear( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.a );\n}\nvec4 LinearTosRGB( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a );\n}\nvec4 RGBEToLinear( in vec4 value ) {\n\treturn vec4( value.rgb * exp2( value.a * 255.0 - 128.0 ), 1.0 );\n}\nvec4 LinearToRGBE( in vec4 value ) {\n\tfloat maxComponent = max( max( value.r, value.g ), value.b );\n\tfloat fExp = clamp( ceil( log2( maxComponent ) ), -128.0, 127.0 );\n\treturn vec4( value.rgb / exp2( fExp ), ( fExp + 128.0 ) / 255.0 );\n}\nvec4 RGBMToLinear( in vec4 value, in float maxRange ) {\n\treturn vec4( value.rgb * value.a * maxRange, 1.0 );\n}\nvec4 LinearToRGBM( in vec4 value, in float maxRange ) {\n\tfloat maxRGB = max( value.r, max( value.g, value.b ) );\n\tfloat M = clamp( maxRGB / maxRange, 0.0, 1.0 );\n\tM = ceil( M * 255.0 ) / 255.0;\n\treturn vec4( value.rgb / ( M * maxRange ), M );\n}\nvec4 RGBDToLinear( in vec4 value, in float maxRange ) {\n\treturn vec4( value.rgb * ( ( maxRange / 255.0 ) / value.a ), 1.0 );\n}\nvec4 LinearToRGBD( in vec4 value, in float maxRange ) {\n\tfloat maxRGB = max( value.r, max( value.g, value.b ) );\n\tfloat D = max( maxRange / maxRGB, 1.0 );\n\tD = min( floor( D ) / 255.0, 1.0 );\n\treturn vec4( value.rgb * ( D * ( 255.0 / maxRange ) ), D );\n}\nconst mat3 cLogLuvM = mat3( 0.2209, 0.3390, 0.4184, 0.1138, 0.6780, 0.7319, 0.0102, 0.1130, 0.2969 );\nvec4 LinearToLogLuv( in vec4 value ) {\n\tvec3 Xp_Y_XYZp = value.rgb * cLogLuvM;\n\tXp_Y_XYZp = max( Xp_Y_XYZp, vec3( 1e-6, 1e-6, 1e-6 ) );\n\tvec4 vResult;\n\tvResult.xy = Xp_Y_XYZp.xy / Xp_Y_XYZp.z;\n\tfloat Le = 2.0 * log2(Xp_Y_XYZp.y) + 127.0;\n\tvResult.w = fract( Le );\n\tvResult.z = ( Le - ( floor( vResult.w * 255.0 ) ) / 255.0 ) / 255.0;\n\treturn vResult;\n}\nconst mat3 cLogLuvInverseM = mat3( 6.0014, -2.7008, -1.7996, -1.3320, 3.1029, -5.7721, 0.3008, -1.0882, 5.6268 );\nvec4 LogLuvToLinear( in vec4 value ) {\n\tfloat Le = value.z * 255.0 + value.w;\n\tvec3 Xp_Y_XYZp;\n\tXp_Y_XYZp.y = exp2( ( Le - 127.0 ) / 2.0 );\n\tXp_Y_XYZp.z = Xp_Y_XYZp.y / value.y;\n\tXp_Y_XYZp.x = value.x * Xp_Y_XYZp.z;\n\tvec3 vRGB = Xp_Y_XYZp.rgb * cLogLuvInverseM;\n\treturn vec4( max( vRGB, 0.0 ), 1.0 );\n}\n", +envmap_fragment:"#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\tvec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( cameraToVertex, worldNormal, refractionRatio );\n\t\t#endif\n\t#else\n\t\tvec3 reflectVec = vReflect;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 envColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\t#elif defined( ENVMAP_TYPE_EQUIREC )\n\t\tvec2 sampleUV;\n\t\treflectVec = normalize( reflectVec );\n\t\tsampleUV.y = asin( clamp( reflectVec.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\t\tsampleUV.x = atan( reflectVec.z, reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\n\t\tvec4 envColor = texture2D( envMap, sampleUV );\n\t#elif defined( ENVMAP_TYPE_SPHERE )\n\t\treflectVec = normalize( reflectVec );\n\t\tvec3 reflectView = normalize( ( viewMatrix * vec4( reflectVec, 0.0 ) ).xyz + vec3( 0.0, 0.0, 1.0 ) );\n\t\tvec4 envColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5 );\n\t#else\n\t\tvec4 envColor = vec4( 0.0 );\n\t#endif\n\tenvColor = envMapTexelToLinear( envColor );\n\t#ifdef ENVMAP_BLENDING_MULTIPLY\n\t\toutgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_MIX )\n\t\toutgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_ADD )\n\t\toutgoingLight += envColor.xyz * specularStrength * reflectivity;\n\t#endif\n#endif\n", +envmap_pars_fragment:"#if defined( USE_ENVMAP ) || defined( PHYSICAL )\n\tuniform float reflectivity;\n\tuniform float envMapIntensity;\n#endif\n#ifdef USE_ENVMAP\n\t#if ! defined( PHYSICAL ) && ( defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) )\n\t\tvarying vec3 vWorldPosition;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tuniform samplerCube envMap;\n\t#else\n\t\tuniform sampler2D envMap;\n\t#endif\n\tuniform float flipEnvMap;\n\tuniform int maxMipLevel;\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( PHYSICAL )\n\t\tuniform float refractionRatio;\n\t#else\n\t\tvarying vec3 vReflect;\n\t#endif\n#endif\n", +envmap_pars_vertex:"#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\tvarying vec3 vWorldPosition;\n\t#else\n\t\tvarying vec3 vReflect;\n\t\tuniform float refractionRatio;\n\t#endif\n#endif\n",envmap_physical_pars_fragment:"#if defined( USE_ENVMAP ) && defined( PHYSICAL )\n\tvec3 getLightProbeIndirectIrradiance( const in GeometricContext geometry, const in int maxMIPLevel ) {\n\t\tvec3 worldNormal = inverseTransformDirection( geometry.normal, viewMatrix );\n\t\t#ifdef ENVMAP_TYPE_CUBE\n\t\t\tvec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = textureCubeLodEXT( envMap, queryVec, float( maxMIPLevel ) );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = textureCube( envMap, queryVec, float( maxMIPLevel ) );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, queryVec, 1.0 );\n\t\t#else\n\t\t\tvec4 envMapColor = vec4( 0.0 );\n\t\t#endif\n\t\treturn PI * envMapColor.rgb * envMapIntensity;\n\t}\n\tfloat getSpecularMIPLevel( const in float blinnShininessExponent, const in int maxMIPLevel ) {\n\t\tfloat maxMIPLevelScalar = float( maxMIPLevel );\n\t\tfloat desiredMIPLevel = maxMIPLevelScalar + 0.79248 - 0.5 * log2( pow2( blinnShininessExponent ) + 1.0 );\n\t\treturn clamp( desiredMIPLevel, 0.0, maxMIPLevelScalar );\n\t}\n\tvec3 getLightProbeIndirectRadiance( const in GeometricContext geometry, const in float blinnShininessExponent, const in int maxMIPLevel ) {\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( -geometry.viewDir, geometry.normal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( -geometry.viewDir, geometry.normal, refractionRatio );\n\t\t#endif\n\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\n\t\tfloat specularMIPLevel = getSpecularMIPLevel( blinnShininessExponent, maxMIPLevel );\n\t\t#ifdef ENVMAP_TYPE_CUBE\n\t\t\tvec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = textureCubeLodEXT( envMap, queryReflectVec, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = textureCube( envMap, queryReflectVec, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, queryReflectVec, BlinnExponentToGGXRoughness(blinnShininessExponent ));\n\t\t#elif defined( ENVMAP_TYPE_EQUIREC )\n\t\t\tvec2 sampleUV;\n\t\t\tsampleUV.y = asin( clamp( reflectVec.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\t\t\tsampleUV.x = atan( reflectVec.z, reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = texture2DLodEXT( envMap, sampleUV, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = texture2D( envMap, sampleUV, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_SPHERE )\n\t\t\tvec3 reflectView = normalize( ( viewMatrix * vec4( reflectVec, 0.0 ) ).xyz + vec3( 0.0,0.0,1.0 ) );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = texture2DLodEXT( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#endif\n\t\treturn envMapColor.rgb * envMapIntensity;\n\t}\n#endif\n", +envmap_vertex:"#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\tvWorldPosition = worldPosition.xyz;\n\t#else\n\t\tvec3 cameraToVertex = normalize( worldPosition.xyz - cameraPosition );\n\t\tvec3 worldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvReflect = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvReflect = refract( cameraToVertex, worldNormal, refractionRatio );\n\t\t#endif\n\t#endif\n#endif\n", +fog_vertex:"#ifdef USE_FOG\n\tfogDepth = -mvPosition.z;\n#endif\n",fog_pars_vertex:"#ifdef USE_FOG\n\tvarying float fogDepth;\n#endif\n",fog_fragment:"#ifdef USE_FOG\n\t#ifdef FOG_EXP2\n\t\tfloat fogFactor = whiteCompliment( exp2( - fogDensity * fogDensity * fogDepth * fogDepth * LOG2 ) );\n\t#else\n\t\tfloat fogFactor = smoothstep( fogNear, fogFar, fogDepth );\n\t#endif\n\tgl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );\n#endif\n",fog_pars_fragment:"#ifdef USE_FOG\n\tuniform vec3 fogColor;\n\tvarying float fogDepth;\n\t#ifdef FOG_EXP2\n\t\tuniform float fogDensity;\n\t#else\n\t\tuniform float fogNear;\n\t\tuniform float fogFar;\n\t#endif\n#endif\n", +gradientmap_pars_fragment:"#ifdef TOON\n\tuniform sampler2D gradientMap;\n\tvec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) {\n\t\tfloat dotNL = dot( normal, lightDirection );\n\t\tvec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 );\n\t\t#ifdef USE_GRADIENTMAP\n\t\t\treturn texture2D( gradientMap, coord ).rgb;\n\t\t#else\n\t\t\treturn ( coord.x < 0.7 ) ? vec3( 0.7 ) : vec3( 1.0 );\n\t\t#endif\n\t}\n#endif\n",lightmap_fragment:"#ifdef USE_LIGHTMAP\n\treflectedLight.indirectDiffuse += PI * texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n#endif\n", +lightmap_pars_fragment:"#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif",lights_lambert_vertex:"vec3 diffuse = vec3( 1.0 );\nGeometricContext geometry;\ngeometry.position = mvPosition.xyz;\ngeometry.normal = normalize( transformedNormal );\ngeometry.viewDir = normalize( -mvPosition.xyz );\nGeometricContext backGeometry;\nbackGeometry.position = geometry.position;\nbackGeometry.normal = -geometry.normal;\nbackGeometry.viewDir = geometry.viewDir;\nvLightFront = vec3( 0.0 );\n#ifdef DOUBLE_SIDED\n\tvLightBack = vec3( 0.0 );\n#endif\nIncidentLight directLight;\nfloat dotNL;\nvec3 directLightColor_Diffuse;\n#if NUM_POINT_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tgetPointDirectLightIrradiance( pointLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tgetSpotDirectLightIrradiance( spotLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_DIR_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tgetDirectionalDirectLightIrradiance( directionalLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\tvLightFront += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += getHemisphereLightIrradiance( hemisphereLights[ i ], backGeometry );\n\t\t#endif\n\t}\n#endif\n", +lights_pars_begin:"uniform vec3 ambientLightColor;\nvec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {\n\tvec3 irradiance = ambientLightColor;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treturn irradiance;\n}\n#if NUM_DIR_LIGHTS > 0\n\tstruct DirectionalLight {\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tint shadow;\n\t\tfloat shadowBias;\n\t\tfloat shadowRadius;\n\t\tvec2 shadowMapSize;\n\t};\n\tuniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];\n\tvoid getDirectionalDirectLightIrradiance( const in DirectionalLight directionalLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tdirectLight.color = directionalLight.color;\n\t\tdirectLight.direction = directionalLight.direction;\n\t\tdirectLight.visible = true;\n\t}\n#endif\n#if NUM_POINT_LIGHTS > 0\n\tstruct PointLight {\n\t\tvec3 position;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tint shadow;\n\t\tfloat shadowBias;\n\t\tfloat shadowRadius;\n\t\tvec2 shadowMapSize;\n\t\tfloat shadowCameraNear;\n\t\tfloat shadowCameraFar;\n\t};\n\tuniform PointLight pointLights[ NUM_POINT_LIGHTS ];\n\tvoid getPointDirectLightIrradiance( const in PointLight pointLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tvec3 lVector = pointLight.position - geometry.position;\n\t\tdirectLight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tdirectLight.color = pointLight.color;\n\t\tdirectLight.color *= punctualLightIntensityToIrradianceFactor( lightDistance, pointLight.distance, pointLight.decay );\n\t\tdirectLight.visible = ( directLight.color != vec3( 0.0 ) );\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tstruct SpotLight {\n\t\tvec3 position;\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tfloat coneCos;\n\t\tfloat penumbraCos;\n\t\tint shadow;\n\t\tfloat shadowBias;\n\t\tfloat shadowRadius;\n\t\tvec2 shadowMapSize;\n\t};\n\tuniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];\n\tvoid getSpotDirectLightIrradiance( const in SpotLight spotLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tvec3 lVector = spotLight.position - geometry.position;\n\t\tdirectLight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tfloat angleCos = dot( directLight.direction, spotLight.direction );\n\t\tif ( angleCos > spotLight.coneCos ) {\n\t\t\tfloat spotEffect = smoothstep( spotLight.coneCos, spotLight.penumbraCos, angleCos );\n\t\t\tdirectLight.color = spotLight.color;\n\t\t\tdirectLight.color *= spotEffect * punctualLightIntensityToIrradianceFactor( lightDistance, spotLight.distance, spotLight.decay );\n\t\t\tdirectLight.visible = true;\n\t\t} else {\n\t\t\tdirectLight.color = vec3( 0.0 );\n\t\t\tdirectLight.visible = false;\n\t\t}\n\t}\n#endif\n#if NUM_RECT_AREA_LIGHTS > 0\n\tstruct RectAreaLight {\n\t\tvec3 color;\n\t\tvec3 position;\n\t\tvec3 halfWidth;\n\t\tvec3 halfHeight;\n\t};\n\tuniform sampler2D ltc_1;\tuniform sampler2D ltc_2;\n\tuniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ];\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tstruct HemisphereLight {\n\t\tvec3 direction;\n\t\tvec3 skyColor;\n\t\tvec3 groundColor;\n\t};\n\tuniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ];\n\tvec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in GeometricContext geometry ) {\n\t\tfloat dotNL = dot( geometry.normal, hemiLight.direction );\n\t\tfloat hemiDiffuseWeight = 0.5 * dotNL + 0.5;\n\t\tvec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight );\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tirradiance *= PI;\n\t\t#endif\n\t\treturn irradiance;\n\t}\n#endif\n", +lights_phong_fragment:"BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;\n",lights_phong_pars_fragment:"varying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\nstruct BlinnPhongMaterial {\n\tvec3\tdiffuseColor;\n\tvec3\tspecularColor;\n\tfloat\tspecularShininess;\n\tfloat\tspecularStrength;\n};\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\t#ifdef TOON\n\t\tvec3 irradiance = getGradientIrradiance( geometry.normal, directLight.direction ) * directLight.color;\n\t#else\n\t\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\t\tvec3 irradiance = dotNL * directLight.color;\n\t#endif\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treflectedLight.directDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n\treflectedLight.directSpecular += irradiance * BRDF_Specular_BlinnPhong( directLight, geometry, material.specularColor, material.specularShininess ) * material.specularStrength;\n}\nvoid RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_BlinnPhong\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_BlinnPhong\n#define Material_LightProbeLOD( material )\t(0)\n", +lights_physical_fragment:"PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\nmaterial.specularRoughness = clamp( roughnessFactor, 0.04, 1.0 );\n#ifdef STANDARD\n\tmaterial.specularColor = mix( vec3( DEFAULT_SPECULAR_COEFFICIENT ), diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = mix( vec3( MAXIMUM_SPECULAR_COEFFICIENT * pow2( reflectivity ) ), diffuseColor.rgb, metalnessFactor );\n\tmaterial.clearCoat = saturate( clearCoat );\tmaterial.clearCoatRoughness = clamp( clearCoatRoughness, 0.04, 1.0 );\n#endif\n", +lights_physical_pars_fragment:"struct PhysicalMaterial {\n\tvec3\tdiffuseColor;\n\tfloat\tspecularRoughness;\n\tvec3\tspecularColor;\n\t#ifndef STANDARD\n\t\tfloat clearCoat;\n\t\tfloat clearCoatRoughness;\n\t#endif\n};\n#define MAXIMUM_SPECULAR_COEFFICIENT 0.16\n#define DEFAULT_SPECULAR_COEFFICIENT 0.04\nfloat clearCoatDHRApprox( const in float roughness, const in float dotNL ) {\n\treturn DEFAULT_SPECULAR_COEFFICIENT + ( 1.0 - DEFAULT_SPECULAR_COEFFICIENT ) * ( pow( 1.0 - dotNL, 5.0 ) * pow( 1.0 - roughness, 2.0 ) );\n}\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 normal = geometry.normal;\n\t\tvec3 viewDir = geometry.viewDir;\n\t\tvec3 position = geometry.position;\n\t\tvec3 lightPos = rectAreaLight.position;\n\t\tvec3 halfWidth = rectAreaLight.halfWidth;\n\t\tvec3 halfHeight = rectAreaLight.halfHeight;\n\t\tvec3 lightColor = rectAreaLight.color;\n\t\tfloat roughness = material.specularRoughness;\n\t\tvec3 rectCoords[ 4 ];\n\t\trectCoords[ 0 ] = lightPos - halfWidth - halfHeight;\t\trectCoords[ 1 ] = lightPos + halfWidth - halfHeight;\n\t\trectCoords[ 2 ] = lightPos + halfWidth + halfHeight;\n\t\trectCoords[ 3 ] = lightPos - halfWidth + halfHeight;\n\t\tvec2 uv = LTC_Uv( normal, viewDir, roughness );\n\t\tvec4 t1 = texture2D( ltc_1, uv );\n\t\tvec4 t2 = texture2D( ltc_2, uv );\n\t\tmat3 mInv = mat3(\n\t\t\tvec3( t1.x, 0, t1.y ),\n\t\t\tvec3( 0, 1, 0 ),\n\t\t\tvec3( t1.z, 0, t1.w )\n\t\t);\n\t\tvec3 fresnel = ( material.specularColor * t2.x + ( vec3( 1.0 ) - material.specularColor ) * t2.y );\n\t\treflectedLight.directSpecular += lightColor * fresnel * LTC_Evaluate( normal, viewDir, position, mInv, rectCoords );\n\t\treflectedLight.directDiffuse += lightColor * material.diffuseColor * LTC_Evaluate( normal, viewDir, position, mat3( 1.0 ), rectCoords );\n\t}\n#endif\nvoid RE_Direct_Physical( const in IncidentLight directLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\t#ifndef STANDARD\n\t\tfloat clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, dotNL );\n\t#else\n\t\tfloat clearCoatDHR = 0.0;\n\t#endif\n\treflectedLight.directSpecular += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Specular_GGX( directLight, geometry, material.specularColor, material.specularRoughness );\n\treflectedLight.directDiffuse += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n\t#ifndef STANDARD\n\t\treflectedLight.directSpecular += irradiance * material.clearCoat * BRDF_Specular_GGX( directLight, geometry, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness );\n\t#endif\n}\nvoid RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 clearCoatRadiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t#ifndef STANDARD\n\t\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\t\tfloat dotNL = dotNV;\n\t\tfloat clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, dotNL );\n\t#else\n\t\tfloat clearCoatDHR = 0.0;\n\t#endif\n\treflectedLight.indirectSpecular += ( 1.0 - clearCoatDHR ) * radiance * BRDF_Specular_GGX_Environment( geometry, material.specularColor, material.specularRoughness );\n\t#ifndef STANDARD\n\t\treflectedLight.indirectSpecular += clearCoatRadiance * material.clearCoat * BRDF_Specular_GGX_Environment( geometry, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness );\n\t#endif\n}\n#define RE_Direct\t\t\t\tRE_Direct_Physical\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_Physical\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Physical\n#define RE_IndirectSpecular\t\tRE_IndirectSpecular_Physical\n#define Material_BlinnShininessExponent( material ) GGXRoughnessToBlinnExponent( material.specularRoughness )\n#define Material_ClearCoat_BlinnShininessExponent( material ) GGXRoughnessToBlinnExponent( material.clearCoatRoughness )\nfloat computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) {\n\treturn saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion );\n}\n", +lights_fragment_begin:"\nGeometricContext geometry;\ngeometry.position = - vViewPosition;\ngeometry.normal = normal;\ngeometry.viewDir = normalize( vViewPosition );\nIncidentLight directLight;\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\n\tPointLight pointLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tgetPointDirectLightIrradiance( pointLight, geometry, directLight );\n\t\t#ifdef USE_SHADOWMAP\n\t\tdirectLight.color *= all( bvec2( pointLight.shadow, directLight.visible ) ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\n\tSpotLight spotLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tgetSpotDirectLightIrradiance( spotLight, geometry, directLight );\n\t\t#ifdef USE_SHADOWMAP\n\t\tdirectLight.color *= all( bvec2( spotLight.shadow, directLight.visible ) ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\n\tDirectionalLight directionalLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tgetDirectionalDirectLightIrradiance( directionalLight, geometry, directLight );\n\t\t#ifdef USE_SHADOWMAP\n\t\tdirectLight.color *= all( bvec2( directionalLight.shadow, directLight.visible ) ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\n\tRectAreaLight rectAreaLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\n\t\trectAreaLight = rectAreaLights[ i ];\n\t\tRE_Direct_RectArea( rectAreaLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if defined( RE_IndirectDiffuse )\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\n\t#if ( NUM_HEMI_LIGHTS > 0 )\n\t\t#pragma unroll_loop\n\t\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\t\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t}\n\t#endif\n#endif\n#if defined( RE_IndirectSpecular )\n\tvec3 radiance = vec3( 0.0 );\n\tvec3 clearCoatRadiance = vec3( 0.0 );\n#endif\n", +lights_fragment_maps:"#if defined( RE_IndirectDiffuse )\n\t#ifdef USE_LIGHTMAP\n\t\tvec3 lightMapIrradiance = texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tlightMapIrradiance *= PI;\n\t\t#endif\n\t\tirradiance += lightMapIrradiance;\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( PHYSICAL ) && defined( ENVMAP_TYPE_CUBE_UV )\n\t\tirradiance += getLightProbeIndirectIrradiance( geometry, maxMipLevel );\n\t#endif\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\tradiance += getLightProbeIndirectRadiance( geometry, Material_BlinnShininessExponent( material ), maxMipLevel );\n\t#ifndef STANDARD\n\t\tclearCoatRadiance += getLightProbeIndirectRadiance( geometry, Material_ClearCoat_BlinnShininessExponent( material ), maxMipLevel );\n\t#endif\n#endif\n", +lights_fragment_end:"#if defined( RE_IndirectDiffuse )\n\tRE_IndirectDiffuse( irradiance, geometry, material, reflectedLight );\n#endif\n#if defined( RE_IndirectSpecular )\n\tRE_IndirectSpecular( radiance, clearCoatRadiance, geometry, material, reflectedLight );\n#endif\n",logdepthbuf_fragment:"#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tgl_FragDepthEXT = log2( vFragDepth ) * logDepthBufFC * 0.5;\n#endif",logdepthbuf_pars_fragment:"#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tuniform float logDepthBufFC;\n\tvarying float vFragDepth;\n#endif\n", +logdepthbuf_pars_vertex:"#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvarying float vFragDepth;\n\t#else\n\t\tuniform float logDepthBufFC;\n\t#endif\n#endif\n",logdepthbuf_vertex:"#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvFragDepth = 1.0 + gl_Position.w;\n\t#else\n\t\tgl_Position.z = log2( max( EPSILON, gl_Position.w + 1.0 ) ) * logDepthBufFC - 1.0;\n\t\tgl_Position.z *= gl_Position.w;\n\t#endif\n#endif\n",map_fragment:"#ifdef USE_MAP\n\tvec4 texelColor = texture2D( map, vUv );\n\ttexelColor = mapTexelToLinear( texelColor );\n\tdiffuseColor *= texelColor;\n#endif\n", +map_pars_fragment:"#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif\n",map_particle_fragment:"#ifdef USE_MAP\n\tvec2 uv = ( uvTransform * vec3( gl_PointCoord.x, 1.0 - gl_PointCoord.y, 1 ) ).xy;\n\tvec4 mapTexel = texture2D( map, uv );\n\tdiffuseColor *= mapTexelToLinear( mapTexel );\n#endif\n",map_particle_pars_fragment:"#ifdef USE_MAP\n\tuniform mat3 uvTransform;\n\tuniform sampler2D map;\n#endif\n",metalnessmap_fragment:"float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif\n", +metalnessmap_pars_fragment:"#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif",morphnormal_vertex:"#ifdef USE_MORPHNORMALS\n\tobjectNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];\n\tobjectNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];\n\tobjectNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];\n\tobjectNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];\n#endif\n",morphtarget_pars_vertex:"#ifdef USE_MORPHTARGETS\n\t#ifndef USE_MORPHNORMALS\n\tuniform float morphTargetInfluences[ 8 ];\n\t#else\n\tuniform float morphTargetInfluences[ 4 ];\n\t#endif\n#endif", +morphtarget_vertex:"#ifdef USE_MORPHTARGETS\n\ttransformed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];\n\ttransformed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];\n\ttransformed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];\n\ttransformed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];\n\t#ifndef USE_MORPHNORMALS\n\ttransformed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];\n\ttransformed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];\n\ttransformed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];\n\ttransformed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];\n\t#endif\n#endif\n", +normal_fragment_begin:"#ifdef FLAT_SHADED\n\tvec3 fdx = vec3( dFdx( vViewPosition.x ), dFdx( vViewPosition.y ), dFdx( vViewPosition.z ) );\n\tvec3 fdy = vec3( dFdy( vViewPosition.x ), dFdy( vViewPosition.y ), dFdy( vViewPosition.z ) );\n\tvec3 normal = normalize( cross( fdx, fdy ) );\n#else\n\tvec3 normal = normalize( vNormal );\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t#endif\n#endif\n",normal_fragment_maps:"#ifdef USE_NORMALMAP\n\t#ifdef OBJECTSPACE_NORMALMAP\n\t\tnormal = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\t\t#ifdef FLIP_SIDED\n\t\t\tnormal = - normal;\n\t\t#endif\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tnormal = normal * ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\t#endif\n\t\tnormal = normalize( normalMatrix * normal );\n\t#else\n\t\tnormal = perturbNormal2Arb( -vViewPosition, normal );\n\t#endif\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );\n#endif\n", +normalmap_pars_fragment:"#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n\t#ifdef OBJECTSPACE_NORMALMAP\n\t\tuniform mat3 normalMatrix;\n\t#else\n\t\tvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {\n\t\t\tvec3 q0 = vec3( dFdx( eye_pos.x ), dFdx( eye_pos.y ), dFdx( eye_pos.z ) );\n\t\t\tvec3 q1 = vec3( dFdy( eye_pos.x ), dFdy( eye_pos.y ), dFdy( eye_pos.z ) );\n\t\t\tvec2 st0 = dFdx( vUv.st );\n\t\t\tvec2 st1 = dFdy( vUv.st );\n\t\t\tfloat scale = sign( st1.t * st0.s - st0.t * st1.s );\n\t\t\tvec3 S = normalize( ( q0 * st1.t - q1 * st0.t ) * scale );\n\t\t\tvec3 T = normalize( ( - q0 * st1.s + q1 * st0.s ) * scale );\n\t\t\tvec3 N = normalize( surf_norm );\n\t\t\tmat3 tsn = mat3( S, T, N );\n\t\t\tvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\t\t\tmapN.xy *= normalScale;\n\t\t\tmapN.xy *= ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\t\treturn normalize( tsn * mapN );\n\t\t}\n\t#endif\n#endif\n", +packing:"vec3 packNormalToRGB( const in vec3 normal ) {\n\treturn normalize( normal ) * 0.5 + 0.5;\n}\nvec3 unpackRGBToNormal( const in vec3 rgb ) {\n\treturn 2.0 * rgb.xyz - 1.0;\n}\nconst float PackUpscale = 256. / 255.;const float UnpackDownscale = 255. / 256.;\nconst vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );\nconst vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );\nconst float ShiftRight8 = 1. / 256.;\nvec4 packDepthToRGBA( const in float v ) {\n\tvec4 r = vec4( fract( v * PackFactors ), v );\n\tr.yzw -= r.xyz * ShiftRight8;\treturn r * PackUpscale;\n}\nfloat unpackRGBAToDepth( const in vec4 v ) {\n\treturn dot( v, UnpackFactors );\n}\nfloat viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( viewZ + near ) / ( near - far );\n}\nfloat orthographicDepthToViewZ( const in float linearClipZ, const in float near, const in float far ) {\n\treturn linearClipZ * ( near - far ) - near;\n}\nfloat viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn (( near + viewZ ) * far ) / (( far - near ) * viewZ );\n}\nfloat perspectiveDepthToViewZ( const in float invClipZ, const in float near, const in float far ) {\n\treturn ( near * far ) / ( ( far - near ) * invClipZ - far );\n}\n", +premultiplied_alpha_fragment:"#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif\n",project_vertex:"vec4 mvPosition = modelViewMatrix * vec4( transformed, 1.0 );\ngl_Position = projectionMatrix * mvPosition;\n",dithering_fragment:"#if defined( DITHERING )\n gl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif\n",dithering_pars_fragment:"#if defined( DITHERING )\n\tvec3 dithering( vec3 color ) {\n\t\tfloat grid_position = rand( gl_FragCoord.xy );\n\t\tvec3 dither_shift_RGB = vec3( 0.25 / 255.0, -0.25 / 255.0, 0.25 / 255.0 );\n\t\tdither_shift_RGB = mix( 2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position );\n\t\treturn color + dither_shift_RGB;\n\t}\n#endif\n", +roughnessmap_fragment:"float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vUv );\n\troughnessFactor *= texelRoughness.g;\n#endif\n",roughnessmap_pars_fragment:"#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif",shadowmap_pars_fragment:"#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\t\tuniform sampler2D directionalShadowMap[ NUM_DIR_LIGHTS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\t\tuniform sampler2D spotShadowMap[ NUM_SPOT_LIGHTS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHTS ];\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\t\tuniform sampler2D pointShadowMap[ NUM_POINT_LIGHTS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHTS ];\n\t#endif\n\tfloat texture2DCompare( sampler2D depths, vec2 uv, float compare ) {\n\t\treturn step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );\n\t}\n\tfloat texture2DShadowLerp( sampler2D depths, vec2 size, vec2 uv, float compare ) {\n\t\tconst vec2 offset = vec2( 0.0, 1.0 );\n\t\tvec2 texelSize = vec2( 1.0 ) / size;\n\t\tvec2 centroidUV = floor( uv * size + 0.5 ) / size;\n\t\tfloat lb = texture2DCompare( depths, centroidUV + texelSize * offset.xx, compare );\n\t\tfloat lt = texture2DCompare( depths, centroidUV + texelSize * offset.xy, compare );\n\t\tfloat rb = texture2DCompare( depths, centroidUV + texelSize * offset.yx, compare );\n\t\tfloat rt = texture2DCompare( depths, centroidUV + texelSize * offset.yy, compare );\n\t\tvec2 f = fract( uv * size + 0.5 );\n\t\tfloat a = mix( lb, lt, f.y );\n\t\tfloat b = mix( rb, rt, f.y );\n\t\tfloat c = mix( a, b, f.x );\n\t\treturn c;\n\t}\n\tfloat getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\tfloat shadow = 1.0;\n\t\tshadowCoord.xyz /= shadowCoord.w;\n\t\tshadowCoord.z += shadowBias;\n\t\tbvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\n\t\tbool inFrustum = all( inFrustumVec );\n\t\tbvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\n\t\tbool frustumTest = all( frustumTestVec );\n\t\tif ( frustumTest ) {\n\t\t#if defined( SHADOWMAP_TYPE_PCF )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\tshadow = (\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\tshadow = texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#endif\n\t\t}\n\t\treturn shadow;\n\t}\n\tvec2 cubeToUV( vec3 v, float texelSizeY ) {\n\t\tvec3 absV = abs( v );\n\t\tfloat scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );\n\t\tabsV *= scaleToCube;\n\t\tv *= scaleToCube * ( 1.0 - 2.0 * texelSizeY );\n\t\tvec2 planar = v.xy;\n\t\tfloat almostATexel = 1.5 * texelSizeY;\n\t\tfloat almostOne = 1.0 - almostATexel;\n\t\tif ( absV.z >= almostOne ) {\n\t\t\tif ( v.z > 0.0 )\n\t\t\t\tplanar.x = 4.0 - v.x;\n\t\t} else if ( absV.x >= almostOne ) {\n\t\t\tfloat signX = sign( v.x );\n\t\t\tplanar.x = v.z * signX + 2.0 * signX;\n\t\t} else if ( absV.y >= almostOne ) {\n\t\t\tfloat signY = sign( v.y );\n\t\t\tplanar.x = v.x + 2.0 * signY + 2.0;\n\t\t\tplanar.y = v.z * signY - 2.0;\n\t\t}\n\t\treturn vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 );\n\t}\n\tfloat getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord, float shadowCameraNear, float shadowCameraFar ) {\n\t\tvec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );\n\t\tvec3 lightToPosition = shadowCoord.xyz;\n\t\tfloat dp = ( length( lightToPosition ) - shadowCameraNear ) / ( shadowCameraFar - shadowCameraNear );\t\tdp += shadowBias;\n\t\tvec3 bd3D = normalize( lightToPosition );\n\t\t#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;\n\t\t\treturn (\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\treturn texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );\n\t\t#endif\n\t}\n#endif\n", +shadowmap_pars_vertex:"#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\t\tuniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHTS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\t\tuniform mat4 spotShadowMatrix[ NUM_SPOT_LIGHTS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHTS ];\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\t\tuniform mat4 pointShadowMatrix[ NUM_POINT_LIGHTS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHTS ];\n\t#endif\n#endif\n", +shadowmap_vertex:"#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tvSpotShadowCoord[ i ] = spotShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n#endif\n", +shadowmask_pars_fragment:"float getShadowMask() {\n\tfloat shadow = 1.0;\n\t#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\tDirectionalLight directionalLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tshadow *= bool( directionalLight.shadow ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t}\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\tSpotLight spotLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tshadow *= bool( spotLight.shadow ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t}\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\tPointLight pointLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tshadow *= bool( pointLight.shadow ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;\n\t}\n\t#endif\n\t#endif\n\treturn shadow;\n}\n", +skinbase_vertex:"#ifdef USE_SKINNING\n\tmat4 boneMatX = getBoneMatrix( skinIndex.x );\n\tmat4 boneMatY = getBoneMatrix( skinIndex.y );\n\tmat4 boneMatZ = getBoneMatrix( skinIndex.z );\n\tmat4 boneMatW = getBoneMatrix( skinIndex.w );\n#endif",skinning_pars_vertex:"#ifdef USE_SKINNING\n\tuniform mat4 bindMatrix;\n\tuniform mat4 bindMatrixInverse;\n\t#ifdef BONE_TEXTURE\n\t\tuniform sampler2D boneTexture;\n\t\tuniform int boneTextureSize;\n\t\tmat4 getBoneMatrix( const in float i ) {\n\t\t\tfloat j = i * 4.0;\n\t\t\tfloat x = mod( j, float( boneTextureSize ) );\n\t\t\tfloat y = floor( j / float( boneTextureSize ) );\n\t\t\tfloat dx = 1.0 / float( boneTextureSize );\n\t\t\tfloat dy = 1.0 / float( boneTextureSize );\n\t\t\ty = dy * ( y + 0.5 );\n\t\t\tvec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );\n\t\t\tvec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );\n\t\t\tvec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );\n\t\t\tvec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );\n\t\t\tmat4 bone = mat4( v1, v2, v3, v4 );\n\t\t\treturn bone;\n\t\t}\n\t#else\n\t\tuniform mat4 boneMatrices[ MAX_BONES ];\n\t\tmat4 getBoneMatrix( const in float i ) {\n\t\t\tmat4 bone = boneMatrices[ int(i) ];\n\t\t\treturn bone;\n\t\t}\n\t#endif\n#endif\n", +skinning_vertex:"#ifdef USE_SKINNING\n\tvec4 skinVertex = bindMatrix * vec4( transformed, 1.0 );\n\tvec4 skinned = vec4( 0.0 );\n\tskinned += boneMatX * skinVertex * skinWeight.x;\n\tskinned += boneMatY * skinVertex * skinWeight.y;\n\tskinned += boneMatZ * skinVertex * skinWeight.z;\n\tskinned += boneMatW * skinVertex * skinWeight.w;\n\ttransformed = ( bindMatrixInverse * skinned ).xyz;\n#endif\n",skinnormal_vertex:"#ifdef USE_SKINNING\n\tmat4 skinMatrix = mat4( 0.0 );\n\tskinMatrix += skinWeight.x * boneMatX;\n\tskinMatrix += skinWeight.y * boneMatY;\n\tskinMatrix += skinWeight.z * boneMatZ;\n\tskinMatrix += skinWeight.w * boneMatW;\n\tskinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;\n\tobjectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;\n#endif\n", +specularmap_fragment:"float specularStrength;\n#ifdef USE_SPECULARMAP\n\tvec4 texelSpecular = texture2D( specularMap, vUv );\n\tspecularStrength = texelSpecular.r;\n#else\n\tspecularStrength = 1.0;\n#endif",specularmap_pars_fragment:"#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif",tonemapping_fragment:"#if defined( TONE_MAPPING )\n gl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif\n",tonemapping_pars_fragment:"#ifndef saturate\n\t#define saturate(a) clamp( a, 0.0, 1.0 )\n#endif\nuniform float toneMappingExposure;\nuniform float toneMappingWhitePoint;\nvec3 LinearToneMapping( vec3 color ) {\n\treturn toneMappingExposure * color;\n}\nvec3 ReinhardToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( color / ( vec3( 1.0 ) + color ) );\n}\n#define Uncharted2Helper( x ) max( ( ( x * ( 0.15 * x + 0.10 * 0.50 ) + 0.20 * 0.02 ) / ( x * ( 0.15 * x + 0.50 ) + 0.20 * 0.30 ) ) - 0.02 / 0.30, vec3( 0.0 ) )\nvec3 Uncharted2ToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( Uncharted2Helper( color ) / Uncharted2Helper( vec3( toneMappingWhitePoint ) ) );\n}\nvec3 OptimizedCineonToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\tcolor = max( vec3( 0.0 ), color - 0.004 );\n\treturn pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) );\n}\n", +uv_pars_fragment:"#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\n\tvarying vec2 vUv;\n#endif",uv_pars_vertex:"#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\n\tvarying vec2 vUv;\n\tuniform mat3 uvTransform;\n#endif\n", +uv_vertex:"#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n#endif",uv2_pars_fragment:"#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvarying vec2 vUv2;\n#endif",uv2_pars_vertex:"#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tattribute vec2 uv2;\n\tvarying vec2 vUv2;\n#endif", +uv2_vertex:"#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvUv2 = uv2;\n#endif",worldpos_vertex:"#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP )\n\tvec4 worldPosition = modelMatrix * vec4( transformed, 1.0 );\n#endif\n",background_frag:"uniform sampler2D t2D;\nvarying vec2 vUv;\nvoid main() {\n\tgl_FragColor = texture2D( t2D, vUv );\n}\n",background_vert:"varying vec2 vUv;\nvoid main() {\n\tvUv = uv;\n\tgl_Position = vec4( position, 1.0 );\n\tgl_Position.z = 1.0;\n}\n", +cube_frag:"uniform samplerCube tCube;\nuniform float tFlip;\nuniform float opacity;\nvarying vec3 vWorldPosition;\nvoid main() {\n\tgl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );\n\tgl_FragColor.a *= opacity;\n}\n",cube_vert:"varying vec3 vWorldPosition;\n#include <common>\nvoid main() {\n\tvWorldPosition = transformDirection( position, modelMatrix );\n\t#include <begin_vertex>\n\t#include <project_vertex>\n\tgl_Position.z = gl_Position.w;\n}\n",depth_frag:"#if DEPTH_PACKING == 3200\n\tuniform float opacity;\n#endif\n#include <common>\n#include <packing>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( 1.0 );\n\t#if DEPTH_PACKING == 3200\n\t\tdiffuseColor.a = opacity;\n\t#endif\n\t#include <map_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <logdepthbuf_fragment>\n\t#if DEPTH_PACKING == 3200\n\t\tgl_FragColor = vec4( vec3( 1.0 - gl_FragCoord.z ), opacity );\n\t#elif DEPTH_PACKING == 3201\n\t\tgl_FragColor = packDepthToRGBA( gl_FragCoord.z );\n\t#endif\n}\n", +depth_vert:"#include <common>\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <skinbase_vertex>\n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include <beginnormal_vertex>\n\t\t#include <morphnormal_vertex>\n\t\t#include <skinnormal_vertex>\n\t#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n}\n", +distanceRGBA_frag:"#define DISTANCE\nuniform vec3 referencePosition;\nuniform float nearDistance;\nuniform float farDistance;\nvarying vec3 vWorldPosition;\n#include <common>\n#include <packing>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main () {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( 1.0 );\n\t#include <map_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\tfloat dist = length( vWorldPosition - referencePosition );\n\tdist = ( dist - nearDistance ) / ( farDistance - nearDistance );\n\tdist = saturate( dist );\n\tgl_FragColor = packDepthToRGBA( dist );\n}\n", +distanceRGBA_vert:"#define DISTANCE\nvarying vec3 vWorldPosition;\n#include <common>\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <skinbase_vertex>\n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include <beginnormal_vertex>\n\t\t#include <morphnormal_vertex>\n\t\t#include <skinnormal_vertex>\n\t#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <worldpos_vertex>\n\t#include <clipping_planes_vertex>\n\tvWorldPosition = worldPosition.xyz;\n}\n", +equirect_frag:"uniform sampler2D tEquirect;\nvarying vec3 vWorldPosition;\n#include <common>\nvoid main() {\n\tvec3 direction = normalize( vWorldPosition );\n\tvec2 sampleUV;\n\tsampleUV.y = asin( clamp( direction.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\tsampleUV.x = atan( direction.z, direction.x ) * RECIPROCAL_PI2 + 0.5;\n\tgl_FragColor = texture2D( tEquirect, sampleUV );\n}\n",equirect_vert:"varying vec3 vWorldPosition;\n#include <common>\nvoid main() {\n\tvWorldPosition = transformDirection( position, modelMatrix );\n\t#include <begin_vertex>\n\t#include <project_vertex>\n}\n", +linedashed_frag:"uniform vec3 diffuse;\nuniform float opacity;\nuniform float dashSize;\nuniform float totalSize;\nvarying float vLineDistance;\n#include <common>\n#include <color_pars_fragment>\n#include <fog_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tif ( mod( vLineDistance, totalSize ) > dashSize ) {\n\t\tdiscard;\n\t}\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <logdepthbuf_fragment>\n\t#include <color_fragment>\n\toutgoingLight = diffuseColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <premultiplied_alpha_fragment>\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n}\n", +linedashed_vert:"uniform float scale;\nattribute float lineDistance;\nvarying float vLineDistance;\n#include <common>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <color_vertex>\n\tvLineDistance = scale * lineDistance;\n\tvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <fog_vertex>\n}\n", +meshbasic_frag:"uniform vec3 diffuse;\nuniform float opacity;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <common>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <uv2_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <envmap_pars_fragment>\n#include <fog_pars_fragment>\n#include <specularmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <specularmap_fragment>\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\t#ifdef USE_LIGHTMAP\n\t\treflectedLight.indirectDiffuse += texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n\t#else\n\t\treflectedLight.indirectDiffuse += vec3( 1.0 );\n\t#endif\n\t#include <aomap_fragment>\n\treflectedLight.indirectDiffuse *= diffuseColor.rgb;\n\tvec3 outgoingLight = reflectedLight.indirectDiffuse;\n\t#include <envmap_fragment>\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <premultiplied_alpha_fragment>\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n}\n", +meshbasic_vert:"#include <common>\n#include <uv_pars_vertex>\n#include <uv2_pars_vertex>\n#include <envmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <uv2_vertex>\n\t#include <color_vertex>\n\t#include <skinbase_vertex>\n\t#ifdef USE_ENVMAP\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <worldpos_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <envmap_vertex>\n\t#include <fog_vertex>\n}\n", +meshlambert_frag:"uniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\nvarying vec3 vLightFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n#endif\n#include <common>\n#include <packing>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <uv2_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <emissivemap_pars_fragment>\n#include <envmap_pars_fragment>\n#include <bsdfs>\n#include <lights_pars_begin>\n#include <fog_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <shadowmask_pars_fragment>\n#include <specularmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <specularmap_fragment>\n\t#include <emissivemap_fragment>\n\treflectedLight.indirectDiffuse = getAmbientLightIrradiance( ambientLightColor );\n\t#include <lightmap_fragment>\n\treflectedLight.indirectDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb );\n\t#ifdef DOUBLE_SIDED\n\t\treflectedLight.directDiffuse = ( gl_FrontFacing ) ? vLightFront : vLightBack;\n\t#else\n\t\treflectedLight.directDiffuse = vLightFront;\n\t#endif\n\treflectedLight.directDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb ) * getShadowMask();\n\t#include <aomap_fragment>\n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include <envmap_fragment>\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}\n", +meshlambert_vert:"#define LAMBERT\nvarying vec3 vLightFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n#endif\n#include <common>\n#include <uv_pars_vertex>\n#include <uv2_pars_vertex>\n#include <envmap_pars_vertex>\n#include <bsdfs>\n#include <lights_pars_begin>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <shadowmap_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <uv2_vertex>\n\t#include <color_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <worldpos_vertex>\n\t#include <envmap_vertex>\n\t#include <lights_lambert_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}\n", +meshmatcap_frag:"#define MATCAP\nuniform vec3 diffuse;\nuniform float opacity;\nuniform sampler2D matcap;\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <common>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <fog_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <normal_fragment_begin>\n\t#include <normal_fragment_maps>\n\tvec3 viewDir = normalize( vViewPosition );\n\tvec3 x = normalize( vec3( viewDir.z, 0.0, - viewDir.x ) );\n\tvec3 y = cross( viewDir, x );\n\tvec2 uv = vec2( dot( x, normal ), dot( y, normal ) ) * 0.495 + 0.5;\n\tvec4 matcapColor = texture2D( matcap, uv );\n\tmatcapColor = matcapTexelToLinear( matcapColor );\n\tvec3 outgoingLight = diffuseColor.rgb * matcapColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <premultiplied_alpha_fragment>\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n}\n", +meshmatcap_vert:"#define MATCAP\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <common>\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#ifndef FLAT_SHADED\n\t\tvNormal = normalize( transformedNormal );\n\t#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <fog_vertex>\n\tvViewPosition = - mvPosition.xyz;\n}\n", +meshphong_frag:"#define PHONG\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float shininess;\nuniform float opacity;\n#include <common>\n#include <packing>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <uv2_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <emissivemap_pars_fragment>\n#include <envmap_pars_fragment>\n#include <gradientmap_pars_fragment>\n#include <fog_pars_fragment>\n#include <bsdfs>\n#include <lights_pars_begin>\n#include <lights_phong_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <specularmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <specularmap_fragment>\n\t#include <normal_fragment_begin>\n\t#include <normal_fragment_maps>\n\t#include <emissivemap_fragment>\n\t#include <lights_phong_fragment>\n\t#include <lights_fragment_begin>\n\t#include <lights_fragment_maps>\n\t#include <lights_fragment_end>\n\t#include <aomap_fragment>\n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\t#include <envmap_fragment>\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}\n", +meshphong_vert:"#define PHONG\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <common>\n#include <uv_pars_vertex>\n#include <uv2_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <envmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <shadowmap_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <uv2_vertex>\n\t#include <color_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\tvViewPosition = - mvPosition.xyz;\n\t#include <worldpos_vertex>\n\t#include <envmap_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}\n", +meshphysical_frag:"#define PHYSICAL\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float roughness;\nuniform float metalness;\nuniform float opacity;\n#ifndef STANDARD\n\tuniform float clearCoat;\n\tuniform float clearCoatRoughness;\n#endif\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <common>\n#include <packing>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <uv2_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <emissivemap_pars_fragment>\n#include <bsdfs>\n#include <cube_uv_reflection_fragment>\n#include <envmap_pars_fragment>\n#include <envmap_physical_pars_fragment>\n#include <fog_pars_fragment>\n#include <lights_pars_begin>\n#include <lights_physical_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <roughnessmap_pars_fragment>\n#include <metalnessmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <roughnessmap_fragment>\n\t#include <metalnessmap_fragment>\n\t#include <normal_fragment_begin>\n\t#include <normal_fragment_maps>\n\t#include <emissivemap_fragment>\n\t#include <lights_physical_fragment>\n\t#include <lights_fragment_begin>\n\t#include <lights_fragment_maps>\n\t#include <lights_fragment_end>\n\t#include <aomap_fragment>\n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}\n", +meshphysical_vert:"#define PHYSICAL\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <common>\n#include <uv_pars_vertex>\n#include <uv2_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <shadowmap_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <uv2_vertex>\n\t#include <color_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\tvViewPosition = - mvPosition.xyz;\n\t#include <worldpos_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}\n", +normal_frag:"#define NORMAL\nuniform float opacity;\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || ( defined( USE_NORMALMAP ) && ! defined( OBJECTSPACE_NORMALMAP ) )\n\tvarying vec3 vViewPosition;\n#endif\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <packing>\n#include <uv_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\nvoid main() {\n\t#include <logdepthbuf_fragment>\n\t#include <normal_fragment_begin>\n\t#include <normal_fragment_maps>\n\tgl_FragColor = vec4( packNormalToRGB( normal ), opacity );\n}\n", +normal_vert:"#define NORMAL\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || ( defined( USE_NORMALMAP ) && ! defined( OBJECTSPACE_NORMALMAP ) )\n\tvarying vec3 vViewPosition;\n#endif\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <logdepthbuf_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || ( defined( USE_NORMALMAP ) && ! defined( OBJECTSPACE_NORMALMAP ) )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n}\n", +points_frag:"uniform vec3 diffuse;\nuniform float opacity;\n#include <common>\n#include <color_pars_fragment>\n#include <map_particle_pars_fragment>\n#include <fog_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <logdepthbuf_fragment>\n\t#include <map_particle_fragment>\n\t#include <color_fragment>\n\t#include <alphatest_fragment>\n\toutgoingLight = diffuseColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <premultiplied_alpha_fragment>\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n}\n", +points_vert:"uniform float size;\nuniform float scale;\n#include <common>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <color_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <project_vertex>\n\tgl_PointSize = size;\n\t#ifdef USE_SIZEATTENUATION\n\t\tbool isPerspective = ( projectionMatrix[ 2 ][ 3 ] == - 1.0 );\n\t\tif ( isPerspective ) gl_PointSize *= ( scale / - mvPosition.z );\n\t#endif\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <worldpos_vertex>\n\t#include <fog_vertex>\n}\n", +shadow_frag:"uniform vec3 color;\nuniform float opacity;\n#include <common>\n#include <packing>\n#include <fog_pars_fragment>\n#include <bsdfs>\n#include <lights_pars_begin>\n#include <shadowmap_pars_fragment>\n#include <shadowmask_pars_fragment>\nvoid main() {\n\tgl_FragColor = vec4( color, opacity * ( 1.0 - getShadowMask() ) );\n\t#include <fog_fragment>\n}\n",shadow_vert:"#include <fog_pars_vertex>\n#include <shadowmap_pars_vertex>\nvoid main() {\n\t#include <begin_vertex>\n\t#include <project_vertex>\n\t#include <worldpos_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}\n", +sprite_frag:"uniform vec3 diffuse;\nuniform float opacity;\n#include <common>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <fog_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <alphatest_fragment>\n\toutgoingLight = diffuseColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n}\n", +sprite_vert:"uniform float rotation;\nuniform vec2 center;\n#include <common>\n#include <uv_pars_vertex>\n#include <fog_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\tvec4 mvPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );\n\tvec2 scale;\n\tscale.x = length( vec3( modelMatrix[ 0 ].x, modelMatrix[ 0 ].y, modelMatrix[ 0 ].z ) );\n\tscale.y = length( vec3( modelMatrix[ 1 ].x, modelMatrix[ 1 ].y, modelMatrix[ 1 ].z ) );\n\t#ifndef USE_SIZEATTENUATION\n\t\tbool isPerspective = ( projectionMatrix[ 2 ][ 3 ] == - 1.0 );\n\t\tif ( isPerspective ) scale *= - mvPosition.z;\n\t#endif\n\tvec2 alignedPosition = ( position.xy - ( center - vec2( 0.5 ) ) ) * scale;\n\tvec2 rotatedPosition;\n\trotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;\n\trotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;\n\tmvPosition.xy += rotatedPosition;\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <fog_vertex>\n}\n"}, +va={merge:function(a){for(var b={},c=0;c<a.length;c++){var d=this.clone(a[c]),e;for(e in d)b[e]=d[e]}return b},clone:function(a){var b={},c;for(c in a){b[c]={};for(var d in a[c]){var e=a[c][d];e&&(e.isColor||e.isMatrix3||e.isMatrix4||e.isVector2||e.isVector3||e.isVector4||e.isTexture)?b[c][d]=e.clone():Array.isArray(e)?b[c][d]=e.slice():b[c][d]=e}}return b}},Wg={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045, +blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495, +darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976, +lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097, +mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736, +rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074};Object.assign(G.prototype, +{isColor:!0,r:1,g:1,b:1,set:function(a){a&&a.isColor?this.copy(a):"number"===typeof a?this.setHex(a):"string"===typeof a&&this.setStyle(a);return this},setScalar:function(a){this.b=this.g=this.r=a;return this},setHex:function(a){a=Math.floor(a);this.r=(a>>16&255)/255;this.g=(a>>8&255)/255;this.b=(a&255)/255;return this},setRGB:function(a,b,c){this.r=a;this.g=b;this.b=c;return this},setHSL:function(){function a(a,c,d){0>d&&(d+=1);1<d&&--d;return d<1/6?a+6*(c-a)*d:.5>d?c:d<2/3?a+6*(c-a)*(2/3-d):a}return function(b, +c,d){b=S.euclideanModulo(b,1);c=S.clamp(c,0,1);d=S.clamp(d,0,1);0===c?this.r=this.g=this.b=d:(c=.5>=d?d*(1+c):d+c-d*c,d=2*d-c,this.r=a(d,c,b+1/3),this.g=a(d,c,b),this.b=a(d,c,b-1/3));return this}}(),setStyle:function(a){function b(b){void 0!==b&&1>parseFloat(b)&&console.warn("THREE.Color: Alpha component of "+a+" will be ignored.")}var c;if(c=/^((?:rgb|hsl)a?)\(\s*([^\)]*)\)/.exec(a)){var d=c[2];switch(c[1]){case "rgb":case "rgba":if(c=/^(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec(d))return this.r= +Math.min(255,parseInt(c[1],10))/255,this.g=Math.min(255,parseInt(c[2],10))/255,this.b=Math.min(255,parseInt(c[3],10))/255,b(c[5]),this;if(c=/^(\d+)%\s*,\s*(\d+)%\s*,\s*(\d+)%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec(d))return this.r=Math.min(100,parseInt(c[1],10))/100,this.g=Math.min(100,parseInt(c[2],10))/100,this.b=Math.min(100,parseInt(c[3],10))/100,b(c[5]),this;break;case "hsl":case "hsla":if(c=/^([0-9]*\.?[0-9]+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec(d)){d=parseFloat(c[1])/ +360;var e=parseInt(c[2],10)/100,f=parseInt(c[3],10)/100;b(c[5]);return this.setHSL(d,e,f)}}}else if(c=/^#([A-Fa-f0-9]+)$/.exec(a)){c=c[1];d=c.length;if(3===d)return this.r=parseInt(c.charAt(0)+c.charAt(0),16)/255,this.g=parseInt(c.charAt(1)+c.charAt(1),16)/255,this.b=parseInt(c.charAt(2)+c.charAt(2),16)/255,this;if(6===d)return this.r=parseInt(c.charAt(0)+c.charAt(1),16)/255,this.g=parseInt(c.charAt(2)+c.charAt(3),16)/255,this.b=parseInt(c.charAt(4)+c.charAt(5),16)/255,this}a&&0<a.length&&(c=Wg[a], +void 0!==c?this.setHex(c):console.warn("THREE.Color: Unknown color "+a));return this},clone:function(){return new this.constructor(this.r,this.g,this.b)},copy:function(a){this.r=a.r;this.g=a.g;this.b=a.b;return this},copyGammaToLinear:function(a,b){void 0===b&&(b=2);this.r=Math.pow(a.r,b);this.g=Math.pow(a.g,b);this.b=Math.pow(a.b,b);return this},copyLinearToGamma:function(a,b){void 0===b&&(b=2);b=0<b?1/b:1;this.r=Math.pow(a.r,b);this.g=Math.pow(a.g,b);this.b=Math.pow(a.b,b);return this},convertGammaToLinear:function(a){this.copyGammaToLinear(this, +a);return this},convertLinearToGamma:function(a){this.copyLinearToGamma(this,a);return this},copySRGBToLinear:function(){function a(a){return.04045>a?.0773993808*a:Math.pow(.9478672986*a+.0521327014,2.4)}return function(b){this.r=a(b.r);this.g=a(b.g);this.b=a(b.b);return this}}(),copyLinearToSRGB:function(){function a(a){return.0031308>a?12.92*a:1.055*Math.pow(a,.41666)-.055}return function(b){this.r=a(b.r);this.g=a(b.g);this.b=a(b.b);return this}}(),convertSRGBToLinear:function(){this.copySRGBToLinear(this); +return this},convertLinearToSRGB:function(){this.copyLinearToSRGB(this);return this},getHex:function(){return 255*this.r<<16^255*this.g<<8^255*this.b<<0},getHexString:function(){return("000000"+this.getHex().toString(16)).slice(-6)},getHSL:function(a){void 0===a&&(console.warn("THREE.Color: .getHSL() target is now required"),a={h:0,s:0,l:0});var b=this.r,c=this.g,d=this.b,e=Math.max(b,c,d),f=Math.min(b,c,d),g,h=(f+e)/2;if(f===e)f=g=0;else{var k=e-f;f=.5>=h?k/(e+f):k/(2-e-f);switch(e){case b:g=(c- +d)/k+(c<d?6:0);break;case c:g=(d-b)/k+2;break;case d:g=(b-c)/k+4}g/=6}a.h=g;a.s=f;a.l=h;return a},getStyle:function(){return"rgb("+(255*this.r|0)+","+(255*this.g|0)+","+(255*this.b|0)+")"},offsetHSL:function(){var a={};return function(b,c,d){this.getHSL(a);a.h+=b;a.s+=c;a.l+=d;this.setHSL(a.h,a.s,a.l);return this}}(),add:function(a){this.r+=a.r;this.g+=a.g;this.b+=a.b;return this},addColors:function(a,b){this.r=a.r+b.r;this.g=a.g+b.g;this.b=a.b+b.b;return this},addScalar:function(a){this.r+=a;this.g+= +a;this.b+=a;return this},sub:function(a){this.r=Math.max(0,this.r-a.r);this.g=Math.max(0,this.g-a.g);this.b=Math.max(0,this.b-a.b);return this},multiply:function(a){this.r*=a.r;this.g*=a.g;this.b*=a.b;return this},multiplyScalar:function(a){this.r*=a;this.g*=a;this.b*=a;return this},lerp:function(a,b){this.r+=(a.r-this.r)*b;this.g+=(a.g-this.g)*b;this.b+=(a.b-this.b)*b;return this},lerpHSL:function(){var a={h:0,s:0,l:0},b={h:0,s:0,l:0};return function(c,d){this.getHSL(a);c.getHSL(b);c=S.lerp(a.h, +b.h,d);var e=S.lerp(a.s,b.s,d);d=S.lerp(a.l,b.l,d);this.setHSL(c,e,d);return this}}(),equals:function(a){return a.r===this.r&&a.g===this.g&&a.b===this.b},fromArray:function(a,b){void 0===b&&(b=0);this.r=a[b];this.g=a[b+1];this.b=a[b+2];return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this.r;a[b+1]=this.g;a[b+2]=this.b;return a},toJSON:function(){return this.getHex()}});var H={common:{diffuse:{value:new G(15658734)},opacity:{value:1},map:{value:null},uvTransform:{value:new oa}, +alphaMap:{value:null}},specularmap:{specularMap:{value:null}},envmap:{envMap:{value:null},flipEnvMap:{value:-1},reflectivity:{value:1},refractionRatio:{value:.98},maxMipLevel:{value:0}},aomap:{aoMap:{value:null},aoMapIntensity:{value:1}},lightmap:{lightMap:{value:null},lightMapIntensity:{value:1}},emissivemap:{emissiveMap:{value:null}},bumpmap:{bumpMap:{value:null},bumpScale:{value:1}},normalmap:{normalMap:{value:null},normalScale:{value:new A(1,1)}},displacementmap:{displacementMap:{value:null}, +displacementScale:{value:1},displacementBias:{value:0}},roughnessmap:{roughnessMap:{value:null}},metalnessmap:{metalnessMap:{value:null}},gradientmap:{gradientMap:{value:null}},fog:{fogDensity:{value:2.5E-4},fogNear:{value:1},fogFar:{value:2E3},fogColor:{value:new G(16777215)}},lights:{ambientLightColor:{value:[]},directionalLights:{value:[],properties:{direction:{},color:{},shadow:{},shadowBias:{},shadowRadius:{},shadowMapSize:{}}},directionalShadowMap:{value:[]},directionalShadowMatrix:{value:[]}, +spotLights:{value:[],properties:{color:{},position:{},direction:{},distance:{},coneCos:{},penumbraCos:{},decay:{},shadow:{},shadowBias:{},shadowRadius:{},shadowMapSize:{}}},spotShadowMap:{value:[]},spotShadowMatrix:{value:[]},pointLights:{value:[],properties:{color:{},position:{},decay:{},distance:{},shadow:{},shadowBias:{},shadowRadius:{},shadowMapSize:{},shadowCameraNear:{},shadowCameraFar:{}}},pointShadowMap:{value:[]},pointShadowMatrix:{value:[]},hemisphereLights:{value:[],properties:{direction:{}, +skyColor:{},groundColor:{}}},rectAreaLights:{value:[],properties:{color:{},position:{},width:{},height:{}}}},points:{diffuse:{value:new G(15658734)},opacity:{value:1},size:{value:1},scale:{value:1},map:{value:null},uvTransform:{value:new oa}},sprite:{diffuse:{value:new G(15658734)},opacity:{value:1},center:{value:new A(.5,.5)},rotation:{value:0},map:{value:null},uvTransform:{value:new oa}}},Qa={basic:{uniforms:va.merge([H.common,H.specularmap,H.envmap,H.aomap,H.lightmap,H.fog]),vertexShader:K.meshbasic_vert, +fragmentShader:K.meshbasic_frag},lambert:{uniforms:va.merge([H.common,H.specularmap,H.envmap,H.aomap,H.lightmap,H.emissivemap,H.fog,H.lights,{emissive:{value:new G(0)}}]),vertexShader:K.meshlambert_vert,fragmentShader:K.meshlambert_frag},phong:{uniforms:va.merge([H.common,H.specularmap,H.envmap,H.aomap,H.lightmap,H.emissivemap,H.bumpmap,H.normalmap,H.displacementmap,H.gradientmap,H.fog,H.lights,{emissive:{value:new G(0)},specular:{value:new G(1118481)},shininess:{value:30}}]),vertexShader:K.meshphong_vert, +fragmentShader:K.meshphong_frag},standard:{uniforms:va.merge([H.common,H.envmap,H.aomap,H.lightmap,H.emissivemap,H.bumpmap,H.normalmap,H.displacementmap,H.roughnessmap,H.metalnessmap,H.fog,H.lights,{emissive:{value:new G(0)},roughness:{value:.5},metalness:{value:.5},envMapIntensity:{value:1}}]),vertexShader:K.meshphysical_vert,fragmentShader:K.meshphysical_frag},matcap:{uniforms:va.merge([H.common,H.bumpmap,H.normalmap,H.displacementmap,H.fog,{matcap:{value:null}}]),vertexShader:K.meshmatcap_vert, +fragmentShader:K.meshmatcap_frag},points:{uniforms:va.merge([H.points,H.fog]),vertexShader:K.points_vert,fragmentShader:K.points_frag},dashed:{uniforms:va.merge([H.common,H.fog,{scale:{value:1},dashSize:{value:1},totalSize:{value:2}}]),vertexShader:K.linedashed_vert,fragmentShader:K.linedashed_frag},depth:{uniforms:va.merge([H.common,H.displacementmap]),vertexShader:K.depth_vert,fragmentShader:K.depth_frag},normal:{uniforms:va.merge([H.common,H.bumpmap,H.normalmap,H.displacementmap,{opacity:{value:1}}]), +vertexShader:K.normal_vert,fragmentShader:K.normal_frag},sprite:{uniforms:va.merge([H.sprite,H.fog]),vertexShader:K.sprite_vert,fragmentShader:K.sprite_frag},background:{uniforms:{t2D:{value:null}},vertexShader:K.background_vert,fragmentShader:K.background_frag},cube:{uniforms:{tCube:{value:null},tFlip:{value:-1},opacity:{value:1}},vertexShader:K.cube_vert,fragmentShader:K.cube_frag},equirect:{uniforms:{tEquirect:{value:null}},vertexShader:K.equirect_vert,fragmentShader:K.equirect_frag},distanceRGBA:{uniforms:va.merge([H.common, +H.displacementmap,{referencePosition:{value:new p},nearDistance:{value:1},farDistance:{value:1E3}}]),vertexShader:K.distanceRGBA_vert,fragmentShader:K.distanceRGBA_frag},shadow:{uniforms:va.merge([H.lights,H.fog,{color:{value:new G(0)},opacity:{value:1}}]),vertexShader:K.shadow_vert,fragmentShader:K.shadow_frag}};Qa.physical={uniforms:va.merge([Qa.standard.uniforms,{clearCoat:{value:0},clearCoatRoughness:{value:0}}]),vertexShader:K.meshphysical_vert,fragmentShader:K.meshphysical_frag};Object.assign(Xa.prototype, +{clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.a=a.a;this.b=a.b;this.c=a.c;this.normal.copy(a.normal);this.color.copy(a.color);this.materialIndex=a.materialIndex;for(var b=0,c=a.vertexNormals.length;b<c;b++)this.vertexNormals[b]=a.vertexNormals[b].clone();b=0;for(c=a.vertexColors.length;b<c;b++)this.vertexColors[b]=a.vertexColors[b].clone();return this}});kb.RotationOrders="XYZ YZX ZXY XZY YXZ ZYX".split(" ");kb.DefaultOrder="XYZ";Object.defineProperties(kb.prototype, +{x:{get:function(){return this._x},set:function(a){this._x=a;this.onChangeCallback()}},y:{get:function(){return this._y},set:function(a){this._y=a;this.onChangeCallback()}},z:{get:function(){return this._z},set:function(a){this._z=a;this.onChangeCallback()}},order:{get:function(){return this._order},set:function(a){this._order=a;this.onChangeCallback()}}});Object.assign(kb.prototype,{isEuler:!0,set:function(a,b,c,d){this._x=a;this._y=b;this._z=c;this._order=d||this._order;this.onChangeCallback(); +return this},clone:function(){return new this.constructor(this._x,this._y,this._z,this._order)},copy:function(a){this._x=a._x;this._y=a._y;this._z=a._z;this._order=a._order;this.onChangeCallback();return this},setFromRotationMatrix:function(a,b,c){var d=S.clamp,e=a.elements;a=e[0];var f=e[4],g=e[8],h=e[1],k=e[5],m=e[9],l=e[2],n=e[6];e=e[10];b=b||this._order;"XYZ"===b?(this._y=Math.asin(d(g,-1,1)),.99999>Math.abs(g)?(this._x=Math.atan2(-m,e),this._z=Math.atan2(-f,a)):(this._x=Math.atan2(n,k),this._z= +0)):"YXZ"===b?(this._x=Math.asin(-d(m,-1,1)),.99999>Math.abs(m)?(this._y=Math.atan2(g,e),this._z=Math.atan2(h,k)):(this._y=Math.atan2(-l,a),this._z=0)):"ZXY"===b?(this._x=Math.asin(d(n,-1,1)),.99999>Math.abs(n)?(this._y=Math.atan2(-l,e),this._z=Math.atan2(-f,k)):(this._y=0,this._z=Math.atan2(h,a))):"ZYX"===b?(this._y=Math.asin(-d(l,-1,1)),.99999>Math.abs(l)?(this._x=Math.atan2(n,e),this._z=Math.atan2(h,a)):(this._x=0,this._z=Math.atan2(-f,k))):"YZX"===b?(this._z=Math.asin(d(h,-1,1)),.99999>Math.abs(h)? +(this._x=Math.atan2(-m,k),this._y=Math.atan2(-l,a)):(this._x=0,this._y=Math.atan2(g,e))):"XZY"===b?(this._z=Math.asin(-d(f,-1,1)),.99999>Math.abs(f)?(this._x=Math.atan2(n,k),this._y=Math.atan2(g,a)):(this._x=Math.atan2(-m,e),this._y=0)):console.warn("THREE.Euler: .setFromRotationMatrix() given unsupported order: "+b);this._order=b;if(!1!==c)this.onChangeCallback();return this},setFromQuaternion:function(){var a=new P;return function(b,c,d){a.makeRotationFromQuaternion(b);return this.setFromRotationMatrix(a, +c,d)}}(),setFromVector3:function(a,b){return this.set(a.x,a.y,a.z,b||this._order)},reorder:function(){var a=new ja;return function(b){a.setFromEuler(this);return this.setFromQuaternion(a,b)}}(),equals:function(a){return a._x===this._x&&a._y===this._y&&a._z===this._z&&a._order===this._order},fromArray:function(a){this._x=a[0];this._y=a[1];this._z=a[2];void 0!==a[3]&&(this._order=a[3]);this.onChangeCallback();return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this._x;a[b+1]= +this._y;a[b+2]=this._z;a[b+3]=this._order;return a},toVector3:function(a){return a?a.set(this._x,this._y,this._z):new p(this._x,this._y,this._z)},onChange:function(a){this.onChangeCallback=a;return this},onChangeCallback:function(){}});Object.assign(Xd.prototype,{set:function(a){this.mask=1<<a|0},enable:function(a){this.mask=this.mask|1<<a|0},toggle:function(a){this.mask^=1<<a|0},disable:function(a){this.mask&=~(1<<a|0)},test:function(a){return 0!==(this.mask&a.mask)}});var If=0;C.DefaultUp=new p(0, +1,0);C.DefaultMatrixAutoUpdate=!0;C.prototype=Object.assign(Object.create(ia.prototype),{constructor:C,isObject3D:!0,onBeforeRender:function(){},onAfterRender:function(){},applyMatrix:function(a){this.matrix.multiplyMatrices(a,this.matrix);this.matrix.decompose(this.position,this.quaternion,this.scale)},applyQuaternion:function(a){this.quaternion.premultiply(a);return this},setRotationFromAxisAngle:function(a,b){this.quaternion.setFromAxisAngle(a,b)},setRotationFromEuler:function(a){this.quaternion.setFromEuler(a, +!0)},setRotationFromMatrix:function(a){this.quaternion.setFromRotationMatrix(a)},setRotationFromQuaternion:function(a){this.quaternion.copy(a)},rotateOnAxis:function(){var a=new ja;return function(b,c){a.setFromAxisAngle(b,c);this.quaternion.multiply(a);return this}}(),rotateOnWorldAxis:function(){var a=new ja;return function(b,c){a.setFromAxisAngle(b,c);this.quaternion.premultiply(a);return this}}(),rotateX:function(){var a=new p(1,0,0);return function(b){return this.rotateOnAxis(a,b)}}(),rotateY:function(){var a= +new p(0,1,0);return function(b){return this.rotateOnAxis(a,b)}}(),rotateZ:function(){var a=new p(0,0,1);return function(b){return this.rotateOnAxis(a,b)}}(),translateOnAxis:function(){var a=new p;return function(b,c){a.copy(b).applyQuaternion(this.quaternion);this.position.add(a.multiplyScalar(c));return this}}(),translateX:function(){var a=new p(1,0,0);return function(b){return this.translateOnAxis(a,b)}}(),translateY:function(){var a=new p(0,1,0);return function(b){return this.translateOnAxis(a, +b)}}(),translateZ:function(){var a=new p(0,0,1);return function(b){return this.translateOnAxis(a,b)}}(),localToWorld:function(a){return a.applyMatrix4(this.matrixWorld)},worldToLocal:function(){var a=new P;return function(b){return b.applyMatrix4(a.getInverse(this.matrixWorld))}}(),lookAt:function(){var a=new ja,b=new P,c=new p,d=new p;return function(e,f,g){e.isVector3?c.copy(e):c.set(e,f,g);e=this.parent;this.updateWorldMatrix(!0,!1);d.setFromMatrixPosition(this.matrixWorld);this.isCamera?b.lookAt(d, +c,this.up):b.lookAt(c,d,this.up);this.quaternion.setFromRotationMatrix(b);e&&(b.extractRotation(e.matrixWorld),a.setFromRotationMatrix(b),this.quaternion.premultiply(a.inverse()))}}(),add:function(a){if(1<arguments.length){for(var b=0;b<arguments.length;b++)this.add(arguments[b]);return this}if(a===this)return console.error("THREE.Object3D.add: object can't be added as a child of itself.",a),this;a&&a.isObject3D?(null!==a.parent&&a.parent.remove(a),a.parent=this,a.dispatchEvent({type:"added"}),this.children.push(a)): +console.error("THREE.Object3D.add: object not an instance of THREE.Object3D.",a);return this},remove:function(a){if(1<arguments.length){for(var b=0;b<arguments.length;b++)this.remove(arguments[b]);return this}b=this.children.indexOf(a);-1!==b&&(a.parent=null,a.dispatchEvent({type:"removed"}),this.children.splice(b,1));return this},getObjectById:function(a){return this.getObjectByProperty("id",a)},getObjectByName:function(a){return this.getObjectByProperty("name",a)},getObjectByProperty:function(a, +b){if(this[a]===b)return this;for(var c=0,d=this.children.length;c<d;c++){var e=this.children[c].getObjectByProperty(a,b);if(void 0!==e)return e}},getWorldPosition:function(a){void 0===a&&(console.warn("THREE.Object3D: .getWorldPosition() target is now required"),a=new p);this.updateMatrixWorld(!0);return a.setFromMatrixPosition(this.matrixWorld)},getWorldQuaternion:function(){var a=new p,b=new p;return function(c){void 0===c&&(console.warn("THREE.Object3D: .getWorldQuaternion() target is now required"), +c=new ja);this.updateMatrixWorld(!0);this.matrixWorld.decompose(a,c,b);return c}}(),getWorldScale:function(){var a=new p,b=new ja;return function(c){void 0===c&&(console.warn("THREE.Object3D: .getWorldScale() target is now required"),c=new p);this.updateMatrixWorld(!0);this.matrixWorld.decompose(a,b,c);return c}}(),getWorldDirection:function(a){void 0===a&&(console.warn("THREE.Object3D: .getWorldDirection() target is now required"),a=new p);this.updateMatrixWorld(!0);var b=this.matrixWorld.elements; +return a.set(b[8],b[9],b[10]).normalize()},raycast:function(){},traverse:function(a){a(this);for(var b=this.children,c=0,d=b.length;c<d;c++)b[c].traverse(a)},traverseVisible:function(a){if(!1!==this.visible){a(this);for(var b=this.children,c=0,d=b.length;c<d;c++)b[c].traverseVisible(a)}},traverseAncestors:function(a){var b=this.parent;null!==b&&(a(b),b.traverseAncestors(a))},updateMatrix:function(){this.matrix.compose(this.position,this.quaternion,this.scale);this.matrixWorldNeedsUpdate=!0},updateMatrixWorld:function(a){this.matrixAutoUpdate&& +this.updateMatrix();if(this.matrixWorldNeedsUpdate||a)null===this.parent?this.matrixWorld.copy(this.matrix):this.matrixWorld.multiplyMatrices(this.parent.matrixWorld,this.matrix),this.matrixWorldNeedsUpdate=!1,a=!0;for(var b=this.children,c=0,d=b.length;c<d;c++)b[c].updateMatrixWorld(a)},updateWorldMatrix:function(a,b){var c=this.parent;!0===a&&null!==c&&c.updateWorldMatrix(!0,!1);this.matrixAutoUpdate&&this.updateMatrix();null===this.parent?this.matrixWorld.copy(this.matrix):this.matrixWorld.multiplyMatrices(this.parent.matrixWorld, +this.matrix);if(!0===b)for(a=this.children,b=0,c=a.length;b<c;b++)a[b].updateWorldMatrix(!1,!0)},toJSON:function(a){function b(b,c){void 0===b[c.uuid]&&(b[c.uuid]=c.toJSON(a));return c.uuid}function c(a){var b=[],c;for(c in a){var d=a[c];delete d.metadata;b.push(d)}return b}var d=void 0===a||"string"===typeof a,e={};d&&(a={geometries:{},materials:{},textures:{},images:{},shapes:{}},e.metadata={version:4.5,type:"Object",generator:"Object3D.toJSON"});var f={};f.uuid=this.uuid;f.type=this.type;""!== +this.name&&(f.name=this.name);!0===this.castShadow&&(f.castShadow=!0);!0===this.receiveShadow&&(f.receiveShadow=!0);!1===this.visible&&(f.visible=!1);!1===this.frustumCulled&&(f.frustumCulled=!1);0!==this.renderOrder&&(f.renderOrder=this.renderOrder);"{}"!==JSON.stringify(this.userData)&&(f.userData=this.userData);f.layers=this.layers.mask;f.matrix=this.matrix.toArray();!1===this.matrixAutoUpdate&&(f.matrixAutoUpdate=!1);if(this.isMesh||this.isLine||this.isPoints){f.geometry=b(a.geometries,this.geometry); +var g=this.geometry.parameters;if(void 0!==g&&void 0!==g.shapes)if(g=g.shapes,Array.isArray(g))for(var h=0,k=g.length;h<k;h++)b(a.shapes,g[h]);else b(a.shapes,g)}if(void 0!==this.material)if(Array.isArray(this.material)){g=[];h=0;for(k=this.material.length;h<k;h++)g.push(b(a.materials,this.material[h]));f.material=g}else f.material=b(a.materials,this.material);if(0<this.children.length)for(f.children=[],h=0;h<this.children.length;h++)f.children.push(this.children[h].toJSON(a).object);if(d){d=c(a.geometries); +h=c(a.materials);k=c(a.textures);var m=c(a.images);g=c(a.shapes);0<d.length&&(e.geometries=d);0<h.length&&(e.materials=h);0<k.length&&(e.textures=k);0<m.length&&(e.images=m);0<g.length&&(e.shapes=g)}e.object=f;return e},clone:function(a){return(new this.constructor).copy(this,a)},copy:function(a,b){void 0===b&&(b=!0);this.name=a.name;this.up.copy(a.up);this.position.copy(a.position);this.quaternion.copy(a.quaternion);this.scale.copy(a.scale);this.matrix.copy(a.matrix);this.matrixWorld.copy(a.matrixWorld); +this.matrixAutoUpdate=a.matrixAutoUpdate;this.matrixWorldNeedsUpdate=a.matrixWorldNeedsUpdate;this.layers.mask=a.layers.mask;this.visible=a.visible;this.castShadow=a.castShadow;this.receiveShadow=a.receiveShadow;this.frustumCulled=a.frustumCulled;this.renderOrder=a.renderOrder;this.userData=JSON.parse(JSON.stringify(a.userData));if(!0===b)for(b=0;b<a.children.length;b++)this.add(a.children[b].clone());return this}});var Jf=0;M.prototype=Object.assign(Object.create(ia.prototype),{constructor:M,isGeometry:!0, +applyMatrix:function(a){for(var b=(new oa).getNormalMatrix(a),c=0,d=this.vertices.length;c<d;c++)this.vertices[c].applyMatrix4(a);c=0;for(d=this.faces.length;c<d;c++){a=this.faces[c];a.normal.applyMatrix3(b).normalize();for(var e=0,f=a.vertexNormals.length;e<f;e++)a.vertexNormals[e].applyMatrix3(b).normalize()}null!==this.boundingBox&&this.computeBoundingBox();null!==this.boundingSphere&&this.computeBoundingSphere();this.normalsNeedUpdate=this.verticesNeedUpdate=!0;return this},rotateX:function(){var a= +new P;return function(b){a.makeRotationX(b);this.applyMatrix(a);return this}}(),rotateY:function(){var a=new P;return function(b){a.makeRotationY(b);this.applyMatrix(a);return this}}(),rotateZ:function(){var a=new P;return function(b){a.makeRotationZ(b);this.applyMatrix(a);return this}}(),translate:function(){var a=new P;return function(b,c,d){a.makeTranslation(b,c,d);this.applyMatrix(a);return this}}(),scale:function(){var a=new P;return function(b,c,d){a.makeScale(b,c,d);this.applyMatrix(a);return this}}(), +lookAt:function(){var a=new C;return function(b){a.lookAt(b);a.updateMatrix();this.applyMatrix(a.matrix)}}(),fromBufferGeometry:function(a){function b(a,b,d,e){var f=void 0!==g?[l[a].clone(),l[b].clone(),l[d].clone()]:[],r=void 0!==h?[c.colors[a].clone(),c.colors[b].clone(),c.colors[d].clone()]:[];e=new Xa(a,b,d,f,r,e);c.faces.push(e);void 0!==k&&c.faceVertexUvs[0].push([n[a].clone(),n[b].clone(),n[d].clone()]);void 0!==m&&c.faceVertexUvs[1].push([q[a].clone(),q[b].clone(),q[d].clone()])}var c=this, +d=null!==a.index?a.index.array:void 0,e=a.attributes,f=e.position.array,g=void 0!==e.normal?e.normal.array:void 0,h=void 0!==e.color?e.color.array:void 0,k=void 0!==e.uv?e.uv.array:void 0,m=void 0!==e.uv2?e.uv2.array:void 0;void 0!==m&&(this.faceVertexUvs[1]=[]);for(var l=[],n=[],q=[],v=e=0;e<f.length;e+=3,v+=2)c.vertices.push(new p(f[e],f[e+1],f[e+2])),void 0!==g&&l.push(new p(g[e],g[e+1],g[e+2])),void 0!==h&&c.colors.push(new G(h[e],h[e+1],h[e+2])),void 0!==k&&n.push(new A(k[v],k[v+1])),void 0!== +m&&q.push(new A(m[v],m[v+1]));var t=a.groups;if(0<t.length)for(e=0;e<t.length;e++){f=t[e];var u=f.start,y=f.count;v=u;for(u+=y;v<u;v+=3)void 0!==d?b(d[v],d[v+1],d[v+2],f.materialIndex):b(v,v+1,v+2,f.materialIndex)}else if(void 0!==d)for(e=0;e<d.length;e+=3)b(d[e],d[e+1],d[e+2]);else for(e=0;e<f.length/3;e+=3)b(e,e+1,e+2);this.computeFaceNormals();null!==a.boundingBox&&(this.boundingBox=a.boundingBox.clone());null!==a.boundingSphere&&(this.boundingSphere=a.boundingSphere.clone());return this},center:function(){var a= +new p;return function(){this.computeBoundingBox();this.boundingBox.getCenter(a).negate();this.translate(a.x,a.y,a.z);return this}}(),normalize:function(){this.computeBoundingSphere();var a=this.boundingSphere.center,b=this.boundingSphere.radius;b=0===b?1:1/b;var c=new P;c.set(b,0,0,-b*a.x,0,b,0,-b*a.y,0,0,b,-b*a.z,0,0,0,1);this.applyMatrix(c);return this},computeFaceNormals:function(){for(var a=new p,b=new p,c=0,d=this.faces.length;c<d;c++){var e=this.faces[c],f=this.vertices[e.a],g=this.vertices[e.b]; +a.subVectors(this.vertices[e.c],g);b.subVectors(f,g);a.cross(b);a.normalize();e.normal.copy(a)}},computeVertexNormals:function(a){void 0===a&&(a=!0);var b;var c=Array(this.vertices.length);var d=0;for(b=this.vertices.length;d<b;d++)c[d]=new p;if(a){var e=new p,f=new p;a=0;for(d=this.faces.length;a<d;a++){b=this.faces[a];var g=this.vertices[b.a];var h=this.vertices[b.b];var k=this.vertices[b.c];e.subVectors(k,h);f.subVectors(g,h);e.cross(f);c[b.a].add(e);c[b.b].add(e);c[b.c].add(e)}}else for(this.computeFaceNormals(), +a=0,d=this.faces.length;a<d;a++)b=this.faces[a],c[b.a].add(b.normal),c[b.b].add(b.normal),c[b.c].add(b.normal);d=0;for(b=this.vertices.length;d<b;d++)c[d].normalize();a=0;for(d=this.faces.length;a<d;a++)b=this.faces[a],g=b.vertexNormals,3===g.length?(g[0].copy(c[b.a]),g[1].copy(c[b.b]),g[2].copy(c[b.c])):(g[0]=c[b.a].clone(),g[1]=c[b.b].clone(),g[2]=c[b.c].clone());0<this.faces.length&&(this.normalsNeedUpdate=!0)},computeFlatVertexNormals:function(){var a;this.computeFaceNormals();var b=0;for(a=this.faces.length;b< +a;b++){var c=this.faces[b];var d=c.vertexNormals;3===d.length?(d[0].copy(c.normal),d[1].copy(c.normal),d[2].copy(c.normal)):(d[0]=c.normal.clone(),d[1]=c.normal.clone(),d[2]=c.normal.clone())}0<this.faces.length&&(this.normalsNeedUpdate=!0)},computeMorphNormals:function(){var a,b;var c=0;for(b=this.faces.length;c<b;c++){var d=this.faces[c];d.__originalFaceNormal?d.__originalFaceNormal.copy(d.normal):d.__originalFaceNormal=d.normal.clone();d.__originalVertexNormals||(d.__originalVertexNormals=[]); +var e=0;for(a=d.vertexNormals.length;e<a;e++)d.__originalVertexNormals[e]?d.__originalVertexNormals[e].copy(d.vertexNormals[e]):d.__originalVertexNormals[e]=d.vertexNormals[e].clone()}var f=new M;f.faces=this.faces;e=0;for(a=this.morphTargets.length;e<a;e++){if(!this.morphNormals[e]){this.morphNormals[e]={};this.morphNormals[e].faceNormals=[];this.morphNormals[e].vertexNormals=[];d=this.morphNormals[e].faceNormals;var g=this.morphNormals[e].vertexNormals;c=0;for(b=this.faces.length;c<b;c++){var h= +new p;var k={a:new p,b:new p,c:new p};d.push(h);g.push(k)}}g=this.morphNormals[e];f.vertices=this.morphTargets[e].vertices;f.computeFaceNormals();f.computeVertexNormals();c=0;for(b=this.faces.length;c<b;c++)d=this.faces[c],h=g.faceNormals[c],k=g.vertexNormals[c],h.copy(d.normal),k.a.copy(d.vertexNormals[0]),k.b.copy(d.vertexNormals[1]),k.c.copy(d.vertexNormals[2])}c=0;for(b=this.faces.length;c<b;c++)d=this.faces[c],d.normal=d.__originalFaceNormal,d.vertexNormals=d.__originalVertexNormals},computeBoundingBox:function(){null=== +this.boundingBox&&(this.boundingBox=new Wa);this.boundingBox.setFromPoints(this.vertices)},computeBoundingSphere:function(){null===this.boundingSphere&&(this.boundingSphere=new Fa);this.boundingSphere.setFromPoints(this.vertices)},merge:function(a,b,c){if(a&&a.isGeometry){var d,e=this.vertices.length,f=this.vertices,g=a.vertices,h=this.faces,k=a.faces,m=this.faceVertexUvs[0],l=a.faceVertexUvs[0],n=this.colors,q=a.colors;void 0===c&&(c=0);void 0!==b&&(d=(new oa).getNormalMatrix(b));a=0;for(var p=g.length;a< +p;a++){var t=g[a].clone();void 0!==b&&t.applyMatrix4(b);f.push(t)}a=0;for(p=q.length;a<p;a++)n.push(q[a].clone());a=0;for(p=k.length;a<p;a++){g=k[a];var u=g.vertexNormals;q=g.vertexColors;n=new Xa(g.a+e,g.b+e,g.c+e);n.normal.copy(g.normal);void 0!==d&&n.normal.applyMatrix3(d).normalize();b=0;for(f=u.length;b<f;b++)t=u[b].clone(),void 0!==d&&t.applyMatrix3(d).normalize(),n.vertexNormals.push(t);n.color.copy(g.color);b=0;for(f=q.length;b<f;b++)t=q[b],n.vertexColors.push(t.clone());n.materialIndex=g.materialIndex+ +c;h.push(n)}a=0;for(p=l.length;a<p;a++)if(c=l[a],d=[],void 0!==c){b=0;for(f=c.length;b<f;b++)d.push(c[b].clone());m.push(d)}}else console.error("THREE.Geometry.merge(): geometry not an instance of THREE.Geometry.",a)},mergeMesh:function(a){a&&a.isMesh?(a.matrixAutoUpdate&&a.updateMatrix(),this.merge(a.geometry,a.matrix)):console.error("THREE.Geometry.mergeMesh(): mesh not an instance of THREE.Mesh.",a)},mergeVertices:function(){var a={},b=[],c=[],d=Math.pow(10,4),e;var f=0;for(e=this.vertices.length;f< +e;f++){var g=this.vertices[f];g=Math.round(g.x*d)+"_"+Math.round(g.y*d)+"_"+Math.round(g.z*d);void 0===a[g]?(a[g]=f,b.push(this.vertices[f]),c[f]=b.length-1):c[f]=c[a[g]]}a=[];f=0;for(e=this.faces.length;f<e;f++)for(d=this.faces[f],d.a=c[d.a],d.b=c[d.b],d.c=c[d.c],d=[d.a,d.b,d.c],g=0;3>g;g++)if(d[g]===d[(g+1)%3]){a.push(f);break}for(f=a.length-1;0<=f;f--)for(d=a[f],this.faces.splice(d,1),c=0,e=this.faceVertexUvs.length;c<e;c++)this.faceVertexUvs[c].splice(d,1);f=this.vertices.length-b.length;this.vertices= +b;return f},setFromPoints:function(a){this.vertices=[];for(var b=0,c=a.length;b<c;b++){var d=a[b];this.vertices.push(new p(d.x,d.y,d.z||0))}return this},sortFacesByMaterialIndex:function(){for(var a=this.faces,b=a.length,c=0;c<b;c++)a[c]._id=c;a.sort(function(a,b){return a.materialIndex-b.materialIndex});var d=this.faceVertexUvs[0],e=this.faceVertexUvs[1],f,g;d&&d.length===b&&(f=[]);e&&e.length===b&&(g=[]);for(c=0;c<b;c++){var h=a[c]._id;f&&f.push(d[h]);g&&g.push(e[h])}f&&(this.faceVertexUvs[0]=f); +g&&(this.faceVertexUvs[1]=g)},toJSON:function(){function a(a,b,c){return c?a|1<<b:a&~(1<<b)}function b(a){var b=a.x.toString()+a.y.toString()+a.z.toString();if(void 0!==m[b])return m[b];m[b]=k.length/3;k.push(a.x,a.y,a.z);return m[b]}function c(a){var b=a.r.toString()+a.g.toString()+a.b.toString();if(void 0!==n[b])return n[b];n[b]=l.length;l.push(a.getHex());return n[b]}function d(a){var b=a.x.toString()+a.y.toString();if(void 0!==p[b])return p[b];p[b]=q.length/2;q.push(a.x,a.y);return p[b]}var e= +{metadata:{version:4.5,type:"Geometry",generator:"Geometry.toJSON"}};e.uuid=this.uuid;e.type=this.type;""!==this.name&&(e.name=this.name);if(void 0!==this.parameters){var f=this.parameters,g;for(g in f)void 0!==f[g]&&(e[g]=f[g]);return e}f=[];for(g=0;g<this.vertices.length;g++){var h=this.vertices[g];f.push(h.x,h.y,h.z)}h=[];var k=[],m={},l=[],n={},q=[],p={};for(g=0;g<this.faces.length;g++){var t=this.faces[g],u=void 0!==this.faceVertexUvs[0][g],y=0<t.normal.length(),x=0<t.vertexNormals.length,w= +1!==t.color.r||1!==t.color.g||1!==t.color.b,D=0<t.vertexColors.length,J=0;J=a(J,0,0);J=a(J,1,!0);J=a(J,2,!1);J=a(J,3,u);J=a(J,4,y);J=a(J,5,x);J=a(J,6,w);J=a(J,7,D);h.push(J);h.push(t.a,t.b,t.c);h.push(t.materialIndex);u&&(u=this.faceVertexUvs[0][g],h.push(d(u[0]),d(u[1]),d(u[2])));y&&h.push(b(t.normal));x&&(y=t.vertexNormals,h.push(b(y[0]),b(y[1]),b(y[2])));w&&h.push(c(t.color));D&&(t=t.vertexColors,h.push(c(t[0]),c(t[1]),c(t[2])))}e.data={};e.data.vertices=f;e.data.normals=k;0<l.length&&(e.data.colors= +l);0<q.length&&(e.data.uvs=[q]);e.data.faces=h;return e},clone:function(){return(new M).copy(this)},copy:function(a){var b,c,d;this.vertices=[];this.colors=[];this.faces=[];this.faceVertexUvs=[[]];this.morphTargets=[];this.morphNormals=[];this.skinWeights=[];this.skinIndices=[];this.lineDistances=[];this.boundingSphere=this.boundingBox=null;this.name=a.name;var e=a.vertices;var f=0;for(b=e.length;f<b;f++)this.vertices.push(e[f].clone());e=a.colors;f=0;for(b=e.length;f<b;f++)this.colors.push(e[f].clone()); +e=a.faces;f=0;for(b=e.length;f<b;f++)this.faces.push(e[f].clone());f=0;for(b=a.faceVertexUvs.length;f<b;f++){var g=a.faceVertexUvs[f];void 0===this.faceVertexUvs[f]&&(this.faceVertexUvs[f]=[]);e=0;for(c=g.length;e<c;e++){var h=g[e],k=[];var m=0;for(d=h.length;m<d;m++)k.push(h[m].clone());this.faceVertexUvs[f].push(k)}}m=a.morphTargets;f=0;for(b=m.length;f<b;f++){d={};d.name=m[f].name;if(void 0!==m[f].vertices)for(d.vertices=[],e=0,c=m[f].vertices.length;e<c;e++)d.vertices.push(m[f].vertices[e].clone()); +if(void 0!==m[f].normals)for(d.normals=[],e=0,c=m[f].normals.length;e<c;e++)d.normals.push(m[f].normals[e].clone());this.morphTargets.push(d)}m=a.morphNormals;f=0;for(b=m.length;f<b;f++){d={};if(void 0!==m[f].vertexNormals)for(d.vertexNormals=[],e=0,c=m[f].vertexNormals.length;e<c;e++)g=m[f].vertexNormals[e],h={},h.a=g.a.clone(),h.b=g.b.clone(),h.c=g.c.clone(),d.vertexNormals.push(h);if(void 0!==m[f].faceNormals)for(d.faceNormals=[],e=0,c=m[f].faceNormals.length;e<c;e++)d.faceNormals.push(m[f].faceNormals[e].clone()); +this.morphNormals.push(d)}e=a.skinWeights;f=0;for(b=e.length;f<b;f++)this.skinWeights.push(e[f].clone());e=a.skinIndices;f=0;for(b=e.length;f<b;f++)this.skinIndices.push(e[f].clone());e=a.lineDistances;f=0;for(b=e.length;f<b;f++)this.lineDistances.push(e[f]);f=a.boundingBox;null!==f&&(this.boundingBox=f.clone());f=a.boundingSphere;null!==f&&(this.boundingSphere=f.clone());this.elementsNeedUpdate=a.elementsNeedUpdate;this.verticesNeedUpdate=a.verticesNeedUpdate;this.uvsNeedUpdate=a.uvsNeedUpdate;this.normalsNeedUpdate= +a.normalsNeedUpdate;this.colorsNeedUpdate=a.colorsNeedUpdate;this.lineDistancesNeedUpdate=a.lineDistancesNeedUpdate;this.groupsNeedUpdate=a.groupsNeedUpdate;return this},dispose:function(){this.dispatchEvent({type:"dispose"})}});Object.defineProperty(I.prototype,"needsUpdate",{set:function(a){!0===a&&this.version++}});Object.assign(I.prototype,{isBufferAttribute:!0,onUploadCallback:function(){},setArray:function(a){if(Array.isArray(a))throw new TypeError("THREE.BufferAttribute: array should be a Typed Array."); +this.count=void 0!==a?a.length/this.itemSize:0;this.array=a;return this},setDynamic:function(a){this.dynamic=a;return this},copy:function(a){this.name=a.name;this.array=new a.array.constructor(a.array);this.itemSize=a.itemSize;this.count=a.count;this.normalized=a.normalized;this.dynamic=a.dynamic;return this},copyAt:function(a,b,c){a*=this.itemSize;c*=b.itemSize;for(var d=0,e=this.itemSize;d<e;d++)this.array[a+d]=b.array[c+d];return this},copyArray:function(a){this.array.set(a);return this},copyColorsArray:function(a){for(var b= +this.array,c=0,d=0,e=a.length;d<e;d++){var f=a[d];void 0===f&&(console.warn("THREE.BufferAttribute.copyColorsArray(): color is undefined",d),f=new G);b[c++]=f.r;b[c++]=f.g;b[c++]=f.b}return this},copyVector2sArray:function(a){for(var b=this.array,c=0,d=0,e=a.length;d<e;d++){var f=a[d];void 0===f&&(console.warn("THREE.BufferAttribute.copyVector2sArray(): vector is undefined",d),f=new A);b[c++]=f.x;b[c++]=f.y}return this},copyVector3sArray:function(a){for(var b=this.array,c=0,d=0,e=a.length;d<e;d++){var f= +a[d];void 0===f&&(console.warn("THREE.BufferAttribute.copyVector3sArray(): vector is undefined",d),f=new p);b[c++]=f.x;b[c++]=f.y;b[c++]=f.z}return this},copyVector4sArray:function(a){for(var b=this.array,c=0,d=0,e=a.length;d<e;d++){var f=a[d];void 0===f&&(console.warn("THREE.BufferAttribute.copyVector4sArray(): vector is undefined",d),f=new Z);b[c++]=f.x;b[c++]=f.y;b[c++]=f.z;b[c++]=f.w}return this},set:function(a,b){void 0===b&&(b=0);this.array.set(a,b);return this},getX:function(a){return this.array[a* +this.itemSize]},setX:function(a,b){this.array[a*this.itemSize]=b;return this},getY:function(a){return this.array[a*this.itemSize+1]},setY:function(a,b){this.array[a*this.itemSize+1]=b;return this},getZ:function(a){return this.array[a*this.itemSize+2]},setZ:function(a,b){this.array[a*this.itemSize+2]=b;return this},getW:function(a){return this.array[a*this.itemSize+3]},setW:function(a,b){this.array[a*this.itemSize+3]=b;return this},setXY:function(a,b,c){a*=this.itemSize;this.array[a+0]=b;this.array[a+ +1]=c;return this},setXYZ:function(a,b,c,d){a*=this.itemSize;this.array[a+0]=b;this.array[a+1]=c;this.array[a+2]=d;return this},setXYZW:function(a,b,c,d,e){a*=this.itemSize;this.array[a+0]=b;this.array[a+1]=c;this.array[a+2]=d;this.array[a+3]=e;return this},onUpload:function(a){this.onUploadCallback=a;return this},clone:function(){return(new this.constructor(this.array,this.itemSize)).copy(this)}});sc.prototype=Object.create(I.prototype);sc.prototype.constructor=sc;tc.prototype=Object.create(I.prototype); +tc.prototype.constructor=tc;uc.prototype=Object.create(I.prototype);uc.prototype.constructor=uc;vc.prototype=Object.create(I.prototype);vc.prototype.constructor=vc;lb.prototype=Object.create(I.prototype);lb.prototype.constructor=lb;wc.prototype=Object.create(I.prototype);wc.prototype.constructor=wc;mb.prototype=Object.create(I.prototype);mb.prototype.constructor=mb;z.prototype=Object.create(I.prototype);z.prototype.constructor=z;xc.prototype=Object.create(I.prototype);xc.prototype.constructor=xc; +Object.assign(Ge.prototype,{computeGroups:function(a){var b=[],c=void 0;a=a.faces;for(var d=0;d<a.length;d++){var e=a[d];if(e.materialIndex!==c){c=e.materialIndex;void 0!==f&&(f.count=3*d-f.start,b.push(f));var f={start:3*d,materialIndex:c}}}void 0!==f&&(f.count=3*d-f.start,b.push(f));this.groups=b},fromGeometry:function(a){var b=a.faces,c=a.vertices,d=a.faceVertexUvs,e=d[0]&&0<d[0].length,f=d[1]&&0<d[1].length,g=a.morphTargets,h=g.length;if(0<h){var k=[];for(var m=0;m<h;m++)k[m]={name:g[m].name, +data:[]};this.morphTargets.position=k}var l=a.morphNormals,n=l.length;if(0<n){var q=[];for(m=0;m<n;m++)q[m]={name:l[m].name,data:[]};this.morphTargets.normal=q}var p=a.skinIndices,t=a.skinWeights,u=p.length===c.length,y=t.length===c.length;0<c.length&&0===b.length&&console.error("THREE.DirectGeometry: Faceless geometries are not supported.");for(m=0;m<b.length;m++){var x=b[m];this.vertices.push(c[x.a],c[x.b],c[x.c]);var w=x.vertexNormals;3===w.length?this.normals.push(w[0],w[1],w[2]):(w=x.normal, +this.normals.push(w,w,w));w=x.vertexColors;3===w.length?this.colors.push(w[0],w[1],w[2]):(w=x.color,this.colors.push(w,w,w));!0===e&&(w=d[0][m],void 0!==w?this.uvs.push(w[0],w[1],w[2]):(console.warn("THREE.DirectGeometry.fromGeometry(): Undefined vertexUv ",m),this.uvs.push(new A,new A,new A)));!0===f&&(w=d[1][m],void 0!==w?this.uvs2.push(w[0],w[1],w[2]):(console.warn("THREE.DirectGeometry.fromGeometry(): Undefined vertexUv2 ",m),this.uvs2.push(new A,new A,new A)));for(w=0;w<h;w++){var D=g[w].vertices; +k[w].data.push(D[x.a],D[x.b],D[x.c])}for(w=0;w<n;w++)D=l[w].vertexNormals[m],q[w].data.push(D.a,D.b,D.c);u&&this.skinIndices.push(p[x.a],p[x.b],p[x.c]);y&&this.skinWeights.push(t[x.a],t[x.b],t[x.c])}this.computeGroups(a);this.verticesNeedUpdate=a.verticesNeedUpdate;this.normalsNeedUpdate=a.normalsNeedUpdate;this.colorsNeedUpdate=a.colorsNeedUpdate;this.uvsNeedUpdate=a.uvsNeedUpdate;this.groupsNeedUpdate=a.groupsNeedUpdate;return this}});var Kf=1;F.prototype=Object.assign(Object.create(ia.prototype), +{constructor:F,isBufferGeometry:!0,getIndex:function(){return this.index},setIndex:function(a){Array.isArray(a)?this.index=new (65535<He(a)?mb:lb)(a,1):this.index=a},addAttribute:function(a,b,c){if(!(b&&b.isBufferAttribute||b&&b.isInterleavedBufferAttribute))return console.warn("THREE.BufferGeometry: .addAttribute() now expects ( name, attribute )."),this.addAttribute(a,new I(b,c));if("index"===a)return console.warn("THREE.BufferGeometry.addAttribute: Use .setIndex() for index attribute."),this.setIndex(b), +this;this.attributes[a]=b;return this},getAttribute:function(a){return this.attributes[a]},removeAttribute:function(a){delete this.attributes[a];return this},addGroup:function(a,b,c){this.groups.push({start:a,count:b,materialIndex:void 0!==c?c:0})},clearGroups:function(){this.groups=[]},setDrawRange:function(a,b){this.drawRange.start=a;this.drawRange.count=b},applyMatrix:function(a){var b=this.attributes.position;void 0!==b&&(a.applyToBufferAttribute(b),b.needsUpdate=!0);b=this.attributes.normal; +void 0!==b&&((new oa).getNormalMatrix(a).applyToBufferAttribute(b),b.needsUpdate=!0);null!==this.boundingBox&&this.computeBoundingBox();null!==this.boundingSphere&&this.computeBoundingSphere();return this},rotateX:function(){var a=new P;return function(b){a.makeRotationX(b);this.applyMatrix(a);return this}}(),rotateY:function(){var a=new P;return function(b){a.makeRotationY(b);this.applyMatrix(a);return this}}(),rotateZ:function(){var a=new P;return function(b){a.makeRotationZ(b);this.applyMatrix(a); +return this}}(),translate:function(){var a=new P;return function(b,c,d){a.makeTranslation(b,c,d);this.applyMatrix(a);return this}}(),scale:function(){var a=new P;return function(b,c,d){a.makeScale(b,c,d);this.applyMatrix(a);return this}}(),lookAt:function(){var a=new C;return function(b){a.lookAt(b);a.updateMatrix();this.applyMatrix(a.matrix)}}(),center:function(){var a=new p;return function(){this.computeBoundingBox();this.boundingBox.getCenter(a).negate();this.translate(a.x,a.y,a.z);return this}}(), +setFromObject:function(a){var b=a.geometry;if(a.isPoints||a.isLine){a=new z(3*b.vertices.length,3);var c=new z(3*b.colors.length,3);this.addAttribute("position",a.copyVector3sArray(b.vertices));this.addAttribute("color",c.copyColorsArray(b.colors));b.lineDistances&&b.lineDistances.length===b.vertices.length&&(a=new z(b.lineDistances.length,1),this.addAttribute("lineDistance",a.copyArray(b.lineDistances)));null!==b.boundingSphere&&(this.boundingSphere=b.boundingSphere.clone());null!==b.boundingBox&& +(this.boundingBox=b.boundingBox.clone())}else a.isMesh&&b&&b.isGeometry&&this.fromGeometry(b);return this},setFromPoints:function(a){for(var b=[],c=0,d=a.length;c<d;c++){var e=a[c];b.push(e.x,e.y,e.z||0)}this.addAttribute("position",new z(b,3));return this},updateFromObject:function(a){var b=a.geometry;if(a.isMesh){var c=b.__directGeometry;!0===b.elementsNeedUpdate&&(c=void 0,b.elementsNeedUpdate=!1);if(void 0===c)return this.fromGeometry(b);c.verticesNeedUpdate=b.verticesNeedUpdate;c.normalsNeedUpdate= +b.normalsNeedUpdate;c.colorsNeedUpdate=b.colorsNeedUpdate;c.uvsNeedUpdate=b.uvsNeedUpdate;c.groupsNeedUpdate=b.groupsNeedUpdate;b.verticesNeedUpdate=!1;b.normalsNeedUpdate=!1;b.colorsNeedUpdate=!1;b.uvsNeedUpdate=!1;b.groupsNeedUpdate=!1;b=c}!0===b.verticesNeedUpdate&&(c=this.attributes.position,void 0!==c&&(c.copyVector3sArray(b.vertices),c.needsUpdate=!0),b.verticesNeedUpdate=!1);!0===b.normalsNeedUpdate&&(c=this.attributes.normal,void 0!==c&&(c.copyVector3sArray(b.normals),c.needsUpdate=!0),b.normalsNeedUpdate= +!1);!0===b.colorsNeedUpdate&&(c=this.attributes.color,void 0!==c&&(c.copyColorsArray(b.colors),c.needsUpdate=!0),b.colorsNeedUpdate=!1);b.uvsNeedUpdate&&(c=this.attributes.uv,void 0!==c&&(c.copyVector2sArray(b.uvs),c.needsUpdate=!0),b.uvsNeedUpdate=!1);b.lineDistancesNeedUpdate&&(c=this.attributes.lineDistance,void 0!==c&&(c.copyArray(b.lineDistances),c.needsUpdate=!0),b.lineDistancesNeedUpdate=!1);b.groupsNeedUpdate&&(b.computeGroups(a.geometry),this.groups=b.groups,b.groupsNeedUpdate=!1);return this}, +fromGeometry:function(a){a.__directGeometry=(new Ge).fromGeometry(a);return this.fromDirectGeometry(a.__directGeometry)},fromDirectGeometry:function(a){var b=new Float32Array(3*a.vertices.length);this.addAttribute("position",(new I(b,3)).copyVector3sArray(a.vertices));0<a.normals.length&&(b=new Float32Array(3*a.normals.length),this.addAttribute("normal",(new I(b,3)).copyVector3sArray(a.normals)));0<a.colors.length&&(b=new Float32Array(3*a.colors.length),this.addAttribute("color",(new I(b,3)).copyColorsArray(a.colors))); +0<a.uvs.length&&(b=new Float32Array(2*a.uvs.length),this.addAttribute("uv",(new I(b,2)).copyVector2sArray(a.uvs)));0<a.uvs2.length&&(b=new Float32Array(2*a.uvs2.length),this.addAttribute("uv2",(new I(b,2)).copyVector2sArray(a.uvs2)));this.groups=a.groups;for(var c in a.morphTargets){b=[];for(var d=a.morphTargets[c],e=0,f=d.length;e<f;e++){var g=d[e],h=new z(3*g.data.length,3);h.name=g.name;b.push(h.copyVector3sArray(g.data))}this.morphAttributes[c]=b}0<a.skinIndices.length&&(c=new z(4*a.skinIndices.length, +4),this.addAttribute("skinIndex",c.copyVector4sArray(a.skinIndices)));0<a.skinWeights.length&&(c=new z(4*a.skinWeights.length,4),this.addAttribute("skinWeight",c.copyVector4sArray(a.skinWeights)));null!==a.boundingSphere&&(this.boundingSphere=a.boundingSphere.clone());null!==a.boundingBox&&(this.boundingBox=a.boundingBox.clone());return this},computeBoundingBox:function(){null===this.boundingBox&&(this.boundingBox=new Wa);var a=this.attributes.position;void 0!==a?this.boundingBox.setFromBufferAttribute(a): +this.boundingBox.makeEmpty();(isNaN(this.boundingBox.min.x)||isNaN(this.boundingBox.min.y)||isNaN(this.boundingBox.min.z))&&console.error('THREE.BufferGeometry.computeBoundingBox: Computed min/max have NaN values. The "position" attribute is likely to have NaN values.',this)},computeBoundingSphere:function(){var a=new Wa,b=new p;return function(){null===this.boundingSphere&&(this.boundingSphere=new Fa);var c=this.attributes.position;if(c){var d=this.boundingSphere.center;a.setFromBufferAttribute(c); +a.getCenter(d);for(var e=0,f=0,g=c.count;f<g;f++)b.x=c.getX(f),b.y=c.getY(f),b.z=c.getZ(f),e=Math.max(e,d.distanceToSquared(b));this.boundingSphere.radius=Math.sqrt(e);isNaN(this.boundingSphere.radius)&&console.error('THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.',this)}}}(),computeFaceNormals:function(){},computeVertexNormals:function(){var a=this.index,b=this.attributes;if(b.position){var c=b.position.array;if(void 0=== +b.normal)this.addAttribute("normal",new I(new Float32Array(c.length),3));else for(var d=b.normal.array,e=0,f=d.length;e<f;e++)d[e]=0;d=b.normal.array;var g=new p,h=new p,k=new p,m=new p,l=new p;if(a){var n=a.array;e=0;for(f=a.count;e<f;e+=3){a=3*n[e+0];var q=3*n[e+1];var v=3*n[e+2];g.fromArray(c,a);h.fromArray(c,q);k.fromArray(c,v);m.subVectors(k,h);l.subVectors(g,h);m.cross(l);d[a]+=m.x;d[a+1]+=m.y;d[a+2]+=m.z;d[q]+=m.x;d[q+1]+=m.y;d[q+2]+=m.z;d[v]+=m.x;d[v+1]+=m.y;d[v+2]+=m.z}}else for(e=0,f=c.length;e< +f;e+=9)g.fromArray(c,e),h.fromArray(c,e+3),k.fromArray(c,e+6),m.subVectors(k,h),l.subVectors(g,h),m.cross(l),d[e]=m.x,d[e+1]=m.y,d[e+2]=m.z,d[e+3]=m.x,d[e+4]=m.y,d[e+5]=m.z,d[e+6]=m.x,d[e+7]=m.y,d[e+8]=m.z;this.normalizeNormals();b.normal.needsUpdate=!0}},merge:function(a,b){if(a&&a.isBufferGeometry){void 0===b&&(b=0,console.warn("THREE.BufferGeometry.merge(): Overwriting original geometry, starting at offset=0. Use BufferGeometryUtils.mergeBufferGeometries() for lossless merge."));var c=this.attributes, +d;for(d in c)if(void 0!==a.attributes[d]){var e=c[d].array,f=a.attributes[d],g=f.array,h=0;for(f=f.itemSize*b;h<g.length;h++,f++)e[f]=g[h]}return this}console.error("THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.",a)},normalizeNormals:function(){var a=new p;return function(){for(var b=this.attributes.normal,c=0,d=b.count;c<d;c++)a.x=b.getX(c),a.y=b.getY(c),a.z=b.getZ(c),a.normalize(),b.setXYZ(c,a.x,a.y,a.z)}}(),toNonIndexed:function(){if(null===this.index)return console.warn("THREE.BufferGeometry.toNonIndexed(): Geometry is already non-indexed."), +this;var a=new F,b=this.index.array,c=this.attributes,d;for(d in c){var e=c[d],f=e.array,g=e.itemSize,h=new f.constructor(b.length*g),k=0;e=0;for(var m=b.length;e<m;e++){var l=b[e]*g;for(var n=0;n<g;n++)h[k++]=f[l++]}a.addAttribute(d,new I(h,g))}b=this.groups;e=0;for(m=b.length;e<m;e++)c=b[e],a.addGroup(c.start,c.count,c.materialIndex);return a},toJSON:function(){var a={metadata:{version:4.5,type:"BufferGeometry",generator:"BufferGeometry.toJSON"}};a.uuid=this.uuid;a.type=this.type;""!==this.name&& +(a.name=this.name);0<Object.keys(this.userData).length&&(a.userData=this.userData);if(void 0!==this.parameters){var b=this.parameters;for(e in b)void 0!==b[e]&&(a[e]=b[e]);return a}a.data={attributes:{}};var c=this.index;null!==c&&(b=Array.prototype.slice.call(c.array),a.data.index={type:c.array.constructor.name,array:b});c=this.attributes;for(e in c){var d=c[e];b=Array.prototype.slice.call(d.array);a.data.attributes[e]={itemSize:d.itemSize,type:d.array.constructor.name,array:b,normalized:d.normalized}}var e= +this.groups;0<e.length&&(a.data.groups=JSON.parse(JSON.stringify(e)));e=this.boundingSphere;null!==e&&(a.data.boundingSphere={center:e.center.toArray(),radius:e.radius});return a},clone:function(){return(new F).copy(this)},copy:function(a){var b;this.index=null;this.attributes={};this.morphAttributes={};this.groups=[];this.boundingSphere=this.boundingBox=null;this.name=a.name;var c=a.index;null!==c&&this.setIndex(c.clone());c=a.attributes;for(g in c)this.addAttribute(g,c[g].clone());var d=a.morphAttributes; +for(g in d){var e=[],f=d[g];c=0;for(b=f.length;c<b;c++)e.push(f[c].clone());this.morphAttributes[g]=e}var g=a.groups;c=0;for(b=g.length;c<b;c++)d=g[c],this.addGroup(d.start,d.count,d.materialIndex);g=a.boundingBox;null!==g&&(this.boundingBox=g.clone());g=a.boundingSphere;null!==g&&(this.boundingSphere=g.clone());this.drawRange.start=a.drawRange.start;this.drawRange.count=a.drawRange.count;this.userData=a.userData;return this},dispose:function(){this.dispatchEvent({type:"dispose"})}});Kb.prototype= +Object.create(M.prototype);Kb.prototype.constructor=Kb;nb.prototype=Object.create(F.prototype);nb.prototype.constructor=nb;yc.prototype=Object.create(M.prototype);yc.prototype.constructor=yc;ob.prototype=Object.create(F.prototype);ob.prototype.constructor=ob;var Lf=0;L.prototype=Object.assign(Object.create(ia.prototype),{constructor:L,isMaterial:!0,onBeforeCompile:function(){},setValues:function(a){if(void 0!==a)for(var b in a){var c=a[b];if(void 0===c)console.warn("THREE.Material: '"+b+"' parameter is undefined."); +else if("shading"===b)console.warn("THREE."+this.type+": .shading has been removed. Use the boolean .flatShading instead."),this.flatShading=1===c?!0:!1;else{var d=this[b];void 0===d?console.warn("THREE."+this.type+": '"+b+"' is not a property of this material."):d&&d.isColor?d.set(c):d&&d.isVector3&&c&&c.isVector3?d.copy(c):this[b]="overdraw"===b?Number(c):c}}},toJSON:function(a){function b(a){var b=[],c;for(c in a){var d=a[c];delete d.metadata;b.push(d)}return b}var c=void 0===a||"string"===typeof a; +c&&(a={textures:{},images:{}});var d={metadata:{version:4.5,type:"Material",generator:"Material.toJSON"}};d.uuid=this.uuid;d.type=this.type;""!==this.name&&(d.name=this.name);this.color&&this.color.isColor&&(d.color=this.color.getHex());void 0!==this.roughness&&(d.roughness=this.roughness);void 0!==this.metalness&&(d.metalness=this.metalness);this.emissive&&this.emissive.isColor&&(d.emissive=this.emissive.getHex());1!==this.emissiveIntensity&&(d.emissiveIntensity=this.emissiveIntensity);this.specular&& +this.specular.isColor&&(d.specular=this.specular.getHex());void 0!==this.shininess&&(d.shininess=this.shininess);void 0!==this.clearCoat&&(d.clearCoat=this.clearCoat);void 0!==this.clearCoatRoughness&&(d.clearCoatRoughness=this.clearCoatRoughness);this.map&&this.map.isTexture&&(d.map=this.map.toJSON(a).uuid);this.alphaMap&&this.alphaMap.isTexture&&(d.alphaMap=this.alphaMap.toJSON(a).uuid);this.lightMap&&this.lightMap.isTexture&&(d.lightMap=this.lightMap.toJSON(a).uuid);this.aoMap&&this.aoMap.isTexture&& +(d.aoMap=this.aoMap.toJSON(a).uuid,d.aoMapIntensity=this.aoMapIntensity);this.bumpMap&&this.bumpMap.isTexture&&(d.bumpMap=this.bumpMap.toJSON(a).uuid,d.bumpScale=this.bumpScale);this.normalMap&&this.normalMap.isTexture&&(d.normalMap=this.normalMap.toJSON(a).uuid,d.normalMapType=this.normalMapType,d.normalScale=this.normalScale.toArray());this.displacementMap&&this.displacementMap.isTexture&&(d.displacementMap=this.displacementMap.toJSON(a).uuid,d.displacementScale=this.displacementScale,d.displacementBias= +this.displacementBias);this.roughnessMap&&this.roughnessMap.isTexture&&(d.roughnessMap=this.roughnessMap.toJSON(a).uuid);this.metalnessMap&&this.metalnessMap.isTexture&&(d.metalnessMap=this.metalnessMap.toJSON(a).uuid);this.emissiveMap&&this.emissiveMap.isTexture&&(d.emissiveMap=this.emissiveMap.toJSON(a).uuid);this.specularMap&&this.specularMap.isTexture&&(d.specularMap=this.specularMap.toJSON(a).uuid);this.envMap&&this.envMap.isTexture&&(d.envMap=this.envMap.toJSON(a).uuid,d.reflectivity=this.reflectivity, +void 0!==this.combine&&(d.combine=this.combine),void 0!==this.envMapIntensity&&(d.envMapIntensity=this.envMapIntensity));this.gradientMap&&this.gradientMap.isTexture&&(d.gradientMap=this.gradientMap.toJSON(a).uuid);void 0!==this.size&&(d.size=this.size);void 0!==this.sizeAttenuation&&(d.sizeAttenuation=this.sizeAttenuation);1!==this.blending&&(d.blending=this.blending);!0===this.flatShading&&(d.flatShading=this.flatShading);0!==this.side&&(d.side=this.side);0!==this.vertexColors&&(d.vertexColors= +this.vertexColors);1>this.opacity&&(d.opacity=this.opacity);!0===this.transparent&&(d.transparent=this.transparent);d.depthFunc=this.depthFunc;d.depthTest=this.depthTest;d.depthWrite=this.depthWrite;0!==this.rotation&&(d.rotation=this.rotation);!0===this.polygonOffset&&(d.polygonOffset=!0);0!==this.polygonOffsetFactor&&(d.polygonOffsetFactor=this.polygonOffsetFactor);0!==this.polygonOffsetUnits&&(d.polygonOffsetUnits=this.polygonOffsetUnits);1!==this.linewidth&&(d.linewidth=this.linewidth);void 0!== +this.dashSize&&(d.dashSize=this.dashSize);void 0!==this.gapSize&&(d.gapSize=this.gapSize);void 0!==this.scale&&(d.scale=this.scale);!0===this.dithering&&(d.dithering=!0);0<this.alphaTest&&(d.alphaTest=this.alphaTest);!0===this.premultipliedAlpha&&(d.premultipliedAlpha=this.premultipliedAlpha);!0===this.wireframe&&(d.wireframe=this.wireframe);1<this.wireframeLinewidth&&(d.wireframeLinewidth=this.wireframeLinewidth);"round"!==this.wireframeLinecap&&(d.wireframeLinecap=this.wireframeLinecap);"round"!== +this.wireframeLinejoin&&(d.wireframeLinejoin=this.wireframeLinejoin);!0===this.morphTargets&&(d.morphTargets=!0);!0===this.skinning&&(d.skinning=!0);!1===this.visible&&(d.visible=!1);"{}"!==JSON.stringify(this.userData)&&(d.userData=this.userData);c&&(c=b(a.textures),a=b(a.images),0<c.length&&(d.textures=c),0<a.length&&(d.images=a));return d},clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.name=a.name;this.fog=a.fog;this.lights=a.lights;this.blending=a.blending;this.side= +a.side;this.flatShading=a.flatShading;this.vertexColors=a.vertexColors;this.opacity=a.opacity;this.transparent=a.transparent;this.blendSrc=a.blendSrc;this.blendDst=a.blendDst;this.blendEquation=a.blendEquation;this.blendSrcAlpha=a.blendSrcAlpha;this.blendDstAlpha=a.blendDstAlpha;this.blendEquationAlpha=a.blendEquationAlpha;this.depthFunc=a.depthFunc;this.depthTest=a.depthTest;this.depthWrite=a.depthWrite;this.colorWrite=a.colorWrite;this.precision=a.precision;this.polygonOffset=a.polygonOffset;this.polygonOffsetFactor= +a.polygonOffsetFactor;this.polygonOffsetUnits=a.polygonOffsetUnits;this.dithering=a.dithering;this.alphaTest=a.alphaTest;this.premultipliedAlpha=a.premultipliedAlpha;this.overdraw=a.overdraw;this.visible=a.visible;this.userData=JSON.parse(JSON.stringify(a.userData));this.clipShadows=a.clipShadows;this.clipIntersection=a.clipIntersection;var b=a.clippingPlanes,c=null;if(null!==b){var d=b.length;c=Array(d);for(var e=0;e!==d;++e)c[e]=b[e].clone()}this.clippingPlanes=c;this.shadowSide=a.shadowSide;return this}, +dispose:function(){this.dispatchEvent({type:"dispose"})}});ka.prototype=Object.create(L.prototype);ka.prototype.constructor=ka;ka.prototype.isShaderMaterial=!0;ka.prototype.copy=function(a){L.prototype.copy.call(this,a);this.fragmentShader=a.fragmentShader;this.vertexShader=a.vertexShader;this.uniforms=va.clone(a.uniforms);this.defines=Object.assign({},a.defines);this.wireframe=a.wireframe;this.wireframeLinewidth=a.wireframeLinewidth;this.lights=a.lights;this.clipping=a.clipping;this.skinning=a.skinning; +this.morphTargets=a.morphTargets;this.morphNormals=a.morphNormals;this.extensions=a.extensions;return this};ka.prototype.toJSON=function(a){var b=L.prototype.toJSON.call(this,a);b.uniforms={};for(var c in this.uniforms){var d=this.uniforms[c].value;b.uniforms[c]=d.isTexture?{type:"t",value:d.toJSON(a).uuid}:d.isColor?{type:"c",value:d.getHex()}:d.isVector2?{type:"v2",value:d.toArray()}:d.isVector3?{type:"v3",value:d.toArray()}:d.isVector4?{type:"v4",value:d.toArray()}:d.isMatrix4?{type:"m4",value:d.toArray()}: +{value:d}}0<Object.keys(this.defines).length&&(b.defines=this.defines);b.vertexShader=this.vertexShader;b.fragmentShader=this.fragmentShader;return b};Object.assign(pb.prototype,{set:function(a,b){this.origin.copy(a);this.direction.copy(b);return this},clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.origin.copy(a.origin);this.direction.copy(a.direction);return this},at:function(a,b){void 0===b&&(console.warn("THREE.Ray: .at() target is now required"),b=new p);return b.copy(this.direction).multiplyScalar(a).add(this.origin)}, +lookAt:function(a){this.direction.copy(a).sub(this.origin).normalize();return this},recast:function(){var a=new p;return function(b){this.origin.copy(this.at(b,a));return this}}(),closestPointToPoint:function(a,b){void 0===b&&(console.warn("THREE.Ray: .closestPointToPoint() target is now required"),b=new p);b.subVectors(a,this.origin);a=b.dot(this.direction);return 0>a?b.copy(this.origin):b.copy(this.direction).multiplyScalar(a).add(this.origin)},distanceToPoint:function(a){return Math.sqrt(this.distanceSqToPoint(a))}, +distanceSqToPoint:function(){var a=new p;return function(b){var c=a.subVectors(b,this.origin).dot(this.direction);if(0>c)return this.origin.distanceToSquared(b);a.copy(this.direction).multiplyScalar(c).add(this.origin);return a.distanceToSquared(b)}}(),distanceSqToSegment:function(){var a=new p,b=new p,c=new p;return function(d,e,f,g){a.copy(d).add(e).multiplyScalar(.5);b.copy(e).sub(d).normalize();c.copy(this.origin).sub(a);var h=.5*d.distanceTo(e),k=-this.direction.dot(b),m=c.dot(this.direction), +l=-c.dot(b),n=c.lengthSq(),q=Math.abs(1-k*k);if(0<q){d=k*l-m;e=k*m-l;var p=h*q;0<=d?e>=-p?e<=p?(h=1/q,d*=h,e*=h,k=d*(d+k*e+2*m)+e*(k*d+e+2*l)+n):(e=h,d=Math.max(0,-(k*e+m)),k=-d*d+e*(e+2*l)+n):(e=-h,d=Math.max(0,-(k*e+m)),k=-d*d+e*(e+2*l)+n):e<=-p?(d=Math.max(0,-(-k*h+m)),e=0<d?-h:Math.min(Math.max(-h,-l),h),k=-d*d+e*(e+2*l)+n):e<=p?(d=0,e=Math.min(Math.max(-h,-l),h),k=e*(e+2*l)+n):(d=Math.max(0,-(k*h+m)),e=0<d?h:Math.min(Math.max(-h,-l),h),k=-d*d+e*(e+2*l)+n)}else e=0<k?-h:h,d=Math.max(0,-(k*e+m)), +k=-d*d+e*(e+2*l)+n;f&&f.copy(this.direction).multiplyScalar(d).add(this.origin);g&&g.copy(b).multiplyScalar(e).add(a);return k}}(),intersectSphere:function(){var a=new p;return function(b,c){a.subVectors(b.center,this.origin);var d=a.dot(this.direction),e=a.dot(a)-d*d;b=b.radius*b.radius;if(e>b)return null;b=Math.sqrt(b-e);e=d-b;d+=b;return 0>e&&0>d?null:0>e?this.at(d,c):this.at(e,c)}}(),intersectsSphere:function(a){return this.distanceSqToPoint(a.center)<=a.radius*a.radius},distanceToPlane:function(a){var b= +a.normal.dot(this.direction);if(0===b)return 0===a.distanceToPoint(this.origin)?0:null;a=-(this.origin.dot(a.normal)+a.constant)/b;return 0<=a?a:null},intersectPlane:function(a,b){a=this.distanceToPlane(a);return null===a?null:this.at(a,b)},intersectsPlane:function(a){var b=a.distanceToPoint(this.origin);return 0===b||0>a.normal.dot(this.direction)*b?!0:!1},intersectBox:function(a,b){var c=1/this.direction.x;var d=1/this.direction.y;var e=1/this.direction.z,f=this.origin;if(0<=c){var g=(a.min.x-f.x)* +c;c*=a.max.x-f.x}else g=(a.max.x-f.x)*c,c*=a.min.x-f.x;if(0<=d){var h=(a.min.y-f.y)*d;d*=a.max.y-f.y}else h=(a.max.y-f.y)*d,d*=a.min.y-f.y;if(g>d||h>c)return null;if(h>g||g!==g)g=h;if(d<c||c!==c)c=d;0<=e?(h=(a.min.z-f.z)*e,a=(a.max.z-f.z)*e):(h=(a.max.z-f.z)*e,a=(a.min.z-f.z)*e);if(g>a||h>c)return null;if(h>g||g!==g)g=h;if(a<c||c!==c)c=a;return 0>c?null:this.at(0<=g?g:c,b)},intersectsBox:function(){var a=new p;return function(b){return null!==this.intersectBox(b,a)}}(),intersectTriangle:function(){var a= +new p,b=new p,c=new p,d=new p;return function(e,f,g,h,k){b.subVectors(f,e);c.subVectors(g,e);d.crossVectors(b,c);f=this.direction.dot(d);if(0<f){if(h)return null;h=1}else if(0>f)h=-1,f=-f;else return null;a.subVectors(this.origin,e);e=h*this.direction.dot(c.crossVectors(a,c));if(0>e)return null;g=h*this.direction.dot(b.cross(a));if(0>g||e+g>f)return null;e=-h*a.dot(d);return 0>e?null:this.at(e/f,k)}}(),applyMatrix4:function(a){this.origin.applyMatrix4(a);this.direction.transformDirection(a);return this}, +equals:function(a){return a.origin.equals(this.origin)&&a.direction.equals(this.direction)}});Object.assign(da,{getNormal:function(){var a=new p;return function(b,c,d,e){void 0===e&&(console.warn("THREE.Triangle: .getNormal() target is now required"),e=new p);e.subVectors(d,c);a.subVectors(b,c);e.cross(a);b=e.lengthSq();return 0<b?e.multiplyScalar(1/Math.sqrt(b)):e.set(0,0,0)}}(),getBarycoord:function(){var a=new p,b=new p,c=new p;return function(d,e,f,g,h){a.subVectors(g,e);b.subVectors(f,e);c.subVectors(d, +e);d=a.dot(a);e=a.dot(b);f=a.dot(c);var k=b.dot(b);g=b.dot(c);var m=d*k-e*e;void 0===h&&(console.warn("THREE.Triangle: .getBarycoord() target is now required"),h=new p);if(0===m)return h.set(-2,-1,-1);m=1/m;k=(k*f-e*g)*m;d=(d*g-e*f)*m;return h.set(1-k-d,d,k)}}(),containsPoint:function(){var a=new p;return function(b,c,d,e){da.getBarycoord(b,c,d,e,a);return 0<=a.x&&0<=a.y&&1>=a.x+a.y}}(),getUV:function(){var a=new p;return function(b,c,d,e,f,g,h,k){this.getBarycoord(b,c,d,e,a);k.set(0,0);k.addScaledVector(f, +a.x);k.addScaledVector(g,a.y);k.addScaledVector(h,a.z);return k}}()});Object.assign(da.prototype,{set:function(a,b,c){this.a.copy(a);this.b.copy(b);this.c.copy(c);return this},setFromPointsAndIndices:function(a,b,c,d){this.a.copy(a[b]);this.b.copy(a[c]);this.c.copy(a[d]);return this},clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.a.copy(a.a);this.b.copy(a.b);this.c.copy(a.c);return this},getArea:function(){var a=new p,b=new p;return function(){a.subVectors(this.c, +this.b);b.subVectors(this.a,this.b);return.5*a.cross(b).length()}}(),getMidpoint:function(a){void 0===a&&(console.warn("THREE.Triangle: .getMidpoint() target is now required"),a=new p);return a.addVectors(this.a,this.b).add(this.c).multiplyScalar(1/3)},getNormal:function(a){return da.getNormal(this.a,this.b,this.c,a)},getPlane:function(a){void 0===a&&(console.warn("THREE.Triangle: .getPlane() target is now required"),a=new p);return a.setFromCoplanarPoints(this.a,this.b,this.c)},getBarycoord:function(a, +b){return da.getBarycoord(a,this.a,this.b,this.c,b)},containsPoint:function(a){return da.containsPoint(a,this.a,this.b,this.c)},getUV:function(a,b,c,d,e){return da.getUV(a,this.a,this.b,this.c,b,c,d,e)},intersectsBox:function(a){return a.intersectsTriangle(this)},closestPointToPoint:function(){var a=new p,b=new p,c=new p,d=new p,e=new p,f=new p;return function(g,h){void 0===h&&(console.warn("THREE.Triangle: .closestPointToPoint() target is now required"),h=new p);var k=this.a,m=this.b,l=this.c;a.subVectors(m, +k);b.subVectors(l,k);d.subVectors(g,k);var n=a.dot(d),q=b.dot(d);if(0>=n&&0>=q)return h.copy(k);e.subVectors(g,m);var v=a.dot(e),t=b.dot(e);if(0<=v&&t<=v)return h.copy(m);var u=n*t-v*q;if(0>=u&&0<=n&&0>=v)return m=n/(n-v),h.copy(k).addScaledVector(a,m);f.subVectors(g,l);g=a.dot(f);var y=b.dot(f);if(0<=y&&g<=y)return h.copy(l);n=g*q-n*y;if(0>=n&&0<=q&&0>=y)return u=q/(q-y),h.copy(k).addScaledVector(b,u);q=v*y-g*t;if(0>=q&&0<=t-v&&0<=g-y)return c.subVectors(l,m),u=(t-v)/(t-v+(g-y)),h.copy(m).addScaledVector(c, +u);l=1/(q+n+u);m=n*l;u*=l;return h.copy(k).addScaledVector(a,m).addScaledVector(b,u)}}(),equals:function(a){return a.a.equals(this.a)&&a.b.equals(this.b)&&a.c.equals(this.c)}});wa.prototype=Object.create(L.prototype);wa.prototype.constructor=wa;wa.prototype.isMeshBasicMaterial=!0;wa.prototype.copy=function(a){L.prototype.copy.call(this,a);this.color.copy(a.color);this.map=a.map;this.lightMap=a.lightMap;this.lightMapIntensity=a.lightMapIntensity;this.aoMap=a.aoMap;this.aoMapIntensity=a.aoMapIntensity; +this.specularMap=a.specularMap;this.alphaMap=a.alphaMap;this.envMap=a.envMap;this.combine=a.combine;this.reflectivity=a.reflectivity;this.refractionRatio=a.refractionRatio;this.wireframe=a.wireframe;this.wireframeLinewidth=a.wireframeLinewidth;this.wireframeLinecap=a.wireframeLinecap;this.wireframeLinejoin=a.wireframeLinejoin;this.skinning=a.skinning;this.morphTargets=a.morphTargets;return this};ua.prototype=Object.assign(Object.create(C.prototype),{constructor:ua,isMesh:!0,setDrawMode:function(a){this.drawMode= +a},copy:function(a){C.prototype.copy.call(this,a);this.drawMode=a.drawMode;void 0!==a.morphTargetInfluences&&(this.morphTargetInfluences=a.morphTargetInfluences.slice());void 0!==a.morphTargetDictionary&&(this.morphTargetDictionary=Object.assign({},a.morphTargetDictionary));return this},updateMorphTargets:function(){var a=this.geometry;if(a.isBufferGeometry){a=a.morphAttributes;var b=Object.keys(a);if(0<b.length){var c=a[b[0]];if(void 0!==c)for(this.morphTargetInfluences=[],this.morphTargetDictionary= +{},a=0,b=c.length;a<b;a++){var d=c[a].name||String(a);this.morphTargetInfluences.push(0);this.morphTargetDictionary[d]=a}}}else if(c=a.morphTargets,void 0!==c&&0<c.length)for(this.morphTargetInfluences=[],this.morphTargetDictionary={},a=0,b=c.length;a<b;a++)d=c[a].name||String(a),this.morphTargetInfluences.push(0),this.morphTargetDictionary[d]=a},raycast:function(){function a(a,b,c,d,e,f,g,h){if(null===(1===b.side?d.intersectTriangle(g,f,e,!0,h):d.intersectTriangle(e,f,g,2!==b.side,h)))return null; +u.copy(h);u.applyMatrix4(a.matrixWorld);b=c.ray.origin.distanceTo(u);return b<c.near||b>c.far?null:{distance:b,point:u.clone(),object:a}}function b(b,c,d,e,k,m,l,r,p){f.fromBufferAttribute(k,l);g.fromBufferAttribute(k,r);h.fromBufferAttribute(k,p);if(b=a(b,c,d,e,f,g,h,t))m&&(n.fromBufferAttribute(m,l),q.fromBufferAttribute(m,r),v.fromBufferAttribute(m,p),b.uv=da.getUV(t,f,g,h,n,q,v,new A)),m=new Xa(l,r,p),da.getNormal(f,g,h,m.normal),b.face=m;return b}var c=new P,d=new pb,e=new Fa,f=new p,g=new p, +h=new p,k=new p,m=new p,l=new p,n=new A,q=new A,v=new A,t=new p,u=new p;return function(r,p){var u=this.geometry,y=this.material,x=this.matrixWorld;if(void 0!==y&&(null===u.boundingSphere&&u.computeBoundingSphere(),e.copy(u.boundingSphere),e.applyMatrix4(x),!1!==r.ray.intersectsSphere(e)&&(c.getInverse(x),d.copy(r.ray).applyMatrix4(c),null===u.boundingBox||!1!==d.intersectsBox(u.boundingBox))))if(u.isBufferGeometry){var z=u.index,C=u.attributes.position,B=u.attributes.uv,F=u.groups;u=u.drawRange; +var I;if(null!==z)if(Array.isArray(y)){var G=0;for(I=F.length;G<I;G++){var H=F[G];var L=y[H.materialIndex];x=Math.max(H.start,u.start);var M=Math.min(H.start+H.count,u.start+u.count);for(H=x;H<M;H+=3){x=z.getX(H);var K=z.getX(H+1);var N=z.getX(H+2);if(x=b(this,L,r,d,C,B,x,K,N))x.faceIndex=Math.floor(H/3),p.push(x)}}}else for(x=Math.max(0,u.start),M=Math.min(z.count,u.start+u.count),G=x,I=M;G<I;G+=3){if(x=z.getX(G),K=z.getX(G+1),N=z.getX(G+2),x=b(this,y,r,d,C,B,x,K,N))x.faceIndex=Math.floor(G/3),p.push(x)}else if(void 0!== +C)if(Array.isArray(y))for(G=0,I=F.length;G<I;G++)for(H=F[G],L=y[H.materialIndex],x=Math.max(H.start,u.start),M=Math.min(H.start+H.count,u.start+u.count),H=x;H<M;H+=3){if(x=H,K=H+1,N=H+2,x=b(this,L,r,d,C,B,x,K,N))x.faceIndex=Math.floor(H/3),p.push(x)}else for(x=Math.max(0,u.start),M=Math.min(C.count,u.start+u.count),G=x,I=M;G<I;G+=3)if(x=G,K=G+1,N=G+2,x=b(this,y,r,d,C,B,x,K,N))x.faceIndex=Math.floor(G/3),p.push(x)}else if(u.isGeometry)for(C=Array.isArray(y),B=u.vertices,F=u.faces,x=u.faceVertexUvs[0], +0<x.length&&(z=x),H=0,M=F.length;H<M;H++)if(K=F[H],x=C?y[K.materialIndex]:y,void 0!==x){G=B[K.a];I=B[K.b];L=B[K.c];if(!0===x.morphTargets){N=u.morphTargets;var P=this.morphTargetInfluences;f.set(0,0,0);g.set(0,0,0);h.set(0,0,0);for(var Q=0,S=N.length;Q<S;Q++){var T=P[Q];if(0!==T){var V=N[Q].vertices;f.addScaledVector(k.subVectors(V[K.a],G),T);g.addScaledVector(m.subVectors(V[K.b],I),T);h.addScaledVector(l.subVectors(V[K.c],L),T)}}f.add(G);g.add(I);h.add(L);G=f;I=g;L=h}if(x=a(this,x,r,d,G,I,L,t))z&& +z[H]&&(N=z[H],n.copy(N[0]),q.copy(N[1]),v.copy(N[2]),x.uv=da.getUV(t,G,I,L,n,q,v,new A)),x.face=K,x.faceIndex=H,p.push(x)}}}(),clone:function(){return(new this.constructor(this.geometry,this.material)).copy(this)}});Ya.prototype=Object.create(Q.prototype);Ya.prototype.constructor=Ya;Ya.prototype.isCubeTexture=!0;Object.defineProperty(Ya.prototype,"images",{get:function(){return this.image},set:function(a){this.image=a}});Mb.prototype=Object.create(Q.prototype);Mb.prototype.constructor=Mb;Mb.prototype.isDataTexture3D= +!0;var Oe=new Q,gg=new Mb,Pe=new Ya,Ie=[],Ke=[],Ne=new Float32Array(16),Me=new Float32Array(9),Le=new Float32Array(4);Te.prototype.updateCache=function(a){var b=this.cache;a instanceof Float32Array&&b.length!==a.length&&(this.cache=new Float32Array(a.length));sa(b,a)};Ue.prototype.setValue=function(a,b,c){for(var d=this.seq,e=0,f=d.length;e!==f;++e){var g=d[e];g.setValue(a,b[g.id],c)}};var Zd=/([\w\d_]+)(\])?(\[|\.)?/g;bb.prototype.setValue=function(a,b,c){b=this.map[b];void 0!==b&&b.setValue(a,c, +this.renderer)};bb.prototype.setOptional=function(a,b,c){b=b[c];void 0!==b&&this.setValue(a,c,b)};bb.upload=function(a,b,c,d){for(var e=0,f=b.length;e!==f;++e){var g=b[e],h=c[g.id];!1!==h.needsUpdate&&g.setValue(a,h.value,d)}};bb.seqWithValue=function(a,b){for(var c=[],d=0,e=a.length;d!==e;++d){var f=a[d];f.id in b&&c.push(f)}return c};var Bg=0,Kg=0;cb.prototype=Object.create(L.prototype);cb.prototype.constructor=cb;cb.prototype.isMeshDepthMaterial=!0;cb.prototype.copy=function(a){L.prototype.copy.call(this, +a);this.depthPacking=a.depthPacking;this.skinning=a.skinning;this.morphTargets=a.morphTargets;this.map=a.map;this.alphaMap=a.alphaMap;this.displacementMap=a.displacementMap;this.displacementScale=a.displacementScale;this.displacementBias=a.displacementBias;this.wireframe=a.wireframe;this.wireframeLinewidth=a.wireframeLinewidth;return this};db.prototype=Object.create(L.prototype);db.prototype.constructor=db;db.prototype.isMeshDistanceMaterial=!0;db.prototype.copy=function(a){L.prototype.copy.call(this, +a);this.referencePosition.copy(a.referencePosition);this.nearDistance=a.nearDistance;this.farDistance=a.farDistance;this.skinning=a.skinning;this.morphTargets=a.morphTargets;this.map=a.map;this.alphaMap=a.alphaMap;this.displacementMap=a.displacementMap;this.displacementScale=a.displacementScale;this.displacementBias=a.displacementBias;return this};Ob.prototype=Object.assign(Object.create(C.prototype),{constructor:Ob,isGroup:!0});Ra.prototype=Object.assign(Object.create(C.prototype),{constructor:Ra, +isCamera:!0,copy:function(a,b){C.prototype.copy.call(this,a,b);this.matrixWorldInverse.copy(a.matrixWorldInverse);this.projectionMatrix.copy(a.projectionMatrix);this.projectionMatrixInverse.copy(a.projectionMatrixInverse);return this},getWorldDirection:function(a){void 0===a&&(console.warn("THREE.Camera: .getWorldDirection() target is now required"),a=new p);this.updateMatrixWorld(!0);var b=this.matrixWorld.elements;return a.set(-b[8],-b[9],-b[10]).normalize()},updateMatrixWorld:function(a){C.prototype.updateMatrixWorld.call(this, +a);this.matrixWorldInverse.getInverse(this.matrixWorld)},clone:function(){return(new this.constructor).copy(this)}});V.prototype=Object.assign(Object.create(Ra.prototype),{constructor:V,isPerspectiveCamera:!0,copy:function(a,b){Ra.prototype.copy.call(this,a,b);this.fov=a.fov;this.zoom=a.zoom;this.near=a.near;this.far=a.far;this.focus=a.focus;this.aspect=a.aspect;this.view=null===a.view?null:Object.assign({},a.view);this.filmGauge=a.filmGauge;this.filmOffset=a.filmOffset;return this},setFocalLength:function(a){a= +.5*this.getFilmHeight()/a;this.fov=2*S.RAD2DEG*Math.atan(a);this.updateProjectionMatrix()},getFocalLength:function(){var a=Math.tan(.5*S.DEG2RAD*this.fov);return.5*this.getFilmHeight()/a},getEffectiveFOV:function(){return 2*S.RAD2DEG*Math.atan(Math.tan(.5*S.DEG2RAD*this.fov)/this.zoom)},getFilmWidth:function(){return this.filmGauge*Math.min(this.aspect,1)},getFilmHeight:function(){return this.filmGauge/Math.max(this.aspect,1)},setViewOffset:function(a,b,c,d,e,f){this.aspect=a/b;null===this.view&& +(this.view={enabled:!0,fullWidth:1,fullHeight:1,offsetX:0,offsetY:0,width:1,height:1});this.view.enabled=!0;this.view.fullWidth=a;this.view.fullHeight=b;this.view.offsetX=c;this.view.offsetY=d;this.view.width=e;this.view.height=f;this.updateProjectionMatrix()},clearViewOffset:function(){null!==this.view&&(this.view.enabled=!1);this.updateProjectionMatrix()},updateProjectionMatrix:function(){var a=this.near,b=a*Math.tan(.5*S.DEG2RAD*this.fov)/this.zoom,c=2*b,d=this.aspect*c,e=-.5*d,f=this.view;if(null!== +this.view&&this.view.enabled){var g=f.fullWidth,h=f.fullHeight;e+=f.offsetX*d/g;b-=f.offsetY*c/h;d*=f.width/g;c*=f.height/h}f=this.filmOffset;0!==f&&(e+=a*f/this.getFilmWidth());this.projectionMatrix.makePerspective(e,e+d,b,b-c,a,this.far);this.projectionMatrixInverse.getInverse(this.projectionMatrix)},toJSON:function(a){a=C.prototype.toJSON.call(this,a);a.object.fov=this.fov;a.object.zoom=this.zoom;a.object.near=this.near;a.object.far=this.far;a.object.focus=this.focus;a.object.aspect=this.aspect; +null!==this.view&&(a.object.view=Object.assign({},this.view));a.object.filmGauge=this.filmGauge;a.object.filmOffset=this.filmOffset;return a}});Cc.prototype=Object.assign(Object.create(V.prototype),{constructor:Cc,isArrayCamera:!0});Pb.prototype.isFogExp2=!0;Pb.prototype.clone=function(){return new Pb(this.color,this.density)};Pb.prototype.toJSON=function(){return{type:"FogExp2",color:this.color.getHex(),density:this.density}};Qb.prototype.isFog=!0;Qb.prototype.clone=function(){return new Qb(this.color, +this.near,this.far)};Qb.prototype.toJSON=function(){return{type:"Fog",color:this.color.getHex(),near:this.near,far:this.far}};vd.prototype=Object.assign(Object.create(C.prototype),{constructor:vd,copy:function(a,b){C.prototype.copy.call(this,a,b);null!==a.background&&(this.background=a.background.clone());null!==a.fog&&(this.fog=a.fog.clone());null!==a.overrideMaterial&&(this.overrideMaterial=a.overrideMaterial.clone());this.autoUpdate=a.autoUpdate;this.matrixAutoUpdate=a.matrixAutoUpdate;return this}, +toJSON:function(a){var b=C.prototype.toJSON.call(this,a);null!==this.background&&(b.object.background=this.background.toJSON(a));null!==this.fog&&(b.object.fog=this.fog.toJSON());return b}});Object.defineProperty(qb.prototype,"needsUpdate",{set:function(a){!0===a&&this.version++}});Object.assign(qb.prototype,{isInterleavedBuffer:!0,onUploadCallback:function(){},setArray:function(a){if(Array.isArray(a))throw new TypeError("THREE.BufferAttribute: array should be a Typed Array.");this.count=void 0!== +a?a.length/this.stride:0;this.array=a;return this},setDynamic:function(a){this.dynamic=a;return this},copy:function(a){this.array=new a.array.constructor(a.array);this.count=a.count;this.stride=a.stride;this.dynamic=a.dynamic;return this},copyAt:function(a,b,c){a*=this.stride;c*=b.stride;for(var d=0,e=this.stride;d<e;d++)this.array[a+d]=b.array[c+d];return this},set:function(a,b){void 0===b&&(b=0);this.array.set(a,b);return this},clone:function(){return(new this.constructor).copy(this)},onUpload:function(a){this.onUploadCallback= +a;return this}});Object.defineProperties(Dc.prototype,{count:{get:function(){return this.data.count}},array:{get:function(){return this.data.array}}});Object.assign(Dc.prototype,{isInterleavedBufferAttribute:!0,setX:function(a,b){this.data.array[a*this.data.stride+this.offset]=b;return this},setY:function(a,b){this.data.array[a*this.data.stride+this.offset+1]=b;return this},setZ:function(a,b){this.data.array[a*this.data.stride+this.offset+2]=b;return this},setW:function(a,b){this.data.array[a*this.data.stride+ +this.offset+3]=b;return this},getX:function(a){return this.data.array[a*this.data.stride+this.offset]},getY:function(a){return this.data.array[a*this.data.stride+this.offset+1]},getZ:function(a){return this.data.array[a*this.data.stride+this.offset+2]},getW:function(a){return this.data.array[a*this.data.stride+this.offset+3]},setXY:function(a,b,c){a=a*this.data.stride+this.offset;this.data.array[a+0]=b;this.data.array[a+1]=c;return this},setXYZ:function(a,b,c,d){a=a*this.data.stride+this.offset;this.data.array[a+ +0]=b;this.data.array[a+1]=c;this.data.array[a+2]=d;return this},setXYZW:function(a,b,c,d,e){a=a*this.data.stride+this.offset;this.data.array[a+0]=b;this.data.array[a+1]=c;this.data.array[a+2]=d;this.data.array[a+3]=e;return this}});fb.prototype=Object.create(L.prototype);fb.prototype.constructor=fb;fb.prototype.isSpriteMaterial=!0;fb.prototype.copy=function(a){L.prototype.copy.call(this,a);this.color.copy(a.color);this.map=a.map;this.rotation=a.rotation;this.sizeAttenuation=a.sizeAttenuation;return this}; +var Rb;Ec.prototype=Object.assign(Object.create(C.prototype),{constructor:Ec,isSprite:!0,raycast:function(){function a(a,b,c,d,h,k){e.subVectors(a,c).addScalar(.5).multiply(d);void 0!==h?(f.x=k*e.x-h*e.y,f.y=h*e.x+k*e.y):f.copy(e);a.copy(b);a.x+=f.x;a.y+=f.y;a.applyMatrix4(g)}var b=new p,c=new p,d=new p,e=new A,f=new A,g=new P,h=new p,k=new p,m=new p,l=new A,n=new A,q=new A;return function(e,f){c.setFromMatrixScale(this.matrixWorld);g.getInverse(this.modelViewMatrix).premultiply(this.matrixWorld); +d.setFromMatrixPosition(this.modelViewMatrix);var r=this.material.rotation;if(0!==r){var p=Math.cos(r);var t=Math.sin(r)}r=this.center;a(h.set(-.5,-.5,0),d,r,c,t,p);a(k.set(.5,-.5,0),d,r,c,t,p);a(m.set(.5,.5,0),d,r,c,t,p);l.set(0,0);n.set(1,0);q.set(1,1);var v=e.ray.intersectTriangle(h,k,m,!1,b);if(null===v&&(a(k.set(-.5,.5,0),d,r,c,t,p),n.set(0,1),v=e.ray.intersectTriangle(h,m,k,!1,b),null===v))return;t=e.ray.origin.distanceTo(b);t<e.near||t>e.far||f.push({distance:t,point:b.clone(),uv:da.getUV(b, +h,k,m,l,n,q,new A),face:null,object:this})}}(),clone:function(){return(new this.constructor(this.material)).copy(this)},copy:function(a){C.prototype.copy.call(this,a);void 0!==a.center&&this.center.copy(a.center);return this}});Fc.prototype=Object.assign(Object.create(C.prototype),{constructor:Fc,copy:function(a){C.prototype.copy.call(this,a,!1);a=a.levels;for(var b=0,c=a.length;b<c;b++){var d=a[b];this.addLevel(d.object.clone(),d.distance)}return this},addLevel:function(a,b){void 0===b&&(b=0);b= +Math.abs(b);for(var c=this.levels,d=0;d<c.length&&!(b<c[d].distance);d++);c.splice(d,0,{distance:b,object:a});this.add(a)},getObjectForDistance:function(a){for(var b=this.levels,c=1,d=b.length;c<d&&!(a<b[c].distance);c++);return b[c-1].object},raycast:function(){var a=new p;return function(b,c){a.setFromMatrixPosition(this.matrixWorld);var d=b.ray.origin.distanceTo(a);this.getObjectForDistance(d).raycast(b,c)}}(),update:function(){var a=new p,b=new p;return function(c){var d=this.levels;if(1<d.length){a.setFromMatrixPosition(c.matrixWorld); +b.setFromMatrixPosition(this.matrixWorld);c=a.distanceTo(b);d[0].object.visible=!0;for(var e=1,f=d.length;e<f;e++)if(c>=d[e].distance)d[e-1].object.visible=!1,d[e].object.visible=!0;else break;for(;e<f;e++)d[e].object.visible=!1}}}(),toJSON:function(a){a=C.prototype.toJSON.call(this,a);a.object.levels=[];for(var b=this.levels,c=0,d=b.length;c<d;c++){var e=b[c];a.object.levels.push({object:e.object.uuid,distance:e.distance})}return a}});Object.assign(Gc.prototype,{calculateInverses:function(){this.boneInverses= +[];for(var a=0,b=this.bones.length;a<b;a++){var c=new P;this.bones[a]&&c.getInverse(this.bones[a].matrixWorld);this.boneInverses.push(c)}},pose:function(){var a,b;var c=0;for(b=this.bones.length;c<b;c++)(a=this.bones[c])&&a.matrixWorld.getInverse(this.boneInverses[c]);c=0;for(b=this.bones.length;c<b;c++)if(a=this.bones[c])a.parent&&a.parent.isBone?(a.matrix.getInverse(a.parent.matrixWorld),a.matrix.multiply(a.matrixWorld)):a.matrix.copy(a.matrixWorld),a.matrix.decompose(a.position,a.quaternion,a.scale)}, +update:function(){var a=new P,b=new P;return function(){for(var c=this.bones,d=this.boneInverses,e=this.boneMatrices,f=this.boneTexture,g=0,h=c.length;g<h;g++)a.multiplyMatrices(c[g]?c[g].matrixWorld:b,d[g]),a.toArray(e,16*g);void 0!==f&&(f.needsUpdate=!0)}}(),clone:function(){return new Gc(this.bones,this.boneInverses)},getBoneByName:function(a){for(var b=0,c=this.bones.length;b<c;b++){var d=this.bones[b];if(d.name===a)return d}}});wd.prototype=Object.assign(Object.create(C.prototype),{constructor:wd, +isBone:!0});xd.prototype=Object.assign(Object.create(ua.prototype),{constructor:xd,isSkinnedMesh:!0,initBones:function(){var a=[],b;if(this.geometry&&void 0!==this.geometry.bones){var c=0;for(b=this.geometry.bones.length;c<b;c++){var d=this.geometry.bones[c];var e=new wd;a.push(e);e.name=d.name;e.position.fromArray(d.pos);e.quaternion.fromArray(d.rotq);void 0!==d.scl&&e.scale.fromArray(d.scl)}c=0;for(b=this.geometry.bones.length;c<b;c++)d=this.geometry.bones[c],-1!==d.parent&&null!==d.parent&&void 0!== +a[d.parent]?a[d.parent].add(a[c]):this.add(a[c])}this.updateMatrixWorld(!0);return a},bind:function(a,b){this.skeleton=a;void 0===b&&(this.updateMatrixWorld(!0),this.skeleton.calculateInverses(),b=this.matrixWorld);this.bindMatrix.copy(b);this.bindMatrixInverse.getInverse(b)},pose:function(){this.skeleton.pose()},normalizeSkinWeights:function(){var a;if(this.geometry&&this.geometry.isGeometry)for(a=0;a<this.geometry.skinWeights.length;a++){var b=this.geometry.skinWeights[a];var c=1/b.manhattanLength(); +Infinity!==c?b.multiplyScalar(c):b.set(1,0,0,0)}else if(this.geometry&&this.geometry.isBufferGeometry){b=new Z;var d=this.geometry.attributes.skinWeight;for(a=0;a<d.count;a++)b.x=d.getX(a),b.y=d.getY(a),b.z=d.getZ(a),b.w=d.getW(a),c=1/b.manhattanLength(),Infinity!==c?b.multiplyScalar(c):b.set(1,0,0,0),d.setXYZW(a,b.x,b.y,b.z,b.w)}},updateMatrixWorld:function(a){ua.prototype.updateMatrixWorld.call(this,a);"attached"===this.bindMode?this.bindMatrixInverse.getInverse(this.matrixWorld):"detached"===this.bindMode? +this.bindMatrixInverse.getInverse(this.bindMatrix):console.warn("THREE.SkinnedMesh: Unrecognized bindMode: "+this.bindMode)},clone:function(){return(new this.constructor(this.geometry,this.material)).copy(this)}});T.prototype=Object.create(L.prototype);T.prototype.constructor=T;T.prototype.isLineBasicMaterial=!0;T.prototype.copy=function(a){L.prototype.copy.call(this,a);this.color.copy(a.color);this.linewidth=a.linewidth;this.linecap=a.linecap;this.linejoin=a.linejoin;return this};pa.prototype=Object.assign(Object.create(C.prototype), +{constructor:pa,isLine:!0,computeLineDistances:function(){var a=new p,b=new p;return function(){var c=this.geometry;if(c.isBufferGeometry)if(null===c.index){for(var d=c.attributes.position,e=[0],f=1,g=d.count;f<g;f++)a.fromBufferAttribute(d,f-1),b.fromBufferAttribute(d,f),e[f]=e[f-1],e[f]+=a.distanceTo(b);c.addAttribute("lineDistance",new z(e,1))}else console.warn("THREE.Line.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.");else if(c.isGeometry)for(d=c.vertices, +e=c.lineDistances,e[0]=0,f=1,g=d.length;f<g;f++)e[f]=e[f-1],e[f]+=d[f-1].distanceTo(d[f]);return this}}(),raycast:function(){var a=new P,b=new pb,c=new Fa;return function(d,e){var f=d.linePrecision,g=this.geometry,h=this.matrixWorld;null===g.boundingSphere&&g.computeBoundingSphere();c.copy(g.boundingSphere);c.applyMatrix4(h);c.radius+=f;if(!1!==d.ray.intersectsSphere(c)){a.getInverse(h);b.copy(d.ray).applyMatrix4(a);f/=(this.scale.x+this.scale.y+this.scale.z)/3;f*=f;var k=new p,m=new p;h=new p;var l= +new p,n=this&&this.isLineSegments?2:1;if(g.isBufferGeometry){var q=g.index,v=g.attributes.position.array;if(null!==q){q=q.array;g=0;for(var t=q.length-1;g<t;g+=n){var u=q[g+1];k.fromArray(v,3*q[g]);m.fromArray(v,3*u);u=b.distanceSqToSegment(k,m,l,h);u>f||(l.applyMatrix4(this.matrixWorld),u=d.ray.origin.distanceTo(l),u<d.near||u>d.far||e.push({distance:u,point:h.clone().applyMatrix4(this.matrixWorld),index:g,face:null,faceIndex:null,object:this}))}}else for(g=0,t=v.length/3-1;g<t;g+=n)k.fromArray(v, +3*g),m.fromArray(v,3*g+3),u=b.distanceSqToSegment(k,m,l,h),u>f||(l.applyMatrix4(this.matrixWorld),u=d.ray.origin.distanceTo(l),u<d.near||u>d.far||e.push({distance:u,point:h.clone().applyMatrix4(this.matrixWorld),index:g,face:null,faceIndex:null,object:this}))}else if(g.isGeometry)for(k=g.vertices,m=k.length,g=0;g<m-1;g+=n)u=b.distanceSqToSegment(k[g],k[g+1],l,h),u>f||(l.applyMatrix4(this.matrixWorld),u=d.ray.origin.distanceTo(l),u<d.near||u>d.far||e.push({distance:u,point:h.clone().applyMatrix4(this.matrixWorld), +index:g,face:null,faceIndex:null,object:this}))}}}(),clone:function(){return(new this.constructor(this.geometry,this.material)).copy(this)}});W.prototype=Object.assign(Object.create(pa.prototype),{constructor:W,isLineSegments:!0,computeLineDistances:function(){var a=new p,b=new p;return function(){var c=this.geometry;if(c.isBufferGeometry)if(null===c.index){for(var d=c.attributes.position,e=[],f=0,g=d.count;f<g;f+=2)a.fromBufferAttribute(d,f),b.fromBufferAttribute(d,f+1),e[f]=0===f?0:e[f-1],e[f+1]= +e[f]+a.distanceTo(b);c.addAttribute("lineDistance",new z(e,1))}else console.warn("THREE.LineSegments.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.");else if(c.isGeometry)for(d=c.vertices,e=c.lineDistances,f=0,g=d.length;f<g;f+=2)a.copy(d[f]),b.copy(d[f+1]),e[f]=0===f?0:e[f-1],e[f+1]=e[f]+a.distanceTo(b);return this}}()});yd.prototype=Object.assign(Object.create(pa.prototype),{constructor:yd,isLineLoop:!0});Ga.prototype=Object.create(L.prototype);Ga.prototype.constructor= +Ga;Ga.prototype.isPointsMaterial=!0;Ga.prototype.copy=function(a){L.prototype.copy.call(this,a);this.color.copy(a.color);this.map=a.map;this.size=a.size;this.sizeAttenuation=a.sizeAttenuation;this.morphTargets=a.morphTargets;return this};Sb.prototype=Object.assign(Object.create(C.prototype),{constructor:Sb,isPoints:!0,raycast:function(){var a=new P,b=new pb,c=new Fa;return function(d,e){function f(a,c){var f=b.distanceSqToPoint(a);f<l&&(b.closestPointToPoint(a,n),n.applyMatrix4(k),a=d.ray.origin.distanceTo(n), +a<d.near||a>d.far||e.push({distance:a,distanceToRay:Math.sqrt(f),point:n.clone(),index:c,face:null,object:g}))}var g=this,h=this.geometry,k=this.matrixWorld,m=d.params.Points.threshold;null===h.boundingSphere&&h.computeBoundingSphere();c.copy(h.boundingSphere);c.applyMatrix4(k);c.radius+=m;if(!1!==d.ray.intersectsSphere(c)){a.getInverse(k);b.copy(d.ray).applyMatrix4(a);m/=(this.scale.x+this.scale.y+this.scale.z)/3;var l=m*m;m=new p;var n=new p;if(h.isBufferGeometry){var q=h.index;h=h.attributes.position.array; +if(null!==q){var v=q.array;q=0;for(var t=v.length;q<t;q++){var u=v[q];m.fromArray(h,3*u);f(m,u)}}else for(q=0,v=h.length/3;q<v;q++)m.fromArray(h,3*q),f(m,q)}else for(m=h.vertices,q=0,v=m.length;q<v;q++)f(m[q],q)}}}(),clone:function(){return(new this.constructor(this.geometry,this.material)).copy(this)}});ce.prototype=Object.assign(Object.create(Q.prototype),{constructor:ce,isVideoTexture:!0,update:function(){var a=this.image;a.readyState>=a.HAVE_CURRENT_DATA&&(this.needsUpdate=!0)}});Tb.prototype= +Object.create(Q.prototype);Tb.prototype.constructor=Tb;Tb.prototype.isCompressedTexture=!0;Hc.prototype=Object.create(Q.prototype);Hc.prototype.constructor=Hc;Hc.prototype.isCanvasTexture=!0;Ic.prototype=Object.create(Q.prototype);Ic.prototype.constructor=Ic;Ic.prototype.isDepthTexture=!0;Ub.prototype=Object.create(F.prototype);Ub.prototype.constructor=Ub;Jc.prototype=Object.create(M.prototype);Jc.prototype.constructor=Jc;Vb.prototype=Object.create(F.prototype);Vb.prototype.constructor=Vb;Kc.prototype= +Object.create(M.prototype);Kc.prototype.constructor=Kc;ma.prototype=Object.create(F.prototype);ma.prototype.constructor=ma;Lc.prototype=Object.create(M.prototype);Lc.prototype.constructor=Lc;Wb.prototype=Object.create(ma.prototype);Wb.prototype.constructor=Wb;Mc.prototype=Object.create(M.prototype);Mc.prototype.constructor=Mc;rb.prototype=Object.create(ma.prototype);rb.prototype.constructor=rb;Nc.prototype=Object.create(M.prototype);Nc.prototype.constructor=Nc;Xb.prototype=Object.create(ma.prototype); +Xb.prototype.constructor=Xb;Oc.prototype=Object.create(M.prototype);Oc.prototype.constructor=Oc;Yb.prototype=Object.create(ma.prototype);Yb.prototype.constructor=Yb;Pc.prototype=Object.create(M.prototype);Pc.prototype.constructor=Pc;Zb.prototype=Object.create(F.prototype);Zb.prototype.constructor=Zb;Qc.prototype=Object.create(M.prototype);Qc.prototype.constructor=Qc;$b.prototype=Object.create(F.prototype);$b.prototype.constructor=$b;Rc.prototype=Object.create(M.prototype);Rc.prototype.constructor= +Rc;ac.prototype=Object.create(F.prototype);ac.prototype.constructor=ac;var Xg={triangulate:function(a,b,c){c=c||2;var d=b&&b.length,e=d?b[0]*c:a.length,f=df(a,0,e,c,!0),g=[];if(!f)return g;var h;if(d){var k=c;d=[];var m;var l=0;for(m=b.length;l<m;l++){var n=b[l]*k;var q=l<m-1?b[l+1]*k:a.length;n=df(a,n,q,k,!1);n===n.next&&(n.steiner=!0);d.push(Sg(n))}d.sort(Qg);for(l=0;l<d.length;l++){b=d[l];k=f;if(k=Rg(b,k))b=gf(k,b),Tc(b,b.next);f=Tc(f,f.next)}}if(a.length>80*c){var p=h=a[0];var t=d=a[1];for(k= +c;k<e;k+=c)l=a[k],b=a[k+1],l<p&&(p=l),b<t&&(t=b),l>h&&(h=l),b>d&&(d=b);h=Math.max(h-p,d-t);h=0!==h?1/h:0}Uc(f,g,c,p,t,h);return g}},Za={area:function(a){for(var b=a.length,c=0,d=b-1,e=0;e<b;d=e++)c+=a[d].x*a[e].y-a[e].x*a[d].y;return.5*c},isClockWise:function(a){return 0>Za.area(a)},triangulateShape:function(a,b){var c=[],d=[],e=[];hf(a);jf(c,a);var f=a.length;b.forEach(hf);for(a=0;a<b.length;a++)d.push(f),f+=b[a].length,jf(c,b[a]);b=Xg.triangulate(c,d);for(a=0;a<b.length;a+=3)e.push(b.slice(a,a+ +3));return e}};tb.prototype=Object.create(M.prototype);tb.prototype.constructor=tb;tb.prototype.toJSON=function(){var a=M.prototype.toJSON.call(this);return kf(this.parameters.shapes,this.parameters.options,a)};Sa.prototype=Object.create(F.prototype);Sa.prototype.constructor=Sa;Sa.prototype.toJSON=function(){var a=F.prototype.toJSON.call(this);return kf(this.parameters.shapes,this.parameters.options,a)};var Tg={generateTopUV:function(a,b,c,d,e){a=b[3*d];d=b[3*d+1];var f=b[3*e];e=b[3*e+1];return[new A(b[3* +c],b[3*c+1]),new A(a,d),new A(f,e)]},generateSideWallUV:function(a,b,c,d,e,f){a=b[3*c];var g=b[3*c+1];c=b[3*c+2];var h=b[3*d],k=b[3*d+1];d=b[3*d+2];var m=b[3*e],l=b[3*e+1];e=b[3*e+2];var n=b[3*f],q=b[3*f+1];b=b[3*f+2];return.01>Math.abs(g-k)?[new A(a,1-c),new A(h,1-d),new A(m,1-e),new A(n,1-b)]:[new A(g,1-c),new A(k,1-d),new A(l,1-e),new A(q,1-b)]}};Wc.prototype=Object.create(M.prototype);Wc.prototype.constructor=Wc;bc.prototype=Object.create(Sa.prototype);bc.prototype.constructor=bc;Xc.prototype= +Object.create(M.prototype);Xc.prototype.constructor=Xc;ub.prototype=Object.create(F.prototype);ub.prototype.constructor=ub;Yc.prototype=Object.create(M.prototype);Yc.prototype.constructor=Yc;cc.prototype=Object.create(F.prototype);cc.prototype.constructor=cc;Zc.prototype=Object.create(M.prototype);Zc.prototype.constructor=Zc;dc.prototype=Object.create(F.prototype);dc.prototype.constructor=dc;vb.prototype=Object.create(M.prototype);vb.prototype.constructor=vb;vb.prototype.toJSON=function(){var a=M.prototype.toJSON.call(this); +return lf(this.parameters.shapes,a)};wb.prototype=Object.create(F.prototype);wb.prototype.constructor=wb;wb.prototype.toJSON=function(){var a=F.prototype.toJSON.call(this);return lf(this.parameters.shapes,a)};ec.prototype=Object.create(F.prototype);ec.prototype.constructor=ec;xb.prototype=Object.create(M.prototype);xb.prototype.constructor=xb;$a.prototype=Object.create(F.prototype);$a.prototype.constructor=$a;$c.prototype=Object.create(xb.prototype);$c.prototype.constructor=$c;ad.prototype=Object.create($a.prototype); +ad.prototype.constructor=ad;bd.prototype=Object.create(M.prototype);bd.prototype.constructor=bd;fc.prototype=Object.create(F.prototype);fc.prototype.constructor=fc;var Ba=Object.freeze({WireframeGeometry:Ub,ParametricGeometry:Jc,ParametricBufferGeometry:Vb,TetrahedronGeometry:Lc,TetrahedronBufferGeometry:Wb,OctahedronGeometry:Mc,OctahedronBufferGeometry:rb,IcosahedronGeometry:Nc,IcosahedronBufferGeometry:Xb,DodecahedronGeometry:Oc,DodecahedronBufferGeometry:Yb,PolyhedronGeometry:Kc,PolyhedronBufferGeometry:ma, +TubeGeometry:Pc,TubeBufferGeometry:Zb,TorusKnotGeometry:Qc,TorusKnotBufferGeometry:$b,TorusGeometry:Rc,TorusBufferGeometry:ac,TextGeometry:Wc,TextBufferGeometry:bc,SphereGeometry:Xc,SphereBufferGeometry:ub,RingGeometry:Yc,RingBufferGeometry:cc,PlaneGeometry:yc,PlaneBufferGeometry:ob,LatheGeometry:Zc,LatheBufferGeometry:dc,ShapeGeometry:vb,ShapeBufferGeometry:wb,ExtrudeGeometry:tb,ExtrudeBufferGeometry:Sa,EdgesGeometry:ec,ConeGeometry:$c,ConeBufferGeometry:ad,CylinderGeometry:xb,CylinderBufferGeometry:$a, +CircleGeometry:bd,CircleBufferGeometry:fc,BoxGeometry:Kb,BoxBufferGeometry:nb});yb.prototype=Object.create(L.prototype);yb.prototype.constructor=yb;yb.prototype.isShadowMaterial=!0;yb.prototype.copy=function(a){L.prototype.copy.call(this,a);this.color.copy(a.color);return this};gc.prototype=Object.create(ka.prototype);gc.prototype.constructor=gc;gc.prototype.isRawShaderMaterial=!0;Ta.prototype=Object.create(L.prototype);Ta.prototype.constructor=Ta;Ta.prototype.isMeshStandardMaterial=!0;Ta.prototype.copy= +function(a){L.prototype.copy.call(this,a);this.defines={STANDARD:""};this.color.copy(a.color);this.roughness=a.roughness;this.metalness=a.metalness;this.map=a.map;this.lightMap=a.lightMap;this.lightMapIntensity=a.lightMapIntensity;this.aoMap=a.aoMap;this.aoMapIntensity=a.aoMapIntensity;this.emissive.copy(a.emissive);this.emissiveMap=a.emissiveMap;this.emissiveIntensity=a.emissiveIntensity;this.bumpMap=a.bumpMap;this.bumpScale=a.bumpScale;this.normalMap=a.normalMap;this.normalMapType=a.normalMapType; +this.normalScale.copy(a.normalScale);this.displacementMap=a.displacementMap;this.displacementScale=a.displacementScale;this.displacementBias=a.displacementBias;this.roughnessMap=a.roughnessMap;this.metalnessMap=a.metalnessMap;this.alphaMap=a.alphaMap;this.envMap=a.envMap;this.envMapIntensity=a.envMapIntensity;this.refractionRatio=a.refractionRatio;this.wireframe=a.wireframe;this.wireframeLinewidth=a.wireframeLinewidth;this.wireframeLinecap=a.wireframeLinecap;this.wireframeLinejoin=a.wireframeLinejoin; +this.skinning=a.skinning;this.morphTargets=a.morphTargets;this.morphNormals=a.morphNormals;return this};zb.prototype=Object.create(Ta.prototype);zb.prototype.constructor=zb;zb.prototype.isMeshPhysicalMaterial=!0;zb.prototype.copy=function(a){Ta.prototype.copy.call(this,a);this.defines={PHYSICAL:""};this.reflectivity=a.reflectivity;this.clearCoat=a.clearCoat;this.clearCoatRoughness=a.clearCoatRoughness;return this};Ha.prototype=Object.create(L.prototype);Ha.prototype.constructor=Ha;Ha.prototype.isMeshPhongMaterial= +!0;Ha.prototype.copy=function(a){L.prototype.copy.call(this,a);this.color.copy(a.color);this.specular.copy(a.specular);this.shininess=a.shininess;this.map=a.map;this.lightMap=a.lightMap;this.lightMapIntensity=a.lightMapIntensity;this.aoMap=a.aoMap;this.aoMapIntensity=a.aoMapIntensity;this.emissive.copy(a.emissive);this.emissiveMap=a.emissiveMap;this.emissiveIntensity=a.emissiveIntensity;this.bumpMap=a.bumpMap;this.bumpScale=a.bumpScale;this.normalMap=a.normalMap;this.normalMapType=a.normalMapType; +this.normalScale.copy(a.normalScale);this.displacementMap=a.displacementMap;this.displacementScale=a.displacementScale;this.displacementBias=a.displacementBias;this.specularMap=a.specularMap;this.alphaMap=a.alphaMap;this.envMap=a.envMap;this.combine=a.combine;this.reflectivity=a.reflectivity;this.refractionRatio=a.refractionRatio;this.wireframe=a.wireframe;this.wireframeLinewidth=a.wireframeLinewidth;this.wireframeLinecap=a.wireframeLinecap;this.wireframeLinejoin=a.wireframeLinejoin;this.skinning= +a.skinning;this.morphTargets=a.morphTargets;this.morphNormals=a.morphNormals;return this};Ab.prototype=Object.create(Ha.prototype);Ab.prototype.constructor=Ab;Ab.prototype.isMeshToonMaterial=!0;Ab.prototype.copy=function(a){Ha.prototype.copy.call(this,a);this.gradientMap=a.gradientMap;return this};Bb.prototype=Object.create(L.prototype);Bb.prototype.constructor=Bb;Bb.prototype.isMeshNormalMaterial=!0;Bb.prototype.copy=function(a){L.prototype.copy.call(this,a);this.bumpMap=a.bumpMap;this.bumpScale= +a.bumpScale;this.normalMap=a.normalMap;this.normalMapType=a.normalMapType;this.normalScale.copy(a.normalScale);this.displacementMap=a.displacementMap;this.displacementScale=a.displacementScale;this.displacementBias=a.displacementBias;this.wireframe=a.wireframe;this.wireframeLinewidth=a.wireframeLinewidth;this.skinning=a.skinning;this.morphTargets=a.morphTargets;this.morphNormals=a.morphNormals;return this};Cb.prototype=Object.create(L.prototype);Cb.prototype.constructor=Cb;Cb.prototype.isMeshLambertMaterial= +!0;Cb.prototype.copy=function(a){L.prototype.copy.call(this,a);this.color.copy(a.color);this.map=a.map;this.lightMap=a.lightMap;this.lightMapIntensity=a.lightMapIntensity;this.aoMap=a.aoMap;this.aoMapIntensity=a.aoMapIntensity;this.emissive.copy(a.emissive);this.emissiveMap=a.emissiveMap;this.emissiveIntensity=a.emissiveIntensity;this.specularMap=a.specularMap;this.alphaMap=a.alphaMap;this.envMap=a.envMap;this.combine=a.combine;this.reflectivity=a.reflectivity;this.refractionRatio=a.refractionRatio; +this.wireframe=a.wireframe;this.wireframeLinewidth=a.wireframeLinewidth;this.wireframeLinecap=a.wireframeLinecap;this.wireframeLinejoin=a.wireframeLinejoin;this.skinning=a.skinning;this.morphTargets=a.morphTargets;this.morphNormals=a.morphNormals;return this};Db.prototype=Object.create(L.prototype);Db.prototype.constructor=Db;Db.prototype.isMeshMatcapMaterial=!0;Db.prototype.copy=function(a){L.prototype.copy.call(this,a);this.defines={MATCAP:""};this.color.copy(a.color);this.matcap=a.matcap;this.map= +a.map;this.bumpMap=a.bumpMap;this.bumpScale=a.bumpScale;this.normalMap=a.normalMap;this.normalMapType=a.normalMapType;this.normalScale.copy(a.normalScale);this.displacementMap=a.displacementMap;this.displacementScale=a.displacementScale;this.displacementBias=a.displacementBias;this.alphaMap=a.alphaMap;this.skinning=a.skinning;this.morphTargets=a.morphTargets;this.morphNormals=a.morphNormals;return this};Eb.prototype=Object.create(T.prototype);Eb.prototype.constructor=Eb;Eb.prototype.isLineDashedMaterial= +!0;Eb.prototype.copy=function(a){T.prototype.copy.call(this,a);this.scale=a.scale;this.dashSize=a.dashSize;this.gapSize=a.gapSize;return this};var Yg=Object.freeze({ShadowMaterial:yb,SpriteMaterial:fb,RawShaderMaterial:gc,ShaderMaterial:ka,PointsMaterial:Ga,MeshPhysicalMaterial:zb,MeshStandardMaterial:Ta,MeshPhongMaterial:Ha,MeshToonMaterial:Ab,MeshNormalMaterial:Bb,MeshLambertMaterial:Cb,MeshDepthMaterial:cb,MeshDistanceMaterial:db,MeshBasicMaterial:wa,MeshMatcapMaterial:Db,LineDashedMaterial:Eb, +LineBasicMaterial:T,Material:L}),Ib={enabled:!1,files:{},add:function(a,b){!1!==this.enabled&&(this.files[a]=b)},get:function(a){if(!1!==this.enabled)return this.files[a]},remove:function(a){delete this.files[a]},clear:function(){this.files={}}},ya=new fe,Oa={};Object.assign(Ia.prototype,{load:function(a,b,c,d){void 0===a&&(a="");void 0!==this.path&&(a=this.path+a);a=this.manager.resolveURL(a);var e=this,f=Ib.get(a);if(void 0!==f)return e.manager.itemStart(a),setTimeout(function(){b&&b(f);e.manager.itemEnd(a)}, +0),f;if(void 0!==Oa[a])Oa[a].push({onLoad:b,onProgress:c,onError:d});else{var g=a.match(/^data:(.*?)(;base64)?,(.*)$/);if(g){c=g[1];var h=!!g[2];g=g[3];g=window.decodeURIComponent(g);h&&(g=window.atob(g));try{var k=(this.responseType||"").toLowerCase();switch(k){case "arraybuffer":case "blob":var m=new Uint8Array(g.length);for(h=0;h<g.length;h++)m[h]=g.charCodeAt(h);var l="blob"===k?new Blob([m.buffer],{type:c}):m.buffer;break;case "document":l=(new DOMParser).parseFromString(g,c);break;case "json":l= +JSON.parse(g);break;default:l=g}window.setTimeout(function(){b&&b(l);e.manager.itemEnd(a)},0)}catch(q){window.setTimeout(function(){d&&d(q);e.manager.itemEnd(a);e.manager.itemError(a)},0)}}else{Oa[a]=[];Oa[a].push({onLoad:b,onProgress:c,onError:d});var n=new XMLHttpRequest;n.open("GET",a,!0);n.addEventListener("load",function(b){var c=this.response;Ib.add(a,c);var d=Oa[a];delete Oa[a];if(200===this.status||0===this.status){0===this.status&&console.warn("THREE.FileLoader: HTTP Status 0 received."); +for(var f=0,g=d.length;f<g;f++){var h=d[f];if(h.onLoad)h.onLoad(c)}e.manager.itemEnd(a)}else{f=0;for(g=d.length;f<g;f++)if(h=d[f],h.onError)h.onError(b);e.manager.itemEnd(a);e.manager.itemError(a)}},!1);n.addEventListener("progress",function(b){for(var c=Oa[a],d=0,e=c.length;d<e;d++){var f=c[d];if(f.onProgress)f.onProgress(b)}},!1);n.addEventListener("error",function(b){var c=Oa[a];delete Oa[a];for(var d=0,f=c.length;d<f;d++){var g=c[d];if(g.onError)g.onError(b)}e.manager.itemEnd(a);e.manager.itemError(a)}, +!1);n.addEventListener("abort",function(b){var c=Oa[a];delete Oa[a];for(var d=0,f=c.length;d<f;d++){var g=c[d];if(g.onError)g.onError(b)}e.manager.itemEnd(a);e.manager.itemError(a)},!1);void 0!==this.responseType&&(n.responseType=this.responseType);void 0!==this.withCredentials&&(n.withCredentials=this.withCredentials);n.overrideMimeType&&n.overrideMimeType(void 0!==this.mimeType?this.mimeType:"text/plain");for(h in this.requestHeader)n.setRequestHeader(h,this.requestHeader[h]);n.send(null)}e.manager.itemStart(a); +return n}},setPath:function(a){this.path=a;return this},setResponseType:function(a){this.responseType=a;return this},setWithCredentials:function(a){this.withCredentials=a;return this},setMimeType:function(a){this.mimeType=a;return this},setRequestHeader:function(a){this.requestHeader=a;return this}});Object.assign(mf.prototype,{load:function(a,b,c,d){function e(e){k.load(a[e],function(a){a=f._parser(a,!0);g[e]={width:a.width,height:a.height,format:a.format,mipmaps:a.mipmaps};m+=1;6===m&&(1===a.mipmapCount&& +(h.minFilter=1006),h.format=a.format,h.needsUpdate=!0,b&&b(h))},c,d)}var f=this,g=[],h=new Tb;h.image=g;var k=new Ia(this.manager);k.setPath(this.path);k.setResponseType("arraybuffer");if(Array.isArray(a))for(var m=0,l=0,n=a.length;l<n;++l)e(l);else k.load(a,function(a){a=f._parser(a,!0);if(a.isCubemap)for(var c=a.mipmaps.length/a.mipmapCount,d=0;d<c;d++){g[d]={mipmaps:[]};for(var e=0;e<a.mipmapCount;e++)g[d].mipmaps.push(a.mipmaps[d*a.mipmapCount+e]),g[d].format=a.format,g[d].width=a.width,g[d].height= +a.height}else h.image.width=a.width,h.image.height=a.height,h.mipmaps=a.mipmaps;1===a.mipmapCount&&(h.minFilter=1006);h.format=a.format;h.needsUpdate=!0;b&&b(h)},c,d);return h},setPath:function(a){this.path=a;return this}});Object.assign(ge.prototype,{load:function(a,b,c,d){var e=this,f=new jb,g=new Ia(this.manager);g.setResponseType("arraybuffer");g.load(a,function(a){if(a=e._parser(a))void 0!==a.image?f.image=a.image:void 0!==a.data&&(f.image.width=a.width,f.image.height=a.height,f.image.data=a.data), +f.wrapS=void 0!==a.wrapS?a.wrapS:1001,f.wrapT=void 0!==a.wrapT?a.wrapT:1001,f.magFilter=void 0!==a.magFilter?a.magFilter:1006,f.minFilter=void 0!==a.minFilter?a.minFilter:1008,f.anisotropy=void 0!==a.anisotropy?a.anisotropy:1,void 0!==a.format&&(f.format=a.format),void 0!==a.type&&(f.type=a.type),void 0!==a.mipmaps&&(f.mipmaps=a.mipmaps),1===a.mipmapCount&&(f.minFilter=1006),f.needsUpdate=!0,b&&b(f,a)},c,d);return f}});Object.assign(cd.prototype,{crossOrigin:"anonymous",load:function(a,b,c,d){function e(){k.removeEventListener("load", +e,!1);k.removeEventListener("error",f,!1);Ib.add(a,this);b&&b(this);g.manager.itemEnd(a)}function f(b){k.removeEventListener("load",e,!1);k.removeEventListener("error",f,!1);d&&d(b);g.manager.itemEnd(a);g.manager.itemError(a)}void 0===a&&(a="");void 0!==this.path&&(a=this.path+a);a=this.manager.resolveURL(a);var g=this,h=Ib.get(a);if(void 0!==h)return g.manager.itemStart(a),setTimeout(function(){b&&b(h);g.manager.itemEnd(a)},0),h;var k=document.createElementNS("http://www.w3.org/1999/xhtml","img"); +k.addEventListener("load",e,!1);k.addEventListener("error",f,!1);"data:"!==a.substr(0,5)&&void 0!==this.crossOrigin&&(k.crossOrigin=this.crossOrigin);g.manager.itemStart(a);k.src=a;return k},setCrossOrigin:function(a){this.crossOrigin=a;return this},setPath:function(a){this.path=a;return this}});Object.assign(he.prototype,{crossOrigin:"anonymous",load:function(a,b,c,d){function e(c){g.load(a[c],function(a){f.images[c]=a;h++;6===h&&(f.needsUpdate=!0,b&&b(f))},void 0,d)}var f=new Ya,g=new cd(this.manager); +g.setCrossOrigin(this.crossOrigin);g.setPath(this.path);var h=0;for(c=0;c<a.length;++c)e(c);return f},setCrossOrigin:function(a){this.crossOrigin=a;return this},setPath:function(a){this.path=a;return this}});Object.assign(Ad.prototype,{crossOrigin:"anonymous",load:function(a,b,c,d){var e=new Q,f=new cd(this.manager);f.setCrossOrigin(this.crossOrigin);f.setPath(this.path);f.load(a,function(c){e.image=c;c=0<a.search(/\.jpe?g$/i)||0===a.search(/^data:image\/jpeg/);e.format=c?1022:1023;e.needsUpdate= +!0;void 0!==b&&b(e)},c,d);return e},setCrossOrigin:function(a){this.crossOrigin=a;return this},setPath:function(a){this.path=a;return this}});Object.assign(N.prototype,{getPoint:function(){console.warn("THREE.Curve: .getPoint() not implemented.");return null},getPointAt:function(a,b){a=this.getUtoTmapping(a);return this.getPoint(a,b)},getPoints:function(a){void 0===a&&(a=5);for(var b=[],c=0;c<=a;c++)b.push(this.getPoint(c/a));return b},getSpacedPoints:function(a){void 0===a&&(a=5);for(var b=[],c= +0;c<=a;c++)b.push(this.getPointAt(c/a));return b},getLength:function(){var a=this.getLengths();return a[a.length-1]},getLengths:function(a){void 0===a&&(a=this.arcLengthDivisions);if(this.cacheArcLengths&&this.cacheArcLengths.length===a+1&&!this.needsUpdate)return this.cacheArcLengths;this.needsUpdate=!1;var b=[],c=this.getPoint(0),d,e=0;b.push(0);for(d=1;d<=a;d++){var f=this.getPoint(d/a);e+=f.distanceTo(c);b.push(e);c=f}return this.cacheArcLengths=b},updateArcLengths:function(){this.needsUpdate= +!0;this.getLengths()},getUtoTmapping:function(a,b){var c=this.getLengths(),d=c.length;b=b?b:a*c[d-1];for(var e=0,f=d-1,g;e<=f;)if(a=Math.floor(e+(f-e)/2),g=c[a]-b,0>g)e=a+1;else if(0<g)f=a-1;else{f=a;break}a=f;if(c[a]===b)return a/(d-1);e=c[a];return(a+(b-e)/(c[a+1]-e))/(d-1)},getTangent:function(a){var b=a-1E-4;a+=1E-4;0>b&&(b=0);1<a&&(a=1);b=this.getPoint(b);return this.getPoint(a).clone().sub(b).normalize()},getTangentAt:function(a){a=this.getUtoTmapping(a);return this.getTangent(a)},computeFrenetFrames:function(a, +b){var c=new p,d=[],e=[],f=[],g=new p,h=new P,k;for(k=0;k<=a;k++){var m=k/a;d[k]=this.getTangentAt(m);d[k].normalize()}e[0]=new p;f[0]=new p;k=Number.MAX_VALUE;m=Math.abs(d[0].x);var l=Math.abs(d[0].y),n=Math.abs(d[0].z);m<=k&&(k=m,c.set(1,0,0));l<=k&&(k=l,c.set(0,1,0));n<=k&&c.set(0,0,1);g.crossVectors(d[0],c).normalize();e[0].crossVectors(d[0],g);f[0].crossVectors(d[0],e[0]);for(k=1;k<=a;k++)e[k]=e[k-1].clone(),f[k]=f[k-1].clone(),g.crossVectors(d[k-1],d[k]),g.length()>Number.EPSILON&&(g.normalize(), +c=Math.acos(S.clamp(d[k-1].dot(d[k]),-1,1)),e[k].applyMatrix4(h.makeRotationAxis(g,c))),f[k].crossVectors(d[k],e[k]);if(!0===b)for(c=Math.acos(S.clamp(e[0].dot(e[a]),-1,1)),c/=a,0<d[0].dot(g.crossVectors(e[0],e[a]))&&(c=-c),k=1;k<=a;k++)e[k].applyMatrix4(h.makeRotationAxis(d[k],c*k)),f[k].crossVectors(d[k],e[k]);return{tangents:d,normals:e,binormals:f}},clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.arcLengthDivisions=a.arcLengthDivisions;return this},toJSON:function(){var a= +{metadata:{version:4.5,type:"Curve",generator:"Curve.toJSON"}};a.arcLengthDivisions=this.arcLengthDivisions;a.type=this.type;return a},fromJSON:function(a){this.arcLengthDivisions=a.arcLengthDivisions;return this}});Ca.prototype=Object.create(N.prototype);Ca.prototype.constructor=Ca;Ca.prototype.isEllipseCurve=!0;Ca.prototype.getPoint=function(a,b){b=b||new A;for(var c=2*Math.PI,d=this.aEndAngle-this.aStartAngle,e=Math.abs(d)<Number.EPSILON;0>d;)d+=c;for(;d>c;)d-=c;d<Number.EPSILON&&(d=e?0:c);!0!== +this.aClockwise||e||(d=d===c?-c:d-c);c=this.aStartAngle+a*d;a=this.aX+this.xRadius*Math.cos(c);var f=this.aY+this.yRadius*Math.sin(c);0!==this.aRotation&&(c=Math.cos(this.aRotation),d=Math.sin(this.aRotation),e=a-this.aX,f-=this.aY,a=e*c-f*d+this.aX,f=e*d+f*c+this.aY);return b.set(a,f)};Ca.prototype.copy=function(a){N.prototype.copy.call(this,a);this.aX=a.aX;this.aY=a.aY;this.xRadius=a.xRadius;this.yRadius=a.yRadius;this.aStartAngle=a.aStartAngle;this.aEndAngle=a.aEndAngle;this.aClockwise=a.aClockwise; +this.aRotation=a.aRotation;return this};Ca.prototype.toJSON=function(){var a=N.prototype.toJSON.call(this);a.aX=this.aX;a.aY=this.aY;a.xRadius=this.xRadius;a.yRadius=this.yRadius;a.aStartAngle=this.aStartAngle;a.aEndAngle=this.aEndAngle;a.aClockwise=this.aClockwise;a.aRotation=this.aRotation;return a};Ca.prototype.fromJSON=function(a){N.prototype.fromJSON.call(this,a);this.aX=a.aX;this.aY=a.aY;this.xRadius=a.xRadius;this.yRadius=a.yRadius;this.aStartAngle=a.aStartAngle;this.aEndAngle=a.aEndAngle; +this.aClockwise=a.aClockwise;this.aRotation=a.aRotation;return this};hc.prototype=Object.create(Ca.prototype);hc.prototype.constructor=hc;hc.prototype.isArcCurve=!0;var Ud=new p,Ce=new ie,De=new ie,Ee=new ie;ha.prototype=Object.create(N.prototype);ha.prototype.constructor=ha;ha.prototype.isCatmullRomCurve3=!0;ha.prototype.getPoint=function(a,b){b=b||new p;var c=this.points,d=c.length;a*=d-(this.closed?0:1);var e=Math.floor(a);a-=e;this.closed?e+=0<e?0:(Math.floor(Math.abs(e)/d)+1)*d:0===a&&e===d- +1&&(e=d-2,a=1);if(this.closed||0<e)var f=c[(e-1)%d];else Ud.subVectors(c[0],c[1]).add(c[0]),f=Ud;var g=c[e%d];var h=c[(e+1)%d];this.closed||e+2<d?c=c[(e+2)%d]:(Ud.subVectors(c[d-1],c[d-2]).add(c[d-1]),c=Ud);if("centripetal"===this.curveType||"chordal"===this.curveType){var k="chordal"===this.curveType?.5:.25;d=Math.pow(f.distanceToSquared(g),k);e=Math.pow(g.distanceToSquared(h),k);k=Math.pow(h.distanceToSquared(c),k);1E-4>e&&(e=1);1E-4>d&&(d=e);1E-4>k&&(k=e);Ce.initNonuniformCatmullRom(f.x,g.x,h.x, +c.x,d,e,k);De.initNonuniformCatmullRom(f.y,g.y,h.y,c.y,d,e,k);Ee.initNonuniformCatmullRom(f.z,g.z,h.z,c.z,d,e,k)}else"catmullrom"===this.curveType&&(Ce.initCatmullRom(f.x,g.x,h.x,c.x,this.tension),De.initCatmullRom(f.y,g.y,h.y,c.y,this.tension),Ee.initCatmullRom(f.z,g.z,h.z,c.z,this.tension));b.set(Ce.calc(a),De.calc(a),Ee.calc(a));return b};ha.prototype.copy=function(a){N.prototype.copy.call(this,a);this.points=[];for(var b=0,c=a.points.length;b<c;b++)this.points.push(a.points[b].clone());this.closed= +a.closed;this.curveType=a.curveType;this.tension=a.tension;return this};ha.prototype.toJSON=function(){var a=N.prototype.toJSON.call(this);a.points=[];for(var b=0,c=this.points.length;b<c;b++)a.points.push(this.points[b].toArray());a.closed=this.closed;a.curveType=this.curveType;a.tension=this.tension;return a};ha.prototype.fromJSON=function(a){N.prototype.fromJSON.call(this,a);this.points=[];for(var b=0,c=a.points.length;b<c;b++){var d=a.points[b];this.points.push((new p).fromArray(d))}this.closed= +a.closed;this.curveType=a.curveType;this.tension=a.tension;return this};Ja.prototype=Object.create(N.prototype);Ja.prototype.constructor=Ja;Ja.prototype.isCubicBezierCurve=!0;Ja.prototype.getPoint=function(a,b){b=b||new A;var c=this.v0,d=this.v1,e=this.v2,f=this.v3;b.set(ed(a,c.x,d.x,e.x,f.x),ed(a,c.y,d.y,e.y,f.y));return b};Ja.prototype.copy=function(a){N.prototype.copy.call(this,a);this.v0.copy(a.v0);this.v1.copy(a.v1);this.v2.copy(a.v2);this.v3.copy(a.v3);return this};Ja.prototype.toJSON=function(){var a= +N.prototype.toJSON.call(this);a.v0=this.v0.toArray();a.v1=this.v1.toArray();a.v2=this.v2.toArray();a.v3=this.v3.toArray();return a};Ja.prototype.fromJSON=function(a){N.prototype.fromJSON.call(this,a);this.v0.fromArray(a.v0);this.v1.fromArray(a.v1);this.v2.fromArray(a.v2);this.v3.fromArray(a.v3);return this};Ua.prototype=Object.create(N.prototype);Ua.prototype.constructor=Ua;Ua.prototype.isCubicBezierCurve3=!0;Ua.prototype.getPoint=function(a,b){b=b||new p;var c=this.v0,d=this.v1,e=this.v2,f=this.v3; +b.set(ed(a,c.x,d.x,e.x,f.x),ed(a,c.y,d.y,e.y,f.y),ed(a,c.z,d.z,e.z,f.z));return b};Ua.prototype.copy=function(a){N.prototype.copy.call(this,a);this.v0.copy(a.v0);this.v1.copy(a.v1);this.v2.copy(a.v2);this.v3.copy(a.v3);return this};Ua.prototype.toJSON=function(){var a=N.prototype.toJSON.call(this);a.v0=this.v0.toArray();a.v1=this.v1.toArray();a.v2=this.v2.toArray();a.v3=this.v3.toArray();return a};Ua.prototype.fromJSON=function(a){N.prototype.fromJSON.call(this,a);this.v0.fromArray(a.v0);this.v1.fromArray(a.v1); +this.v2.fromArray(a.v2);this.v3.fromArray(a.v3);return this};za.prototype=Object.create(N.prototype);za.prototype.constructor=za;za.prototype.isLineCurve=!0;za.prototype.getPoint=function(a,b){b=b||new A;1===a?b.copy(this.v2):(b.copy(this.v2).sub(this.v1),b.multiplyScalar(a).add(this.v1));return b};za.prototype.getPointAt=function(a,b){return this.getPoint(a,b)};za.prototype.getTangent=function(){return this.v2.clone().sub(this.v1).normalize()};za.prototype.copy=function(a){N.prototype.copy.call(this, +a);this.v1.copy(a.v1);this.v2.copy(a.v2);return this};za.prototype.toJSON=function(){var a=N.prototype.toJSON.call(this);a.v1=this.v1.toArray();a.v2=this.v2.toArray();return a};za.prototype.fromJSON=function(a){N.prototype.fromJSON.call(this,a);this.v1.fromArray(a.v1);this.v2.fromArray(a.v2);return this};Ka.prototype=Object.create(N.prototype);Ka.prototype.constructor=Ka;Ka.prototype.isLineCurve3=!0;Ka.prototype.getPoint=function(a,b){b=b||new p;1===a?b.copy(this.v2):(b.copy(this.v2).sub(this.v1), +b.multiplyScalar(a).add(this.v1));return b};Ka.prototype.getPointAt=function(a,b){return this.getPoint(a,b)};Ka.prototype.copy=function(a){N.prototype.copy.call(this,a);this.v1.copy(a.v1);this.v2.copy(a.v2);return this};Ka.prototype.toJSON=function(){var a=N.prototype.toJSON.call(this);a.v1=this.v1.toArray();a.v2=this.v2.toArray();return a};Ka.prototype.fromJSON=function(a){N.prototype.fromJSON.call(this,a);this.v1.fromArray(a.v1);this.v2.fromArray(a.v2);return this};La.prototype=Object.create(N.prototype); +La.prototype.constructor=La;La.prototype.isQuadraticBezierCurve=!0;La.prototype.getPoint=function(a,b){b=b||new A;var c=this.v0,d=this.v1,e=this.v2;b.set(dd(a,c.x,d.x,e.x),dd(a,c.y,d.y,e.y));return b};La.prototype.copy=function(a){N.prototype.copy.call(this,a);this.v0.copy(a.v0);this.v1.copy(a.v1);this.v2.copy(a.v2);return this};La.prototype.toJSON=function(){var a=N.prototype.toJSON.call(this);a.v0=this.v0.toArray();a.v1=this.v1.toArray();a.v2=this.v2.toArray();return a};La.prototype.fromJSON=function(a){N.prototype.fromJSON.call(this, +a);this.v0.fromArray(a.v0);this.v1.fromArray(a.v1);this.v2.fromArray(a.v2);return this};Va.prototype=Object.create(N.prototype);Va.prototype.constructor=Va;Va.prototype.isQuadraticBezierCurve3=!0;Va.prototype.getPoint=function(a,b){b=b||new p;var c=this.v0,d=this.v1,e=this.v2;b.set(dd(a,c.x,d.x,e.x),dd(a,c.y,d.y,e.y),dd(a,c.z,d.z,e.z));return b};Va.prototype.copy=function(a){N.prototype.copy.call(this,a);this.v0.copy(a.v0);this.v1.copy(a.v1);this.v2.copy(a.v2);return this};Va.prototype.toJSON=function(){var a= +N.prototype.toJSON.call(this);a.v0=this.v0.toArray();a.v1=this.v1.toArray();a.v2=this.v2.toArray();return a};Va.prototype.fromJSON=function(a){N.prototype.fromJSON.call(this,a);this.v0.fromArray(a.v0);this.v1.fromArray(a.v1);this.v2.fromArray(a.v2);return this};Ma.prototype=Object.create(N.prototype);Ma.prototype.constructor=Ma;Ma.prototype.isSplineCurve=!0;Ma.prototype.getPoint=function(a,b){b=b||new A;var c=this.points,d=(c.length-1)*a;a=Math.floor(d);d-=a;var e=c[0===a?a:a-1],f=c[a],g=c[a>c.length- +2?c.length-1:a+1];c=c[a>c.length-3?c.length-1:a+2];b.set(nf(d,e.x,f.x,g.x,c.x),nf(d,e.y,f.y,g.y,c.y));return b};Ma.prototype.copy=function(a){N.prototype.copy.call(this,a);this.points=[];for(var b=0,c=a.points.length;b<c;b++)this.points.push(a.points[b].clone());return this};Ma.prototype.toJSON=function(){var a=N.prototype.toJSON.call(this);a.points=[];for(var b=0,c=this.points.length;b<c;b++)a.points.push(this.points[b].toArray());return a};Ma.prototype.fromJSON=function(a){N.prototype.fromJSON.call(this, +a);this.points=[];for(var b=0,c=a.points.length;b<c;b++){var d=a.points[b];this.points.push((new A).fromArray(d))}return this};var Cf=Object.freeze({ArcCurve:hc,CatmullRomCurve3:ha,CubicBezierCurve:Ja,CubicBezierCurve3:Ua,EllipseCurve:Ca,LineCurve:za,LineCurve3:Ka,QuadraticBezierCurve:La,QuadraticBezierCurve3:Va,SplineCurve:Ma});ab.prototype=Object.assign(Object.create(N.prototype),{constructor:ab,add:function(a){this.curves.push(a)},closePath:function(){var a=this.curves[0].getPoint(0),b=this.curves[this.curves.length- +1].getPoint(1);a.equals(b)||this.curves.push(new za(b,a))},getPoint:function(a){var b=a*this.getLength(),c=this.getCurveLengths();for(a=0;a<c.length;){if(c[a]>=b)return b=c[a]-b,a=this.curves[a],c=a.getLength(),a.getPointAt(0===c?0:1-b/c);a++}return null},getLength:function(){var a=this.getCurveLengths();return a[a.length-1]},updateArcLengths:function(){this.needsUpdate=!0;this.cacheLengths=null;this.getCurveLengths()},getCurveLengths:function(){if(this.cacheLengths&&this.cacheLengths.length===this.curves.length)return this.cacheLengths; +for(var a=[],b=0,c=0,d=this.curves.length;c<d;c++)b+=this.curves[c].getLength(),a.push(b);return this.cacheLengths=a},getSpacedPoints:function(a){void 0===a&&(a=40);for(var b=[],c=0;c<=a;c++)b.push(this.getPoint(c/a));this.autoClose&&b.push(b[0]);return b},getPoints:function(a){a=a||12;for(var b=[],c,d=0,e=this.curves;d<e.length;d++){var f=e[d];f=f.getPoints(f&&f.isEllipseCurve?2*a:f&&(f.isLineCurve||f.isLineCurve3)?1:f&&f.isSplineCurve?a*f.points.length:a);for(var g=0;g<f.length;g++){var h=f[g]; +c&&c.equals(h)||(b.push(h),c=h)}}this.autoClose&&1<b.length&&!b[b.length-1].equals(b[0])&&b.push(b[0]);return b},copy:function(a){N.prototype.copy.call(this,a);this.curves=[];for(var b=0,c=a.curves.length;b<c;b++)this.curves.push(a.curves[b].clone());this.autoClose=a.autoClose;return this},toJSON:function(){var a=N.prototype.toJSON.call(this);a.autoClose=this.autoClose;a.curves=[];for(var b=0,c=this.curves.length;b<c;b++)a.curves.push(this.curves[b].toJSON());return a},fromJSON:function(a){N.prototype.fromJSON.call(this, +a);this.autoClose=a.autoClose;this.curves=[];for(var b=0,c=a.curves.length;b<c;b++){var d=a.curves[b];this.curves.push((new Cf[d.type]).fromJSON(d))}return this}});Na.prototype=Object.assign(Object.create(ab.prototype),{constructor:Na,setFromPoints:function(a){this.moveTo(a[0].x,a[0].y);for(var b=1,c=a.length;b<c;b++)this.lineTo(a[b].x,a[b].y)},moveTo:function(a,b){this.currentPoint.set(a,b)},lineTo:function(a,b){var c=new za(this.currentPoint.clone(),new A(a,b));this.curves.push(c);this.currentPoint.set(a, +b)},quadraticCurveTo:function(a,b,c,d){a=new La(this.currentPoint.clone(),new A(a,b),new A(c,d));this.curves.push(a);this.currentPoint.set(c,d)},bezierCurveTo:function(a,b,c,d,e,f){a=new Ja(this.currentPoint.clone(),new A(a,b),new A(c,d),new A(e,f));this.curves.push(a);this.currentPoint.set(e,f)},splineThru:function(a){var b=[this.currentPoint.clone()].concat(a);b=new Ma(b);this.curves.push(b);this.currentPoint.copy(a[a.length-1])},arc:function(a,b,c,d,e,f){this.absarc(a+this.currentPoint.x,b+this.currentPoint.y, +c,d,e,f)},absarc:function(a,b,c,d,e,f){this.absellipse(a,b,c,c,d,e,f)},ellipse:function(a,b,c,d,e,f,g,h){this.absellipse(a+this.currentPoint.x,b+this.currentPoint.y,c,d,e,f,g,h)},absellipse:function(a,b,c,d,e,f,g,h){a=new Ca(a,b,c,d,e,f,g,h);0<this.curves.length&&(b=a.getPoint(0),b.equals(this.currentPoint)||this.lineTo(b.x,b.y));this.curves.push(a);a=a.getPoint(1);this.currentPoint.copy(a)},copy:function(a){ab.prototype.copy.call(this,a);this.currentPoint.copy(a.currentPoint);return this},toJSON:function(){var a= +ab.prototype.toJSON.call(this);a.currentPoint=this.currentPoint.toArray();return a},fromJSON:function(a){ab.prototype.fromJSON.call(this,a);this.currentPoint.fromArray(a.currentPoint);return this}});gb.prototype=Object.assign(Object.create(Na.prototype),{constructor:gb,getPointsHoles:function(a){for(var b=[],c=0,d=this.holes.length;c<d;c++)b[c]=this.holes[c].getPoints(a);return b},extractPoints:function(a){return{shape:this.getPoints(a),holes:this.getPointsHoles(a)}},copy:function(a){Na.prototype.copy.call(this, +a);this.holes=[];for(var b=0,c=a.holes.length;b<c;b++)this.holes.push(a.holes[b].clone());return this},toJSON:function(){var a=Na.prototype.toJSON.call(this);a.uuid=this.uuid;a.holes=[];for(var b=0,c=this.holes.length;b<c;b++)a.holes.push(this.holes[b].toJSON());return a},fromJSON:function(a){Na.prototype.fromJSON.call(this,a);this.uuid=a.uuid;this.holes=[];for(var b=0,c=a.holes.length;b<c;b++){var d=a.holes[b];this.holes.push((new Na).fromJSON(d))}return this}});ca.prototype=Object.assign(Object.create(C.prototype), +{constructor:ca,isLight:!0,copy:function(a){C.prototype.copy.call(this,a);this.color.copy(a.color);this.intensity=a.intensity;return this},toJSON:function(a){a=C.prototype.toJSON.call(this,a);a.object.color=this.color.getHex();a.object.intensity=this.intensity;void 0!==this.groundColor&&(a.object.groundColor=this.groundColor.getHex());void 0!==this.distance&&(a.object.distance=this.distance);void 0!==this.angle&&(a.object.angle=this.angle);void 0!==this.decay&&(a.object.decay=this.decay);void 0!== +this.penumbra&&(a.object.penumbra=this.penumbra);void 0!==this.shadow&&(a.object.shadow=this.shadow.toJSON());return a}});Bd.prototype=Object.assign(Object.create(ca.prototype),{constructor:Bd,isHemisphereLight:!0,copy:function(a){ca.prototype.copy.call(this,a);this.groundColor.copy(a.groundColor);return this}});Object.assign(Fb.prototype,{copy:function(a){this.camera=a.camera.clone();this.bias=a.bias;this.radius=a.radius;this.mapSize.copy(a.mapSize);return this},clone:function(){return(new this.constructor).copy(this)}, +toJSON:function(){var a={};0!==this.bias&&(a.bias=this.bias);1!==this.radius&&(a.radius=this.radius);if(512!==this.mapSize.x||512!==this.mapSize.y)a.mapSize=this.mapSize.toArray();a.camera=this.camera.toJSON(!1).object;delete a.camera.matrix;return a}});Cd.prototype=Object.assign(Object.create(Fb.prototype),{constructor:Cd,isSpotLightShadow:!0,update:function(a){var b=this.camera,c=2*S.RAD2DEG*a.angle,d=this.mapSize.width/this.mapSize.height;a=a.distance||b.far;if(c!==b.fov||d!==b.aspect||a!==b.far)b.fov= +c,b.aspect=d,b.far=a,b.updateProjectionMatrix()}});Dd.prototype=Object.assign(Object.create(ca.prototype),{constructor:Dd,isSpotLight:!0,copy:function(a){ca.prototype.copy.call(this,a);this.distance=a.distance;this.angle=a.angle;this.penumbra=a.penumbra;this.decay=a.decay;this.target=a.target.clone();this.shadow=a.shadow.clone();return this}});Ed.prototype=Object.assign(Object.create(ca.prototype),{constructor:Ed,isPointLight:!0,copy:function(a){ca.prototype.copy.call(this,a);this.distance=a.distance; +this.decay=a.decay;this.shadow=a.shadow.clone();return this}});fd.prototype=Object.assign(Object.create(Ra.prototype),{constructor:fd,isOrthographicCamera:!0,copy:function(a,b){Ra.prototype.copy.call(this,a,b);this.left=a.left;this.right=a.right;this.top=a.top;this.bottom=a.bottom;this.near=a.near;this.far=a.far;this.zoom=a.zoom;this.view=null===a.view?null:Object.assign({},a.view);return this},setViewOffset:function(a,b,c,d,e,f){null===this.view&&(this.view={enabled:!0,fullWidth:1,fullHeight:1,offsetX:0, +offsetY:0,width:1,height:1});this.view.enabled=!0;this.view.fullWidth=a;this.view.fullHeight=b;this.view.offsetX=c;this.view.offsetY=d;this.view.width=e;this.view.height=f;this.updateProjectionMatrix()},clearViewOffset:function(){null!==this.view&&(this.view.enabled=!1);this.updateProjectionMatrix()},updateProjectionMatrix:function(){var a=(this.right-this.left)/(2*this.zoom),b=(this.top-this.bottom)/(2*this.zoom),c=(this.right+this.left)/2,d=(this.top+this.bottom)/2,e=c-a;c+=a;a=d+b;b=d-b;if(null!== +this.view&&this.view.enabled){c=this.zoom/(this.view.width/this.view.fullWidth);b=this.zoom/(this.view.height/this.view.fullHeight);var f=(this.right-this.left)/this.view.width;d=(this.top-this.bottom)/this.view.height;e+=this.view.offsetX/c*f;c=e+this.view.width/c*f;a-=this.view.offsetY/b*d;b=a-this.view.height/b*d}this.projectionMatrix.makeOrthographic(e,c,a,b,this.near,this.far);this.projectionMatrixInverse.getInverse(this.projectionMatrix)},toJSON:function(a){a=C.prototype.toJSON.call(this,a); +a.object.zoom=this.zoom;a.object.left=this.left;a.object.right=this.right;a.object.top=this.top;a.object.bottom=this.bottom;a.object.near=this.near;a.object.far=this.far;null!==this.view&&(a.object.view=Object.assign({},this.view));return a}});Fd.prototype=Object.assign(Object.create(Fb.prototype),{constructor:Fd});Gd.prototype=Object.assign(Object.create(ca.prototype),{constructor:Gd,isDirectionalLight:!0,copy:function(a){ca.prototype.copy.call(this,a);this.target=a.target.clone();this.shadow=a.shadow.clone(); +return this}});Hd.prototype=Object.assign(Object.create(ca.prototype),{constructor:Hd,isAmbientLight:!0});Id.prototype=Object.assign(Object.create(ca.prototype),{constructor:Id,isRectAreaLight:!0,copy:function(a){ca.prototype.copy.call(this,a);this.width=a.width;this.height=a.height;return this},toJSON:function(a){a=ca.prototype.toJSON.call(this,a);a.object.width=this.width;a.object.height=this.height;return a}});var ra={arraySlice:function(a,b,c){return ra.isTypedArray(a)?new a.constructor(a.subarray(b, +void 0!==c?c:a.length)):a.slice(b,c)},convertArray:function(a,b,c){return!a||!c&&a.constructor===b?a:"number"===typeof b.BYTES_PER_ELEMENT?new b(a):Array.prototype.slice.call(a)},isTypedArray:function(a){return ArrayBuffer.isView(a)&&!(a instanceof DataView)},getKeyframeOrder:function(a){for(var b=a.length,c=Array(b),d=0;d!==b;++d)c[d]=d;c.sort(function(b,c){return a[b]-a[c]});return c},sortedArray:function(a,b,c){for(var d=a.length,e=new a.constructor(d),f=0,g=0;g!==d;++f)for(var h=c[f]*b,k=0;k!== +b;++k)e[g++]=a[h+k];return e},flattenJSON:function(a,b,c,d){for(var e=1,f=a[0];void 0!==f&&void 0===f[d];)f=a[e++];if(void 0!==f){var g=f[d];if(void 0!==g)if(Array.isArray(g)){do g=f[d],void 0!==g&&(b.push(f.time),c.push.apply(c,g)),f=a[e++];while(void 0!==f)}else if(void 0!==g.toArray){do g=f[d],void 0!==g&&(b.push(f.time),g.toArray(c,c.length)),f=a[e++];while(void 0!==f)}else{do g=f[d],void 0!==g&&(b.push(f.time),c.push(g)),f=a[e++];while(void 0!==f)}}}};Object.assign(Aa.prototype,{evaluate:function(a){var b= +this.parameterPositions,c=this._cachedIndex,d=b[c],e=b[c-1];a:{b:{c:{d:if(!(a<d)){for(var f=c+2;;){if(void 0===d){if(a<e)break d;this._cachedIndex=c=b.length;return this.afterEnd_(c-1,a,e)}if(c===f)break;e=d;d=b[++c];if(a<d)break b}d=b.length;break c}if(a>=e)break a;else{f=b[1];a<f&&(c=2,e=f);for(f=c-2;;){if(void 0===e)return this._cachedIndex=0,this.beforeStart_(0,a,d);if(c===f)break;d=e;e=b[--c-1];if(a>=e)break b}d=c;c=0}}for(;c<d;)e=c+d>>>1,a<b[e]?d=e:c=e+1;d=b[c];e=b[c-1];if(void 0===e)return this._cachedIndex= +0,this.beforeStart_(0,a,d);if(void 0===d)return this._cachedIndex=c=b.length,this.afterEnd_(c-1,e,a)}this._cachedIndex=c;this.intervalChanged_(c,e,d)}return this.interpolate_(c,e,a,d)},settings:null,DefaultSettings_:{},getSettings_:function(){return this.settings||this.DefaultSettings_},copySampleValue_:function(a){var b=this.resultBuffer,c=this.sampleValues,d=this.valueSize;a*=d;for(var e=0;e!==d;++e)b[e]=c[a+e];return b},interpolate_:function(){throw Error("call to abstract method");},intervalChanged_:function(){}}); +Object.assign(Aa.prototype,{beforeStart_:Aa.prototype.copySampleValue_,afterEnd_:Aa.prototype.copySampleValue_});Jd.prototype=Object.assign(Object.create(Aa.prototype),{constructor:Jd,DefaultSettings_:{endingStart:2400,endingEnd:2400},intervalChanged_:function(a,b,c){var d=this.parameterPositions,e=a-2,f=a+1,g=d[e],h=d[f];if(void 0===g)switch(this.getSettings_().endingStart){case 2401:e=a;g=2*b-c;break;case 2402:e=d.length-2;g=b+d[e]-d[e+1];break;default:e=a,g=c}if(void 0===h)switch(this.getSettings_().endingEnd){case 2401:f= +a;h=2*c-b;break;case 2402:f=1;h=c+d[1]-d[0];break;default:f=a-1,h=b}a=.5*(c-b);d=this.valueSize;this._weightPrev=a/(b-g);this._weightNext=a/(h-c);this._offsetPrev=e*d;this._offsetNext=f*d},interpolate_:function(a,b,c,d){var e=this.resultBuffer,f=this.sampleValues,g=this.valueSize;a*=g;var h=a-g,k=this._offsetPrev,m=this._offsetNext,l=this._weightPrev,n=this._weightNext,q=(c-b)/(d-b);c=q*q;d=c*q;b=-l*d+2*l*c-l*q;l=(1+l)*d+(-1.5-2*l)*c+(-.5+l)*q+1;q=(-1-n)*d+(1.5+n)*c+.5*q;n=n*d-n*c;for(c=0;c!==g;++c)e[c]= +b*f[k+c]+l*f[h+c]+q*f[a+c]+n*f[m+c];return e}});gd.prototype=Object.assign(Object.create(Aa.prototype),{constructor:gd,interpolate_:function(a,b,c,d){var e=this.resultBuffer,f=this.sampleValues,g=this.valueSize;a*=g;var h=a-g;b=(c-b)/(d-b);c=1-b;for(d=0;d!==g;++d)e[d]=f[h+d]*c+f[a+d]*b;return e}});Kd.prototype=Object.assign(Object.create(Aa.prototype),{constructor:Kd,interpolate_:function(a){return this.copySampleValue_(a-1)}});Object.assign(qa,{toJSON:function(a){var b=a.constructor;if(void 0!== +b.toJSON)b=b.toJSON(a);else{b={name:a.name,times:ra.convertArray(a.times,Array),values:ra.convertArray(a.values,Array)};var c=a.getInterpolation();c!==a.DefaultInterpolation&&(b.interpolation=c)}b.type=a.ValueTypeName;return b}});Object.assign(qa.prototype,{constructor:qa,TimeBufferType:Float32Array,ValueBufferType:Float32Array,DefaultInterpolation:2301,InterpolantFactoryMethodDiscrete:function(a){return new Kd(this.times,this.values,this.getValueSize(),a)},InterpolantFactoryMethodLinear:function(a){return new gd(this.times, +this.values,this.getValueSize(),a)},InterpolantFactoryMethodSmooth:function(a){return new Jd(this.times,this.values,this.getValueSize(),a)},setInterpolation:function(a){switch(a){case 2300:var b=this.InterpolantFactoryMethodDiscrete;break;case 2301:b=this.InterpolantFactoryMethodLinear;break;case 2302:b=this.InterpolantFactoryMethodSmooth}if(void 0===b){b="unsupported interpolation for "+this.ValueTypeName+" keyframe track named "+this.name;if(void 0===this.createInterpolant)if(a!==this.DefaultInterpolation)this.setInterpolation(this.DefaultInterpolation); +else throw Error(b);console.warn("THREE.KeyframeTrack:",b);return this}this.createInterpolant=b;return this},getInterpolation:function(){switch(this.createInterpolant){case this.InterpolantFactoryMethodDiscrete:return 2300;case this.InterpolantFactoryMethodLinear:return 2301;case this.InterpolantFactoryMethodSmooth:return 2302}},getValueSize:function(){return this.values.length/this.times.length},shift:function(a){if(0!==a)for(var b=this.times,c=0,d=b.length;c!==d;++c)b[c]+=a;return this},scale:function(a){if(1!== +a)for(var b=this.times,c=0,d=b.length;c!==d;++c)b[c]*=a;return this},trim:function(a,b){for(var c=this.times,d=c.length,e=0,f=d-1;e!==d&&c[e]<a;)++e;for(;-1!==f&&c[f]>b;)--f;++f;if(0!==e||f!==d)e>=f&&(f=Math.max(f,1),e=f-1),a=this.getValueSize(),this.times=ra.arraySlice(c,e,f),this.values=ra.arraySlice(this.values,e*a,f*a);return this},validate:function(){var a=!0,b=this.getValueSize();0!==b-Math.floor(b)&&(console.error("THREE.KeyframeTrack: Invalid value size in track.",this),a=!1);var c=this.times; +b=this.values;var d=c.length;0===d&&(console.error("THREE.KeyframeTrack: Track is empty.",this),a=!1);for(var e=null,f=0;f!==d;f++){var g=c[f];if("number"===typeof g&&isNaN(g)){console.error("THREE.KeyframeTrack: Time is not a valid number.",this,f,g);a=!1;break}if(null!==e&&e>g){console.error("THREE.KeyframeTrack: Out of order keys.",this,f,g,e);a=!1;break}e=g}if(void 0!==b&&ra.isTypedArray(b))for(f=0,c=b.length;f!==c;++f)if(d=b[f],isNaN(d)){console.error("THREE.KeyframeTrack: Value is not a valid number.", +this,f,d);a=!1;break}return a},optimize:function(){for(var a=this.times,b=this.values,c=this.getValueSize(),d=2302===this.getInterpolation(),e=1,f=a.length-1,g=1;g<f;++g){var h=!1,k=a[g];if(k!==a[g+1]&&(1!==g||k!==k[0]))if(d)h=!0;else{var m=g*c,l=m-c,n=m+c;for(k=0;k!==c;++k){var q=b[m+k];if(q!==b[l+k]||q!==b[n+k]){h=!0;break}}}if(h){if(g!==e)for(a[e]=a[g],h=g*c,m=e*c,k=0;k!==c;++k)b[m+k]=b[h+k];++e}}if(0<f){a[e]=a[f];h=f*c;m=e*c;for(k=0;k!==c;++k)b[m+k]=b[h+k];++e}e!==a.length&&(this.times=ra.arraySlice(a, +0,e),this.values=ra.arraySlice(b,0,e*c));return this}});Ld.prototype=Object.assign(Object.create(qa.prototype),{constructor:Ld,ValueTypeName:"bool",ValueBufferType:Array,DefaultInterpolation:2300,InterpolantFactoryMethodLinear:void 0,InterpolantFactoryMethodSmooth:void 0});Md.prototype=Object.assign(Object.create(qa.prototype),{constructor:Md,ValueTypeName:"color"});ic.prototype=Object.assign(Object.create(qa.prototype),{constructor:ic,ValueTypeName:"number"});Nd.prototype=Object.assign(Object.create(Aa.prototype), +{constructor:Nd,interpolate_:function(a,b,c,d){var e=this.resultBuffer,f=this.sampleValues,g=this.valueSize;a*=g;b=(c-b)/(d-b);for(c=a+g;a!==c;a+=4)ja.slerpFlat(e,0,f,a-g,f,a,b);return e}});hd.prototype=Object.assign(Object.create(qa.prototype),{constructor:hd,ValueTypeName:"quaternion",DefaultInterpolation:2301,InterpolantFactoryMethodLinear:function(a){return new Nd(this.times,this.values,this.getValueSize(),a)},InterpolantFactoryMethodSmooth:void 0});Od.prototype=Object.assign(Object.create(qa.prototype), +{constructor:Od,ValueTypeName:"string",ValueBufferType:Array,DefaultInterpolation:2300,InterpolantFactoryMethodLinear:void 0,InterpolantFactoryMethodSmooth:void 0});jc.prototype=Object.assign(Object.create(qa.prototype),{constructor:jc,ValueTypeName:"vector"});Object.assign(Ea,{parse:function(a){for(var b=[],c=a.tracks,d=1/(a.fps||1),e=0,f=c.length;e!==f;++e)b.push(Vg(c[e]).scale(d));return new Ea(a.name,a.duration,b)},toJSON:function(a){var b=[],c=a.tracks;a={name:a.name,duration:a.duration,tracks:b, +uuid:a.uuid};for(var d=0,e=c.length;d!==e;++d)b.push(qa.toJSON(c[d]));return a},CreateFromMorphTargetSequence:function(a,b,c,d){for(var e=b.length,f=[],g=0;g<e;g++){var h=[],k=[];h.push((g+e-1)%e,g,(g+1)%e);k.push(0,1,0);var m=ra.getKeyframeOrder(h);h=ra.sortedArray(h,1,m);k=ra.sortedArray(k,1,m);d||0!==h[0]||(h.push(e),k.push(k[0]));f.push((new ic(".morphTargetInfluences["+b[g].name+"]",h,k)).scale(1/c))}return new Ea(a,-1,f)},findByName:function(a,b){var c=a;Array.isArray(a)||(c=a.geometry&&a.geometry.animations|| +a.animations);for(a=0;a<c.length;a++)if(c[a].name===b)return c[a];return null},CreateClipsFromMorphTargetSequences:function(a,b,c){for(var d={},e=/^([\w-]*?)([\d]+)$/,f=0,g=a.length;f<g;f++){var h=a[f],k=h.name.match(e);if(k&&1<k.length){var m=k[1];(k=d[m])||(d[m]=k=[]);k.push(h)}}a=[];for(m in d)a.push(Ea.CreateFromMorphTargetSequence(m,d[m],b,c));return a},parseAnimation:function(a,b){if(!a)return console.error("THREE.AnimationClip: No animation in JSONLoader data."),null;var c=function(a,b,c,d, +e){if(0!==c.length){var f=[],g=[];ra.flattenJSON(c,f,g,d);0!==f.length&&e.push(new a(b,f,g))}},d=[],e=a.name||"default",f=a.length||-1,g=a.fps||30;a=a.hierarchy||[];for(var h=0;h<a.length;h++){var k=a[h].keys;if(k&&0!==k.length)if(k[0].morphTargets){f={};for(var m=0;m<k.length;m++)if(k[m].morphTargets)for(var l=0;l<k[m].morphTargets.length;l++)f[k[m].morphTargets[l]]=-1;for(var n in f){var q=[],p=[];for(l=0;l!==k[m].morphTargets.length;++l){var t=k[m];q.push(t.time);p.push(t.morphTarget===n?1:0)}d.push(new ic(".morphTargetInfluence["+ +n+"]",q,p))}f=f.length*(g||1)}else m=".bones["+b[h].name+"]",c(jc,m+".position",k,"pos",d),c(hd,m+".quaternion",k,"rot",d),c(jc,m+".scale",k,"scl",d)}return 0===d.length?null:new Ea(e,f,d)}});Object.assign(Ea.prototype,{resetDuration:function(){for(var a=0,b=0,c=this.tracks.length;b!==c;++b){var d=this.tracks[b];a=Math.max(a,d.times[d.times.length-1])}this.duration=a;return this},trim:function(){for(var a=0;a<this.tracks.length;a++)this.tracks[a].trim(0,this.duration);return this},validate:function(){for(var a= +!0,b=0;b<this.tracks.length;b++)a=a&&this.tracks[b].validate();return a},optimize:function(){for(var a=0;a<this.tracks.length;a++)this.tracks[a].optimize();return this}});Object.assign(Pd.prototype,{load:function(a,b,c,d){var e=this;(new Ia(e.manager)).load(a,function(a){b(e.parse(JSON.parse(a)))},c,d)},setTextures:function(a){this.textures=a},parse:function(a){function b(a){void 0===c[a]&&console.warn("THREE.MaterialLoader: Undefined texture",a);return c[a]}var c=this.textures,d=new Yg[a.type];void 0!== +a.uuid&&(d.uuid=a.uuid);void 0!==a.name&&(d.name=a.name);void 0!==a.color&&d.color.setHex(a.color);void 0!==a.roughness&&(d.roughness=a.roughness);void 0!==a.metalness&&(d.metalness=a.metalness);void 0!==a.emissive&&d.emissive.setHex(a.emissive);void 0!==a.specular&&d.specular.setHex(a.specular);void 0!==a.shininess&&(d.shininess=a.shininess);void 0!==a.clearCoat&&(d.clearCoat=a.clearCoat);void 0!==a.clearCoatRoughness&&(d.clearCoatRoughness=a.clearCoatRoughness);void 0!==a.vertexColors&&(d.vertexColors= +a.vertexColors);void 0!==a.fog&&(d.fog=a.fog);void 0!==a.flatShading&&(d.flatShading=a.flatShading);void 0!==a.blending&&(d.blending=a.blending);void 0!==a.combine&&(d.combine=a.combine);void 0!==a.side&&(d.side=a.side);void 0!==a.opacity&&(d.opacity=a.opacity);void 0!==a.transparent&&(d.transparent=a.transparent);void 0!==a.alphaTest&&(d.alphaTest=a.alphaTest);void 0!==a.depthTest&&(d.depthTest=a.depthTest);void 0!==a.depthWrite&&(d.depthWrite=a.depthWrite);void 0!==a.colorWrite&&(d.colorWrite=a.colorWrite); +void 0!==a.wireframe&&(d.wireframe=a.wireframe);void 0!==a.wireframeLinewidth&&(d.wireframeLinewidth=a.wireframeLinewidth);void 0!==a.wireframeLinecap&&(d.wireframeLinecap=a.wireframeLinecap);void 0!==a.wireframeLinejoin&&(d.wireframeLinejoin=a.wireframeLinejoin);void 0!==a.rotation&&(d.rotation=a.rotation);1!==a.linewidth&&(d.linewidth=a.linewidth);void 0!==a.dashSize&&(d.dashSize=a.dashSize);void 0!==a.gapSize&&(d.gapSize=a.gapSize);void 0!==a.scale&&(d.scale=a.scale);void 0!==a.polygonOffset&& +(d.polygonOffset=a.polygonOffset);void 0!==a.polygonOffsetFactor&&(d.polygonOffsetFactor=a.polygonOffsetFactor);void 0!==a.polygonOffsetUnits&&(d.polygonOffsetUnits=a.polygonOffsetUnits);void 0!==a.skinning&&(d.skinning=a.skinning);void 0!==a.morphTargets&&(d.morphTargets=a.morphTargets);void 0!==a.dithering&&(d.dithering=a.dithering);void 0!==a.visible&&(d.visible=a.visible);void 0!==a.userData&&(d.userData=a.userData);if(void 0!==a.uniforms)for(var e in a.uniforms){var f=a.uniforms[e];d.uniforms[e]= +{};switch(f.type){case "t":d.uniforms[e].value=b(f.value);break;case "c":d.uniforms[e].value=(new G).setHex(f.value);break;case "v2":d.uniforms[e].value=(new A).fromArray(f.value);break;case "v3":d.uniforms[e].value=(new p).fromArray(f.value);break;case "v4":d.uniforms[e].value=(new Z).fromArray(f.value);break;case "m4":d.uniforms[e].value=(new P).fromArray(f.value);break;default:d.uniforms[e].value=f.value}}void 0!==a.defines&&(d.defines=a.defines);void 0!==a.vertexShader&&(d.vertexShader=a.vertexShader); +void 0!==a.fragmentShader&&(d.fragmentShader=a.fragmentShader);void 0!==a.shading&&(d.flatShading=1===a.shading);void 0!==a.size&&(d.size=a.size);void 0!==a.sizeAttenuation&&(d.sizeAttenuation=a.sizeAttenuation);void 0!==a.map&&(d.map=b(a.map));void 0!==a.alphaMap&&(d.alphaMap=b(a.alphaMap),d.transparent=!0);void 0!==a.bumpMap&&(d.bumpMap=b(a.bumpMap));void 0!==a.bumpScale&&(d.bumpScale=a.bumpScale);void 0!==a.normalMap&&(d.normalMap=b(a.normalMap));void 0!==a.normalMapType&&(d.normalMapType=a.normalMapType); +void 0!==a.normalScale&&(e=a.normalScale,!1===Array.isArray(e)&&(e=[e,e]),d.normalScale=(new A).fromArray(e));void 0!==a.displacementMap&&(d.displacementMap=b(a.displacementMap));void 0!==a.displacementScale&&(d.displacementScale=a.displacementScale);void 0!==a.displacementBias&&(d.displacementBias=a.displacementBias);void 0!==a.roughnessMap&&(d.roughnessMap=b(a.roughnessMap));void 0!==a.metalnessMap&&(d.metalnessMap=b(a.metalnessMap));void 0!==a.emissiveMap&&(d.emissiveMap=b(a.emissiveMap));void 0!== +a.emissiveIntensity&&(d.emissiveIntensity=a.emissiveIntensity);void 0!==a.specularMap&&(d.specularMap=b(a.specularMap));void 0!==a.envMap&&(d.envMap=b(a.envMap));void 0!==a.envMapIntensity&&(d.envMapIntensity=a.envMapIntensity);void 0!==a.reflectivity&&(d.reflectivity=a.reflectivity);void 0!==a.lightMap&&(d.lightMap=b(a.lightMap));void 0!==a.lightMapIntensity&&(d.lightMapIntensity=a.lightMapIntensity);void 0!==a.aoMap&&(d.aoMap=b(a.aoMap));void 0!==a.aoMapIntensity&&(d.aoMapIntensity=a.aoMapIntensity); +void 0!==a.gradientMap&&(d.gradientMap=b(a.gradientMap));return d}});Object.assign(je.prototype,{load:function(a,b,c,d){var e=this;(new Ia(e.manager)).load(a,function(a){b(e.parse(JSON.parse(a)))},c,d)},parse:function(a){var b=new F,c=a.data.index;void 0!==c&&(c=new Df[c.type](c.array),b.setIndex(new I(c,1)));var d=a.data.attributes;for(f in d){var e=d[f];c=new Df[e.type](e.array);b.addAttribute(f,new I(c,e.itemSize,e.normalized))}var f=a.data.groups||a.data.drawcalls||a.data.offsets;if(void 0!== +f)for(c=0,d=f.length;c!==d;++c)e=f[c],b.addGroup(e.start,e.count,e.materialIndex);a=a.data.boundingSphere;void 0!==a&&(f=new p,void 0!==a.center&&f.fromArray(a.center),b.boundingSphere=new Fa(f,a.radius));return b}});var Df={Int8Array:Int8Array,Uint8Array:Uint8Array,Uint8ClampedArray:"undefined"!==typeof Uint8ClampedArray?Uint8ClampedArray:Uint8Array,Int16Array:Int16Array,Uint16Array:Uint16Array,Int32Array:Int32Array,Uint32Array:Uint32Array,Float32Array:Float32Array,Float64Array:Float64Array};kc.Handlers= +{handlers:[],add:function(a,b){this.handlers.push(a,b)},get:function(a){for(var b=this.handlers,c=0,d=b.length;c<d;c+=2){var e=b[c+1];if(b[c].test(a))return e}return null}};Object.assign(kc.prototype,{crossOrigin:"anonymous",onLoadStart:function(){},onLoadProgress:function(){},onLoadComplete:function(){},initMaterials:function(a,b,c){for(var d=[],e=0;e<a.length;++e)d[e]=this.createMaterial(a[e],b,c);return d},createMaterial:function(){var a={NoBlending:0,NormalBlending:1,AdditiveBlending:2,SubtractiveBlending:3, +MultiplyBlending:4,CustomBlending:5},b=new G,c=new Ad,d=new Pd;return function(e,f,g){function h(a,b,d,e,h){a=f+a;var m=kc.Handlers.get(a);null!==m?a=m.load(a):(c.setCrossOrigin(g),a=c.load(a));void 0!==b&&(a.repeat.fromArray(b),1!==b[0]&&(a.wrapS=1E3),1!==b[1]&&(a.wrapT=1E3));void 0!==d&&a.offset.fromArray(d);void 0!==e&&("repeat"===e[0]&&(a.wrapS=1E3),"mirror"===e[0]&&(a.wrapS=1002),"repeat"===e[1]&&(a.wrapT=1E3),"mirror"===e[1]&&(a.wrapT=1002));void 0!==h&&(a.anisotropy=h);b=S.generateUUID();k[b]= +a;return b}var k={},m={uuid:S.generateUUID(),type:"MeshLambertMaterial"},l;for(l in e){var n=e[l];switch(l){case "DbgColor":case "DbgIndex":case "opticalDensity":case "illumination":break;case "DbgName":m.name=n;break;case "blending":m.blending=a[n];break;case "colorAmbient":case "mapAmbient":console.warn("THREE.Loader.createMaterial:",l,"is no longer supported.");break;case "colorDiffuse":m.color=b.fromArray(n).getHex();break;case "colorSpecular":m.specular=b.fromArray(n).getHex();break;case "colorEmissive":m.emissive= +b.fromArray(n).getHex();break;case "specularCoef":m.shininess=n;break;case "shading":"basic"===n.toLowerCase()&&(m.type="MeshBasicMaterial");"phong"===n.toLowerCase()&&(m.type="MeshPhongMaterial");"standard"===n.toLowerCase()&&(m.type="MeshStandardMaterial");break;case "mapDiffuse":m.map=h(n,e.mapDiffuseRepeat,e.mapDiffuseOffset,e.mapDiffuseWrap,e.mapDiffuseAnisotropy);break;case "mapDiffuseRepeat":case "mapDiffuseOffset":case "mapDiffuseWrap":case "mapDiffuseAnisotropy":break;case "mapEmissive":m.emissiveMap= +h(n,e.mapEmissiveRepeat,e.mapEmissiveOffset,e.mapEmissiveWrap,e.mapEmissiveAnisotropy);break;case "mapEmissiveRepeat":case "mapEmissiveOffset":case "mapEmissiveWrap":case "mapEmissiveAnisotropy":break;case "mapLight":m.lightMap=h(n,e.mapLightRepeat,e.mapLightOffset,e.mapLightWrap,e.mapLightAnisotropy);break;case "mapLightRepeat":case "mapLightOffset":case "mapLightWrap":case "mapLightAnisotropy":break;case "mapAO":m.aoMap=h(n,e.mapAORepeat,e.mapAOOffset,e.mapAOWrap,e.mapAOAnisotropy);break;case "mapAORepeat":case "mapAOOffset":case "mapAOWrap":case "mapAOAnisotropy":break; +case "mapBump":m.bumpMap=h(n,e.mapBumpRepeat,e.mapBumpOffset,e.mapBumpWrap,e.mapBumpAnisotropy);break;case "mapBumpScale":m.bumpScale=n;break;case "mapBumpRepeat":case "mapBumpOffset":case "mapBumpWrap":case "mapBumpAnisotropy":break;case "mapNormal":m.normalMap=h(n,e.mapNormalRepeat,e.mapNormalOffset,e.mapNormalWrap,e.mapNormalAnisotropy);break;case "mapNormalFactor":m.normalScale=n;break;case "mapNormalRepeat":case "mapNormalOffset":case "mapNormalWrap":case "mapNormalAnisotropy":break;case "mapSpecular":m.specularMap= +h(n,e.mapSpecularRepeat,e.mapSpecularOffset,e.mapSpecularWrap,e.mapSpecularAnisotropy);break;case "mapSpecularRepeat":case "mapSpecularOffset":case "mapSpecularWrap":case "mapSpecularAnisotropy":break;case "mapMetalness":m.metalnessMap=h(n,e.mapMetalnessRepeat,e.mapMetalnessOffset,e.mapMetalnessWrap,e.mapMetalnessAnisotropy);break;case "mapMetalnessRepeat":case "mapMetalnessOffset":case "mapMetalnessWrap":case "mapMetalnessAnisotropy":break;case "mapRoughness":m.roughnessMap=h(n,e.mapRoughnessRepeat, +e.mapRoughnessOffset,e.mapRoughnessWrap,e.mapRoughnessAnisotropy);break;case "mapRoughnessRepeat":case "mapRoughnessOffset":case "mapRoughnessWrap":case "mapRoughnessAnisotropy":break;case "mapAlpha":m.alphaMap=h(n,e.mapAlphaRepeat,e.mapAlphaOffset,e.mapAlphaWrap,e.mapAlphaAnisotropy);break;case "mapAlphaRepeat":case "mapAlphaOffset":case "mapAlphaWrap":case "mapAlphaAnisotropy":break;case "flipSided":m.side=1;break;case "doubleSided":m.side=2;break;case "transparency":console.warn("THREE.Loader.createMaterial: transparency has been renamed to opacity"); +m.opacity=n;break;case "depthTest":case "depthWrite":case "colorWrite":case "opacity":case "reflectivity":case "transparent":case "visible":case "wireframe":m[l]=n;break;case "vertexColors":!0===n&&(m.vertexColors=2);"face"===n&&(m.vertexColors=1);break;default:console.error("THREE.Loader.createMaterial: Unsupported",l,n)}}"MeshBasicMaterial"===m.type&&delete m.emissive;"MeshPhongMaterial"!==m.type&&delete m.specular;1>m.opacity&&(m.transparent=!0);d.setTextures(k);return d.parse(m)}}()});var Fe= +{decodeText:function(a){if("undefined"!==typeof TextDecoder)return(new TextDecoder).decode(a);for(var b="",c=0,d=a.length;c<d;c++)b+=String.fromCharCode(a[c]);return decodeURIComponent(escape(b))},extractUrlBase:function(a){var b=a.lastIndexOf("/");return-1===b?"./":a.substr(0,b+1)}};Object.assign(Qd.prototype,{crossOrigin:"anonymous",load:function(a,b,c,d){var e=this,f=void 0===this.path?Fe.extractUrlBase(a):this.path,g=new Ia(this.manager);g.setPath(this.path);g.setWithCredentials(this.withCredentials); +g.load(a,function(c){c=JSON.parse(c);var d=c.metadata;if(void 0!==d&&(d=d.type,void 0!==d&&"object"===d.toLowerCase())){console.error("THREE.JSONLoader: "+a+" should be loaded with THREE.ObjectLoader instead.");return}c=e.parse(c,f);b(c.geometry,c.materials)},c,d)},setPath:function(a){this.path=a;return this},setResourcePath:function(a){this.resourcePath=a;return this},setCrossOrigin:function(a){this.crossOrigin=a;return this},parse:function(){return function(a,b){void 0!==a.data&&(a=a.data);a.scale= +void 0!==a.scale?1/a.scale:1;var c=new M,d=a,e,f,g,h=d.faces;var k=d.vertices;var m=d.normals,l=d.colors;var n=d.scale;var q=0;if(void 0!==d.uvs){for(e=0;e<d.uvs.length;e++)d.uvs[e].length&&q++;for(e=0;e<q;e++)c.faceVertexUvs[e]=[]}var v=0;for(g=k.length;v<g;)e=new p,e.x=k[v++]*n,e.y=k[v++]*n,e.z=k[v++]*n,c.vertices.push(e);v=0;for(g=h.length;v<g;){k=h[v++];var t=k&1;var u=k&2;e=k&8;var y=k&16;var x=k&32;n=k&64;k&=128;if(t){t=new Xa;t.a=h[v];t.b=h[v+1];t.c=h[v+3];var w=new Xa;w.a=h[v+1];w.b=h[v+2]; +w.c=h[v+3];v+=4;u&&(u=h[v++],t.materialIndex=u,w.materialIndex=u);u=c.faces.length;if(e)for(e=0;e<q;e++){var D=d.uvs[e];c.faceVertexUvs[e][u]=[];c.faceVertexUvs[e][u+1]=[];for(f=0;4>f;f++){var z=h[v++];var C=D[2*z];z=D[2*z+1];C=new A(C,z);2!==f&&c.faceVertexUvs[e][u].push(C);0!==f&&c.faceVertexUvs[e][u+1].push(C)}}y&&(y=3*h[v++],t.normal.set(m[y++],m[y++],m[y]),w.normal.copy(t.normal));if(x)for(e=0;4>e;e++)y=3*h[v++],x=new p(m[y++],m[y++],m[y]),2!==e&&t.vertexNormals.push(x),0!==e&&w.vertexNormals.push(x); +n&&(n=h[v++],n=l[n],t.color.setHex(n),w.color.setHex(n));if(k)for(e=0;4>e;e++)n=h[v++],n=l[n],2!==e&&t.vertexColors.push(new G(n)),0!==e&&w.vertexColors.push(new G(n));c.faces.push(t);c.faces.push(w)}else{t=new Xa;t.a=h[v++];t.b=h[v++];t.c=h[v++];u&&(u=h[v++],t.materialIndex=u);u=c.faces.length;if(e)for(e=0;e<q;e++)for(D=d.uvs[e],c.faceVertexUvs[e][u]=[],f=0;3>f;f++)z=h[v++],C=D[2*z],z=D[2*z+1],C=new A(C,z),c.faceVertexUvs[e][u].push(C);y&&(y=3*h[v++],t.normal.set(m[y++],m[y++],m[y]));if(x)for(e= +0;3>e;e++)y=3*h[v++],x=new p(m[y++],m[y++],m[y]),t.vertexNormals.push(x);n&&(n=h[v++],t.color.setHex(l[n]));if(k)for(e=0;3>e;e++)n=h[v++],t.vertexColors.push(new G(l[n]));c.faces.push(t)}}d=a;v=void 0!==d.influencesPerVertex?d.influencesPerVertex:2;if(d.skinWeights)for(g=0,h=d.skinWeights.length;g<h;g+=v)c.skinWeights.push(new Z(d.skinWeights[g],1<v?d.skinWeights[g+1]:0,2<v?d.skinWeights[g+2]:0,3<v?d.skinWeights[g+3]:0));if(d.skinIndices)for(g=0,h=d.skinIndices.length;g<h;g+=v)c.skinIndices.push(new Z(d.skinIndices[g], +1<v?d.skinIndices[g+1]:0,2<v?d.skinIndices[g+2]:0,3<v?d.skinIndices[g+3]:0));c.bones=d.bones;c.bones&&0<c.bones.length&&(c.skinWeights.length!==c.skinIndices.length||c.skinIndices.length!==c.vertices.length)&&console.warn("When skinning, number of vertices ("+c.vertices.length+"), skinIndices ("+c.skinIndices.length+"), and skinWeights ("+c.skinWeights.length+") should match.");g=a;h=g.scale;if(void 0!==g.morphTargets)for(d=0,v=g.morphTargets.length;d<v;d++)for(c.morphTargets[d]={},c.morphTargets[d].name= +g.morphTargets[d].name,c.morphTargets[d].vertices=[],m=c.morphTargets[d].vertices,l=g.morphTargets[d].vertices,q=0,k=l.length;q<k;q+=3)n=new p,n.x=l[q]*h,n.y=l[q+1]*h,n.z=l[q+2]*h,m.push(n);if(void 0!==g.morphColors&&0<g.morphColors.length)for(console.warn('THREE.JSONLoader: "morphColors" no longer supported. Using them as face colors.'),h=c.faces,g=g.morphColors[0].colors,d=0,v=h.length;d<v;d++)h[d].color.fromArray(g,3*d);g=a;d=[];v=[];void 0!==g.animation&&v.push(g.animation);void 0!==g.animations&& +(g.animations.length?v=v.concat(g.animations):v.push(g.animations));for(g=0;g<v.length;g++)(h=Ea.parseAnimation(v[g],c.bones))&&d.push(h);c.morphTargets&&(v=Ea.CreateClipsFromMorphTargetSequences(c.morphTargets,10),d=d.concat(v));0<d.length&&(c.animations=d);c.computeFaceNormals();c.computeBoundingSphere();if(void 0===a.materials||0===a.materials.length)return{geometry:c};a=kc.prototype.initMaterials(a.materials,this.resourcePath||b,this.crossOrigin);return{geometry:c,materials:a}}}()});Object.assign(of.prototype, +{crossOrigin:"anonymous",load:function(a,b,c,d){""===this.texturePath&&(this.texturePath=a.substring(0,a.lastIndexOf("/")+1));var e=this;(new Ia(e.manager)).load(a,function(c){var f=null;try{f=JSON.parse(c)}catch(h){void 0!==d&&d(h);console.error("THREE:ObjectLoader: Can't parse "+a+".",h.message);return}c=f.metadata;void 0===c||void 0===c.type||"geometry"===c.type.toLowerCase()?console.error("THREE.ObjectLoader: Can't load "+a+". Use THREE.JSONLoader instead."):e.parse(f,b)},c,d)},setTexturePath:function(a){this.texturePath= +a;return this},setCrossOrigin:function(a){this.crossOrigin=a;return this},parse:function(a,b){var c=this.parseShape(a.shapes);c=this.parseGeometries(a.geometries,c);var d=this.parseImages(a.images,function(){void 0!==b&&b(e)});d=this.parseTextures(a.textures,d);d=this.parseMaterials(a.materials,d);var e=this.parseObject(a.object,c,d);a.animations&&(e.animations=this.parseAnimations(a.animations));void 0!==a.images&&0!==a.images.length||void 0===b||b(e);return e},parseShape:function(a){var b={};if(void 0!== +a)for(var c=0,d=a.length;c<d;c++){var e=(new gb).fromJSON(a[c]);b[e.uuid]=e}return b},parseGeometries:function(a,b){var c={};if(void 0!==a)for(var d=new Qd,e=new je,f=0,g=a.length;f<g;f++){var h=a[f];switch(h.type){case "PlaneGeometry":case "PlaneBufferGeometry":var k=new Ba[h.type](h.width,h.height,h.widthSegments,h.heightSegments);break;case "BoxGeometry":case "BoxBufferGeometry":case "CubeGeometry":k=new Ba[h.type](h.width,h.height,h.depth,h.widthSegments,h.heightSegments,h.depthSegments);break; +case "CircleGeometry":case "CircleBufferGeometry":k=new Ba[h.type](h.radius,h.segments,h.thetaStart,h.thetaLength);break;case "CylinderGeometry":case "CylinderBufferGeometry":k=new Ba[h.type](h.radiusTop,h.radiusBottom,h.height,h.radialSegments,h.heightSegments,h.openEnded,h.thetaStart,h.thetaLength);break;case "ConeGeometry":case "ConeBufferGeometry":k=new Ba[h.type](h.radius,h.height,h.radialSegments,h.heightSegments,h.openEnded,h.thetaStart,h.thetaLength);break;case "SphereGeometry":case "SphereBufferGeometry":k= +new Ba[h.type](h.radius,h.widthSegments,h.heightSegments,h.phiStart,h.phiLength,h.thetaStart,h.thetaLength);break;case "DodecahedronGeometry":case "DodecahedronBufferGeometry":case "IcosahedronGeometry":case "IcosahedronBufferGeometry":case "OctahedronGeometry":case "OctahedronBufferGeometry":case "TetrahedronGeometry":case "TetrahedronBufferGeometry":k=new Ba[h.type](h.radius,h.detail);break;case "RingGeometry":case "RingBufferGeometry":k=new Ba[h.type](h.innerRadius,h.outerRadius,h.thetaSegments, +h.phiSegments,h.thetaStart,h.thetaLength);break;case "TorusGeometry":case "TorusBufferGeometry":k=new Ba[h.type](h.radius,h.tube,h.radialSegments,h.tubularSegments,h.arc);break;case "TorusKnotGeometry":case "TorusKnotBufferGeometry":k=new Ba[h.type](h.radius,h.tube,h.tubularSegments,h.radialSegments,h.p,h.q);break;case "LatheGeometry":case "LatheBufferGeometry":k=new Ba[h.type](h.points,h.segments,h.phiStart,h.phiLength);break;case "PolyhedronGeometry":case "PolyhedronBufferGeometry":k=new Ba[h.type](h.vertices, +h.indices,h.radius,h.details);break;case "ShapeGeometry":case "ShapeBufferGeometry":k=[];for(var m=0,l=h.shapes.length;m<l;m++){var n=b[h.shapes[m]];k.push(n)}k=new Ba[h.type](k,h.curveSegments);break;case "ExtrudeGeometry":case "ExtrudeBufferGeometry":k=[];m=0;for(l=h.shapes.length;m<l;m++)n=b[h.shapes[m]],k.push(n);m=h.options.extrudePath;void 0!==m&&(h.options.extrudePath=(new Cf[m.type]).fromJSON(m));k=new Ba[h.type](k,h.options);break;case "BufferGeometry":k=e.parse(h);break;case "Geometry":k= +d.parse(h,this.texturePath).geometry;break;default:console.warn('THREE.ObjectLoader: Unsupported geometry type "'+h.type+'"');continue}k.uuid=h.uuid;void 0!==h.name&&(k.name=h.name);!0===k.isBufferGeometry&&void 0!==h.userData&&(k.userData=h.userData);c[h.uuid]=k}return c},parseMaterials:function(a,b){var c={};if(void 0!==a){var d=new Pd;d.setTextures(b);b=0;for(var e=a.length;b<e;b++){var f=a[b];if("MultiMaterial"===f.type){for(var g=[],h=0;h<f.materials.length;h++)g.push(d.parse(f.materials[h])); +c[f.uuid]=g}else c[f.uuid]=d.parse(f)}}return c},parseAnimations:function(a){for(var b=[],c=0;c<a.length;c++){var d=a[c],e=Ea.parse(d);void 0!==d.uuid&&(e.uuid=d.uuid);b.push(e)}return b},parseImages:function(a,b){function c(a){d.manager.itemStart(a);return f.load(a,function(){d.manager.itemEnd(a)},void 0,function(){d.manager.itemEnd(a);d.manager.itemError(a)})}var d=this,e={};if(void 0!==a&&0<a.length){b=new fe(b);var f=new cd(b);f.setCrossOrigin(this.crossOrigin);b=0;for(var g=a.length;b<g;b++){var h= +a[b],k=h.url;if(Array.isArray(k)){e[h.uuid]=[];for(var m=0,l=k.length;m<l;m++){var n=k[m];n=/^(\/\/)|([a-z]+:(\/\/)?)/i.test(n)?n:d.texturePath+n;e[h.uuid].push(c(n))}}else n=/^(\/\/)|([a-z]+:(\/\/)?)/i.test(h.url)?h.url:d.texturePath+h.url,e[h.uuid]=c(n)}}return e},parseTextures:function(a,b){function c(a,b){if("number"===typeof a)return a;console.warn("THREE.ObjectLoader.parseTexture: Constant should be in numeric form.",a);return b[a]}var d={};if(void 0!==a)for(var e=0,f=a.length;e<f;e++){var g= +a[e];void 0===g.image&&console.warn('THREE.ObjectLoader: No "image" specified for',g.uuid);void 0===b[g.image]&&console.warn("THREE.ObjectLoader: Undefined image",g.image);var h=Array.isArray(b[g.image])?new Ya(b[g.image]):new Q(b[g.image]);h.needsUpdate=!0;h.uuid=g.uuid;void 0!==g.name&&(h.name=g.name);void 0!==g.mapping&&(h.mapping=c(g.mapping,Zg));void 0!==g.offset&&h.offset.fromArray(g.offset);void 0!==g.repeat&&h.repeat.fromArray(g.repeat);void 0!==g.center&&h.center.fromArray(g.center);void 0!== +g.rotation&&(h.rotation=g.rotation);void 0!==g.wrap&&(h.wrapS=c(g.wrap[0],Ef),h.wrapT=c(g.wrap[1],Ef));void 0!==g.format&&(h.format=g.format);void 0!==g.minFilter&&(h.minFilter=c(g.minFilter,Ff));void 0!==g.magFilter&&(h.magFilter=c(g.magFilter,Ff));void 0!==g.anisotropy&&(h.anisotropy=g.anisotropy);void 0!==g.flipY&&(h.flipY=g.flipY);d[g.uuid]=h}return d},parseObject:function(a,b,c){function d(a){void 0===b[a]&&console.warn("THREE.ObjectLoader: Undefined geometry",a);return b[a]}function e(a){if(void 0!== +a){if(Array.isArray(a)){for(var b=[],d=0,e=a.length;d<e;d++){var f=a[d];void 0===c[f]&&console.warn("THREE.ObjectLoader: Undefined material",f);b.push(c[f])}return b}void 0===c[a]&&console.warn("THREE.ObjectLoader: Undefined material",a);return c[a]}}switch(a.type){case "Scene":var f=new vd;void 0!==a.background&&Number.isInteger(a.background)&&(f.background=new G(a.background));void 0!==a.fog&&("Fog"===a.fog.type?f.fog=new Qb(a.fog.color,a.fog.near,a.fog.far):"FogExp2"===a.fog.type&&(f.fog=new Pb(a.fog.color, +a.fog.density)));break;case "PerspectiveCamera":f=new V(a.fov,a.aspect,a.near,a.far);void 0!==a.focus&&(f.focus=a.focus);void 0!==a.zoom&&(f.zoom=a.zoom);void 0!==a.filmGauge&&(f.filmGauge=a.filmGauge);void 0!==a.filmOffset&&(f.filmOffset=a.filmOffset);void 0!==a.view&&(f.view=Object.assign({},a.view));break;case "OrthographicCamera":f=new fd(a.left,a.right,a.top,a.bottom,a.near,a.far);void 0!==a.zoom&&(f.zoom=a.zoom);void 0!==a.view&&(f.view=Object.assign({},a.view));break;case "AmbientLight":f= +new Hd(a.color,a.intensity);break;case "DirectionalLight":f=new Gd(a.color,a.intensity);break;case "PointLight":f=new Ed(a.color,a.intensity,a.distance,a.decay);break;case "RectAreaLight":f=new Id(a.color,a.intensity,a.width,a.height);break;case "SpotLight":f=new Dd(a.color,a.intensity,a.distance,a.angle,a.penumbra,a.decay);break;case "HemisphereLight":f=new Bd(a.color,a.groundColor,a.intensity);break;case "SkinnedMesh":console.warn("THREE.ObjectLoader.parseObject() does not support SkinnedMesh yet."); +case "Mesh":f=d(a.geometry);var g=e(a.material);f=f.bones&&0<f.bones.length?new xd(f,g):new ua(f,g);break;case "LOD":f=new Fc;break;case "Line":f=new pa(d(a.geometry),e(a.material),a.mode);break;case "LineLoop":f=new yd(d(a.geometry),e(a.material));break;case "LineSegments":f=new W(d(a.geometry),e(a.material));break;case "PointCloud":case "Points":f=new Sb(d(a.geometry),e(a.material));break;case "Sprite":f=new Ec(e(a.material));break;case "Group":f=new Ob;break;default:f=new C}f.uuid=a.uuid;void 0!== +a.name&&(f.name=a.name);void 0!==a.matrix?(f.matrix.fromArray(a.matrix),void 0!==a.matrixAutoUpdate&&(f.matrixAutoUpdate=a.matrixAutoUpdate),f.matrixAutoUpdate&&f.matrix.decompose(f.position,f.quaternion,f.scale)):(void 0!==a.position&&f.position.fromArray(a.position),void 0!==a.rotation&&f.rotation.fromArray(a.rotation),void 0!==a.quaternion&&f.quaternion.fromArray(a.quaternion),void 0!==a.scale&&f.scale.fromArray(a.scale));void 0!==a.castShadow&&(f.castShadow=a.castShadow);void 0!==a.receiveShadow&& +(f.receiveShadow=a.receiveShadow);a.shadow&&(void 0!==a.shadow.bias&&(f.shadow.bias=a.shadow.bias),void 0!==a.shadow.radius&&(f.shadow.radius=a.shadow.radius),void 0!==a.shadow.mapSize&&f.shadow.mapSize.fromArray(a.shadow.mapSize),void 0!==a.shadow.camera&&(f.shadow.camera=this.parseObject(a.shadow.camera)));void 0!==a.visible&&(f.visible=a.visible);void 0!==a.frustumCulled&&(f.frustumCulled=a.frustumCulled);void 0!==a.renderOrder&&(f.renderOrder=a.renderOrder);void 0!==a.userData&&(f.userData=a.userData); +void 0!==a.layers&&(f.layers.mask=a.layers);if(void 0!==a.children){g=a.children;for(var h=0;h<g.length;h++)f.add(this.parseObject(g[h],b,c))}if("LOD"===a.type)for(a=a.levels,g=0;g<a.length;g++){h=a[g];var k=f.getObjectByProperty("uuid",h.object);void 0!==k&&f.addLevel(k,h.distance)}return f}});var Zg={UVMapping:300,CubeReflectionMapping:301,CubeRefractionMapping:302,EquirectangularReflectionMapping:303,EquirectangularRefractionMapping:304,SphericalReflectionMapping:305,CubeUVReflectionMapping:306, +CubeUVRefractionMapping:307},Ef={RepeatWrapping:1E3,ClampToEdgeWrapping:1001,MirroredRepeatWrapping:1002},Ff={NearestFilter:1003,NearestMipMapNearestFilter:1004,NearestMipMapLinearFilter:1005,LinearFilter:1006,LinearMipMapNearestFilter:1007,LinearMipMapLinearFilter:1008};ke.prototype={constructor:ke,setOptions:function(a){this.options=a;return this},load:function(a,b,c,d){void 0===a&&(a="");void 0!==this.path&&(a=this.path+a);a=this.manager.resolveURL(a);var e=this,f=Ib.get(a);if(void 0!==f)return e.manager.itemStart(a), +setTimeout(function(){b&&b(f);e.manager.itemEnd(a)},0),f;fetch(a).then(function(a){return a.blob()}).then(function(a){return createImageBitmap(a,e.options)}).then(function(c){Ib.add(a,c);b&&b(c);e.manager.itemEnd(a)}).catch(function(b){d&&d(b);e.manager.itemEnd(a);e.manager.itemError(a)})},setCrossOrigin:function(){return this},setPath:function(a){this.path=a;return this}};Object.assign(le.prototype,{moveTo:function(a,b){this.currentPath=new Na;this.subPaths.push(this.currentPath);this.currentPath.moveTo(a, +b)},lineTo:function(a,b){this.currentPath.lineTo(a,b)},quadraticCurveTo:function(a,b,c,d){this.currentPath.quadraticCurveTo(a,b,c,d)},bezierCurveTo:function(a,b,c,d,e,f){this.currentPath.bezierCurveTo(a,b,c,d,e,f)},splineThru:function(a){this.currentPath.splineThru(a)},toShapes:function(a,b){function c(a){for(var b=[],c=0,d=a.length;c<d;c++){var e=a[c],f=new gb;f.curves=e.curves;b.push(f)}return b}function d(a,b){for(var c=b.length,d=!1,e=c-1,f=0;f<c;e=f++){var g=b[e],h=b[f],k=h.x-g.x,m=h.y-g.y;if(Math.abs(m)> +Number.EPSILON){if(0>m&&(g=b[f],k=-k,h=b[e],m=-m),!(a.y<g.y||a.y>h.y))if(a.y===g.y){if(a.x===g.x)return!0}else{e=m*(a.x-g.x)-k*(a.y-g.y);if(0===e)return!0;0>e||(d=!d)}}else if(a.y===g.y&&(h.x<=a.x&&a.x<=g.x||g.x<=a.x&&a.x<=h.x))return!0}return d}var e=Za.isClockWise,f=this.subPaths;if(0===f.length)return[];if(!0===b)return c(f);b=[];if(1===f.length){var g=f[0];var h=new gb;h.curves=g.curves;b.push(h);return b}var k=!e(f[0].getPoints());k=a?!k:k;h=[];var m=[],l=[],n=0;m[n]=void 0;l[n]=[];for(var p= +0,v=f.length;p<v;p++){g=f[p];var t=g.getPoints();var u=e(t);(u=a?!u:u)?(!k&&m[n]&&n++,m[n]={s:new gb,p:t},m[n].s.curves=g.curves,k&&n++,l[n]=[]):l[n].push({h:g,p:t[0]})}if(!m[0])return c(f);if(1<m.length){p=!1;a=[];e=0;for(f=m.length;e<f;e++)h[e]=[];e=0;for(f=m.length;e<f;e++)for(g=l[e],u=0;u<g.length;u++){k=g[u];n=!0;for(t=0;t<m.length;t++)d(k.p,m[t].p)&&(e!==t&&a.push({froms:e,tos:t,hole:u}),n?(n=!1,h[t].push(k)):p=!0);n&&h[e].push(k)}0<a.length&&(p||(l=h))}p=0;for(e=m.length;p<e;p++)for(h=m[p].s, +b.push(h),a=l[p],f=0,g=a.length;f<g;f++)h.holes.push(a[f].h);return b}});Object.assign(me.prototype,{isFont:!0,generateShapes:function(a,b){void 0===b&&(b=100);var c=[],d=b;b=this.data;var e=Array.from?Array.from(a):String(a).split("");d/=b.resolution;var f=(b.boundingBox.yMax-b.boundingBox.yMin+b.underlineThickness)*d;a=[];for(var g=0,h=0,k=0;k<e.length;k++){var m=e[k];if("\n"===m)g=0,h-=f;else{var l=d;var n=g,p=h;if(m=b.glyphs[m]||b.glyphs["?"]){var v=new le;if(m.o)for(var t=m._cachedOutline||(m._cachedOutline= +m.o.split(" ")),u=0,y=t.length;u<y;)switch(t[u++]){case "m":var x=t[u++]*l+n;var w=t[u++]*l+p;v.moveTo(x,w);break;case "l":x=t[u++]*l+n;w=t[u++]*l+p;v.lineTo(x,w);break;case "q":var z=t[u++]*l+n;var A=t[u++]*l+p;var C=t[u++]*l+n;var F=t[u++]*l+p;v.quadraticCurveTo(C,F,z,A);break;case "b":z=t[u++]*l+n,A=t[u++]*l+p,C=t[u++]*l+n,F=t[u++]*l+p,x=t[u++]*l+n,w=t[u++]*l+p,v.bezierCurveTo(C,F,x,w,z,A)}l={offsetX:m.ha*l,path:v}}else l=void 0;g+=l.offsetX;a.push(l.path)}}b=0;for(e=a.length;b<e;b++)Array.prototype.push.apply(c, +a[b].toShapes());return c}});Object.assign(pf.prototype,{load:function(a,b,c,d){var e=this,f=new Ia(this.manager);f.setPath(this.path);f.load(a,function(a){try{var c=JSON.parse(a)}catch(k){console.warn("THREE.FontLoader: typeface.js support is being deprecated. Use typeface.json instead."),c=JSON.parse(a.substring(65,a.length-2))}a=e.parse(c);b&&b(a)},c,d)},parse:function(a){return new me(a)},setPath:function(a){this.path=a;return this}});var Vd,pe={getContext:function(){void 0===Vd&&(Vd=new (window.AudioContext|| +window.webkitAudioContext));return Vd},setContext:function(a){Vd=a}};Object.assign(ne.prototype,{load:function(a,b,c,d){var e=new Ia(this.manager);e.setResponseType("arraybuffer");e.load(a,function(a){a=a.slice(0);pe.getContext().decodeAudioData(a,function(a){b(a)})},c,d)}});Object.assign(qf.prototype,{update:function(){var a,b,c,d,e,f,g,h,k=new P,m=new P;return function(l){if(a!==this||b!==l.focus||c!==l.fov||d!==l.aspect*this.aspect||e!==l.near||f!==l.far||g!==l.zoom||h!==this.eyeSep){a=this;b= +l.focus;c=l.fov;d=l.aspect*this.aspect;e=l.near;f=l.far;g=l.zoom;var n=l.projectionMatrix.clone();h=this.eyeSep/2;var p=h*e/b,r=e*Math.tan(S.DEG2RAD*c*.5)/g;m.elements[12]=-h;k.elements[12]=h;var t=-r*d+p;var u=r*d+p;n.elements[0]=2*e/(u-t);n.elements[8]=(u+t)/(u-t);this.cameraL.projectionMatrix.copy(n);t=-r*d-p;u=r*d-p;n.elements[0]=2*e/(u-t);n.elements[8]=(u+t)/(u-t);this.cameraR.projectionMatrix.copy(n)}this.cameraL.matrixWorld.copy(l.matrixWorld).multiply(m);this.cameraR.matrixWorld.copy(l.matrixWorld).multiply(k)}}()}); +id.prototype=Object.create(C.prototype);id.prototype.constructor=id;oe.prototype=Object.assign(Object.create(C.prototype),{constructor:oe,getInput:function(){return this.gain},removeFilter:function(){null!==this.filter&&(this.gain.disconnect(this.filter),this.filter.disconnect(this.context.destination),this.gain.connect(this.context.destination),this.filter=null);return this},getFilter:function(){return this.filter},setFilter:function(a){null!==this.filter?(this.gain.disconnect(this.filter),this.filter.disconnect(this.context.destination)): +this.gain.disconnect(this.context.destination);this.filter=a;this.gain.connect(this.filter);this.filter.connect(this.context.destination);return this},getMasterVolume:function(){return this.gain.gain.value},setMasterVolume:function(a){this.gain.gain.setTargetAtTime(a,this.context.currentTime,.01);return this},updateMatrixWorld:function(){var a=new p,b=new ja,c=new p,d=new p;return function(e){C.prototype.updateMatrixWorld.call(this,e);e=this.context.listener;var f=this.up;this.matrixWorld.decompose(a, +b,c);d.set(0,0,-1).applyQuaternion(b);e.positionX?(e.positionX.setValueAtTime(a.x,this.context.currentTime),e.positionY.setValueAtTime(a.y,this.context.currentTime),e.positionZ.setValueAtTime(a.z,this.context.currentTime),e.forwardX.setValueAtTime(d.x,this.context.currentTime),e.forwardY.setValueAtTime(d.y,this.context.currentTime),e.forwardZ.setValueAtTime(d.z,this.context.currentTime),e.upX.setValueAtTime(f.x,this.context.currentTime),e.upY.setValueAtTime(f.y,this.context.currentTime),e.upZ.setValueAtTime(f.z, +this.context.currentTime)):(e.setPosition(a.x,a.y,a.z),e.setOrientation(d.x,d.y,d.z,f.x,f.y,f.z))}}()});lc.prototype=Object.assign(Object.create(C.prototype),{constructor:lc,getOutput:function(){return this.gain},setNodeSource:function(a){this.hasPlaybackControl=!1;this.sourceType="audioNode";this.source=a;this.connect();return this},setMediaElementSource:function(a){this.hasPlaybackControl=!1;this.sourceType="mediaNode";this.source=this.context.createMediaElementSource(a);this.connect();return this}, +setBuffer:function(a){this.buffer=a;this.sourceType="buffer";this.autoplay&&this.play();return this},play:function(){if(!0===this.isPlaying)console.warn("THREE.Audio: Audio is already playing.");else if(!1===this.hasPlaybackControl)console.warn("THREE.Audio: this Audio has no playback control.");else{var a=this.context.createBufferSource();a.buffer=this.buffer;a.loop=this.loop;a.onended=this.onEnded.bind(this);a.playbackRate.setValueAtTime(this.playbackRate,this.startTime);this.startTime=this.context.currentTime; +a.start(this.startTime,this.offset);this.isPlaying=!0;this.source=a;return this.connect()}},pause:function(){if(!1===this.hasPlaybackControl)console.warn("THREE.Audio: this Audio has no playback control.");else return!0===this.isPlaying&&(this.source.stop(),this.source.onended=null,this.offset+=(this.context.currentTime-this.startTime)*this.playbackRate,this.isPlaying=!1),this},stop:function(){if(!1===this.hasPlaybackControl)console.warn("THREE.Audio: this Audio has no playback control.");else return this.source.stop(), +this.source.onended=null,this.offset=0,this.isPlaying=!1,this},connect:function(){if(0<this.filters.length){this.source.connect(this.filters[0]);for(var a=1,b=this.filters.length;a<b;a++)this.filters[a-1].connect(this.filters[a]);this.filters[this.filters.length-1].connect(this.getOutput())}else this.source.connect(this.getOutput());return this},disconnect:function(){if(0<this.filters.length){this.source.disconnect(this.filters[0]);for(var a=1,b=this.filters.length;a<b;a++)this.filters[a-1].disconnect(this.filters[a]); +this.filters[this.filters.length-1].disconnect(this.getOutput())}else this.source.disconnect(this.getOutput());return this},getFilters:function(){return this.filters},setFilters:function(a){a||(a=[]);!0===this.isPlaying?(this.disconnect(),this.filters=a,this.connect()):this.filters=a;return this},getFilter:function(){return this.getFilters()[0]},setFilter:function(a){return this.setFilters(a?[a]:[])},setPlaybackRate:function(a){if(!1===this.hasPlaybackControl)console.warn("THREE.Audio: this Audio has no playback control."); +else return this.playbackRate=a,!0===this.isPlaying&&this.source.playbackRate.setValueAtTime(this.playbackRate,this.context.currentTime),this},getPlaybackRate:function(){return this.playbackRate},onEnded:function(){this.isPlaying=!1},getLoop:function(){return!1===this.hasPlaybackControl?(console.warn("THREE.Audio: this Audio has no playback control."),!1):this.loop},setLoop:function(a){if(!1===this.hasPlaybackControl)console.warn("THREE.Audio: this Audio has no playback control.");else return this.loop= +a,!0===this.isPlaying&&(this.source.loop=this.loop),this},getVolume:function(){return this.gain.gain.value},setVolume:function(a){this.gain.gain.setTargetAtTime(a,this.context.currentTime,.01);return this}});qe.prototype=Object.assign(Object.create(lc.prototype),{constructor:qe,getOutput:function(){return this.panner},getRefDistance:function(){return this.panner.refDistance},setRefDistance:function(a){this.panner.refDistance=a;return this},getRolloffFactor:function(){return this.panner.rolloffFactor}, +setRolloffFactor:function(a){this.panner.rolloffFactor=a;return this},getDistanceModel:function(){return this.panner.distanceModel},setDistanceModel:function(a){this.panner.distanceModel=a;return this},getMaxDistance:function(){return this.panner.maxDistance},setMaxDistance:function(a){this.panner.maxDistance=a;return this},setDirectionalCone:function(a,b,c){this.panner.coneInnerAngle=a;this.panner.coneOuterAngle=b;this.panner.coneOuterGain=c;return this},updateMatrixWorld:function(){var a=new p, +b=new ja,c=new p,d=new p;return function(e){C.prototype.updateMatrixWorld.call(this,e);e=this.panner;this.matrixWorld.decompose(a,b,c);d.set(0,0,1).applyQuaternion(b);e.setPosition(a.x,a.y,a.z);e.setOrientation(d.x,d.y,d.z)}}()});Object.assign(re.prototype,{getFrequencyData:function(){this.analyser.getByteFrequencyData(this.data);return this.data},getAverageFrequency:function(){for(var a=0,b=this.getFrequencyData(),c=0;c<b.length;c++)a+=b[c];return a/b.length}});Object.assign(se.prototype,{accumulate:function(a, +b){var c=this.buffer,d=this.valueSize;a=a*d+d;var e=this.cumulativeWeight;if(0===e){for(e=0;e!==d;++e)c[a+e]=c[e];e=b}else e+=b,this._mixBufferRegion(c,a,0,b/e,d);this.cumulativeWeight=e},apply:function(a){var b=this.valueSize,c=this.buffer;a=a*b+b;var d=this.cumulativeWeight,e=this.binding;this.cumulativeWeight=0;1>d&&this._mixBufferRegion(c,a,3*b,1-d,b);d=b;for(var f=b+b;d!==f;++d)if(c[d]!==c[d+b]){e.setValue(c,a);break}},saveOriginalState:function(){var a=this.buffer,b=this.valueSize,c=3*b;this.binding.getValue(a, +c);for(var d=b;d!==c;++d)a[d]=a[c+d%b];this.cumulativeWeight=0},restoreOriginalState:function(){this.binding.setValue(this.buffer,3*this.valueSize)},_select:function(a,b,c,d,e){if(.5<=d)for(d=0;d!==e;++d)a[b+d]=a[c+d]},_slerp:function(a,b,c,d){ja.slerpFlat(a,b,a,b,a,c,d)},_lerp:function(a,b,c,d,e){for(var f=1-d,g=0;g!==e;++g){var h=b+g;a[h]=a[h]*f+a[c+g]*d}}});Object.assign(rf.prototype,{getValue:function(a,b){this.bind();var c=this._bindings[this._targetGroup.nCachedObjects_];void 0!==c&&c.getValue(a, +b)},setValue:function(a,b){for(var c=this._bindings,d=this._targetGroup.nCachedObjects_,e=c.length;d!==e;++d)c[d].setValue(a,b)},bind:function(){for(var a=this._bindings,b=this._targetGroup.nCachedObjects_,c=a.length;b!==c;++b)a[b].bind()},unbind:function(){for(var a=this._bindings,b=this._targetGroup.nCachedObjects_,c=a.length;b!==c;++b)a[b].unbind()}});Object.assign(ta,{Composite:rf,create:function(a,b,c){return a&&a.isAnimationObjectGroup?new ta.Composite(a,b,c):new ta(a,b,c)},sanitizeNodeName:function(){var a= +/[\[\]\.:\/]/g;return function(b){return b.replace(/\s/g,"_").replace(a,"")}}(),parseTrackName:function(){var a="[^"+"\\[\\]\\.:\\/".replace("\\.","")+"]",b=/((?:WC+[\/:])*)/.source.replace("WC","[^\\[\\]\\.:\\/]");a=/(WCOD+)?/.source.replace("WCOD",a);var c=/(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace("WC","[^\\[\\]\\.:\\/]"),d=/\.(WC+)(?:\[(.+)\])?/.source.replace("WC","[^\\[\\]\\.:\\/]"),e=new RegExp("^"+b+a+c+d+"$"),f=["material","materials","bones"];return function(a){var b=e.exec(a);if(!b)throw Error("PropertyBinding: Cannot parse trackName: "+ +a);b={nodeName:b[2],objectName:b[3],objectIndex:b[4],propertyName:b[5],propertyIndex:b[6]};var c=b.nodeName&&b.nodeName.lastIndexOf(".");if(void 0!==c&&-1!==c){var d=b.nodeName.substring(c+1);-1!==f.indexOf(d)&&(b.nodeName=b.nodeName.substring(0,c),b.objectName=d)}if(null===b.propertyName||0===b.propertyName.length)throw Error("PropertyBinding: can not parse propertyName from trackName: "+a);return b}}(),findNode:function(a,b){if(!b||""===b||"root"===b||"."===b||-1===b||b===a.name||b===a.uuid)return a; +if(a.skeleton){var c=a.skeleton.getBoneByName(b);if(void 0!==c)return c}if(a.children){var d=function(a){for(var c=0;c<a.length;c++){var e=a[c];if(e.name===b||e.uuid===b||(e=d(e.children)))return e}return null};if(a=d(a.children))return a}return null}});Object.assign(ta.prototype,{_getValue_unavailable:function(){},_setValue_unavailable:function(){},BindingType:{Direct:0,EntireArray:1,ArrayElement:2,HasFromToArray:3},Versioning:{None:0,NeedsUpdate:1,MatrixWorldNeedsUpdate:2},GetterByBindingType:[function(a, +b){a[b]=this.node[this.propertyName]},function(a,b){for(var c=this.resolvedProperty,d=0,e=c.length;d!==e;++d)a[b++]=c[d]},function(a,b){a[b]=this.resolvedProperty[this.propertyIndex]},function(a,b){this.resolvedProperty.toArray(a,b)}],SetterByBindingTypeAndVersioning:[[function(a,b){this.targetObject[this.propertyName]=a[b]},function(a,b){this.targetObject[this.propertyName]=a[b];this.targetObject.needsUpdate=!0},function(a,b){this.targetObject[this.propertyName]=a[b];this.targetObject.matrixWorldNeedsUpdate= +!0}],[function(a,b){for(var c=this.resolvedProperty,d=0,e=c.length;d!==e;++d)c[d]=a[b++]},function(a,b){for(var c=this.resolvedProperty,d=0,e=c.length;d!==e;++d)c[d]=a[b++];this.targetObject.needsUpdate=!0},function(a,b){for(var c=this.resolvedProperty,d=0,e=c.length;d!==e;++d)c[d]=a[b++];this.targetObject.matrixWorldNeedsUpdate=!0}],[function(a,b){this.resolvedProperty[this.propertyIndex]=a[b]},function(a,b){this.resolvedProperty[this.propertyIndex]=a[b];this.targetObject.needsUpdate=!0},function(a, +b){this.resolvedProperty[this.propertyIndex]=a[b];this.targetObject.matrixWorldNeedsUpdate=!0}],[function(a,b){this.resolvedProperty.fromArray(a,b)},function(a,b){this.resolvedProperty.fromArray(a,b);this.targetObject.needsUpdate=!0},function(a,b){this.resolvedProperty.fromArray(a,b);this.targetObject.matrixWorldNeedsUpdate=!0}]],getValue:function(a,b){this.bind();this.getValue(a,b)},setValue:function(a,b){this.bind();this.setValue(a,b)},bind:function(){var a=this.node,b=this.parsedPath,c=b.objectName, +d=b.propertyName,e=b.propertyIndex;a||(this.node=a=ta.findNode(this.rootNode,b.nodeName)||this.rootNode);this.getValue=this._getValue_unavailable;this.setValue=this._setValue_unavailable;if(a){if(c){var f=b.objectIndex;switch(c){case "materials":if(!a.material){console.error("THREE.PropertyBinding: Can not bind to material as node does not have a material.",this);return}if(!a.material.materials){console.error("THREE.PropertyBinding: Can not bind to material.materials as node.material does not have a materials array.", +this);return}a=a.material.materials;break;case "bones":if(!a.skeleton){console.error("THREE.PropertyBinding: Can not bind to bones as node does not have a skeleton.",this);return}a=a.skeleton.bones;for(c=0;c<a.length;c++)if(a[c].name===f){f=c;break}break;default:if(void 0===a[c]){console.error("THREE.PropertyBinding: Can not bind to objectName of node undefined.",this);return}a=a[c]}if(void 0!==f){if(void 0===a[f]){console.error("THREE.PropertyBinding: Trying to bind to objectIndex of objectName, but is undefined.", +this,a);return}a=a[f]}}f=a[d];if(void 0===f)console.error("THREE.PropertyBinding: Trying to update property for track: "+b.nodeName+"."+d+" but it wasn't found.",a);else{b=this.Versioning.None;this.targetObject=a;void 0!==a.needsUpdate?b=this.Versioning.NeedsUpdate:void 0!==a.matrixWorldNeedsUpdate&&(b=this.Versioning.MatrixWorldNeedsUpdate);c=this.BindingType.Direct;if(void 0!==e){if("morphTargetInfluences"===d){if(!a.geometry){console.error("THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.", +this);return}if(a.geometry.isBufferGeometry){if(!a.geometry.morphAttributes){console.error("THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphAttributes.",this);return}for(c=0;c<this.node.geometry.morphAttributes.position.length;c++)if(a.geometry.morphAttributes.position[c].name===e){e=c;break}}else{if(!a.geometry.morphTargets){console.error("THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphTargets.", +this);return}for(c=0;c<this.node.geometry.morphTargets.length;c++)if(a.geometry.morphTargets[c].name===e){e=c;break}}}c=this.BindingType.ArrayElement;this.resolvedProperty=f;this.propertyIndex=e}else void 0!==f.fromArray&&void 0!==f.toArray?(c=this.BindingType.HasFromToArray,this.resolvedProperty=f):Array.isArray(f)?(c=this.BindingType.EntireArray,this.resolvedProperty=f):this.propertyName=d;this.getValue=this.GetterByBindingType[c];this.setValue=this.SetterByBindingTypeAndVersioning[c][b]}}else console.error("THREE.PropertyBinding: Trying to update node for track: "+ +this.path+" but it wasn't found.")},unbind:function(){this.node=null;this.getValue=this._getValue_unbound;this.setValue=this._setValue_unbound}});Object.assign(ta.prototype,{_getValue_unbound:ta.prototype.getValue,_setValue_unbound:ta.prototype.setValue});Object.assign(sf.prototype,{isAnimationObjectGroup:!0,add:function(){for(var a=this._objects,b=a.length,c=this.nCachedObjects_,d=this._indicesByUUID,e=this._paths,f=this._parsedPaths,g=this._bindings,h=g.length,k=void 0,l=0,p=arguments.length;l!== +p;++l){var n=arguments[l],q=n.uuid,v=d[q];if(void 0===v){v=b++;d[q]=v;a.push(n);q=0;for(var t=h;q!==t;++q)g[q].push(new ta(n,e[q],f[q]))}else if(v<c){k=a[v];var u=--c;t=a[u];d[t.uuid]=v;a[v]=t;d[q]=u;a[u]=n;q=0;for(t=h;q!==t;++q){var y=g[q],x=y[v];y[v]=y[u];void 0===x&&(x=new ta(n,e[q],f[q]));y[u]=x}}else a[v]!==k&&console.error("THREE.AnimationObjectGroup: Different objects with the same UUID detected. Clean the caches or recreate your infrastructure when reloading scenes.")}this.nCachedObjects_= +c},remove:function(){for(var a=this._objects,b=this.nCachedObjects_,c=this._indicesByUUID,d=this._bindings,e=d.length,f=0,g=arguments.length;f!==g;++f){var h=arguments[f],k=h.uuid,l=c[k];if(void 0!==l&&l>=b){var p=b++,n=a[p];c[n.uuid]=l;a[l]=n;c[k]=p;a[p]=h;h=0;for(k=e;h!==k;++h){n=d[h];var q=n[l];n[l]=n[p];n[p]=q}}}this.nCachedObjects_=b},uncache:function(){for(var a=this._objects,b=a.length,c=this.nCachedObjects_,d=this._indicesByUUID,e=this._bindings,f=e.length,g=0,h=arguments.length;g!==h;++g){var k= +arguments[g].uuid,l=d[k];if(void 0!==l)if(delete d[k],l<c){k=--c;var p=a[k],n=--b,q=a[n];d[p.uuid]=l;a[l]=p;d[q.uuid]=k;a[k]=q;a.pop();p=0;for(q=f;p!==q;++p){var v=e[p],t=v[n];v[l]=v[k];v[k]=t;v.pop()}}else for(n=--b,q=a[n],d[q.uuid]=l,a[l]=q,a.pop(),p=0,q=f;p!==q;++p)v=e[p],v[l]=v[n],v.pop()}this.nCachedObjects_=c},subscribe_:function(a,b){var c=this._bindingsIndicesByPath,d=c[a],e=this._bindings;if(void 0!==d)return e[d];var f=this._paths,g=this._parsedPaths,h=this._objects,k=this.nCachedObjects_, +l=Array(h.length);d=e.length;c[a]=d;f.push(a);g.push(b);e.push(l);c=k;for(d=h.length;c!==d;++c)l[c]=new ta(h[c],a,b);return l},unsubscribe_:function(a){var b=this._bindingsIndicesByPath,c=b[a];if(void 0!==c){var d=this._paths,e=this._parsedPaths,f=this._bindings,g=f.length-1,h=f[g];b[a[g]]=c;f[c]=h;f.pop();e[c]=e[g];e.pop();d[c]=d[g];d.pop()}}});Object.assign(tf.prototype,{play:function(){this._mixer._activateAction(this);return this},stop:function(){this._mixer._deactivateAction(this);return this.reset()}, +reset:function(){this.paused=!1;this.enabled=!0;this.time=0;this._loopCount=-1;this._startTime=null;return this.stopFading().stopWarping()},isRunning:function(){return this.enabled&&!this.paused&&0!==this.timeScale&&null===this._startTime&&this._mixer._isActiveAction(this)},isScheduled:function(){return this._mixer._isActiveAction(this)},startAt:function(a){this._startTime=a;return this},setLoop:function(a,b){this.loop=a;this.repetitions=b;return this},setEffectiveWeight:function(a){this.weight=a; +this._effectiveWeight=this.enabled?a:0;return this.stopFading()},getEffectiveWeight:function(){return this._effectiveWeight},fadeIn:function(a){return this._scheduleFading(a,0,1)},fadeOut:function(a){return this._scheduleFading(a,1,0)},crossFadeFrom:function(a,b,c){a.fadeOut(b);this.fadeIn(b);if(c){c=this._clip.duration;var d=a._clip.duration,e=c/d;a.warp(1,d/c,b);this.warp(e,1,b)}return this},crossFadeTo:function(a,b,c){return a.crossFadeFrom(this,b,c)},stopFading:function(){var a=this._weightInterpolant; +null!==a&&(this._weightInterpolant=null,this._mixer._takeBackControlInterpolant(a));return this},setEffectiveTimeScale:function(a){this.timeScale=a;this._effectiveTimeScale=this.paused?0:a;return this.stopWarping()},getEffectiveTimeScale:function(){return this._effectiveTimeScale},setDuration:function(a){this.timeScale=this._clip.duration/a;return this.stopWarping()},syncWith:function(a){this.time=a.time;this.timeScale=a.timeScale;return this.stopWarping()},halt:function(a){return this.warp(this._effectiveTimeScale, +0,a)},warp:function(a,b,c){var d=this._mixer,e=d.time,f=this._timeScaleInterpolant,g=this.timeScale;null===f&&(this._timeScaleInterpolant=f=d._lendControlInterpolant());d=f.parameterPositions;f=f.sampleValues;d[0]=e;d[1]=e+c;f[0]=a/g;f[1]=b/g;return this},stopWarping:function(){var a=this._timeScaleInterpolant;null!==a&&(this._timeScaleInterpolant=null,this._mixer._takeBackControlInterpolant(a));return this},getMixer:function(){return this._mixer},getClip:function(){return this._clip},getRoot:function(){return this._localRoot|| +this._mixer._root},_update:function(a,b,c,d){if(this.enabled){var e=this._startTime;if(null!==e){b=(a-e)*c;if(0>b||0===c)return;this._startTime=null;b*=c}b*=this._updateTimeScale(a);c=this._updateTime(b);a=this._updateWeight(a);if(0<a){b=this._interpolants;e=this._propertyBindings;for(var f=0,g=b.length;f!==g;++f)b[f].evaluate(c),e[f].accumulate(d,a)}}else this._updateWeight(a)},_updateWeight:function(a){var b=0;if(this.enabled){b=this.weight;var c=this._weightInterpolant;if(null!==c){var d=c.evaluate(a)[0]; +b*=d;a>c.parameterPositions[1]&&(this.stopFading(),0===d&&(this.enabled=!1))}}return this._effectiveWeight=b},_updateTimeScale:function(a){var b=0;if(!this.paused){b=this.timeScale;var c=this._timeScaleInterpolant;if(null!==c){var d=c.evaluate(a)[0];b*=d;a>c.parameterPositions[1]&&(this.stopWarping(),0===b?this.paused=!0:this.timeScale=b)}}return this._effectiveTimeScale=b},_updateTime:function(a){var b=this.time+a,c=this._clip.duration,d=this.loop,e=this._loopCount,f=2202===d;if(0===a)return-1=== +e?b:f&&1===(e&1)?c-b:b;if(2200===d)a:{if(-1===e&&(this._loopCount=0,this._setEndings(!0,!0,!1)),b>=c)b=c;else if(0>b)b=0;else break a;this.clampWhenFinished?this.paused=!0:this.enabled=!1;this._mixer.dispatchEvent({type:"finished",action:this,direction:0>a?-1:1})}else{-1===e&&(0<=a?(e=0,this._setEndings(!0,0===this.repetitions,f)):this._setEndings(0===this.repetitions,!0,f));if(b>=c||0>b){d=Math.floor(b/c);b-=c*d;e+=Math.abs(d);var g=this.repetitions-e;0>=g?(this.clampWhenFinished?this.paused=!0: +this.enabled=!1,b=0<a?c:0,this._mixer.dispatchEvent({type:"finished",action:this,direction:0<a?1:-1})):(1===g?(a=0>a,this._setEndings(a,!a,f)):this._setEndings(!1,!1,f),this._loopCount=e,this._mixer.dispatchEvent({type:"loop",action:this,loopDelta:d}))}if(f&&1===(e&1))return this.time=b,c-b}return this.time=b},_setEndings:function(a,b,c){var d=this._interpolantSettings;c?(d.endingStart=2401,d.endingEnd=2401):(d.endingStart=a?this.zeroSlopeAtStart?2401:2400:2402,d.endingEnd=b?this.zeroSlopeAtEnd?2401: +2400:2402)},_scheduleFading:function(a,b,c){var d=this._mixer,e=d.time,f=this._weightInterpolant;null===f&&(this._weightInterpolant=f=d._lendControlInterpolant());d=f.parameterPositions;f=f.sampleValues;d[0]=e;f[0]=b;d[1]=e+a;f[1]=c;return this}});te.prototype=Object.assign(Object.create(ia.prototype),{constructor:te,_bindAction:function(a,b){var c=a._localRoot||this._root,d=a._clip.tracks,e=d.length,f=a._propertyBindings;a=a._interpolants;var g=c.uuid,h=this._bindingsByRootAndName,k=h[g];void 0=== +k&&(k={},h[g]=k);for(h=0;h!==e;++h){var l=d[h],p=l.name,n=k[p];if(void 0===n){n=f[h];if(void 0!==n){null===n._cacheIndex&&(++n.referenceCount,this._addInactiveBinding(n,g,p));continue}n=new se(ta.create(c,p,b&&b._propertyBindings[h].binding.parsedPath),l.ValueTypeName,l.getValueSize());++n.referenceCount;this._addInactiveBinding(n,g,p)}f[h]=n;a[h].resultBuffer=n.buffer}},_activateAction:function(a){if(!this._isActiveAction(a)){if(null===a._cacheIndex){var b=(a._localRoot||this._root).uuid,c=a._clip.uuid, +d=this._actionsByClip[c];this._bindAction(a,d&&d.knownActions[0]);this._addInactiveAction(a,c,b)}b=a._propertyBindings;c=0;for(d=b.length;c!==d;++c){var e=b[c];0===e.useCount++&&(this._lendBinding(e),e.saveOriginalState())}this._lendAction(a)}},_deactivateAction:function(a){if(this._isActiveAction(a)){for(var b=a._propertyBindings,c=0,d=b.length;c!==d;++c){var e=b[c];0===--e.useCount&&(e.restoreOriginalState(),this._takeBackBinding(e))}this._takeBackAction(a)}},_initMemoryManager:function(){this._actions= +[];this._nActiveActions=0;this._actionsByClip={};this._bindings=[];this._nActiveBindings=0;this._bindingsByRootAndName={};this._controlInterpolants=[];this._nActiveControlInterpolants=0;var a=this;this.stats={actions:{get total(){return a._actions.length},get inUse(){return a._nActiveActions}},bindings:{get total(){return a._bindings.length},get inUse(){return a._nActiveBindings}},controlInterpolants:{get total(){return a._controlInterpolants.length},get inUse(){return a._nActiveControlInterpolants}}}}, +_isActiveAction:function(a){a=a._cacheIndex;return null!==a&&a<this._nActiveActions},_addInactiveAction:function(a,b,c){var d=this._actions,e=this._actionsByClip,f=e[b];void 0===f?(f={knownActions:[a],actionByRoot:{}},a._byClipCacheIndex=0,e[b]=f):(b=f.knownActions,a._byClipCacheIndex=b.length,b.push(a));a._cacheIndex=d.length;d.push(a);f.actionByRoot[c]=a},_removeInactiveAction:function(a){var b=this._actions,c=b[b.length-1],d=a._cacheIndex;c._cacheIndex=d;b[d]=c;b.pop();a._cacheIndex=null;b=a._clip.uuid; +c=this._actionsByClip;d=c[b];var e=d.knownActions,f=e[e.length-1],g=a._byClipCacheIndex;f._byClipCacheIndex=g;e[g]=f;e.pop();a._byClipCacheIndex=null;delete d.actionByRoot[(a._localRoot||this._root).uuid];0===e.length&&delete c[b];this._removeInactiveBindingsForAction(a)},_removeInactiveBindingsForAction:function(a){a=a._propertyBindings;for(var b=0,c=a.length;b!==c;++b){var d=a[b];0===--d.referenceCount&&this._removeInactiveBinding(d)}},_lendAction:function(a){var b=this._actions,c=a._cacheIndex, +d=this._nActiveActions++,e=b[d];a._cacheIndex=d;b[d]=a;e._cacheIndex=c;b[c]=e},_takeBackAction:function(a){var b=this._actions,c=a._cacheIndex,d=--this._nActiveActions,e=b[d];a._cacheIndex=d;b[d]=a;e._cacheIndex=c;b[c]=e},_addInactiveBinding:function(a,b,c){var d=this._bindingsByRootAndName,e=d[b],f=this._bindings;void 0===e&&(e={},d[b]=e);e[c]=a;a._cacheIndex=f.length;f.push(a)},_removeInactiveBinding:function(a){var b=this._bindings,c=a.binding,d=c.rootNode.uuid;c=c.path;var e=this._bindingsByRootAndName, +f=e[d],g=b[b.length-1];a=a._cacheIndex;g._cacheIndex=a;b[a]=g;b.pop();delete f[c];a:{for(var h in f)break a;delete e[d]}},_lendBinding:function(a){var b=this._bindings,c=a._cacheIndex,d=this._nActiveBindings++,e=b[d];a._cacheIndex=d;b[d]=a;e._cacheIndex=c;b[c]=e},_takeBackBinding:function(a){var b=this._bindings,c=a._cacheIndex,d=--this._nActiveBindings,e=b[d];a._cacheIndex=d;b[d]=a;e._cacheIndex=c;b[c]=e},_lendControlInterpolant:function(){var a=this._controlInterpolants,b=this._nActiveControlInterpolants++, +c=a[b];void 0===c&&(c=new gd(new Float32Array(2),new Float32Array(2),1,this._controlInterpolantsResultBuffer),c.__cacheIndex=b,a[b]=c);return c},_takeBackControlInterpolant:function(a){var b=this._controlInterpolants,c=a.__cacheIndex,d=--this._nActiveControlInterpolants,e=b[d];a.__cacheIndex=d;b[d]=a;e.__cacheIndex=c;b[c]=e},_controlInterpolantsResultBuffer:new Float32Array(1),clipAction:function(a,b){var c=b||this._root,d=c.uuid;c="string"===typeof a?Ea.findByName(c,a):a;a=null!==c?c.uuid:a;var e= +this._actionsByClip[a],f=null;if(void 0!==e){f=e.actionByRoot[d];if(void 0!==f)return f;f=e.knownActions[0];null===c&&(c=f._clip)}if(null===c)return null;b=new tf(this,c,b);this._bindAction(b,f);this._addInactiveAction(b,a,d);return b},existingAction:function(a,b){var c=b||this._root;b=c.uuid;c="string"===typeof a?Ea.findByName(c,a):a;a=this._actionsByClip[c?c.uuid:a];return void 0!==a?a.actionByRoot[b]||null:null},stopAllAction:function(){for(var a=this._actions,b=this._nActiveActions,c=this._bindings, +d=this._nActiveBindings,e=this._nActiveBindings=this._nActiveActions=0;e!==b;++e)a[e].reset();for(e=0;e!==d;++e)c[e].useCount=0;return this},update:function(a){a*=this.timeScale;for(var b=this._actions,c=this._nActiveActions,d=this.time+=a,e=Math.sign(a),f=this._accuIndex^=1,g=0;g!==c;++g)b[g]._update(d,a,e,f);a=this._bindings;b=this._nActiveBindings;for(g=0;g!==b;++g)a[g].apply(f);return this},getRoot:function(){return this._root},uncacheClip:function(a){var b=this._actions;a=a.uuid;var c=this._actionsByClip, +d=c[a];if(void 0!==d){d=d.knownActions;for(var e=0,f=d.length;e!==f;++e){var g=d[e];this._deactivateAction(g);var h=g._cacheIndex,k=b[b.length-1];g._cacheIndex=null;g._byClipCacheIndex=null;k._cacheIndex=h;b[h]=k;b.pop();this._removeInactiveBindingsForAction(g)}delete c[a]}},uncacheRoot:function(a){a=a.uuid;var b=this._actionsByClip;for(d in b){var c=b[d].actionByRoot[a];void 0!==c&&(this._deactivateAction(c),this._removeInactiveAction(c))}var d=this._bindingsByRootAndName[a];if(void 0!==d)for(var e in d)a= +d[e],a.restoreOriginalState(),this._removeInactiveBinding(a)},uncacheAction:function(a,b){a=this.existingAction(a,b);null!==a&&(this._deactivateAction(a),this._removeInactiveAction(a))}});Rd.prototype.clone=function(){return new Rd(void 0===this.value.clone?this.value:this.value.clone())};ue.prototype=Object.assign(Object.create(F.prototype),{constructor:ue,isInstancedBufferGeometry:!0,copy:function(a){F.prototype.copy.call(this,a);this.maxInstancedCount=a.maxInstancedCount;return this},clone:function(){return(new this.constructor).copy(this)}}); +ve.prototype=Object.assign(Object.create(qb.prototype),{constructor:ve,isInstancedInterleavedBuffer:!0,copy:function(a){qb.prototype.copy.call(this,a);this.meshPerAttribute=a.meshPerAttribute;return this}});we.prototype=Object.assign(Object.create(I.prototype),{constructor:we,isInstancedBufferAttribute:!0,copy:function(a){I.prototype.copy.call(this,a);this.meshPerAttribute=a.meshPerAttribute;return this}});Object.assign(uf.prototype,{linePrecision:1,set:function(a,b){this.ray.set(a,b)},setFromCamera:function(a, +b){b&&b.isPerspectiveCamera?(this.ray.origin.setFromMatrixPosition(b.matrixWorld),this.ray.direction.set(a.x,a.y,.5).unproject(b).sub(this.ray.origin).normalize()):b&&b.isOrthographicCamera?(this.ray.origin.set(a.x,a.y,(b.near+b.far)/(b.near-b.far)).unproject(b),this.ray.direction.set(0,0,-1).transformDirection(b.matrixWorld)):console.error("THREE.Raycaster: Unsupported camera type.")},intersectObject:function(a,b,c){c=c||[];xe(a,this,c,b);c.sort(vf);return c},intersectObjects:function(a,b,c){c=c|| +[];if(!1===Array.isArray(a))return console.warn("THREE.Raycaster.intersectObjects: objects is not an Array."),c;for(var d=0,e=a.length;d<e;d++)xe(a[d],this,c,b);c.sort(vf);return c}});Object.assign(wf.prototype,{start:function(){this.oldTime=this.startTime=("undefined"===typeof performance?Date:performance).now();this.elapsedTime=0;this.running=!0},stop:function(){this.getElapsedTime();this.autoStart=this.running=!1},getElapsedTime:function(){this.getDelta();return this.elapsedTime},getDelta:function(){var a= +0;if(this.autoStart&&!this.running)return this.start(),0;if(this.running){var b=("undefined"===typeof performance?Date:performance).now();a=(b-this.oldTime)/1E3;this.oldTime=b;this.elapsedTime+=a}return a}});Object.assign(xf.prototype,{set:function(a,b,c){this.radius=a;this.phi=b;this.theta=c;return this},clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.radius=a.radius;this.phi=a.phi;this.theta=a.theta;return this},makeSafe:function(){this.phi=Math.max(1E-6,Math.min(Math.PI- +1E-6,this.phi));return this},setFromVector3:function(a){return this.setFromCartesianCoords(a.x,a.y,a.z)},setFromCartesianCoords:function(a,b,c){this.radius=Math.sqrt(a*a+b*b+c*c);0===this.radius?this.phi=this.theta=0:(this.theta=Math.atan2(a,c),this.phi=Math.acos(S.clamp(b/this.radius,-1,1)));return this}});Object.assign(yf.prototype,{set:function(a,b,c){this.radius=a;this.theta=b;this.y=c;return this},clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.radius=a.radius; +this.theta=a.theta;this.y=a.y;return this},setFromVector3:function(a){return this.setFromCartesianCoords(a.x,a.y,a.z)},setFromCartesianCoords:function(a,b,c){this.radius=Math.sqrt(a*a+c*c);this.theta=Math.atan2(a,c);this.y=b;return this}});Object.assign(ye.prototype,{set:function(a,b){this.min.copy(a);this.max.copy(b);return this},setFromPoints:function(a){this.makeEmpty();for(var b=0,c=a.length;b<c;b++)this.expandByPoint(a[b]);return this},setFromCenterAndSize:function(){var a=new A;return function(b, +c){c=a.copy(c).multiplyScalar(.5);this.min.copy(b).sub(c);this.max.copy(b).add(c);return this}}(),clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.min.copy(a.min);this.max.copy(a.max);return this},makeEmpty:function(){this.min.x=this.min.y=Infinity;this.max.x=this.max.y=-Infinity;return this},isEmpty:function(){return this.max.x<this.min.x||this.max.y<this.min.y},getCenter:function(a){void 0===a&&(console.warn("THREE.Box2: .getCenter() target is now required"),a=new A); +return this.isEmpty()?a.set(0,0):a.addVectors(this.min,this.max).multiplyScalar(.5)},getSize:function(a){void 0===a&&(console.warn("THREE.Box2: .getSize() target is now required"),a=new A);return this.isEmpty()?a.set(0,0):a.subVectors(this.max,this.min)},expandByPoint:function(a){this.min.min(a);this.max.max(a);return this},expandByVector:function(a){this.min.sub(a);this.max.add(a);return this},expandByScalar:function(a){this.min.addScalar(-a);this.max.addScalar(a);return this},containsPoint:function(a){return a.x< +this.min.x||a.x>this.max.x||a.y<this.min.y||a.y>this.max.y?!1:!0},containsBox:function(a){return this.min.x<=a.min.x&&a.max.x<=this.max.x&&this.min.y<=a.min.y&&a.max.y<=this.max.y},getParameter:function(a,b){void 0===b&&(console.warn("THREE.Box2: .getParameter() target is now required"),b=new A);return b.set((a.x-this.min.x)/(this.max.x-this.min.x),(a.y-this.min.y)/(this.max.y-this.min.y))},intersectsBox:function(a){return a.max.x<this.min.x||a.min.x>this.max.x||a.max.y<this.min.y||a.min.y>this.max.y? +!1:!0},clampPoint:function(a,b){void 0===b&&(console.warn("THREE.Box2: .clampPoint() target is now required"),b=new A);return b.copy(a).clamp(this.min,this.max)},distanceToPoint:function(){var a=new A;return function(b){return a.copy(b).clamp(this.min,this.max).sub(b).length()}}(),intersect:function(a){this.min.max(a.min);this.max.min(a.max);return this},union:function(a){this.min.min(a.min);this.max.max(a.max);return this},translate:function(a){this.min.add(a);this.max.add(a);return this},equals:function(a){return a.min.equals(this.min)&& +a.max.equals(this.max)}});Object.assign(ze.prototype,{set:function(a,b){this.start.copy(a);this.end.copy(b);return this},clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.start.copy(a.start);this.end.copy(a.end);return this},getCenter:function(a){void 0===a&&(console.warn("THREE.Line3: .getCenter() target is now required"),a=new p);return a.addVectors(this.start,this.end).multiplyScalar(.5)},delta:function(a){void 0===a&&(console.warn("THREE.Line3: .delta() target is now required"), +a=new p);return a.subVectors(this.end,this.start)},distanceSq:function(){return this.start.distanceToSquared(this.end)},distance:function(){return this.start.distanceTo(this.end)},at:function(a,b){void 0===b&&(console.warn("THREE.Line3: .at() target is now required"),b=new p);return this.delta(b).multiplyScalar(a).add(this.start)},closestPointToPointParameter:function(){var a=new p,b=new p;return function(c,d){a.subVectors(c,this.start);b.subVectors(this.end,this.start);c=b.dot(b);c=b.dot(a)/c;d&& +(c=S.clamp(c,0,1));return c}}(),closestPointToPoint:function(a,b,c){a=this.closestPointToPointParameter(a,b);void 0===c&&(console.warn("THREE.Line3: .closestPointToPoint() target is now required"),c=new p);return this.delta(c).multiplyScalar(a).add(this.start)},applyMatrix4:function(a){this.start.applyMatrix4(a);this.end.applyMatrix4(a);return this},equals:function(a){return a.start.equals(this.start)&&a.end.equals(this.end)}});jd.prototype=Object.create(C.prototype);jd.prototype.constructor=jd;jd.prototype.isImmediateRenderObject= +!0;kd.prototype=Object.create(W.prototype);kd.prototype.constructor=kd;kd.prototype.update=function(){var a=new p,b=new p,c=new oa;return function(){var d=["a","b","c"];this.object.updateMatrixWorld(!0);c.getNormalMatrix(this.object.matrixWorld);var e=this.object.matrixWorld,f=this.geometry.attributes.position,g=this.object.geometry;if(g&&g.isGeometry)for(var h=g.vertices,k=g.faces,l=g=0,p=k.length;l<p;l++)for(var n=k[l],q=0,v=n.vertexNormals.length;q<v;q++){var t=n.vertexNormals[q];a.copy(h[n[d[q]]]).applyMatrix4(e); +b.copy(t).applyMatrix3(c).normalize().multiplyScalar(this.size).add(a);f.setXYZ(g,a.x,a.y,a.z);g+=1;f.setXYZ(g,b.x,b.y,b.z);g+=1}else if(g&&g.isBufferGeometry)for(d=g.attributes.position,h=g.attributes.normal,q=g=0,v=d.count;q<v;q++)a.set(d.getX(q),d.getY(q),d.getZ(q)).applyMatrix4(e),b.set(h.getX(q),h.getY(q),h.getZ(q)),b.applyMatrix3(c).normalize().multiplyScalar(this.size).add(a),f.setXYZ(g,a.x,a.y,a.z),g+=1,f.setXYZ(g,b.x,b.y,b.z),g+=1;f.needsUpdate=!0}}();mc.prototype=Object.create(C.prototype); +mc.prototype.constructor=mc;mc.prototype.dispose=function(){this.cone.geometry.dispose();this.cone.material.dispose()};mc.prototype.update=function(){var a=new p,b=new p;return function(){this.light.updateMatrixWorld();var c=this.light.distance?this.light.distance:1E3,d=c*Math.tan(this.light.angle);this.cone.scale.set(d,d,c);a.setFromMatrixPosition(this.light.matrixWorld);b.setFromMatrixPosition(this.light.target.matrixWorld);this.cone.lookAt(b.sub(a));void 0!==this.color?this.cone.material.color.set(this.color): +this.cone.material.color.copy(this.light.color)}}();nc.prototype=Object.create(W.prototype);nc.prototype.constructor=nc;nc.prototype.updateMatrixWorld=function(){var a=new p,b=new P,c=new P;return function(d){var e=this.bones,f=this.geometry,g=f.getAttribute("position");c.getInverse(this.root.matrixWorld);for(var h=0,k=0;h<e.length;h++){var l=e[h];l.parent&&l.parent.isBone&&(b.multiplyMatrices(c,l.matrixWorld),a.setFromMatrixPosition(b),g.setXYZ(k,a.x,a.y,a.z),b.multiplyMatrices(c,l.parent.matrixWorld), +a.setFromMatrixPosition(b),g.setXYZ(k+1,a.x,a.y,a.z),k+=2)}f.getAttribute("position").needsUpdate=!0;C.prototype.updateMatrixWorld.call(this,d)}}();oc.prototype=Object.create(ua.prototype);oc.prototype.constructor=oc;oc.prototype.dispose=function(){this.geometry.dispose();this.material.dispose()};oc.prototype.update=function(){void 0!==this.color?this.material.color.set(this.color):this.material.color.copy(this.light.color)};pc.prototype=Object.create(C.prototype);pc.prototype.constructor=pc;pc.prototype.dispose= +function(){this.children[0].geometry.dispose();this.children[0].material.dispose()};pc.prototype.update=function(){var a=.5*this.light.width,b=.5*this.light.height,c=this.line.geometry.attributes.position,d=c.array;d[0]=a;d[1]=-b;d[2]=0;d[3]=a;d[4]=b;d[5]=0;d[6]=-a;d[7]=b;d[8]=0;d[9]=-a;d[10]=-b;d[11]=0;d[12]=a;d[13]=-b;d[14]=0;c.needsUpdate=!0;void 0!==this.color?this.line.material.color.set(this.color):this.line.material.color.copy(this.light.color)};qc.prototype=Object.create(C.prototype);qc.prototype.constructor= +qc;qc.prototype.dispose=function(){this.children[0].geometry.dispose();this.children[0].material.dispose()};qc.prototype.update=function(){var a=new p,b=new G,c=new G;return function(){var d=this.children[0];if(void 0!==this.color)this.material.color.set(this.color);else{var e=d.geometry.getAttribute("color");b.copy(this.light.color);c.copy(this.light.groundColor);for(var f=0,g=e.count;f<g;f++){var h=f<g/2?b:c;e.setXYZ(f,h.r,h.g,h.b)}e.needsUpdate=!0}d.lookAt(a.setFromMatrixPosition(this.light.matrixWorld).negate())}}(); +ld.prototype=Object.create(W.prototype);ld.prototype.constructor=ld;Sd.prototype=Object.create(W.prototype);Sd.prototype.constructor=Sd;md.prototype=Object.create(W.prototype);md.prototype.constructor=md;md.prototype.update=function(){var a=new p,b=new p,c=new oa;return function(){this.object.updateMatrixWorld(!0);c.getNormalMatrix(this.object.matrixWorld);var d=this.object.matrixWorld,e=this.geometry.attributes.position,f=this.object.geometry,g=f.vertices;f=f.faces;for(var h=0,k=0,l=f.length;k<l;k++){var p= +f[k],n=p.normal;a.copy(g[p.a]).add(g[p.b]).add(g[p.c]).divideScalar(3).applyMatrix4(d);b.copy(n).applyMatrix3(c).normalize().multiplyScalar(this.size).add(a);e.setXYZ(h,a.x,a.y,a.z);h+=1;e.setXYZ(h,b.x,b.y,b.z);h+=1}e.needsUpdate=!0}}();rc.prototype=Object.create(C.prototype);rc.prototype.constructor=rc;rc.prototype.dispose=function(){this.lightPlane.geometry.dispose();this.lightPlane.material.dispose();this.targetLine.geometry.dispose();this.targetLine.material.dispose()};rc.prototype.update=function(){var a= +new p,b=new p,c=new p;return function(){a.setFromMatrixPosition(this.light.matrixWorld);b.setFromMatrixPosition(this.light.target.matrixWorld);c.subVectors(b,a);this.lightPlane.lookAt(c);void 0!==this.color?(this.lightPlane.material.color.set(this.color),this.targetLine.material.color.set(this.color)):(this.lightPlane.material.color.copy(this.light.color),this.targetLine.material.color.copy(this.light.color));this.targetLine.lookAt(c);this.targetLine.scale.z=c.length()}}();nd.prototype=Object.create(W.prototype); +nd.prototype.constructor=nd;nd.prototype.update=function(){function a(a,g,h,k){d.set(g,h,k).unproject(e);a=c[a];if(void 0!==a)for(g=b.getAttribute("position"),h=0,k=a.length;h<k;h++)g.setXYZ(a[h],d.x,d.y,d.z)}var b,c,d=new p,e=new Ra;return function(){b=this.geometry;c=this.pointMap;e.projectionMatrix.copy(this.camera.projectionMatrix);a("c",0,0,-1);a("t",0,0,1);a("n1",-1,-1,-1);a("n2",1,-1,-1);a("n3",-1,1,-1);a("n4",1,1,-1);a("f1",-1,-1,1);a("f2",1,-1,1);a("f3",-1,1,1);a("f4",1,1,1);a("u1",.7,1.1, +-1);a("u2",-.7,1.1,-1);a("u3",0,2,-1);a("cf1",-1,0,1);a("cf2",1,0,1);a("cf3",0,-1,1);a("cf4",0,1,1);a("cn1",-1,0,-1);a("cn2",1,0,-1);a("cn3",0,-1,-1);a("cn4",0,1,-1);b.getAttribute("position").needsUpdate=!0}}();Gb.prototype=Object.create(W.prototype);Gb.prototype.constructor=Gb;Gb.prototype.update=function(){var a=new Wa;return function(b){void 0!==b&&console.warn("THREE.BoxHelper: .update() has no longer arguments.");void 0!==this.object&&a.setFromObject(this.object);if(!a.isEmpty()){b=a.min;var c= +a.max,d=this.geometry.attributes.position,e=d.array;e[0]=c.x;e[1]=c.y;e[2]=c.z;e[3]=b.x;e[4]=c.y;e[5]=c.z;e[6]=b.x;e[7]=b.y;e[8]=c.z;e[9]=c.x;e[10]=b.y;e[11]=c.z;e[12]=c.x;e[13]=c.y;e[14]=b.z;e[15]=b.x;e[16]=c.y;e[17]=b.z;e[18]=b.x;e[19]=b.y;e[20]=b.z;e[21]=c.x;e[22]=b.y;e[23]=b.z;d.needsUpdate=!0;this.geometry.computeBoundingSphere()}}}();Gb.prototype.setFromObject=function(a){this.object=a;this.update();return this};od.prototype=Object.create(W.prototype);od.prototype.constructor=od;od.prototype.updateMatrixWorld= +function(a){var b=this.box;b.isEmpty()||(b.getCenter(this.position),b.getSize(this.scale),this.scale.multiplyScalar(.5),C.prototype.updateMatrixWorld.call(this,a))};pd.prototype=Object.create(pa.prototype);pd.prototype.constructor=pd;pd.prototype.updateMatrixWorld=function(a){var b=-this.plane.constant;1E-8>Math.abs(b)&&(b=1E-8);this.scale.set(.5*this.size,.5*this.size,b);this.children[0].material.side=0>b?1:0;this.lookAt(this.plane.normal);C.prototype.updateMatrixWorld.call(this,a)};var Td,Ae;Hb.prototype= +Object.create(C.prototype);Hb.prototype.constructor=Hb;Hb.prototype.setDirection=function(){var a=new p,b;return function(c){.99999<c.y?this.quaternion.set(0,0,0,1):-.99999>c.y?this.quaternion.set(1,0,0,0):(a.set(c.z,0,-c.x).normalize(),b=Math.acos(c.y),this.quaternion.setFromAxisAngle(a,b))}}();Hb.prototype.setLength=function(a,b,c){void 0===b&&(b=.2*a);void 0===c&&(c=.2*b);this.line.scale.set(1,Math.max(0,a-b),1);this.line.updateMatrix();this.cone.scale.set(c,b,c);this.cone.position.y=a;this.cone.updateMatrix()}; +Hb.prototype.setColor=function(a){this.line.material.color.copy(a);this.cone.material.color.copy(a)};qd.prototype=Object.create(W.prototype);qd.prototype.constructor=qd;N.create=function(a,b){console.log("THREE.Curve.create() has been deprecated");a.prototype=Object.create(N.prototype);a.prototype.constructor=a;a.prototype.getPoint=b;return a};Object.assign(ab.prototype,{createPointsGeometry:function(a){console.warn("THREE.CurvePath: .createPointsGeometry() has been removed. Use new THREE.Geometry().setFromPoints( points ) instead."); +a=this.getPoints(a);return this.createGeometry(a)},createSpacedPointsGeometry:function(a){console.warn("THREE.CurvePath: .createSpacedPointsGeometry() has been removed. Use new THREE.Geometry().setFromPoints( points ) instead.");a=this.getSpacedPoints(a);return this.createGeometry(a)},createGeometry:function(a){console.warn("THREE.CurvePath: .createGeometry() has been removed. Use new THREE.Geometry().setFromPoints( points ) instead.");for(var b=new M,c=0,d=a.length;c<d;c++){var e=a[c];b.vertices.push(new p(e.x, +e.y,e.z||0))}return b}});Object.assign(Na.prototype,{fromPoints:function(a){console.warn("THREE.Path: .fromPoints() has been renamed to .setFromPoints().");this.setFromPoints(a)}});Af.prototype=Object.create(ha.prototype);Bf.prototype=Object.create(ha.prototype);Be.prototype=Object.create(ha.prototype);Object.assign(Be.prototype,{initFromArray:function(){console.error("THREE.Spline: .initFromArray() has been removed.")},getControlPointsArray:function(){console.error("THREE.Spline: .getControlPointsArray() has been removed.")}, +reparametrizeByArcLength:function(){console.error("THREE.Spline: .reparametrizeByArcLength() has been removed.")}});ld.prototype.setColors=function(){console.error("THREE.GridHelper: setColors() has been deprecated, pass them in the constructor instead.")};nc.prototype.update=function(){console.error("THREE.SkeletonHelper: update() no longer needs to be called.")};Object.assign(kc.prototype,{extractUrlBase:function(a){console.warn("THREE.Loader: .extractUrlBase() has been deprecated. Use THREE.LoaderUtils.extractUrlBase() instead."); +return Fe.extractUrlBase(a)}});Object.assign(Qd.prototype,{setTexturePath:function(a){console.warn("THREE.JSONLoader: .setTexturePath() has been renamed to .setResourcePath().");return this.setResourcePath(a)}});Object.assign(ye.prototype,{center:function(a){console.warn("THREE.Box2: .center() has been renamed to .getCenter().");return this.getCenter(a)},empty:function(){console.warn("THREE.Box2: .empty() has been renamed to .isEmpty().");return this.isEmpty()},isIntersectionBox:function(a){console.warn("THREE.Box2: .isIntersectionBox() has been renamed to .intersectsBox()."); +return this.intersectsBox(a)},size:function(a){console.warn("THREE.Box2: .size() has been renamed to .getSize().");return this.getSize(a)}});Object.assign(Wa.prototype,{center:function(a){console.warn("THREE.Box3: .center() has been renamed to .getCenter().");return this.getCenter(a)},empty:function(){console.warn("THREE.Box3: .empty() has been renamed to .isEmpty().");return this.isEmpty()},isIntersectionBox:function(a){console.warn("THREE.Box3: .isIntersectionBox() has been renamed to .intersectsBox()."); +return this.intersectsBox(a)},isIntersectionSphere:function(a){console.warn("THREE.Box3: .isIntersectionSphere() has been renamed to .intersectsSphere().");return this.intersectsSphere(a)},size:function(a){console.warn("THREE.Box3: .size() has been renamed to .getSize().");return this.getSize(a)}});ze.prototype.center=function(a){console.warn("THREE.Line3: .center() has been renamed to .getCenter().");return this.getCenter(a)};Object.assign(S,{random16:function(){console.warn("THREE.Math: .random16() has been deprecated. Use Math.random() instead."); +return Math.random()},nearestPowerOfTwo:function(a){console.warn("THREE.Math: .nearestPowerOfTwo() has been renamed to .floorPowerOfTwo().");return S.floorPowerOfTwo(a)},nextPowerOfTwo:function(a){console.warn("THREE.Math: .nextPowerOfTwo() has been renamed to .ceilPowerOfTwo().");return S.ceilPowerOfTwo(a)}});Object.assign(oa.prototype,{flattenToArrayOffset:function(a,b){console.warn("THREE.Matrix3: .flattenToArrayOffset() has been deprecated. Use .toArray() instead.");return this.toArray(a,b)}, +multiplyVector3:function(a){console.warn("THREE.Matrix3: .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.");return a.applyMatrix3(this)},multiplyVector3Array:function(){console.error("THREE.Matrix3: .multiplyVector3Array() has been removed.")},applyToBuffer:function(a){console.warn("THREE.Matrix3: .applyToBuffer() has been removed. Use matrix.applyToBufferAttribute( attribute ) instead.");return this.applyToBufferAttribute(a)},applyToVector3Array:function(){console.error("THREE.Matrix3: .applyToVector3Array() has been removed.")}}); +Object.assign(P.prototype,{extractPosition:function(a){console.warn("THREE.Matrix4: .extractPosition() has been renamed to .copyPosition().");return this.copyPosition(a)},flattenToArrayOffset:function(a,b){console.warn("THREE.Matrix4: .flattenToArrayOffset() has been deprecated. Use .toArray() instead.");return this.toArray(a,b)},getPosition:function(){var a;return function(){void 0===a&&(a=new p);console.warn("THREE.Matrix4: .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead."); +return a.setFromMatrixColumn(this,3)}}(),setRotationFromQuaternion:function(a){console.warn("THREE.Matrix4: .setRotationFromQuaternion() has been renamed to .makeRotationFromQuaternion().");return this.makeRotationFromQuaternion(a)},multiplyToArray:function(){console.warn("THREE.Matrix4: .multiplyToArray() has been removed.")},multiplyVector3:function(a){console.warn("THREE.Matrix4: .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) instead.");return a.applyMatrix4(this)},multiplyVector4:function(a){console.warn("THREE.Matrix4: .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead."); +return a.applyMatrix4(this)},multiplyVector3Array:function(){console.error("THREE.Matrix4: .multiplyVector3Array() has been removed.")},rotateAxis:function(a){console.warn("THREE.Matrix4: .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.");a.transformDirection(this)},crossVector:function(a){console.warn("THREE.Matrix4: .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.");return a.applyMatrix4(this)},translate:function(){console.error("THREE.Matrix4: .translate() has been removed.")}, +rotateX:function(){console.error("THREE.Matrix4: .rotateX() has been removed.")},rotateY:function(){console.error("THREE.Matrix4: .rotateY() has been removed.")},rotateZ:function(){console.error("THREE.Matrix4: .rotateZ() has been removed.")},rotateByAxis:function(){console.error("THREE.Matrix4: .rotateByAxis() has been removed.")},applyToBuffer:function(a){console.warn("THREE.Matrix4: .applyToBuffer() has been removed. Use matrix.applyToBufferAttribute( attribute ) instead.");return this.applyToBufferAttribute(a)}, +applyToVector3Array:function(){console.error("THREE.Matrix4: .applyToVector3Array() has been removed.")},makeFrustum:function(a,b,c,d,e,f){console.warn("THREE.Matrix4: .makeFrustum() has been removed. Use .makePerspective( left, right, top, bottom, near, far ) instead.");return this.makePerspective(a,b,d,c,e,f)}});Pa.prototype.isIntersectionLine=function(a){console.warn("THREE.Plane: .isIntersectionLine() has been renamed to .intersectsLine().");return this.intersectsLine(a)};ja.prototype.multiplyVector3= +function(a){console.warn("THREE.Quaternion: .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.");return a.applyQuaternion(this)};Object.assign(pb.prototype,{isIntersectionBox:function(a){console.warn("THREE.Ray: .isIntersectionBox() has been renamed to .intersectsBox().");return this.intersectsBox(a)},isIntersectionPlane:function(a){console.warn("THREE.Ray: .isIntersectionPlane() has been renamed to .intersectsPlane().");return this.intersectsPlane(a)},isIntersectionSphere:function(a){console.warn("THREE.Ray: .isIntersectionSphere() has been renamed to .intersectsSphere()."); +return this.intersectsSphere(a)}});Object.assign(da.prototype,{area:function(){console.warn("THREE.Triangle: .area() has been renamed to .getArea().");return this.getArea()},barycoordFromPoint:function(a,b){console.warn("THREE.Triangle: .barycoordFromPoint() has been renamed to .getBarycoord().");return this.getBarycoord(a,b)},midpoint:function(a){console.warn("THREE.Triangle: .midpoint() has been renamed to .getMidpoint().");return this.getMidpoint(a)},normal:function(a){console.warn("THREE.Triangle: .normal() has been renamed to .getNormal()."); +return this.getNormal(a)},plane:function(a){console.warn("THREE.Triangle: .plane() has been renamed to .getPlane().");return this.getPlane(a)}});Object.assign(da,{barycoordFromPoint:function(a,b,c,d,e){console.warn("THREE.Triangle: .barycoordFromPoint() has been renamed to .getBarycoord().");return da.getBarycoord(a,b,c,d,e)},normal:function(a,b,c,d){console.warn("THREE.Triangle: .normal() has been renamed to .getNormal().");return da.getNormal(a,b,c,d)}});Object.assign(gb.prototype,{extractAllPoints:function(a){console.warn("THREE.Shape: .extractAllPoints() has been removed. Use .extractPoints() instead."); +return this.extractPoints(a)},extrude:function(a){console.warn("THREE.Shape: .extrude() has been removed. Use ExtrudeGeometry() instead.");return new tb(this,a)},makeGeometry:function(a){console.warn("THREE.Shape: .makeGeometry() has been removed. Use ShapeGeometry() instead.");return new vb(this,a)}});Object.assign(A.prototype,{fromAttribute:function(a,b,c){console.warn("THREE.Vector2: .fromAttribute() has been renamed to .fromBufferAttribute().");return this.fromBufferAttribute(a,b,c)},distanceToManhattan:function(a){console.warn("THREE.Vector2: .distanceToManhattan() has been renamed to .manhattanDistanceTo()."); +return this.manhattanDistanceTo(a)},lengthManhattan:function(){console.warn("THREE.Vector2: .lengthManhattan() has been renamed to .manhattanLength().");return this.manhattanLength()}});Object.assign(p.prototype,{setEulerFromRotationMatrix:function(){console.error("THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead.")},setEulerFromQuaternion:function(){console.error("THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead.")}, +getPositionFromMatrix:function(a){console.warn("THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition().");return this.setFromMatrixPosition(a)},getScaleFromMatrix:function(a){console.warn("THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale().");return this.setFromMatrixScale(a)},getColumnFromMatrix:function(a,b){console.warn("THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn().");return this.setFromMatrixColumn(b, +a)},applyProjection:function(a){console.warn("THREE.Vector3: .applyProjection() has been removed. Use .applyMatrix4( m ) instead.");return this.applyMatrix4(a)},fromAttribute:function(a,b,c){console.warn("THREE.Vector3: .fromAttribute() has been renamed to .fromBufferAttribute().");return this.fromBufferAttribute(a,b,c)},distanceToManhattan:function(a){console.warn("THREE.Vector3: .distanceToManhattan() has been renamed to .manhattanDistanceTo().");return this.manhattanDistanceTo(a)},lengthManhattan:function(){console.warn("THREE.Vector3: .lengthManhattan() has been renamed to .manhattanLength()."); +return this.manhattanLength()}});Object.assign(Z.prototype,{fromAttribute:function(a,b,c){console.warn("THREE.Vector4: .fromAttribute() has been renamed to .fromBufferAttribute().");return this.fromBufferAttribute(a,b,c)},lengthManhattan:function(){console.warn("THREE.Vector4: .lengthManhattan() has been renamed to .manhattanLength().");return this.manhattanLength()}});Object.assign(M.prototype,{computeTangents:function(){console.error("THREE.Geometry: .computeTangents() has been removed.")},computeLineDistances:function(){console.error("THREE.Geometry: .computeLineDistances() has been removed. Use THREE.Line.computeLineDistances() instead.")}}); +Object.assign(C.prototype,{getChildByName:function(a){console.warn("THREE.Object3D: .getChildByName() has been renamed to .getObjectByName().");return this.getObjectByName(a)},renderDepth:function(){console.warn("THREE.Object3D: .renderDepth has been removed. Use .renderOrder, instead.")},translate:function(a,b){console.warn("THREE.Object3D: .translate() has been removed. Use .translateOnAxis( axis, distance ) instead.");return this.translateOnAxis(b,a)},getWorldRotation:function(){console.error("THREE.Object3D: .getWorldRotation() has been removed. Use THREE.Object3D.getWorldQuaternion( target ) instead.")}}); +Object.defineProperties(C.prototype,{eulerOrder:{get:function(){console.warn("THREE.Object3D: .eulerOrder is now .rotation.order.");return this.rotation.order},set:function(a){console.warn("THREE.Object3D: .eulerOrder is now .rotation.order.");this.rotation.order=a}},useQuaternion:{get:function(){console.warn("THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.")},set:function(){console.warn("THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.")}}}); +Object.defineProperties(Fc.prototype,{objects:{get:function(){console.warn("THREE.LOD: .objects has been renamed to .levels.");return this.levels}}});Object.defineProperty(Gc.prototype,"useVertexTexture",{get:function(){console.warn("THREE.Skeleton: useVertexTexture has been removed.")},set:function(){console.warn("THREE.Skeleton: useVertexTexture has been removed.")}});Object.defineProperty(N.prototype,"__arcLengthDivisions",{get:function(){console.warn("THREE.Curve: .__arcLengthDivisions is now .arcLengthDivisions."); +return this.arcLengthDivisions},set:function(a){console.warn("THREE.Curve: .__arcLengthDivisions is now .arcLengthDivisions.");this.arcLengthDivisions=a}});V.prototype.setLens=function(a,b){console.warn("THREE.PerspectiveCamera.setLens is deprecated. Use .setFocalLength and .filmGauge for a photographic setup.");void 0!==b&&(this.filmGauge=b);this.setFocalLength(a)};Object.defineProperties(ca.prototype,{onlyShadow:{set:function(){console.warn("THREE.Light: .onlyShadow has been removed.")}},shadowCameraFov:{set:function(a){console.warn("THREE.Light: .shadowCameraFov is now .shadow.camera.fov."); +this.shadow.camera.fov=a}},shadowCameraLeft:{set:function(a){console.warn("THREE.Light: .shadowCameraLeft is now .shadow.camera.left.");this.shadow.camera.left=a}},shadowCameraRight:{set:function(a){console.warn("THREE.Light: .shadowCameraRight is now .shadow.camera.right.");this.shadow.camera.right=a}},shadowCameraTop:{set:function(a){console.warn("THREE.Light: .shadowCameraTop is now .shadow.camera.top.");this.shadow.camera.top=a}},shadowCameraBottom:{set:function(a){console.warn("THREE.Light: .shadowCameraBottom is now .shadow.camera.bottom."); +this.shadow.camera.bottom=a}},shadowCameraNear:{set:function(a){console.warn("THREE.Light: .shadowCameraNear is now .shadow.camera.near.");this.shadow.camera.near=a}},shadowCameraFar:{set:function(a){console.warn("THREE.Light: .shadowCameraFar is now .shadow.camera.far.");this.shadow.camera.far=a}},shadowCameraVisible:{set:function(){console.warn("THREE.Light: .shadowCameraVisible has been removed. Use new THREE.CameraHelper( light.shadow.camera ) instead.")}},shadowBias:{set:function(a){console.warn("THREE.Light: .shadowBias is now .shadow.bias."); +this.shadow.bias=a}},shadowDarkness:{set:function(){console.warn("THREE.Light: .shadowDarkness has been removed.")}},shadowMapWidth:{set:function(a){console.warn("THREE.Light: .shadowMapWidth is now .shadow.mapSize.width.");this.shadow.mapSize.width=a}},shadowMapHeight:{set:function(a){console.warn("THREE.Light: .shadowMapHeight is now .shadow.mapSize.height.");this.shadow.mapSize.height=a}}});Object.defineProperties(I.prototype,{length:{get:function(){console.warn("THREE.BufferAttribute: .length has been deprecated. Use .count instead."); +return this.array.length}},copyIndicesArray:function(){console.error("THREE.BufferAttribute: .copyIndicesArray() has been removed.")}});Object.assign(F.prototype,{addIndex:function(a){console.warn("THREE.BufferGeometry: .addIndex() has been renamed to .setIndex().");this.setIndex(a)},addDrawCall:function(a,b,c){void 0!==c&&console.warn("THREE.BufferGeometry: .addDrawCall() no longer supports indexOffset.");console.warn("THREE.BufferGeometry: .addDrawCall() is now .addGroup().");this.addGroup(a,b)}, +clearDrawCalls:function(){console.warn("THREE.BufferGeometry: .clearDrawCalls() is now .clearGroups().");this.clearGroups()},computeTangents:function(){console.warn("THREE.BufferGeometry: .computeTangents() has been removed.")},computeOffsets:function(){console.warn("THREE.BufferGeometry: .computeOffsets() has been removed.")}});Object.defineProperties(F.prototype,{drawcalls:{get:function(){console.error("THREE.BufferGeometry: .drawcalls has been renamed to .groups.");return this.groups}},offsets:{get:function(){console.warn("THREE.BufferGeometry: .offsets has been renamed to .groups."); +return this.groups}}});Object.assign(Sa.prototype,{getArrays:function(){console.error("THREE.ExtrudeBufferGeometry: .getArrays() has been removed.")},addShapeList:function(){console.error("THREE.ExtrudeBufferGeometry: .addShapeList() has been removed.")},addShape:function(){console.error("THREE.ExtrudeBufferGeometry: .addShape() has been removed.")}});Object.defineProperties(Rd.prototype,{dynamic:{set:function(){console.warn("THREE.Uniform: .dynamic has been removed. Use object.onBeforeRender() instead.")}}, +onUpdate:{value:function(){console.warn("THREE.Uniform: .onUpdate() has been removed. Use object.onBeforeRender() instead.");return this}}});Object.defineProperties(L.prototype,{wrapAround:{get:function(){console.warn("THREE.Material: .wrapAround has been removed.")},set:function(){console.warn("THREE.Material: .wrapAround has been removed.")}},wrapRGB:{get:function(){console.warn("THREE.Material: .wrapRGB has been removed.");return new G}},shading:{get:function(){console.error("THREE."+this.type+ +": .shading has been removed. Use the boolean .flatShading instead.")},set:function(a){console.warn("THREE."+this.type+": .shading has been removed. Use the boolean .flatShading instead.");this.flatShading=1===a}}});Object.defineProperties(Ha.prototype,{metal:{get:function(){console.warn("THREE.MeshPhongMaterial: .metal has been removed. Use THREE.MeshStandardMaterial instead.");return!1},set:function(){console.warn("THREE.MeshPhongMaterial: .metal has been removed. Use THREE.MeshStandardMaterial instead")}}}); +Object.defineProperties(ka.prototype,{derivatives:{get:function(){console.warn("THREE.ShaderMaterial: .derivatives has been moved to .extensions.derivatives.");return this.extensions.derivatives},set:function(a){console.warn("THREE. ShaderMaterial: .derivatives has been moved to .extensions.derivatives.");this.extensions.derivatives=a}}});Object.assign(be.prototype,{clearTarget:function(a,b,c,d){console.warn("THREE.WebGLRenderer: .clearTarget() has been deprecated. Use .setRenderTarget() and .clear() instead."); +this.setRenderTarget(a);this.clear(b,c,d)},animate:function(a){console.warn("THREE.WebGLRenderer: .animate() is now .setAnimationLoop().");this.setAnimationLoop(a)},getCurrentRenderTarget:function(){console.warn("THREE.WebGLRenderer: .getCurrentRenderTarget() is now .getRenderTarget().");return this.getRenderTarget()},getMaxAnisotropy:function(){console.warn("THREE.WebGLRenderer: .getMaxAnisotropy() is now .capabilities.getMaxAnisotropy().");return this.capabilities.getMaxAnisotropy()},getPrecision:function(){console.warn("THREE.WebGLRenderer: .getPrecision() is now .capabilities.precision."); +return this.capabilities.precision},resetGLState:function(){console.warn("THREE.WebGLRenderer: .resetGLState() is now .state.reset().");return this.state.reset()},supportsFloatTextures:function(){console.warn("THREE.WebGLRenderer: .supportsFloatTextures() is now .extensions.get( 'OES_texture_float' ).");return this.extensions.get("OES_texture_float")},supportsHalfFloatTextures:function(){console.warn("THREE.WebGLRenderer: .supportsHalfFloatTextures() is now .extensions.get( 'OES_texture_half_float' )."); +return this.extensions.get("OES_texture_half_float")},supportsStandardDerivatives:function(){console.warn("THREE.WebGLRenderer: .supportsStandardDerivatives() is now .extensions.get( 'OES_standard_derivatives' ).");return this.extensions.get("OES_standard_derivatives")},supportsCompressedTextureS3TC:function(){console.warn("THREE.WebGLRenderer: .supportsCompressedTextureS3TC() is now .extensions.get( 'WEBGL_compressed_texture_s3tc' ).");return this.extensions.get("WEBGL_compressed_texture_s3tc")}, +supportsCompressedTexturePVRTC:function(){console.warn("THREE.WebGLRenderer: .supportsCompressedTexturePVRTC() is now .extensions.get( 'WEBGL_compressed_texture_pvrtc' ).");return this.extensions.get("WEBGL_compressed_texture_pvrtc")},supportsBlendMinMax:function(){console.warn("THREE.WebGLRenderer: .supportsBlendMinMax() is now .extensions.get( 'EXT_blend_minmax' ).");return this.extensions.get("EXT_blend_minmax")},supportsVertexTextures:function(){console.warn("THREE.WebGLRenderer: .supportsVertexTextures() is now .capabilities.vertexTextures."); +return this.capabilities.vertexTextures},supportsInstancedArrays:function(){console.warn("THREE.WebGLRenderer: .supportsInstancedArrays() is now .extensions.get( 'ANGLE_instanced_arrays' ).");return this.extensions.get("ANGLE_instanced_arrays")},enableScissorTest:function(a){console.warn("THREE.WebGLRenderer: .enableScissorTest() is now .setScissorTest().");this.setScissorTest(a)},initMaterial:function(){console.warn("THREE.WebGLRenderer: .initMaterial() has been removed.")},addPrePlugin:function(){console.warn("THREE.WebGLRenderer: .addPrePlugin() has been removed.")}, +addPostPlugin:function(){console.warn("THREE.WebGLRenderer: .addPostPlugin() has been removed.")},updateShadowMap:function(){console.warn("THREE.WebGLRenderer: .updateShadowMap() has been removed.")},setFaceCulling:function(){console.warn("THREE.WebGLRenderer: .setFaceCulling() has been removed.")}});Object.defineProperties(be.prototype,{shadowMapEnabled:{get:function(){return this.shadowMap.enabled},set:function(a){console.warn("THREE.WebGLRenderer: .shadowMapEnabled is now .shadowMap.enabled."); +this.shadowMap.enabled=a}},shadowMapType:{get:function(){return this.shadowMap.type},set:function(a){console.warn("THREE.WebGLRenderer: .shadowMapType is now .shadowMap.type.");this.shadowMap.type=a}},shadowMapCullFace:{get:function(){console.warn("THREE.WebGLRenderer: .shadowMapCullFace has been removed. Set Material.shadowSide instead.")},set:function(){console.warn("THREE.WebGLRenderer: .shadowMapCullFace has been removed. Set Material.shadowSide instead.")}}});Object.defineProperties(af.prototype, +{cullFace:{get:function(){console.warn("THREE.WebGLRenderer: .shadowMap.cullFace has been removed. Set Material.shadowSide instead.")},set:function(){console.warn("THREE.WebGLRenderer: .shadowMap.cullFace has been removed. Set Material.shadowSide instead.")}},renderReverseSided:{get:function(){console.warn("THREE.WebGLRenderer: .shadowMap.renderReverseSided has been removed. Set Material.shadowSide instead.")},set:function(){console.warn("THREE.WebGLRenderer: .shadowMap.renderReverseSided has been removed. Set Material.shadowSide instead.")}}, +renderSingleSided:{get:function(){console.warn("THREE.WebGLRenderer: .shadowMap.renderSingleSided has been removed. Set Material.shadowSide instead.")},set:function(){console.warn("THREE.WebGLRenderer: .shadowMap.renderSingleSided has been removed. Set Material.shadowSide instead.")}}});Object.defineProperties(ib.prototype,{wrapS:{get:function(){console.warn("THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.");return this.texture.wrapS},set:function(a){console.warn("THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS."); +this.texture.wrapS=a}},wrapT:{get:function(){console.warn("THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.");return this.texture.wrapT},set:function(a){console.warn("THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.");this.texture.wrapT=a}},magFilter:{get:function(){console.warn("THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.");return this.texture.magFilter},set:function(a){console.warn("THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.");this.texture.magFilter= +a}},minFilter:{get:function(){console.warn("THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.");return this.texture.minFilter},set:function(a){console.warn("THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.");this.texture.minFilter=a}},anisotropy:{get:function(){console.warn("THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.");return this.texture.anisotropy},set:function(a){console.warn("THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.");this.texture.anisotropy= +a}},offset:{get:function(){console.warn("THREE.WebGLRenderTarget: .offset is now .texture.offset.");return this.texture.offset},set:function(a){console.warn("THREE.WebGLRenderTarget: .offset is now .texture.offset.");this.texture.offset=a}},repeat:{get:function(){console.warn("THREE.WebGLRenderTarget: .repeat is now .texture.repeat.");return this.texture.repeat},set:function(a){console.warn("THREE.WebGLRenderTarget: .repeat is now .texture.repeat.");this.texture.repeat=a}},format:{get:function(){console.warn("THREE.WebGLRenderTarget: .format is now .texture.format."); +return this.texture.format},set:function(a){console.warn("THREE.WebGLRenderTarget: .format is now .texture.format.");this.texture.format=a}},type:{get:function(){console.warn("THREE.WebGLRenderTarget: .type is now .texture.type.");return this.texture.type},set:function(a){console.warn("THREE.WebGLRenderTarget: .type is now .texture.type.");this.texture.type=a}},generateMipmaps:{get:function(){console.warn("THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.");return this.texture.generateMipmaps}, +set:function(a){console.warn("THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.");this.texture.generateMipmaps=a}}});Object.defineProperties(cf.prototype,{standing:{set:function(){console.warn("THREE.WebVRManager: .standing has been removed.")}},userHeight:{set:function(){console.warn("THREE.WebVRManager: .userHeight has been removed.")}}});lc.prototype.load=function(a){console.warn("THREE.Audio: .load has been deprecated. Use THREE.AudioLoader instead.");var b=this;(new ne).load(a, +function(a){b.setBuffer(a)});return this};re.prototype.getData=function(){console.warn("THREE.AudioAnalyser: .getData() is now .getFrequencyData().");return this.getFrequencyData()};id.prototype.updateCubeMap=function(a,b){console.warn("THREE.CubeCamera: .updateCubeMap() is now .update().");return this.update(a,b)};hb.crossOrigin=void 0;hb.loadTexture=function(a,b,c,d){console.warn("THREE.ImageUtils.loadTexture has been deprecated. Use THREE.TextureLoader() instead.");var e=new Ad;e.setCrossOrigin(this.crossOrigin); +a=e.load(a,c,void 0,d);b&&(a.mapping=b);return a};hb.loadTextureCube=function(a,b,c,d){console.warn("THREE.ImageUtils.loadTextureCube has been deprecated. Use THREE.CubeTextureLoader() instead.");var e=new he;e.setCrossOrigin(this.crossOrigin);a=e.load(a,c,void 0,d);b&&(a.mapping=b);return a};hb.loadCompressedTexture=function(){console.error("THREE.ImageUtils.loadCompressedTexture has been removed. Use THREE.DDSLoader instead.")};hb.loadCompressedTextureCube=function(){console.error("THREE.ImageUtils.loadCompressedTextureCube has been removed. Use THREE.DDSLoader instead.")}; +l.WebGLRenderTargetCube=Jb;l.WebGLRenderTarget=ib;l.WebGLRenderer=be;l.ShaderLib=Qa;l.UniformsLib=H;l.UniformsUtils=va;l.ShaderChunk=K;l.FogExp2=Pb;l.Fog=Qb;l.Scene=vd;l.Sprite=Ec;l.LOD=Fc;l.SkinnedMesh=xd;l.Skeleton=Gc;l.Bone=wd;l.Mesh=ua;l.LineSegments=W;l.LineLoop=yd;l.Line=pa;l.Points=Sb;l.Group=Ob;l.VideoTexture=ce;l.DataTexture=jb;l.DataTexture3D=Mb;l.CompressedTexture=Tb;l.CubeTexture=Ya;l.CanvasTexture=Hc;l.DepthTexture=Ic;l.Texture=Q;l.CompressedTextureLoader=mf;l.DataTextureLoader=ge;l.CubeTextureLoader= +he;l.TextureLoader=Ad;l.ObjectLoader=of;l.MaterialLoader=Pd;l.BufferGeometryLoader=je;l.DefaultLoadingManager=ya;l.LoadingManager=fe;l.JSONLoader=Qd;l.ImageLoader=cd;l.ImageBitmapLoader=ke;l.FontLoader=pf;l.FileLoader=Ia;l.Loader=kc;l.LoaderUtils=Fe;l.Cache=Ib;l.AudioLoader=ne;l.SpotLightShadow=Cd;l.SpotLight=Dd;l.PointLight=Ed;l.RectAreaLight=Id;l.HemisphereLight=Bd;l.DirectionalLightShadow=Fd;l.DirectionalLight=Gd;l.AmbientLight=Hd;l.LightShadow=Fb;l.Light=ca;l.StereoCamera=qf;l.PerspectiveCamera= +V;l.OrthographicCamera=fd;l.CubeCamera=id;l.ArrayCamera=Cc;l.Camera=Ra;l.AudioListener=oe;l.PositionalAudio=qe;l.AudioContext=pe;l.AudioAnalyser=re;l.Audio=lc;l.VectorKeyframeTrack=jc;l.StringKeyframeTrack=Od;l.QuaternionKeyframeTrack=hd;l.NumberKeyframeTrack=ic;l.ColorKeyframeTrack=Md;l.BooleanKeyframeTrack=Ld;l.PropertyMixer=se;l.PropertyBinding=ta;l.KeyframeTrack=qa;l.AnimationUtils=ra;l.AnimationObjectGroup=sf;l.AnimationMixer=te;l.AnimationClip=Ea;l.Uniform=Rd;l.InstancedBufferGeometry=ue;l.BufferGeometry= +F;l.Geometry=M;l.InterleavedBufferAttribute=Dc;l.InstancedInterleavedBuffer=ve;l.InterleavedBuffer=qb;l.InstancedBufferAttribute=we;l.Face3=Xa;l.Object3D=C;l.Raycaster=uf;l.Layers=Xd;l.EventDispatcher=ia;l.Clock=wf;l.QuaternionLinearInterpolant=Nd;l.LinearInterpolant=gd;l.DiscreteInterpolant=Kd;l.CubicInterpolant=Jd;l.Interpolant=Aa;l.Triangle=da;l.Math=S;l.Spherical=xf;l.Cylindrical=yf;l.Plane=Pa;l.Frustum=rd;l.Sphere=Fa;l.Ray=pb;l.Matrix4=P;l.Matrix3=oa;l.Box3=Wa;l.Box2=ye;l.Line3=ze;l.Euler=kb; +l.Vector4=Z;l.Vector3=p;l.Vector2=A;l.Quaternion=ja;l.Color=G;l.ImmediateRenderObject=jd;l.VertexNormalsHelper=kd;l.SpotLightHelper=mc;l.SkeletonHelper=nc;l.PointLightHelper=oc;l.RectAreaLightHelper=pc;l.HemisphereLightHelper=qc;l.GridHelper=ld;l.PolarGridHelper=Sd;l.FaceNormalsHelper=md;l.DirectionalLightHelper=rc;l.CameraHelper=nd;l.BoxHelper=Gb;l.Box3Helper=od;l.PlaneHelper=pd;l.ArrowHelper=Hb;l.AxesHelper=qd;l.Shape=gb;l.Path=Na;l.ShapePath=le;l.Font=me;l.CurvePath=ab;l.Curve=N;l.ImageUtils=hb; +l.ShapeUtils=Za;l.WebGLUtils=bf;l.WireframeGeometry=Ub;l.ParametricGeometry=Jc;l.ParametricBufferGeometry=Vb;l.TetrahedronGeometry=Lc;l.TetrahedronBufferGeometry=Wb;l.OctahedronGeometry=Mc;l.OctahedronBufferGeometry=rb;l.IcosahedronGeometry=Nc;l.IcosahedronBufferGeometry=Xb;l.DodecahedronGeometry=Oc;l.DodecahedronBufferGeometry=Yb;l.PolyhedronGeometry=Kc;l.PolyhedronBufferGeometry=ma;l.TubeGeometry=Pc;l.TubeBufferGeometry=Zb;l.TorusKnotGeometry=Qc;l.TorusKnotBufferGeometry=$b;l.TorusGeometry=Rc;l.TorusBufferGeometry= +ac;l.TextGeometry=Wc;l.TextBufferGeometry=bc;l.SphereGeometry=Xc;l.SphereBufferGeometry=ub;l.RingGeometry=Yc;l.RingBufferGeometry=cc;l.PlaneGeometry=yc;l.PlaneBufferGeometry=ob;l.LatheGeometry=Zc;l.LatheBufferGeometry=dc;l.ShapeGeometry=vb;l.ShapeBufferGeometry=wb;l.ExtrudeGeometry=tb;l.ExtrudeBufferGeometry=Sa;l.EdgesGeometry=ec;l.ConeGeometry=$c;l.ConeBufferGeometry=ad;l.CylinderGeometry=xb;l.CylinderBufferGeometry=$a;l.CircleGeometry=bd;l.CircleBufferGeometry=fc;l.BoxGeometry=Kb;l.BoxBufferGeometry= +nb;l.ShadowMaterial=yb;l.SpriteMaterial=fb;l.RawShaderMaterial=gc;l.ShaderMaterial=ka;l.PointsMaterial=Ga;l.MeshPhysicalMaterial=zb;l.MeshStandardMaterial=Ta;l.MeshPhongMaterial=Ha;l.MeshToonMaterial=Ab;l.MeshNormalMaterial=Bb;l.MeshLambertMaterial=Cb;l.MeshDepthMaterial=cb;l.MeshDistanceMaterial=db;l.MeshBasicMaterial=wa;l.MeshMatcapMaterial=Db;l.LineDashedMaterial=Eb;l.LineBasicMaterial=T;l.Material=L;l.Float64BufferAttribute=xc;l.Float32BufferAttribute=z;l.Uint32BufferAttribute=mb;l.Int32BufferAttribute= +wc;l.Uint16BufferAttribute=lb;l.Int16BufferAttribute=vc;l.Uint8ClampedBufferAttribute=uc;l.Uint8BufferAttribute=tc;l.Int8BufferAttribute=sc;l.BufferAttribute=I;l.ArcCurve=hc;l.CatmullRomCurve3=ha;l.CubicBezierCurve=Ja;l.CubicBezierCurve3=Ua;l.EllipseCurve=Ca;l.LineCurve=za;l.LineCurve3=Ka;l.QuadraticBezierCurve=La;l.QuadraticBezierCurve3=Va;l.SplineCurve=Ma;l.REVISION="97";l.MOUSE={LEFT:0,MIDDLE:1,RIGHT:2};l.CullFaceNone=0;l.CullFaceBack=1;l.CullFaceFront=2;l.CullFaceFrontBack=3;l.FrontFaceDirectionCW= +0;l.FrontFaceDirectionCCW=1;l.BasicShadowMap=0;l.PCFShadowMap=1;l.PCFSoftShadowMap=2;l.FrontSide=0;l.BackSide=1;l.DoubleSide=2;l.FlatShading=1;l.SmoothShading=2;l.NoColors=0;l.FaceColors=1;l.VertexColors=2;l.NoBlending=0;l.NormalBlending=1;l.AdditiveBlending=2;l.SubtractiveBlending=3;l.MultiplyBlending=4;l.CustomBlending=5;l.AddEquation=100;l.SubtractEquation=101;l.ReverseSubtractEquation=102;l.MinEquation=103;l.MaxEquation=104;l.ZeroFactor=200;l.OneFactor=201;l.SrcColorFactor=202;l.OneMinusSrcColorFactor= +203;l.SrcAlphaFactor=204;l.OneMinusSrcAlphaFactor=205;l.DstAlphaFactor=206;l.OneMinusDstAlphaFactor=207;l.DstColorFactor=208;l.OneMinusDstColorFactor=209;l.SrcAlphaSaturateFactor=210;l.NeverDepth=0;l.AlwaysDepth=1;l.LessDepth=2;l.LessEqualDepth=3;l.EqualDepth=4;l.GreaterEqualDepth=5;l.GreaterDepth=6;l.NotEqualDepth=7;l.MultiplyOperation=0;l.MixOperation=1;l.AddOperation=2;l.NoToneMapping=0;l.LinearToneMapping=1;l.ReinhardToneMapping=2;l.Uncharted2ToneMapping=3;l.CineonToneMapping=4;l.UVMapping=300; +l.CubeReflectionMapping=301;l.CubeRefractionMapping=302;l.EquirectangularReflectionMapping=303;l.EquirectangularRefractionMapping=304;l.SphericalReflectionMapping=305;l.CubeUVReflectionMapping=306;l.CubeUVRefractionMapping=307;l.RepeatWrapping=1E3;l.ClampToEdgeWrapping=1001;l.MirroredRepeatWrapping=1002;l.NearestFilter=1003;l.NearestMipMapNearestFilter=1004;l.NearestMipMapLinearFilter=1005;l.LinearFilter=1006;l.LinearMipMapNearestFilter=1007;l.LinearMipMapLinearFilter=1008;l.UnsignedByteType=1009; +l.ByteType=1010;l.ShortType=1011;l.UnsignedShortType=1012;l.IntType=1013;l.UnsignedIntType=1014;l.FloatType=1015;l.HalfFloatType=1016;l.UnsignedShort4444Type=1017;l.UnsignedShort5551Type=1018;l.UnsignedShort565Type=1019;l.UnsignedInt248Type=1020;l.AlphaFormat=1021;l.RGBFormat=1022;l.RGBAFormat=1023;l.LuminanceFormat=1024;l.LuminanceAlphaFormat=1025;l.RGBEFormat=1023;l.DepthFormat=1026;l.DepthStencilFormat=1027;l.RedFormat=1028;l.RGB_S3TC_DXT1_Format=33776;l.RGBA_S3TC_DXT1_Format=33777;l.RGBA_S3TC_DXT3_Format= +33778;l.RGBA_S3TC_DXT5_Format=33779;l.RGB_PVRTC_4BPPV1_Format=35840;l.RGB_PVRTC_2BPPV1_Format=35841;l.RGBA_PVRTC_4BPPV1_Format=35842;l.RGBA_PVRTC_2BPPV1_Format=35843;l.RGB_ETC1_Format=36196;l.RGBA_ASTC_4x4_Format=37808;l.RGBA_ASTC_5x4_Format=37809;l.RGBA_ASTC_5x5_Format=37810;l.RGBA_ASTC_6x5_Format=37811;l.RGBA_ASTC_6x6_Format=37812;l.RGBA_ASTC_8x5_Format=37813;l.RGBA_ASTC_8x6_Format=37814;l.RGBA_ASTC_8x8_Format=37815;l.RGBA_ASTC_10x5_Format=37816;l.RGBA_ASTC_10x6_Format=37817;l.RGBA_ASTC_10x8_Format= +37818;l.RGBA_ASTC_10x10_Format=37819;l.RGBA_ASTC_12x10_Format=37820;l.RGBA_ASTC_12x12_Format=37821;l.LoopOnce=2200;l.LoopRepeat=2201;l.LoopPingPong=2202;l.InterpolateDiscrete=2300;l.InterpolateLinear=2301;l.InterpolateSmooth=2302;l.ZeroCurvatureEnding=2400;l.ZeroSlopeEnding=2401;l.WrapAroundEnding=2402;l.TrianglesDrawMode=0;l.TriangleStripDrawMode=1;l.TriangleFanDrawMode=2;l.LinearEncoding=3E3;l.sRGBEncoding=3001;l.GammaEncoding=3007;l.RGBEEncoding=3002;l.LogLuvEncoding=3003;l.RGBM7Encoding=3004; +l.RGBM16Encoding=3005;l.RGBDEncoding=3006;l.BasicDepthPacking=3200;l.RGBADepthPacking=3201;l.TangentSpaceNormalMap=0;l.ObjectSpaceNormalMap=1;l.CubeGeometry=Kb;l.Face4=function(a,b,c,d,e,f,g){console.warn("THREE.Face4 has been removed. A THREE.Face3 will be created instead.");return new Xa(a,b,c,e,f,g)};l.LineStrip=0;l.LinePieces=1;l.MeshFaceMaterial=function(a){console.warn("THREE.MeshFaceMaterial has been removed. Use an Array instead.");return a};l.MultiMaterial=function(a){void 0===a&&(a=[]); +console.warn("THREE.MultiMaterial has been removed. Use an Array instead.");a.isMultiMaterial=!0;a.materials=a;a.clone=function(){return a.slice()};return a};l.PointCloud=function(a,b){console.warn("THREE.PointCloud has been renamed to THREE.Points.");return new Sb(a,b)};l.Particle=function(a){console.warn("THREE.Particle has been renamed to THREE.Sprite.");return new Ec(a)};l.ParticleSystem=function(a,b){console.warn("THREE.ParticleSystem has been renamed to THREE.Points.");return new Sb(a,b)};l.PointCloudMaterial= +function(a){console.warn("THREE.PointCloudMaterial has been renamed to THREE.PointsMaterial.");return new Ga(a)};l.ParticleBasicMaterial=function(a){console.warn("THREE.ParticleBasicMaterial has been renamed to THREE.PointsMaterial.");return new Ga(a)};l.ParticleSystemMaterial=function(a){console.warn("THREE.ParticleSystemMaterial has been renamed to THREE.PointsMaterial.");return new Ga(a)};l.Vertex=function(a,b,c){console.warn("THREE.Vertex has been removed. Use THREE.Vector3 instead.");return new p(a, +b,c)};l.DynamicBufferAttribute=function(a,b){console.warn("THREE.DynamicBufferAttribute has been removed. Use new THREE.BufferAttribute().setDynamic( true ) instead.");return(new I(a,b)).setDynamic(!0)};l.Int8Attribute=function(a,b){console.warn("THREE.Int8Attribute has been removed. Use new THREE.Int8BufferAttribute() instead.");return new sc(a,b)};l.Uint8Attribute=function(a,b){console.warn("THREE.Uint8Attribute has been removed. Use new THREE.Uint8BufferAttribute() instead.");return new tc(a,b)}; +l.Uint8ClampedAttribute=function(a,b){console.warn("THREE.Uint8ClampedAttribute has been removed. Use new THREE.Uint8ClampedBufferAttribute() instead.");return new uc(a,b)};l.Int16Attribute=function(a,b){console.warn("THREE.Int16Attribute has been removed. Use new THREE.Int16BufferAttribute() instead.");return new vc(a,b)};l.Uint16Attribute=function(a,b){console.warn("THREE.Uint16Attribute has been removed. Use new THREE.Uint16BufferAttribute() instead.");return new lb(a,b)};l.Int32Attribute=function(a, +b){console.warn("THREE.Int32Attribute has been removed. Use new THREE.Int32BufferAttribute() instead.");return new wc(a,b)};l.Uint32Attribute=function(a,b){console.warn("THREE.Uint32Attribute has been removed. Use new THREE.Uint32BufferAttribute() instead.");return new mb(a,b)};l.Float32Attribute=function(a,b){console.warn("THREE.Float32Attribute has been removed. Use new THREE.Float32BufferAttribute() instead.");return new z(a,b)};l.Float64Attribute=function(a,b){console.warn("THREE.Float64Attribute has been removed. Use new THREE.Float64BufferAttribute() instead."); +return new xc(a,b)};l.ClosedSplineCurve3=Af;l.SplineCurve3=Bf;l.Spline=Be;l.AxisHelper=function(a){console.warn("THREE.AxisHelper has been renamed to THREE.AxesHelper.");return new qd(a)};l.BoundingBoxHelper=function(a,b){console.warn("THREE.BoundingBoxHelper has been deprecated. Creating a THREE.BoxHelper instead.");return new Gb(a,b)};l.EdgesHelper=function(a,b){console.warn("THREE.EdgesHelper has been removed. Use THREE.EdgesGeometry instead.");return new W(new ec(a.geometry),new T({color:void 0!== +b?b:16777215}))};l.WireframeHelper=function(a,b){console.warn("THREE.WireframeHelper has been removed. Use THREE.WireframeGeometry instead.");return new W(new Ub(a.geometry),new T({color:void 0!==b?b:16777215}))};l.XHRLoader=function(a){console.warn("THREE.XHRLoader has been renamed to THREE.FileLoader.");return new Ia(a)};l.BinaryTextureLoader=function(a){console.warn("THREE.BinaryTextureLoader has been renamed to THREE.DataTextureLoader.");return new ge(a)};l.GeometryUtils={merge:function(a,b,c){console.warn("THREE.GeometryUtils: .merge() has been moved to Geometry. Use geometry.merge( geometry2, matrix, materialIndexOffset ) instead."); +if(b.isMesh){b.matrixAutoUpdate&&b.updateMatrix();var d=b.matrix;b=b.geometry}a.merge(b,d,c)},center:function(a){console.warn("THREE.GeometryUtils: .center() has been moved to Geometry. Use geometry.center() instead.");return a.center()}};l.Projector=function(){console.error("THREE.Projector has been moved to /examples/js/renderers/Projector.js.");this.projectVector=function(a,b){console.warn("THREE.Projector: .projectVector() is now vector.project().");a.project(b)};this.unprojectVector=function(a, +b){console.warn("THREE.Projector: .unprojectVector() is now vector.unproject().");a.unproject(b)};this.pickingRay=function(){console.error("THREE.Projector: .pickingRay() is now raycaster.setFromCamera().")}};l.CanvasRenderer=function(){console.error("THREE.CanvasRenderer has been moved to /examples/js/renderers/CanvasRenderer.js");this.domElement=document.createElementNS("http://www.w3.org/1999/xhtml","canvas");this.clear=function(){};this.render=function(){};this.setClearColor=function(){};this.setSize= +function(){}};l.SceneUtils={createMultiMaterialObject:function(){console.error("THREE.SceneUtils has been moved to /examples/js/utils/SceneUtils.js")},detach:function(){console.error("THREE.SceneUtils has been moved to /examples/js/utils/SceneUtils.js")},attach:function(){console.error("THREE.SceneUtils has been moved to /examples/js/utils/SceneUtils.js")}};l.LensFlare=function(){console.error("THREE.LensFlare has been moved to /examples/js/objects/Lensflare.js")};Object.defineProperty(l,"__esModule", +{value:!0})}); diff --git a/js/scripts/touch-punch.min.js b/js/scripts/touch-punch.min.js new file mode 100644 index 00000000000..31272ce6fd9 --- /dev/null +++ b/js/scripts/touch-punch.min.js @@ -0,0 +1,11 @@ +/*! + * jQuery UI Touch Punch 0.2.3 + * + * Copyright 2011–2014, Dave Furfero + * Dual licensed under the MIT or GPL Version 2 licenses. + * + * Depends: + * jquery.ui.widget.js + * jquery.ui.mouse.js + */ +!function(a){function f(a,b){if(!(a.originalEvent.touches.length>1)){a.preventDefault();var c=a.originalEvent.changedTouches[0],d=document.createEvent("MouseEvents");d.initMouseEvent(b,!0,!0,window,1,c.screenX,c.screenY,c.clientX,c.clientY,!1,!1,!1,!1,0,null),a.target.dispatchEvent(d)}}if(a.support.touch="ontouchend"in document,a.support.touch){var e,b=a.ui.mouse.prototype,c=b._mouseInit,d=b._mouseDestroy;b._touchStart=function(a){var b=this;!e&&b._mouseCapture(a.originalEvent.changedTouches[0])&&(e=!0,b._touchMoved=!1,f(a,"mouseover"),f(a,"mousemove"),f(a,"mousedown"))},b._touchMove=function(a){e&&(this._touchMoved=!0,f(a,"mousemove"))},b._touchEnd=function(a){e&&(f(a,"mouseup"),f(a,"mouseout"),this._touchMoved||f(a,"click"),e=!1)},b._mouseInit=function(){var b=this;b.element.bind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b,"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),c.call(b)},b._mouseDestroy=function(){var b=this;b.element.unbind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b,"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),d.call(b)}}}(jQuery); \ No newline at end of file diff --git a/js/style/JSRootGeoPainter.css b/js/style/JSRootGeoPainter.css new file mode 100644 index 00000000000..6dcb47da28d --- /dev/null +++ b/js/style/JSRootGeoPainter.css @@ -0,0 +1,295 @@ +/* Interface stylesheet for JSROOT TGeo classes */ + +.jsroot .img_geoarb8 { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAJ0Uk5TAAB2k804AAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAAAEgAAABIAEbJaz4AAAB1SURBVBjTdY6rEYAwEETTy6lzK8/Fo+Jj18dTAjUgaQGfGiggtRDE8RtY93Zu514If2nzk2ux9c5TZkwXbiWTUavzws69oBfpYBrMT4r0Jhsw+QfRgQSw+CaKRsKsnV+SaF8MN49RBSgPUxO85PMl5n4tfGUH2gghs2uPAeQAAAAldEVYdGRhdGU6Y3JlYXRlADIwMTUtMTItMDJUMTQ6MjY6MjkrMDE6MDDARtd2AAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE0LTExLTEyVDA4OjM5OjE5KzAxOjAwO3ydwwAAAABJRU5ErkJggg=="); +} + +.jsroot .img_geocombi { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAJiS0dEAP+Hj8y/AAAACXBIWXMAAABIAAAASABGyWs+AAAAlUlEQVQoz5VQMQ4CMQyzEUNnBqT7Bo+4nZUH8gj+welWJsQDkHoCEYakTXMHSFiq2jqu4xRAEl2A7w4myWzpzCSZRZ658ldKu1hPnFsequBIc/hcLli3l52MAIANtpWrDsv8waGTW6BPuFtsdZArXyFuj33TQpazGEQF38phipnLgItxRcAoOeNpzv4PTXnC42fb//AGI5YqfQAU8dkAAAAldEVYdGRhdGU6Y3JlYXRlADIwMTUtMTItMDJUMTQ6MjY6MjkrMDE6MDDARtd2AAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE0LTExLTEyVDA4OjM5OjE5KzAxOjAwO3ydwwAAAABJRU5ErkJggg=="); +} + +.jsroot .img_geocone { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAJ0Uk5TAAB2k804AAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAAAEgAAABIAEbJaz4AAACRSURBVBjTdY+xDcNACEVvEm/ggo6Olva37IB0C3iEzJABvAHFTXBDeJRwthMnUvylk44vPjxK+afeokX0flQhJO7L4pafSOMxzaxIKc/Tc7SIjNLyieyZSjBzc4DqMZI0HTMonWPBNlogOLeuewbg9c0hOiIqH7DKmTCuFykjHe4XOzQ58XVMGxzt575tKzd6AX9yMkcWyPlsAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE1LTEyLTAyVDE0OjI2OjI5KzAxOjAwwEbXdgAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNC0xMS0xMlQwODozOToxOSswMTowMDt8ncMAAAAASUVORK5CYII="); +} + +.jsroot .img_geogtra { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAJ0Uk5TAAB2k804AAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAAAEgAAABIAEbJaz4AAACCSURBVBjTVc+hDQMxDAVQD1FyqCQk0MwsCwQEG3+eCW6B0FvheDboFMGepTlVitPP/Cz5y0S/mNkw8pySU9INJDDH4vM4Usm5OrQXasXtkA+tQF+zxfcDY8EVwgNeiwmA37TEccK5oLOwQtuCj7BM2Fq7iGrxVqJbSsH+GzXs+798AThwKMh3/6jDAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE1LTEyLTAyVDE0OjI2OjI5KzAxOjAwwEbXdgAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNC0xMS0xMlQwODozOToxOSswMTowMDt8ncMAAAAASUVORK5CYII="); +} + +.jsroot .img_geomedium { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAABVQTFRFAAAAAAAAMDAww8PDWKj/////gICAG0/C4AAAAAF0Uk5TAEDm2GYAAAABYktHRAX4b+nHAAAACXBIWXMAAABIAAAASABGyWs+AAAAXElEQVQI102MwRGAMAgEuQ6IDwvQCjQdhAl/H7ED038JHhkd3dcOLAgESFARaAqnEB3yrj6QSEym1RbbOKinN+8q2Esui1GaX7VXSi4RUbxHRbER8X6O5Pg/fLgBBzMN8HfXD3AAAAAldEVYdGRhdGU6Y3JlYXRlADIwMTUtMTItMDJUMTQ6MjY6MjkrMDE6MDDARtd2AAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE0LTExLTEyVDA4OjM5OjE5KzAxOjAwO3ydwwAAAABJRU5ErkJggg=="); +} + +.jsroot .img_geopara { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAJ0Uk5TAAB2k804AAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAAAEgAAABIAEbJaz4AAABtSURBVBjTY2DADq5MT7+CzD9kaKjp+QhJYIWqublhMbKAgpOnZxWSQJdsVJTndCSBKoWoAM/VSALpqlEBAYeQBKJAAsi2BGgCBZDdEWUYFZCOLFBlGOWJ7AyGFeaotjIccopageK3R12PGHABACTYHWd0tGw6AAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE1LTEyLTAyVDE0OjI2OjI5KzAxOjAwwEbXdgAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNC0xMS0xMlQwODozOToxOSswMTowMDt8ncMAAAAASUVORK5CYII="); +} + +.jsroot .img_georotation { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAJiS0dEAP+Hj8y/AAAACXBIWXMAAABIAAAASABGyWs+AAAAiklEQVQoz2NgYGBgYGDg+A/BmIAFIvyDEbs0AwMTAwHACLPiB5QVBTdpGSOSCZjScDcgc4z+32BgYGBgEGIQw3QDLkdCTZD8/xJFeBfDVxQT/j9n/MeIrMCNIRBJwX8GRuzGM/yHKMAljeILNFOuMTyEisEUMKIqucrwB2oyIhyQpH8y/MZrLWkAAHFzIHIc0Q5yAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE1LTEyLTAyVDE0OjI2OjI5KzAxOjAwwEbXdgAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNC0xMS0xMlQwODozOToxOSswMTowMDt8ncMAAAAASUVORK5CYII="); +} + +.jsroot .img_geotranslation { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAJ0Uk5TAAB2k804AAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAAAEgAAABIAEbJaz4AAABESURBVBjTY2DgYGAAYzjgAAIQgSLAgSwAAcrWUUCAJBAVhSpgBAQumALGCJPAAsriHIS0IAQ4UAU4cGphQBWwZSAOAADGJBKdZk/rHQAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxNS0xMi0wMlQxNDoyNjoyOSswMTowMMBG13YAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTQtMTEtMTJUMDg6Mzk6MTkrMDE6MDA7fJ3DAAAAAElFTkSuQmCC"); +} + +.jsroot .img_geotrd2 { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAJ0Uk5TAAB2k804AAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAAAEgAAABIAEbJaz4AAABsSURBVBjTbY+xDcAwCARZx6UraiaAmpoRvIIb75PWI2QITxIiRQKk0CCO/xcA/NZ9LRs7RkJEYg3QxczUwoGsXiMAoe8lAelqRWFNKpiNXZLAalRDd0f3TMgeMckABKsCDmu+442RddeHz9cf9jUkW8smGn8AAAAldEVYdGRhdGU6Y3JlYXRlADIwMTUtMTItMDJUMTQ6MjY6MjkrMDE6MDDARtd2AAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE0LTExLTEyVDA4OjM5OjE5KzAxOjAwO3ydwwAAAABJRU5ErkJggg=="); +} + +.jsroot .img_geovolume { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAB5QTFRFAAAAMDAw///Ay8uc/7+Q/4BgmJh4gIDgAAD/////CZb2ugAAAAF0Uk5TAEDm2GYAAAABYktHRAnx2aXsAAAACXBIWXMAAABIAAAASABGyWs+AAAAR0lEQVQI12NggAEBIBAEQgYGQUYQAyIGIhgwAZMSGCgwMJuEKimFOhswsKWAGG4JDGxJIBk1EEO9o6NIDVkEpgauC24ODAAASQ8Pkj/retYAAAAldEVYdGRhdGU6Y3JlYXRlADIwMTUtMTItMDJUMTQ6MjY6MjkrMDE6MDDARtd2AAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE0LTExLTEyVDA4OjM5OjE5KzAxOjAwO3ydwwAAAABJRU5ErkJggg=="); +} + +.jsroot .img_geoassembly { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAA9QTFRFAAAAMDAw/wAAAAD/////jEo0BQAAAAF0Uk5TAEDm2GYAAAABYktHRASPaNlRAAAACXBIWXMAAABIAAAASABGyWs+AAAAOklEQVQI12NggAFGRgEgEBRgEBSAMhgYGQQEgAR+oARGDIwCIAYjUL0A2DQQg9nY2ABVBKoGrgsDAADxzgNboMz8zQAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxNS0xMi0wMlQxNDoyNjoyOSswMTowMMBG13YAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTQtMTEtMTJUMDg6Mzk6MTkrMDE6MDA7fJ3DAAAAAElFTkSuQmCC"); +} + +.jsroot .img_geocomposite { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAJ0Uk5TAAB2k804AAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAAAEgAAABIAEbJaz4AAABuSURBVBjTY2AgF2hqgQCCr+0V4O7hFmgCF7CJyKysKkmxhfGNLaw9SppqAi2gfMuY5Agrl+ZaC6iAUXRJZX6Ic0klTMA5urapPFY5NRcmYKFqWl8S5RobBRNg0PbNT3a1dDGH8RlM3LysTRjIBwAG6xrzJt11BAAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxNS0xMi0wMlQxNDoyNjoyOSswMTowMMBG13YAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTQtMTEtMTJUMDg6Mzk6MTkrMDE6MDA7fJ3DAAAAAElFTkSuQmCC"); +} + +.jsroot .img_geoctub { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAJ0Uk5TAAB2k804AAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAAAEgAAABIAEbJaz4AAACESURBVBjTdc+xDcMwDARA7cKKHTuWX37LHaw+vQbQAJomA7j2DB7FhCMFCZB8pxPwJEv5kQcZW+3HencRBekak4aaMQIi8YJdAQ1CMeE0UBkuaLMETklQ9Alhka0JzzXWqLVBuQYPpWcVuBbZjZafNRYcDk9o/b07bvhINz+/zxu1/M0FSRcmAk/HaIcAAAAldEVYdGRhdGU6Y3JlYXRlADIwMTUtMTItMDJUMTQ6MjY6MjkrMDE6MDDARtd2AAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE0LTExLTEyVDA4OjM5OjE5KzAxOjAwO3ydwwAAAABJRU5ErkJggg=="); +} + +.jsroot .img_geohype { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAJ0Uk5TAAB2k804AAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAAAEgAAABIAEbJaz4AAACKSURBVBjTbU+rFQQhDKQSDDISEYuMREfHx6eHKMpYuf5qoIQt5bgDblfcuJk3nySEhSvceDV3c/ejT66lspopE9pXyIlkCrHMBACpu1DClekQAREi/loviCnF/NhRwJLaQ6hVhPjB8bOCsjlnNnNl0FWJVWxAqGzHONRHpu5Ml+nQ+8GzNW9n+Is3eg80Nk0iiwoAAAAldEVYdGRhdGU6Y3JlYXRlADIwMTUtMTItMDJUMTQ6MjY6MjkrMDE6MDDARtd2AAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE0LTExLTEyVDA4OjM5OjE5KzAxOjAwO3ydwwAAAABJRU5ErkJggg=="); +} + +.jsroot .img_geomixture { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAACFQTFRFAAAAAAAAKysrVVUA//8B//8AgICAqqpV398gv79A////VYJtlwAAAAF0Uk5TAEDm2GYAAAABYktHRApo0PRWAAAACXBIWXMAAABIAAAASABGyWs+AAAAXklEQVQI12NgwASCQsJCgoZAhoADq1tKIJAhEpDGxpYIZKgxsLElgBhibAkOCY4gKTaGkPRGIEPUIYEBrEaAIY0tDawmgYWNgREkkjCVjRWkWCUhLY0FJCIIBljsBgCZTAykgaRiRwAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxNS0xMi0wMlQxNDoyNjoyOSswMTowMMBG13YAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTQtMTEtMTJUMDg6Mzk6MTkrMDE6MDA7fJ3DAAAAAElFTkSuQmCC"); +} + +.jsroot .img_geopcon { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAJ0Uk5TAAB2k804AAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAAAEgAAABIAEbJaz4AAACJSURBVBjTdc+hGcQwCIZhhjl/rkgWiECj8XgGyAbZoD5LdIRMkEnKkV575n75Pp8AgLU54dmh6mauelyAL2Qzxfe2sklioq6FacFAcRFXYhwJHdU5rDD2hEYB/CmoJVRMiIJqgtENuoqA8ltAlYAqRH4d1tGkwzTqN2gA7Nv+fUwkgZ/3mg34txM+szzATJS1HQAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxNS0xMi0wMlQxNDoyNjoyOSswMTowMMBG13YAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTQtMTEtMTJUMDg6Mzk6MTkrMDE6MDA7fJ3DAAAAAElFTkSuQmCC"); +} + +.jsroot .img_geosphere { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAJ0Uk5TAAB2k804AAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAAAEgAAABIAEbJaz4AAACFSURBVBjTdY+xEcQwCAQp5QNFjpQ5vZACFBFTADFFfKYCXINzlUAJruXll2ekxDAEt9zcANFbXb2mqm56dxsymAH0yccAJaeNi0h5QGyfxGJmivMPjj0nmLsbRmyFCss3rlbpcUjfS8wLUNRcJyCF6uqg2IvYCnoKC7f1kSbA6riTz7evfwj3Ml+H3KBqAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE1LTEyLTAyVDE0OjI2OjI5KzAxOjAwwEbXdgAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNC0xMS0xMlQwODozOToxOSswMTowMDt8ncMAAAAASUVORK5CYII="); +} + +.jsroot .img_geotrap { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAJ0Uk5TAAB2k804AAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAAAEgAAABIAEbJaz4AAAB5SURBVBjTbY+hFYAwDETZB1OJi4yNPp0JqjtAZ2AELL5DdABmIS2PtLxHXH7u7l2W5W+uHMHpGiCHLYR1yw4SCZMIXBOJWVSjK7QDDAu4g8OBmAKK4sAEDdR3rw8YmcUcrEijKKhl7lN1IQPn9ExlgU6/WEyc75+5AYK0KY5oHBDfAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE1LTEyLTAyVDE0OjI2OjI5KzAxOjAwwEbXdgAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNC0xMS0xMlQwODozOToxOSswMTowMDt8ncMAAAAASUVORK5CYII="); +} + +.jsroot .img_geotubeseg { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAJ0Uk5TAAB2k804AAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAAAEgAAABIAEbJaz4AAACBSURBVBjTdc+hEcQwDARA12P6QFBQ9LDwcXEVkA7SQTr4BlJBakgpsWdsh/wfux3NSCrlV86Mlrxmz1pBWq3bAHwETohxABVmDZADQp1BE+wDNnGywzHgmHDOreJNTDH3Xn3CVX0dpu2MHcIFBkYp/gKsQ8SCQ72V+36/+2aWf3kAQfgshnpXF0wAAAAldEVYdGRhdGU6Y3JlYXRlADIwMTUtMTItMDJUMTQ6MjY6MjkrMDE6MDDARtd2AAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE0LTExLTEyVDA4OjM5OjE5KzAxOjAwO3ydwwAAAABJRU5ErkJggg=="); +} + +.jsroot .img_geoxtru { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAJ0Uk5TAAB2k804AAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAAAEgAAABIAEbJaz4AAABcSURBVBjTY2AgEmhpeZV56vmWwQW00QUYwAJlSAI6XmVqukh8PT1bT03PchhXX09Pr9wQIQDiJ+ZowgWAXD3bck+QQDlCQTkDQgCoxA/ERBKwhbDglgA1lDMQDwCc/Rvq8nYsWgAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxNS0xMi0wMlQxNDoyNjoyOSswMTowMMBG13YAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTQtMTEtMTJUMDg6Mzk6MTkrMDE6MDA7fJ3DAAAAAElFTkSuQmCC"); +} + +.jsroot .img_geobbox { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAJ0Uk5TAAB2k804AAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAAAEgAAABIAEbJaz4AAAB/SURBVBjTVc+hEYAwDAXQLlNRF1tVGxn9NRswQiSSCdgDyQBM0FlIIb2WuL77uf6E8E0N02wKYRwDciTKREVvB04GuZSyOMCABRB1WGzF3uDNQTvs/RcDtJXT4fSEXA5XoiQt0ttVSm8Co2psIOvoimjAOqBmFtH5wEP2373TPIvTK1nrpULXAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE1LTEyLTAyVDE0OjI2OjI5KzAxOjAwwEbXdgAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNC0xMS0xMlQwODozOToxOSswMTowMDt8ncMAAAAASUVORK5CYII="); +} + +.jsroot .img_geoconeseg { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAJ0Uk5TAAB2k804AAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAAAEgAAABIAEbJaz4AAAB4SURBVBjTdc6hEcAgDAXQbFNZXHQkFlkd/30myAIMwAws0gmYpVzvoFyv/S5P/B+izzQ387ZA2pkDnvsU1SQLVIFrOM4JFmEaYp2gCQbmPEGODhJ8jt7Am47hwgrzInGAifa/elUZnQLY00iU30BZAV+BWi2VfnIBv1osbHH8jX0AAAAldEVYdGRhdGU6Y3JlYXRlADIwMTUtMTItMDJUMTQ6MjY6MjkrMDE6MDDARtd2AAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE0LTExLTEyVDA4OjM5OjE5KzAxOjAwO3ydwwAAAABJRU5ErkJggg=="); +} + +.jsroot .img_geoeltu { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAJ0Uk5TAAB2k804AAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAAAEgAAABIAEbJaz4AAACGSURBVBjTdY+hFYUwDEU7xq9CIXC4uNjY6KczQXeoYgVMR2ABRmCGjvIp/6dgiEruueedvBDuOR57LQnKyc8CJmKO+N8bieIUPtmBWjIIx8XDBHYCipsnql1g2D0UP2OoDqwBncf+RdZmzFMHizRjog7KZYzawd4Ay93lEAPWR7WAvNbwMl/XwSxBV8qCjgAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxNS0xMi0wMlQxNDoyNjoyOSswMTowMMBG13YAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTQtMTEtMTJUMDg6Mzk6MTkrMDE6MDA7fJ3DAAAAAElFTkSuQmCC"); +} + +.jsroot .img_geomaterial { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAJiS0dEAP+Hj8y/AAAACXBIWXMAAABIAAAASABGyWs+AAAAbElEQVQoz62QMRbAIAhDP319Xon7j54qHSyCtaMZFCUkRjgDIdRU9yZUCfg8ut5aAHdcxtoNurmgA3ABNKIR9KimhSukPe2qxcCYC0pfFXx/aFWo7i42KKItOpopqvvnLzJmtlZTS7EfGAfwAM4EQbLIGV0sAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE1LTEyLTAyVDE0OjI2OjI5KzAxOjAwwEbXdgAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNC0xMS0xMlQwODozOToxOSswMTowMDt8ncMAAAAASUVORK5CYII="); +} + +.jsroot .img_geoparab { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAJ0Uk5TAAB2k804AAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAAAEgAAABIAEbJaz4AAAB/SURBVBjTbY+xDYAwDAQ9UAp3X7p0m9o9dUZgA9oMwAjpMwMzMAnYBAQSX9mn9+tN9KOtzsWsLOvYCziUGNX3nnCLJRzKPgeYrhPW7FJNLUB3YJazYKQKTnBaxgXRzNmJcrt7XCHQp9kEB1wfELEir/KGj4Foh8A+/zW1nf51AFabKZuWK+mNAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE1LTEyLTAyVDE0OjI2OjI5KzAxOjAwwEbXdgAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNC0xMS0xMlQwODozOToxOSswMTowMDt8ncMAAAAASUVORK5CYII="); +} + +.jsroot .img_geopgon { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAJ0Uk5TAAB2k804AAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAAAEgAAABIAEbJaz4AAABwSURBVBjTY2AgDlwAAzh3sX1sPRDEeuwDc+8V2dsHgQQ8LCzq74HkLSzs7Yva2tLt7S3sN4MNiDUGKQmysCi6BzWkzcI+PdY+aDPCljZlj1iFOUjW1tvHLjYuQhJIt5/DcAFZYLH9YnSn7iPST9gAACbsJth21haFAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE1LTEyLTAyVDE0OjI2OjI5KzAxOjAwwEbXdgAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNC0xMS0xMlQwODozOToxOSswMTowMDt8ncMAAAAASUVORK5CYII="); +} + +.jsroot .img_geotorus { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAJ0Uk5TAAB2k804AAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAAAEgAAABIAEbJaz4AAACGSURBVBjTjY+hFcMwDEQ9SkFggXGIoejhw+LiGkBDlHoAr+AhgjNL5byChuXeE7gvPelUyjOds/f5Zw0ggfj5KVCPMBWeyx+SbQ1XUriAC2XfpWWxjQQEZasRtRHiCUAj3qN4JaolUJppzh4q7dUTdHFXW/tH9OuswWm3nI7tc08+/eGLl758ey9KpKrNOQAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxNS0xMi0wMlQxNDoyNjoyOSswMTowMMBG13YAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTQtMTEtMTJUMDg6Mzk6MTkrMDE6MDA7fJ3DAAAAAElFTkSuQmCC"); +} + +.jsroot .img_geotrd1 { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAJ0Uk5TAAB2k804AAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAAAEgAAABIAEbJaz4AAAB/SURBVBjTbc6xDQMhDAVQ9qH6lUtal65/zQ5IDMAMmYAZrmKGm4FJzlEQQUo+bvwkG4fwm9lbodV7w40Y4WGfSxQiXiJlQfZOjWRb8Ioi3tKuBQMCo7+9N72BzPsfAuoTdUP9QN8wgOQwvsfWmHzpeT5BKydMNW0nhJGvGf7mAc5WKO9e5N2dAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE1LTEyLTAyVDE0OjI2OjI5KzAxOjAwwEbXdgAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNC0xMS0xMlQwODozOToxOSswMTowMDt8ncMAAAAASUVORK5CYII="); +} + +.jsroot .img_geotube { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAJ0Uk5TAAB2k804AAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAAAEgAAABIAEbJaz4AAACGSURBVBjTRc+tEcAwCAXgLFNbWeSzSDQazw5doWNUZIOM0BEyS/NHy10E30HyklKvWnJ+0le3sJoKn3X2z7GRuvG++YRyMMDt0IIKUXMzxbnugJi5m9K1gNnGBOUFElAWGMaKIKI4xoQggl00gT+A9hXWgDwnfqgsHRAx2m+8bfjfdyrx5AtsSjpwu+M2RgAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxNS0xMi0wMlQxNDoyNjoyOSswMTowMMBG13YAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTQtMTEtMTJUMDg6Mzk6MTkrMDE6MDA7fJ3DAAAAAElFTkSuQmCC"); +} + +.jsroot .img_evepoints { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAABJQTFRF////n4mJcEdKRDMzcEdH////lLE/CwAAAAF0Uk5TAEDm2GYAAAABYktHRACIBR1IAAAACXBIWXMAAABIAAAASABGyWs+AAAAI0lEQVQI12NgIAowIpgKEJIZLiAgAKWZGQzQ9UGlWIizBQgAN4IAvGtVrTcAAAAldEVYdGRhdGU6Y3JlYXRlADIwMTYtMDktMDJUMTU6MDQ6MzgrMDI6MDDPyc7hAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE2LTA5LTAyVDE1OjA0OjM4KzAyOjAwvpR2XQAAAABJRU5ErkJggg=="); +} + +.jsroot .img_evetrack { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAJiS0dEAP+Hj8y/AAAACXBIWXMAAABIAAAASABGyWs+AAAAqElEQVQoz32RMQrCQBBFf4IgSMB0IpGkMpVHCFh7BbHIGTyVhU0K8QYewEKsbVJZaCUiPAsXV8Puzhaz7H8zs5+JUDjikLilQr5zpCRl5xMXZNScQE5gSMGaz70jjUAJcw5c3UBMTsUe+9Kzf065SbropeLXimWfDIgoab/tOyPGzOhz53+oSWcSGh7UdB2ZNKXBZdgAuUdEKJYmrEILyVgG6pE2tEHgDfe42rbjYzSHAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE2LTA5LTAyVDE1OjA0OjQ3KzAyOjAwM0S3EQAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNi0wOS0wMlQxNTowNDo0NyswMjowMEIZD60AAAAASUVORK5CYII="); +} + +.jsroot .geovis_this { + background-color: lightgreen; +} + +.jsroot .geovis_daughters { + background-color: lightblue; +} + +.jsroot .geovis_all { + background-color: yellow; +} + +/* stylesheets for toolbar buttons */ +.jsroot .toolbar { + position: absolute; + bottom: 2px; + left: 2px; + z-index: 1001; + background: rgba(255, 255, 255, 0.7); +} + +.jsroot .toolbar-group { + float: left; + display: inline-block; + box-sizing: border-box; + position: relative; + bottom: 23px; + vertical-align: middle; + white-space: nowrap; +} + +.jsroot .toolbar-group:first-child { + margin-left: 2px; +} + +.jsroot .toolbar-group a { + position: relative; + font-size: 16px; + padding: 3px 1px; + cursor: pointer; + line-height: normal; + box-sizing: border-box; +} + +.jsroot .toolbar-group a svg { + position: relative; + top: 2px; +} + +.jsroot .toolbar-btn path { + fill: rgba(0, 31, 95, 0.2); +} + +.jsroot .toolbar-btn path .active, +.jsroot .toolbar-btn path:hover { + fill: rgba(0, 22, 72, 0.5); +} + +.jsroot .toolbar-btn-bright path { + fill: rgba(255, 224, 160, 0.2); +} + +.jsroot .toolbar-btn-bright path .active, +.jsroot .toolbar-btn-bright path:hover { + fill: rgba(255, 233, 183, 0.5); +} + +.geo_info { + position: absolute; + text-align: center; + vertical-align: middle; + top: 45%; + left: 40%; + color: red; + font-size: 150%; +} diff --git a/js/style/JSRootPainter.css b/js/style/JSRootPainter.css new file mode 100644 index 00000000000..715a87b092d --- /dev/null +++ b/js/style/JSRootPainter.css @@ -0,0 +1,707 @@ +/* Interface stylesheet for Javascript ROOT Web Page. */ + +.jsroot .h_tree { + display: block; + white-space: nowrap; +} + +.jsroot .h_tree * { + padding: 0; + margin: 0; + font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; + box-sizing: content-box; + line-height: 14px +} + +.jsroot .h_tree img { + border: 0px; + vertical-align: middle; +} + +.jsroot .h_tree a { + white-space: nowrap; + text-decoration: none; + vertical-align: top; + white-space: nowrap; + padding: 1px 2px 0px 2px; + display: inline-block; + margin: 0; +} + +.jsroot .h_tree p { + font-weight: bold; + white-space: nowrap; + text-decoration: none; + vertical-align: top; + white-space: nowrap; + padding: 1px 2px 0px 2px; + display: inline-block; + margin: 0; +} + +.jsroot .h_value_str { + color: green; +} + +.jsroot .h_value_num { + color: blue; +} + +.jsroot .h_line { + height: 18px; + display: block; +} + +.jsroot .h_button { + cursor: pointer; + color: blue; + text-decoration: underline; +} + +.jsroot .h_item { + cursor: pointer; +} + +.jsroot .h_item:hover { + text-decoration: underline; +} + +.jsroot .h_childs { + overflow: hidden; + display: block; +} + +.jsroot .img_minus { + display: inline-block; + height: 18px; + width: 18px; + background-image: url("data:image/gif;base64, R0lGODlhEgASAJEDAIKCgoCAgAAAAP///yH5BAEAAAMALAAAAAASABIAAAInnD+By+2rnpyhWvsizE0zf4CIIpRlgiqaiDosa7zZdU22A9y6u98FADs="); +} + +.jsroot .img_minusbottom { + display: inline-block; + height: 18px; + width: 18px; + background-image: url("data:image/gif;base64, R0lGODlhEgASAJECAICAgAAAAP///wAAACH5BAEAAAIALAAAAAASABIAAAImlC+Ay+2rnpygWvsizE0zf4CIEpRlgiqaiDosa7zZdU32jed6XgAAOw=="); +} + +.jsroot .img_plus { + display: inline-block; + height: 18px; + width: 18px; + background-image: url("data:image/gif;base64, R0lGODlhEgASAJECAICAgAAAAP///wAAACH5BAEAAAIALAAAAAASABIAAAIqlC+Ay+2rnpygWvsizCcczWieAW7BeSaqookfZ4yqU5LZdU06vfe8rysAADs="); +} + +.jsroot .img_plusbottom { + display: inline-block; + height: 18px; + width: 18px; + background-image: url("data:image/gif;base64, R0lGODlhEgASAJECAICAgAAAAP///wAAACH5BAEAAAIALAAAAAASABIAAAIplC+Ay+2rnpygWvsizCcczWieAW7BeSaqookfZ4yqU5LZdU36zvd+XwAAOw=="); +} + +.jsroot .img_empty { + display: inline-block; + height: 18px; + width: 18px; + background-image: url("data:image/gif;base64, R0lGODlhEgASAJEAAAAAAP///4CAgP///yH5BAEAAAMALAAAAAASABIAAAIPnI+py+0Po5y02ouz3pwXADs="); +} + +.jsroot .img_line { + display: inline-block; + height: 18px; + width: 18px; + background-image: url("data:image/gif;base64, R0lGODlhEgASAIABAICAgP///yH5BAEAAAEALAAAAAASABIAAAIZjB+Ay+2rnpwo0uss3kfz7X1XKE5k+ZxoAQA7"); +} + +.jsroot .img_join { + display: inline-block; + height: 18px; + width: 18px; + background-image: url("data:image/gif;base64, R0lGODlhEgASAIABAICAgP///yH5BAEAAAEALAAAAAASABIAAAIcjB+Ay+2rnpwo0uss3kf5BGocNJZiSZ2opK5BAQA7"); +} + +.jsroot .img_joinbottom { + display: inline-block; + height: 18px; + width: 18px; + background-image: url("data:image/gif;base64, R0lGODlhEgASAIABAICAgP///yH5BAEAAAEALAAAAAASABIAAAIZjB+Ay+2rnpwo0uss3kf5BGrcSJbmiaZGAQA7"); +} + +.jsroot .img_base { + display: inline-block; + height: 18px; + width: 18px; + background-image: url("data:image/gif;base64, R0lGODlhEwASAPcAAPv6/Pn4+mnN/4zf/764x2vO//Dv84HZ/5jl/0ZGmfTz9vLy8lHB/+zr70u+/7S03IODtd7d6c/P0ndqiq/w/4Pb/5SKo/Py9fPy9tTU121kjd/f4MzM062tx5+zy5rO67GwxNDM14d8mJzn/7awwry713zX/9bW27u71lFRmW5uoZ+fxjOy/zm1/9HQ2o3g/2xfgZeMplav7sn9/6Cgv37X/6Dp/3jU/2uJ2M7J1JC63vn5+v38/d7e38PD0Z7o/9LR4LS01cPDzPb1+Nzb5IJ2lHCEv5bk/53C3MrJ3X56t+np6YF7o3JsndTU5Wtgh5GHoKaesuLi4mrO/19RdnnV/4WBqF5QdWPK/4+PvW5uu4+PuuHh4q7w/97e68C9z63w/9PT0+zs7FtbmWVXerS0yaqitpuSqWVlpcL6/8jD0H/C9mVajqWu3nFwpYqHtFfE/42DnaWl0bTz/5OPt+7u7tra5Y+Yz+Tk56fM6Gek5pG50LGpvOHh72LJ/9XU5lbD/6GnwHpujfDu8mxpntzb45qav7PH41+n6JeXyUZGopyYsWeGyDu2/6LQ44re/1yV41TD/8LC1zix/sS/zdTU4Y+gsd/c5L7z+a6uzE+3+XG89L6+087O1sTD3K2twoGBtWVbgomo4P///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAKMALAAAAAATABIAAAjtAEcJFLgDTyE7SVCsAAJgoMNRYTII8fEpkAckOpiEaPhwlARLexxhmpEGzJEmBAJ0HMXhw6MfXeZQsDHADZ8hK13kMTEAwQgEL2oYiaJgJZFDU24cqHCgSgFGFgysBJAJkB8BBQRggQNJxKCVo0rIcMAgEgMHmnBMaADWEyIWLRptEqWETRG2K//ombSmjRZFoaCo4djRyZ0HchIlSECIRNGVXur0WcAlCJoUoOhcAltpyQIxPSRtGQPhjRkMKyN0krLhBCcaKrJoOCO1I48vi0CU6WDIyhNBKcEGyBEDBpUrZOJQugC2ufPnDwMCADs="); +} + +.jsroot .img_folder { + display: inline-block; + height: 18px; + width: 18px; + background-image: url("data:image/gif;base64, R0lGODlhEgASANUAAPv7++/v79u3UsyZNOTk5MHBwaNxC8KPKre3t55sBrqHIpxqBMmWMb2KJbOBG5lnAdu3cbWCHaBuCMuYM///urB+GMWSLad1D8eUL6ampqVzDbeEH6t5E8iVMMCNKMbGxq58FppoAqh2EKx6FP/Ub//4k+vr6///nP/bdf/kf//viba2tv//////mQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAC4ALAAAAAASABIAAAaRQJdwSCwaj8ik0jUYTBidAEA5YFkplANhehxABGAwpKHYRByVwHBibbvbo8+Q0TrZ7/jWBTHEtP6AgX8GK0MWLSWJiostEoVCBy0qk5SVLQmPLh4tKZ2eny0LmQ0tKKanqC0hmQotJK+wsS0PfEIBZxUgHCIaBhIJCw8ZBUMABAUrycrLBQREAAEm0tPUUktKQQA7"); +} + +.jsroot .img_folderopen { + display: inline-block; + height: 18px; + width: 18px; + background-image: url("data:image/gif;base64, R0lGODlhEgASANUAAO/v76VzDfv7+8yZNMHBweTk5JpoAqBuCMuYM8mWMZ5sBpxqBPr7/Le3t///pcaaGvDker2KJc+iJqd1D7B+GOKzQ8KPKqJwCrOBG7WCHbeEH9e4QNq/bP/rhJlnAffwiaampuLBUMmgIf3VcKRyDP/XhLqHIqNxC8iVMMbGxqx6FP/kf//bdf/vievr67a2tv/4k8aaGf//nP//mf///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAADUALAAAAAASABIAAAaVwJpwSCwaj8ikUjgYIBIogEA5oFkZDEtheqzKvl9axKTJYCiAIYIGblutqtQwQYPZ73jZpCGM+f+AfiEdJy99M21tMxwxJQeGNTGIeHcyHzEjCpAAki2en54OIhULkAKSMiuqqysOGxIGkDWcMyy2t7YQDx58QqcBwMAkFwcKCwYgBEQFBC/Oz9AEBUUALtbX2FJLSUEAOw=="); +} + +.jsroot .img_page { + display: inline-block; + height: 18px; + width: 18px; + background-image: url("data:image/gif;base64, R0lGODlhEgASAOYAAPv7++/v7/j7/+32/8HBweTk5P39/djr/8Df//7///P5/8Ph//T09fn5+YGVw2t0pc7n/15hkFWn7ZOq0nqDsMDA/9nh7YSbyoqo2eTx/5G46pK873N+sPX6//f395Cjy83m/7rd/9jl9m13qGVqmoeh0n+OvI+z5Yyu387T//b6/2dtnvz9/32JtpS/8sbGxv7+/tvn92lwom96rHJ8rnSAsoep3NHp/8nk/7e3t+vr67a2tun1/3V4o+Hw/9vt/////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAEEALAAAAAASABIAAAejgEGCg4SFhoeILjaLjDY1AQCHG0AGAA0eDBY1E5CGGjBAoQkCMTUSHwGGJwaiAh0iNbEvhiihAgIDPDwpFRw5hhgsuLk8Pz8HNL+FJSoKuT4+xzczyoQXzjzQxjcgI9WDDrraPzc4OA/fgibZ0eTmCzLpQS0Z7TflCwgr8hT2EOYIQpCQ16OgwYMRCBgqQGCHw4cOCRQwBCCAjosYL3ZCxNFQIAA7"); +} + +.jsroot .img_question { + display: inline-block; + height: 18px; + width: 18px; + background-image: url("data:image/gif;base64, R0lGODlhEgASAPelAOP0//7//9bs//n///j//9Ls/8Pn//r//6rB1t3f5crO2N7g5k1livT4+7PW9dXt/+v4/+Xl5LHW9Ov6/+j1/6CyxrfCz9rd5Nzj6un1/Z6ouwcvj8HBzO7+/+3//+Ln7BUuXNHv/6K4y+/9/wEBZvX08snn/19qhufs8fP7/87n/+/t7czr/5q1yk55q97v/3Cfztnu//z//+X6/ypIdMHY7rPc/7fX9cbl/9/h52WHr2yKrd/0/9fw/4KTs9rm75Svzb2+ya690pu92mWJrcT3//H//+Dv/Xym35S216Ouwsvt/3N/mMnZ5gEBcMnq/wEBXs/o/wEBetzw/zdYpTdZpsvP2ClGml2N3b3H0Nzu/2Z2lF1ricrl/93w/97h6JqluktojM/u/+/z9g8pVff4+ebu9q+1xa6/zzdFaIiXr5Wyz0xslrTK4uL//2uIp11rh8Xj/NXn+Oz2/9bf6bG2xAEBePP//1xwkK/K5Nbr/8fp/2OBtG53kai3ykVCYwEBde/6/7O4xabI+fD//+by/x8+jDhZpM/q/6jK58nO19ny/7jV7ZO42NHr/9H4/2ZwimSV6VBxwMDX7Nvf5hYwX5m20sfb6Ieqyk9Yjr/k/cPM2NDp/+/098Tl9yQ9jLfW+Mne8sjU30JklP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAKUALAAAAAASABIAAAjxAEsJHEiwoMEyGMaQWthg0xeDAlGUWKjoz5mFAegY/LBiIalMUK54JCWEoJkIpA6kSDmoAykKgRaqGSiq04A5A5r4AKOEAAAtE2S0USAwSwYIhUb8METiUwAvemLMCMVEoIUjAF5MIYXAThUCDzgVWDQJjkA0cngIEHAHCCAqRqJ0QeQoDxeBFS71KKDCwxonhwiZwPEkzo4+AimJqBFCjBs+UjZ4WmLgxhAQVgb6acGIBShJkbAgMSAhCQ1IBTW8sZRI055HDhoRqXQCYo4tDMJgsqGDTJo6EAlyYFNkVJDgBgXBcJEAucEFeC44n04wIAA7"); +} + +.jsroot .img_histo1d { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/gif;base64, iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAADAFBMVEW9vb2np6empqanpqenpqivr6//AAD3+fn09vb19vf3+Pv8+v//+//29/v3+fr19vbZ3Nza3d7X0+Lb3t7b3N3AwMP2+PimpqXe4+Th6uvQ0dTi6uzg5ebFx8nt6vb////r5/T2+fnl4e3a3uDN0NT7/P6lpqX3+vvn9vhcVVHu+//W1uH48//29P///f+mpqelpqb4/v/t/f9oY2H6///59v/x8fXw9fny9/78/v+lpqf7//9iXl12dHPW2t/R1tdtaGbT2dpoZmT6/v9ycnKCgoJpZGJ6dnT3///2///0//95entpa2t+gIKLjI55d3aDgYBvcXL1+/z9/v6lpaWGiIt7fH6Ji42SlJeEhIZubGyMjI17fYD+//+kpKSmpaaRk5WIioyRk5aYmp2OkJJ+f4KTlZilpKWcnqGVl5qcnqCfoaOYmp6PkZOdn6GsrrGoqq6qrK+rrbGpq66lp6uqrbCoqq20tLSsrKzc3NzMzMzPz88AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB6enrU4/9iYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmLU4/9KSkoAAAAAAAAAAAB6enrU4//m5uZiYmLm5uZiYmLm5uZiYmLm5uZiYmLm5ubU4/9KSkoAAAAAAAAAAAB6enrU4/9KSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkrU4/9KSkoAAAAAAAAAAABubm7U4//U4//U4//U4//U4//U4//U4//U4//U4//U4//U4/9KSkoAAAAAAAAAAABubm5KSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkpKSkoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABt6dBwBYjWHVG2AAAAB3RSTlP///////8AGksDRgAAAAlwSFlzAAALEgAACxIB0t1+/AAAAOxJREFUeNpjYGBkggBmFmYmRlY2BkZ2DhDg5OLm4eblY2RjYOIXEBQSFhEFkgKCYkxsDOKcEpJS0jKycvJS8gpcIAFFJWUVGFIFCqipa8hrymtpy+sI6crr6bMxGBgayRvLm8iamkmZW1gCBayslWxs7ewd7OwdlZStrYC2ODm7uLrJu3t4usl7mRiwMeh7+/j6+VsHBMr7+wQFhwAFQsPCIyKjomOiIsOiYuPYGOITEpOSU1LTElNTElPlgQLpGZlZ2Tm5eZm5OZm5IAGm/ILCouKS0rKS4oISeaDDypniEICpgo2hsgoZVLMBAHIaNxuoIXy2AAAAAElFTkSuQmCC"); +} + +.jsroot .img_histo2d { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/gif;base64, iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAACXBIWXMAAAsSAAALEgHS3X78AAABUUlEQVR42o1R0U7CQBDkU/w/v8qk1/OhCS+88miMiQYMBMNRTqiisQiRhF6h13adsuVKDEYvm81kdmdv9q7V7XallP65I30UrpErLGW73SaiFtDF5dXWmNNITJrubJ4RWUI2qU33GTorAdSJMeMwhOxpEE20noRTYISaajBcMrsdOlkgME+/vILtPw6j+BPg5vZuFRuUgZGX71tc2AjALuYrpWcP/WE1+ADAADMAY/OyFghfpJnlSTCAvLb1YDbJmArC5izwQa0K4g5EdgSbTQKTX8keOC8bgXSWAEbqmbs5BmPF3iyR8I+vdNrhIj3ewzdnlaBeWroCDHBZxWtm9DzaEyU2L8pSCNEI+N76+fVs8rE8fbeRUiWR53kHgWgs6cXbD2OOIScQnji7g7OE2UVZNILflnbrulx/XKfTAfL+OugJgqAShGF4/7/T6/Ug+AYZrx7y3UV8agAAAABJRU5ErkJggg=="); +} + +.jsroot .img_histo3d { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/gif;base64, iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAADAFBMVEX////48OjIgTrHfjjKgTr78+yixH9HiQBHiACiw37jvJXfpVP6wzT7zTn7yj3lp1qOhyJzvgCa3wCa3gB2ugBinQ6Pt2D4+vfOjEr96p3986z83mT99rD99a3WhEvC0kaU3gCV3ADG71zo/KORzw1gowBonS3Z5snHfTb6uyD6tzD+/Nb7z0/70D3KdTXI1l3h+qTi+KXD7luU3ACY3gCc4QCi3g1QjwXHfjr710T6xi/+9sn70UH73E/MdDqhvQCi1BKkug2XxACU1wCS2ADD51rr9aJXkw/MpYDgpkb71U7+9MP7007hnEO3niOj0hGq3SCZtQCbtQCjtwj//+7F4Vui0wBDhgDk5eTMxcGxfi3TfTq+fyPPz4ak3xux5TG87kmZuwCZvACWtgDf8a+c0gCy3yNLiwD7/Ps1iwCiyAPF3F7j7bG67EW77kmq5yWYzwCZwwCTugDc8KTE51ve9YZCigCgwgCVuQDa5p7U9YSq4yWT2gCV2wCT2wCp2h/y+9HC6lW87DlChQBGigCixgCYvgDK3nyXvgC72UjG7mSj3xXL7XDK7W7b9J+36TrG9lBDhQBHigClywCbxQDJ33SXvwCYvQCcwADq+8S77Ei460Hd+KDD9VHU/2VEhgBdlR1rowCXwwDK4W6bxgCaxQCVvQDp/L+/8k7F91fn/6zC9V18tiNbkx/U1dSyv6RglihnoQCYwwChyQDs/7/P/2fE92F5tCBdkib19vXW1taoupVLiwNooQCWwADo/7h5tSBFhgaouZXx8vHOz86ftYVJiQBNjQKetIXt7u3Nzs0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBfAAAAAAAAAA2tmA2tmAAACQAAAAAAAAAAAAAAAAAAAAAATgAABNBfMAAAAAAAAA2tpQ2tpQAACQAAAAAAAAAAAAAAAAAAAAAAdQAABNBfMAAAAAAAAA2tsg2tsgAACQAAAAAAAAAAAAAAAAAAAAAAggAABNBfMCaVmCSAAAAAXRSTlMAQObYZgAAAAlwSFlzAAALEgAACxIB0t1+/AAAAQVJREFUeNpjYGBkYmZhZWBj5+BkAAMubh5ePn4BQSFhEVExcaCAhKSUtIysnLyCopKyiqqaOoOGppa2jq6evoGhkbGJqZk5g4WllbWNrZ29g6OTs4urmzuDh6eXt4+vn39AYFBwSGhYOENEZFR0TGxcfEJiUnJKalo6A0NGZlZ2Tm5efkFhUXFJqTnQnrLyisqq6prauvqGxqZmoEBLa1t7R2dXd09vX/+EiUCBSZOnTJ02fcbMWbPnzJ03HyiwYOGixUuWLlu+YuWq1WvWAgXWrd+wcdPmTVu2btu+Y/06kHd27tq9Z+++/QcOHtq1E+JBhsNHjh47fuLIYQYEOHnq1EkwAwCuO1brXBOTOwAAAABJRU5ErkJggg=="); +} + +.jsroot .img_graph { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AEFCgohaz8VogAAAT9JREFUOMulkz1LQlEYx39XmrIhcLa5i4mD4JBQrtHieDbb+gx3dbl9hca7tLi4VOsRMkKQVO7LLAQNNdSQgyJPg903tDT8w4HzPDznd56Xc1BKCVsokzTGjhPBXDcQAAEZDgPZCHDQaESH5/PYXyqZxp8A349vGHkjOXo3uXtp035sy79KABi8DQCwshb7x3U6gIYU6KNej+1kEwUEjbQeWtIb9mTsOCIgN1eXgiYd96OdcKNBOoCuQc47pFgoGmHw7skZTK9X16CUku5zV9BIkhz4vgSuG/nsWzvKIhmXAah+VpfJsxnGZMKkUln05NwykqOORq6UWkn+TRokXFEG/Vx/45c3fbrnFKjpRVkZgHKxbAC8NptrAfm9PAD2l42VtdJjDDwv2CSLpSaGMgsFc91hpdRFKtNtf6OxLeAbVYSb7ipFh3AAAAAASUVORK5CYII="); +} + +.jsroot .img_mgraph { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/gif;base64, iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAADAFBMVEW9vb2np6empqanpqenpqivr68AAAD3+fn09vb19vf3+Pv8+v//+//29/v3+fr19vbZ3Nza3d6/wcLb3t7b3N3AwMPi4et2oz0yfwDh3+n2+PimpqXe4+Th6uvD0NHi6uzg5ebFx8nt6vY2ggDs/881gQDr5/T2+fnFz9DDZVrAIhDEZVvJ0tTN0NTX0+IvZAA4hAAuYgDT0N77/P6lpqX3+vvn9vi/JRL81cHBJhTu+//W1uEkXgD48//29P8fWwD//f+mpqelpqb4/v/t/f+yCwDBKBi3CgD6//8kYAD59v/x8fXQ0dTw9fny9/78/v+lpqf7//+wAADV5ezZ5e7g6PQjZQDf4+/W2t/R1tfT2drT3+OvAAD9///6/v/////k4vIiXwC1AAD3///2///X6Oz0//9+rUgzfwAwdADa6u6xCwDAJxb5///1+/z9/v6lpaUwfADo/8vl4e3a3uDb6eu+IxL808C+IhDZ5+nW2tr+//+kpKSmpaaArUgvewB1oj39/v/e5ebVd227HgvJa2H8///6/PylpKXn4+ze4eLg5+j9/v20tLSsrKzc3NzMzMzPz88AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAPAAAAAAEAAAEAAABzL1z/CSMAAAAAAAAAAAAAAAMAAAAmCTsAAAAAAAAAAAAAAAAAAAQAAQEAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7op0gAAAAB3RSTlP///////8AGksDRgAAAAlwSFlzAAALEgAACxIB0t1+/AAAAOhJREFUeNpjYGBkggBmFmYmRlY2BkZ2DhDg5OLm4eblY2RjYOIXEBQSFhEVE5cQl5RiYmOQ5pSRlZNXUFRSVlFV4wIJqGtoamnr6OrpGxgaGQMFTEzNzC0sraxtbPXs7B0c2RicnF1c3dw9PL28fXz9/IECAYFBwSGhYeERkVHRMYEBQFti4+ITEuOTklNSg9I8nNgYHOPTMzLjA7Oyc7Jz8/ILQAKFRRnFJaVl5RWVVdU1bAy18XX1DfGNTc0trW3t8UCBjvj4+M746q74+O7qHpAAUzwyADqsl6kGAZj62Bj6JyCDiWwAyPNF46u5fYIAAAAASUVORK5CYII="); +} + +.jsroot .img_tree { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/gif;base64, iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAABIAAAASABGyWs+AAAACXZwQWcAAAAQAAAAEABcxq3DAAACjklEQVQ4y4WTy49LcRzFP+2tzmVUr9dIDJOWGGVBicgEyTQTCzIetUFssDKJSFhY2SARCYvBbGrj8QcIkYglk8xCmEQ9xqNexbQVY2Zub3un9/W7PwstHZH4Jie/7+Kc8/suzgnwr+kjBqSBbm2lkm6bHyH3XM9SZQ8Z8s3UQJPo0IJVof5EZ7v2faxMrKONlhmQWN5GSFEwLbhybjBPhDwVsmQ4AaA09Mou+k8d702EAzXiS6KEgzahoIthGOi6DtKlN71GS+/cEPs0WewaX2R9ZphssP776UhESY0WSpQNg7Jh4Anx+zgJVKpV3uZyvHjzir27NwGs/XVBH8c7N2nnjx7eSqlYxPM8JCCkxBU+rhA4dVhCYJgmyc4Ej96/7rLi8nNAPc/k2ZNp7cnTpziuiy8lvpSI+tvYhS/xpY8vJXMiEbZv3MzFq3cJqaqiPX72jnKt9kfQRPZ9f5qZ70sMawyAas1GseIy1rNtVXK8Mkm1VsP2PBzhYQuB5Qns+t6AJQSqqlIcrTAy+ONGENBWLF3MN71MxXGo1mE6DqbrYLou8z/a7L3uMKvgUnU8xk2T3u71ADGFDdgvCx/3TwkLEfKxhWDHbY+eYZ+Obz6tJcmRApRsuJ8Ex4Po7Jl8/TDBl7flm4Gm5F1vSZKaFQUh4cB9OLgaDB3UVrjwA+6tBnKAis4El8lwujmJSVQeoKAxFzqDcG0KWhZC6R30tUJRQD3Odxqy4G+DDFks4pisY5RLgRx5pZ5T4cKy95yhSrxZDBCaVqIMOpAd2EIeSEW7wLQh3Ar7RtCHbk0v0vQy1WdgCymgf147Sa0dhAOVMZgoALDu2BDZ/xloQAzQgIOhMCnPYQ+gHRvi4d/8n00kYDRVLifLAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDEwLTAyLTExVDE0OjUxOjE3LTA2OjAwHh/NoQAAACV0RVh0ZGF0ZTptb2RpZnkAMjAwNC0wOS0yMFQxNzoxMDoyNi0wNTowMCcJijsAAAAASUVORK5CYII="); +} + +.jsroot .img_branch { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/gif;base64, iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAADAFBMVEX///99plFAfADL27hpmyfP8YxyoilSiRiv0XGGygK02VtRiBmVwjh8xQCcziFZkhLz9+9BfQB2rwaCyACRygFQigXw9Ox0mkpXkQCJzwBblgBmkzP8/fxEgQBCfwBEgQejwITe3t5hkC1CfgBfjynZ2tmSq3eArDu72oNvoDJajyTY2dhFgQDCzLqhvn9EgAazx55XkwCVzC2824GMs1J0oUTY48xajiK72YR9qj2Tq3dhkix+th99xAB3uADA3oQ+fABEgABIgwW82oOUyi5VkgCf0CaEygB+wwCbzjN1mkrA3YZ1tAB7wAB+uB1vl0JdmgCJwwCKzwBoqAB4nVBikiuayzZ8wQCFywCg0Sjd3t1lkjFBfABLgwhKgwlmpgCK0QCJxQBclwDMzMzPz89GggCDpFxDfgCIpmPl5eUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABhAABQEABuZQBjYQBvcgAIZABiYQBlZAAABQDU/wCx/wCO/wBr/wBI/wAl/wAA/wAA3AAAuQAAlgAAcwAAUADU/wCx/wCO/wBr/wBI/wAl/wAA/gAA3AAAuQAAlgAAcwAAUADj/wDH/wCr/wCP/wBz/wBX/wBV/wBJ3AA9uQAxlgAlcwAZUADw/wDi/wDU/wDG/wC4/wCq/wCq/wCS3AB6uQBilgBKcwAyUAD//wD//wD//wD//wD//wD//wD+/gDc3AC5uQCWlgBzcwBQUAD/8AD/4gD/1AD/xgD/uAD/qgD/qgDckgC5egCWYgBzSgBQMgD/4wD/xwD/qwD/jwD/cwD/VwD/VQDcSQC5PQCWMQBzJQBQGQD/1AD/sQD/jgD/awD/SAD/JQD+AADcAAC5AACWAABzAABQAAD/1AD/sQD/jgD/awD/SAD/JQD/AADcAACwULzWAAAAAXRSTlMAQObYZgAAAAlwSFlzAAALEgAACxIB0t1+/AAAALZJREFUeNpjYAADRiZGBmTAzMLKxowswM7BycWNLMDEw8vHL4AkICgkLCIqhiQgLiEpJS0D5cjKySsoKimrqMJk1dQ1NLW0dXQZ9PTlZEECBoZGxiamOmbmmhaWViABaxtbO3sHRycTZxdXA7ANbu4enkxeDt4+vn7WIAH/gMCg4JBQprDwiEhBkEBUtGBMrI5OXHxCYpI/2BrV5OSU5NS09BjB6CiE01JTM5KTVZHcmpycCWEAANfrHJleKislAAAAAElFTkSuQmCC"); +} + +.jsroot .img_leaf { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/gif;base64, iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAADAFBMVEX////M27mQs2tilDA9eQA7egBbkhVTjAxJgwWBqVdGgQBrnySdxViu0WrE4oaYv2PC35NtoCqxvaSevX5FgAB7qje73nDK6neu109vpyVupCGo2kJ9xwBQhBtilC9pnx7G63PM6olgnAB/vQBDigCVv0yb1CaDzAB8uBJwmkNnnBnB52ui2Ca94WZopAE/hgCtz2ue2CmDywCByACKujtdjyqdvHpdlhLV9YdkowCFxwCw1lFXmAJvpC5jng1coABlpwBprAB8sitAfABDfgKx31Gr3TuCsi5sqABtqgBUkxTV85zL7I213mef0j+OxyKk00k/ewCp3TCSyhCw0mRRjQC23HmU0h55wQB5vQB4uQB1tgCIwBeJxgCBvQDC3ndCjACYx1204Fx6wwB7vQB1tABzsQBBfQBpkzdtpQB9tQA/iQCMu1SMukNUlQBYmQBsqAd4rh11rwZyrQBvqgBDfwCqvZVWkQBUnACp0Hq/43K733C+4X+w12eZyT2IvSN5sgpZkwBxmUSDqFlbnACJzQy742p/wwB2ugBysgBwrwBvqwBwqQBhmgBCfwDV2NN8pk1foACO1QBZmABRkABpqwB3uQB0sgB0rgBnogBUjgC7w7NymkFdnQBUhxmis41okjdCfgBGgQWHpWPMzMzb3NtumD5NhQzT09Pv8O/a2trOz87l5eXc3NzPz88AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABtHAA4HXQAAEgAAB9CTigAAABCfCQ4HTxy6Kw4HXRy+8xy+8wAAMwAAAAAAAAAAAAAAAAAAAAAAAgAAAgAABgYAAG7AAAAACgAAAgAAAgYAAEAAAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4Hnw4HnwAAFRpRiYmO2V0aWRtSSY7ZWdsZVNpdGNBO251amRGO3R0bCYmO3J3ZWlvVCY7c2xuaVc7d28ABCwBG8q3AAAAAXRSTlMAQObYZgAAAAlwSFlzAAALEgAACxIB0t1+/AAAAOtJREFUeNpjYIACRiZmFlY2dg4ol5OLm4eXj19AUAjMFRYRFROXkJSSlpEF8+XkFRSVlFVU1dQ1NMF8LW0dXT19A0MjYxNTIN/M3MLSytrG1s7ewdHJGSjg4urm7uHp5e3j6+cfABIIDAoOCVUJC4+IjIqOAQk4x8bFJyQmJadEpaalpQMFMjKzsnNy8/ILCouKS0qBAmXlFZVV1TW1dfUNJY1NQIHmlta29o7ozq7unt6+fgaGCRMnTZ4ydVrU9BkzZ5XOBiqYM3HuvPkL0tPTFy5avATkzqXLlq9YuWoJEKxeA/Ho2nUMyAAA9OtDOfv2TiUAAAAASUVORK5CYII="); +} + +.jsroot .img_leaf_method { + display: inline-block; + height: 16px; + width: 16px; + background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAKlBMVEUAAAAAgADzExMAgIAAAADAwMCAgADxGRnuFxLnHhHuIyPKJQ/rLi7////aW8ZOAAAAAXRSTlMAQObYZgAAAAFiS0dEDfa0YfUAAAAHdElNRQfgCxIPFR/msbP7AAAAaUlEQVQI12NggANBBiYFMMNQxAjCYA4UUoZIBRpBGMyiQorGIIaxWRCEwSYo3igiCNJlaLkwGSwkJn1QGMhgNDQ0TDU2dACqERYTDksGG5SkmGoApBnFhBRTBUAiaYJpDIJgs10cGBgdACxbDamu76Z5AAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE3LTAxLTE3VDA5OjMwOjM1KzAxOjAwyGHxKQAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNi0xMS0xOFQxNToyMTozMSswMTowMJgvuUkAAAAASUVORK5CYII='); +} + +.jsroot .img_globe { + display: inline-block; + height: 19px; + width: 18px; + background-image: url("data:image/gif;base64, R0lGODlhEwASAPcAAPr7/AFyAQFCpwGD6jy3/wE9on7N0AE+pAFjyMLI0AE2mwF94wGP9QFpzgU3nISSopWgrmJsfTNLfgFHqAFuBilNiTp4sLnGzwWb/0xYb/P09mRygGl0hRlnMgR12V2Pr6e4xF9peS2Cyh5FpBdSfgF84YmisdPa30hjvw+foQFYvlWj4HWIlkWb5gk5n/b4+gw+kgFMscXb6ylmieDj5ju2pylTsniElgqd/u/x8wGW/O7v8SVMsUq+JSSJXQFiwfv+/AFqvB9ntobZeKbc/9vt+B+YmW2rvKruzQGPkm3PPrjmxQFIklrFLVbD4QGMYaXkoIPD13LC+nGw5AGFQHG66gF2eBaJxket9sLf84HI+wF7axBdbg2c0CR+1QFsEIfJ7yqoUIbH41tldgF+KzVTjn3QfitZgTJZkaDR8gKDsXeWrE+zogE3nCeKzQFtJ0tknjdnbQGB6EJgxQFqAcLJ0WC//yKm/wE+o7vI0ARozEOz/4/g/4KToyaX4/D09pCpuNHV24HA6gw7oAF/AXWKnEVSb5TI6VzDTrPprxBQts7e6FNdcBA9oySd9RRjPAhnD2NvgIydrF+6wdLo9v7//2K+twKSdDmKyeD56wGCyHq12VnF+ZXXsARdTjZWthShoo7gtilDlAFw1RCXvF+z6p/R8kqZzAF0Oj5jjFuJqgFoAkRgxtzr9YmcrJKsugFlylfBgxJGhjJIeFnFuhmi/+bo65ipt8Hn+UhVco7B5SZowAGBKoaZqAGGAVHBUwF8Qq7Y819qe4DEoVyYwrnb8QGN9GCy6QFTuHB9jgGY/gFRtuTu9ZOhr150iwFbwTFiwFus4h9mYt/y+kWZ35vM7hGfccz43Xy/6m3BuS1GiYveqDRfwnbUV4rdu////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAN8ALAAAAAATABIAAAj/AL8JHEiwVTVspar8ITiwiJhswyaBibJJUq9Trxh+S2OAVihvSzqRcoTpmy5ADIPFqrHtGpBETbrIuXJEBgiGbHoogTItExJOoAbw8rHmAkFTC8KYwTWkGx8COp4AozAjD8Epo4wQQfTLCQEcxqigoiONBUFqerRYspYCgzIGmgi98cRlA8EVLaR4UJPk0oASVgKs6kAiBMFDdrzAarDFF5kgCJA9ilNBGMFjWAQse/YjwBcVMfCcgTMr2UBKe0QIaHNgAiQmBRS4+CSKEYSBWe44E6JoEAxZDhrxmDPCEAcaA4vVinTCwi5uKFhBs6EtQ4QEOQYy8+NGUDRiqdCUJJGQa8yNQDsADHyxSNUHE4Vc3erzoFkdWxoAVNLIv7///98EBAA7"); +} + +.jsroot .img_canvas { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/gif;base64, iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAADAFBMVEX/AAC1t7etsLCsrq6rrq6rrq2tr6+0tratsK/////p6enIysrl5OTn5uXo5+ajpaXo5+dhhKdliKlmialgg6elp6f6+/vIycnr7Ozw7u7x7u7x7u3t6+vLzMvp7vbs7/bz8PD17+3z7u2rrq/6xS76xy13zv9+z/+EwLF4zP/38/NfgqWAoL36uCj6vCmR2f+TxamSrBmNvoj++fz8+Pf69/WZ3f+g4P+n4/+Cnw2Dox16nQ3//f9hg6eBob6x5/+46f+77P+p2NKSZhOi1s////7//fusrq98sB6CsyWDtSmFuC9+dBl/tilfgqasr6+sr7DbAADcAABcgqWAoLyusLC4urqssLCssLGrsLCrr7Ctr67c3NzMzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABoAAAKAgJldmV0dU8GB3JvTnZDBWVyb2xsYwdjYWxhUBB0bmVrY2F1b3IICGRPYmFyZWQAAAXj1P/Hsf+rjv+Pa/9zSP9XJf9VAP9JANw9ALkxAJYlAHMZAFDU1P+xsf+Ojv9ra/9ISP8lJf8AAP4AANwAALkAAJYAAHMAAFDU4/+xx/+Oq/9rj/9Ic/8lV/8AVf8ASdwAPbkAMZYAJXMAGVDU8P+x4v+O1P9rxv9IuP8lqv8Aqv8AktwAerkAYpYASnMAMlDU//+x//+O//9r//9I//8l//8A/v4A3NwAubkAlpYAc3MAUFDU//Cx/+KO/9Rr/8ZI/7gl/6oA/6oA3JIAuXoAlmIAc0oAUDLU/+Ox/8eO/6tr/49I/3Ml/1cA/1UA3EkAuT0AljEAcyUAUBnU/9Sx/7GO/45r/2tI/0gl/yUA/gAA3AAAuQAAlgAAcwAAUADj/9TH/7Gr/46P/2tz/0hX/yVV/wBJ3AAQ+AFLAAAAAXRSTlMAQObYZgAAAAlwSFlzAAALEgAACxIB0t1+/AAAALpJREFUeNpjYGBkYmZhYWFlYWNngAAOTijg4oYIMHPy8PLx8nDycwpwQwUEhYSFRDhFxTi5xCECEpJS0jKcsqL8nGwgARZOOXkFRSWwMcwgAWVOFVU1dQ1NLW0dmICunr6BoZGxiSlEgJnTzNzC0sraxtYOJmDv4Ojk7MLp6gYRcOf08PTy9vHl9IOa4c+JAGCBAM7AoEDOwEDO4BCIABOSilCQQBhTeERkVGS4f3R0aBhIICYWAWIYGAClIBsa7hXG7gAAAABJRU5ErkJggg=="); +} + +.jsroot .img_profile { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/gif;base64, iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAACXBIWXMAAAsSAAALEgHS3X78AAABZElEQVR42o1R22rCQBD1U/p//apCNtsHwRdfBaFIKbRoUVKMMTWBWIxVCq2b+07POrn4UKjDMpw9O2fm7G5vNBpJKe2/Qto4uEc2WMrBYEBEPaAky36UulwnlSRpUeZEBSGrpEiyHJVGAPVJqZvbO3ftv83Dle+vvPV4/LD0PGYAcKrSFJUsEOgHKoj3s9dFGH9uou3k8ekQKxyDQcYpBnYC7Hm9zBZmlL8BiIJDC0AWpa4FwhZJXoDCBgYAjgU5ToBt+k1tL14ssFNNvIEBAFwVljJlSDBfpwyg1ISnYoEsiHju5XLcd+T50q0tEQm7eaWKKNfUWgKApUsbPFY0lzY6DraEZm585Do/CLMzqLQWQnSC9k34lVa7PTsBs/zYOa4LB5ZlnQXCbif40Ra50jUwE6JtCcMlUiMQlugEQYisG8CWtGlRdQL+jmui/rjhcAhk/Reo6ff7RuB53vN1MZ1OIfgFQC1cuR3Y6lIAAAAASUVORK5CYII="); +} + +.jsroot .img_execute { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEXAwMAAxwCvbOAvAAAAAXRSTlMAQObYZgAAAAlwSFlzAAALEgAACxIB0t1+/AAAACBJREFUCFtjYIABHgYGfiA6wMD/gYH/B5g8ABLhYUAGAHniBNrUPuoHAAAAAElFTkSuQmCC"); +} + +.jsroot .img_file { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQEAYAAABPYyMiAAAABmJLR0T///////8JWPfcAAAACXBIWXMAAABIAAAASABGyWs+AAAACXZwQWcAAAAQAAAAEABcxq3DAAAA2klEQVRIx61VURbDIAgTX+9ljg4n2z5sNouj1ml+LE9rQkSU5PA6kTZBToTznj5aqKqq+py4lFJKScnMzCwlAAB6IbnNuyXycd1g3oHrf32CmR9mZqpVOdDHs2DmI+c+AiJixu1RAN9xFUcdWCjVIr8xCX8Jubc8Ao9CJF8nRFgNJBxZSCEkjmrIxxSS0yIAoBU4OkpfU8sCPEbEvqaOXcR31zWORbYJ8EI8rsK+DWm7gMVb8F/GK7eg6818jNjJZjMn0agY7x6oxqL5sWbIbhLHoQN78PQ5F3kDgX8u9tphBfoAAAAldEVYdGRhdGU6Y3JlYXRlADIwMTUtMDItMDZUMTA6Mjc6MzErMDE6MDChLu/mAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE0LTExLTEyVDA4OjM5OjIwKzAxOjAwIGvf8wAAAABJRU5ErkJggg=="); +} + +.jsroot .img_text { + display: inline-block; + height: 18px; + width: 18px; + background-image: url("data:image/gif;base64,R0lGODlhEgASALMAAP/////MzP+Zmf9mZv8zM/8AAMzM/8zMzJmZ/5mZmWZm/2ZmZjMz/zMzMwAA/////yH5BAUUAA8ALAAAAAASABIAAARo8MlJq73SKGSwdSDjUQoIjhNYOujDnGAnFXRBZKoBIpMw1ICHaaigBAq/AUK1CVEIhcfPNFlRbAEBEvWr0VDYQLYgkCQWh8XiAfgRymPyoTFRa2uPO009maP8ZmsjAHxnBygLDQ1zihEAOw=="); +} + +.jsroot .img_task { + display: inline-block; + height: 18px; + width: 18px; + background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAAAVCAAAAACMfPpKAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAJiS0dEAP+Hj8y/AAAACXBIWXMAAABIAAAASABGyWs+AAAATklEQVQY05XQUQoAIAgD0N3JY3fIChWttKR9xYvBCj0J0FsI3VVKQflwV22J0oyo3LOCc6pHW4dqi56v2CebbpMLtcmr+uTizz6UYpBnADSS8gvhaL5WAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE2LTA0LTA3VDA5OjQyOjQ4KzAyOjAwMgzRmQAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNC0xMS0xMlQwODozOToxOCswMTowMJ0LlncAAAAASUVORK5CYII='); +} + +.jsroot .img_pavetext { + display: inline-block; + height: 18px; + width: 18px; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAJ0Uk5TAAB2k804AAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAAAEgAAABIAEbJaz4AAAAsSURBVBjTY2CgCuBAAt1gASS5KKgARBpJACSEooIsARRbkABYoDsKCRDhEQBA2Am/6OrPewAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxNi0wMS0wNFQxMDoxODoyNyswMTowMHsz6UQAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTQtMTEtMTJUMDg6Mzk6MjArMDE6MDAga9/zAAAAAElFTkSuQmCC"); +} + +.jsroot .img_pavelabel { + display: inline-block; + height: 18px; + width: 18px; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAJ0Uk5TAAB2k804AAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAAAEgAAABIAEbJaz4AAAApSURBVBjTY2CgCuBAAt1gASS5KJgABzUEgABFANUWJAAWYIhCAkR4BAAHoAkEyi2U3wAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxNi0wMS0wNFQxMDoxODoyNyswMTowMHsz6UQAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTQtMTEtMTJUMDg6Mzk6MjArMDE6MDAga9/zAAAAAElFTkSuQmCC"); +} + +.jsroot .img_list { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AEECTc01vBgywAAAE9JREFUOMu1k8ERwDAMwqRc9l/Z/eeRpKZlABkOLFD0JQGgAAah5kp8Y30F2HEwDhGTCG6tX5yqtAV/acEdwHQHl0Y8RbA7pLIxRPziGyM9xLEOKSpp/5AAAAAASUVORK5CYII="); +} + +.jsroot .img_color { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAM1BMVEUAAAAA4xcavGZGS1xZT79lW+9wdvFz/3N6fo3RISTZwXbyniXz80v/AAD/zAD/66v//6vGWiYeAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAADswAAA7MAbGhBn4AAAAHdElNRQfgAQQLLBhOmhPcAAAAIklEQVQY02NgRgEMDAzMnLzcfDwC7IxMbKwsQ10A3XMEAQA3JQVNowlkTAAAAABJRU5ErkJggg=="); +} + +.jsroot .img_colz { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAMFBMVEV6fo0A4xcavGZGS1xZT79lW+9wdvFz/3PRISTZwXbyniXz80v/AAD/zAD/66v//6t1AkcGAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAADswAAA7MAbGhBn4AAAAHdElNRQfgAQQLNwdqpNWzAAAAT0lEQVQI12NgYGAwNjZmAAOLjmY0hs2ZwxCG1arFEIbt3csQhvXuzRCG/f/PEIZ5eTGEYSgoDGEYKSlDGGZpyRCGaWgwhGHi4gxhwG0HAwCr3BFWzqCkcAAAAABJRU5ErkJggg=="); +} + +.jsroot .img_frame { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfgAQQLOwq4oOYCAAAAcUlEQVQoz7WQMQqAMAxFX0Uk4OLgIbp4oZ7BA/cOXR0KDnGpRbGayT+EQF74nw+GHIBo+5hdWdqAaFDoLIsegCSeWE0VcMxXYM6xvmiZSYDTooSR4WlxzzBZwGYBuwWs4mWUpVHJe1H9F1J7yC4ov+kAkTYXFCNzDrEAAAAASUVORK5CYII="); +} + +.jsroot .img_class { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QAvQC9AL1pQtWoAAAAjUlEQVR42p2T2wnAIAxFM0g/O6jDdBBHcAyHKKQYjfiI0UY4P8I9BG4CID8smB4+8SUsohpO3CFzKqmBFrhCO4kqQnCR6MJF4BEJTVQFhBAmASNIZkH6a0OMc8oUDAu8z7RhTTBVyIIEhxeCdYWjQApvK2TBrgGpwpP1livsBXC0ROMO/LqDKjKEzaf8AZWbJP6pTT9BAAAATHpUWHRTb2Z0d2FyZQAAeNpz0FDW9MxNTE/1TUzPTM5WMNEz0jNQsLTUNzDWNzBUSC7KLC6pdMitLC7JTNZLLdZLKS3IzyvRS87PBQDzvxJ8u4pLSgAAADN6VFh0U2lnbmF0dXJlAAB42ktKs0hLMkk2MzJKNEuzMLKwtEizSElMMbNITUw0NUtNAQCc7Qma0Goe1QAAAABJRU5ErkJggg=="); +} + +.jsroot .img_member { + display: inline-block; + height: 16px; + width: 16px; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QAvQC9AL1pQtWoAAAAX0lEQVR42mNgAAIVBob/+DADPgBS8GCPBV6M1xCKDcDnBRcoZhgW4D8DBV75v2bLATAmxyC4ZmRMrCFYNfeU9BBvwJwpS8AYWTNZBoAwTDPFBpAciDCDyNFMtXSAFwAAUyq0GRPbbz4AAABMelRYdFNvZnR3YXJlAAB42nPQUNb0zE1MT/VNTM9MzlYw0TPSM1CwtNQ3MNY3MFRILsosLql0yK0sLslM1kst1kspLcjPK9FLzs8FAPO/Eny7iktKAAAAM3pUWHRTaWduYXR1cmUAAHjaS01JNrE0S00zSbU0NEsxMbMwM0xOSjYwNzY3NLRIMjUCAJcdCJ2BHe6SAAAAAElFTkSuQmCC"); +} + + .jsroot .img_tf1 { + display: inline-block; + height: 16px; + width: 16px; + background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAADFBMVEX/////AP8/SMz///+Cf5VqAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAAHdElNRQfgCw4QHgSCla+2AAAAL0lEQVQI12MQYAACrAQXiFBoABINCgwMQgwcDAwSDEwMDKmhodMYJjAwaKDrAAEAoRAEjHDJ/uQAAAAldEVYdGRhdGU6Y3JlYXRlADIwMTYtMTEtMTRUMTc6Mjk6MjErMDE6MDDxcSccAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE2LTExLTE0VDE3OjI5OjA1KzAxOjAwNka8zgAAAABJRU5ErkJggg=='); +} + + .jsroot .img_tf2 { + display: inline-block; + height: 16px; + width: 16px; + background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAADFBMVEX/////AP8A/wD////pL6WoAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAAHdElNRQfgCw4PNgzGaW1jAAAARUlEQVQI12NgEGDQZAASKkBigQKQ6GhgYBDiYgASIiAigIGBS8iBgUFhEpCnoAEkUkNDQxkagUIMrUDMMAVETAARQI0MAD5GCJ7tAr1aAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE2LTExLTE0VDE2OjUxOjUzKzAxOjAwi1Gz3gAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNi0xMS0xNFQxNjo1MTozNiswMTowMG5bLUIAAAAASUVORK5CYII='); +} + +/*-------------------------------------------------- + tooltip style for 3d drawings + --------------------------------------------------*/ + +.jsroot_tt3d_main { + opacity: 1; + filter: alpha(opacity=1); + position: absolute; + display: block; + overflow: hidden; + z-index: 101; +} +.jsroot_tt3d_cont { + display: block; + padding: 2px 12px 3px 7px; + margin-left: 5px; + font-size: 11px; + background: #777; + color: #fff; +} + +.jsroot .xaxis path, +.jsroot .xaxis line, +.jsroot .yaxis path, +.jsroot .yaxis line, +.jsroot .zaxis path, +.jsroot .zaxis line { + fill: none; + stroke: #000; + shape-rendering: crispEdges; +} + +.jsroot .brush .extent { + stroke: #fff; + fill-opacity: 0.125; + shape-rendering: crispEdges; +} + +.jsroot rect.h1bin { + stroke: #4572A7; + fill: #4572A7; + opacity: 0; +} + +.jsroot rect.zoom { + stroke: steelblue; + fill-opacity: 0.1; +} + +.jsroot svg:not(:root) { + overflow: hidden; +} + + +/*-------------------------------------------------- + context menu + --------------------------------------------------*/ + +.jsroot_ctxmenu { + position: absolute; + min-width: 48px; + height: auto; + margin: 0; + margin-left: 0px; + margin-top: 0px; + border: 1px solid #999; + background: #F8F8F8; + box-shadow: 2px 2px 2px #AAA; + z-index: 101; + overflow: visible; + line-height: 14px; +} + +.jsroot_ctxmenu li { + font-size: 12px; + padding: 1px; + white-space: nowrap; +} + +.jsroot .fast_command { + width: 30px; + height: 30px; + margin: 2px; + padding: 2px; + border-width: 2px; +} + +.jsroot .fast_command img { + max-width: 100%; + max-height: 100%; +} + +/*-------------------------------------------------- + Flexible MDI display + --------------------------------------------------*/ + +.jsroot .flex_header { + height: 23px; + overflow: hidden; +} + +.jsroot .flex_header p { + margin: 1px; + float: left; + font-size: 14px; + padding-left: 5px; +} + +.jsroot .flex_draw { + overflow: hidden; + width: 100%; + height: calc(100% - 26px); + background: white; +} + +.jsroot .flex_frame { + border: 1px solid black; + box-shadow: 1px 1px 2px 2px #aaa; +} + +.jsroot-flex-resizable-helper { + border: 2px dotted #00F; +} + +/* stylesheet for floating browser */ +.jsroot .float_browser { + position: absolute; + bottom: 35px; + top: 5px; + width: 300px; + background: #E6E6FA; + padding: 5px; + overflow: auto; +} + +/*-------------------------------------------------- + progress message + --------------------------------------------------*/ + +#jsroot_progressbox { + position: absolute; + min-width: 100px; + height: auto; + overflow: visible; + z-index: 101; + border: 1px solid #999; + background: #F8F8F8; + left: 10px; + bottom: 10px; +} + +#jsroot_progressbox p { + font-size: 10px; + margin-left: 10px; + margin-right: 10px; + margin-top: 3px; + margin-bottom: 3px; +} + + +.jsroot [data-title]:before, +.jsroot [data-title]:after { + position: absolute; + -webkit-transform: translate3d(0, 0, 0); + -moz-transform: translate3d(0, 0, 0); + -ms-transform: translate3d(0, 0, 0); + -o-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + display: none; + opacity: 0; + z-index: 1001; + pointer-events: none; + bottom: 100%; + left: 100%; +} + +.jsroot [data-title]:hover:before, +.jsroot [data-title]:hover:after { + display: block; + opacity: 0.9; +} + +.jsroot [data-title]:after { + content: attr(data-title); + background: #69738a; + color: white; + padding: 4px 5px; + font-family: "Open Sans", verdana, arial, sans-serif; + font-size: 11px; + line-height: 11px; + white-space: nowrap; + margin-left: -18px; + border-radius: 2px; +} + +/* stylesheet for embedded toolbar buttons */ + +.jsroot .svg_toolbar_btn { + fill: steelblue; + cursor: pointer; + opacity: 0.3; +} + +.jsroot .svg_toolbar_btn:hover { + opacity: 1.0; +} + +.jsroot_noselect { + -webkit-touch-callout: none; /* iOS Safari */ + -webkit-user-select: none; /* Safari */ + -khtml-user-select: none; /* Konqueror HTML */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* Internet Explorer/Edge */ + user-select: none; /* Non-prefixed version, currently supported by Chrome and Opera */ +} + +/* stylesheet for enlarged canvas */ +#jsroot_enlarge_div { + position: absolute; + margin: 0px; + border: 0px; + padding: 0px; + left: 1px; + right: 1px; + top: 1px; + bottom: 1px; + background: white; + opacity: 0.95; + z-index: 100; + overflow: hidden; +} + +/* stylesheet for browser */ + +.jsroot_browser { + pointer-events: none; + position: absolute; + left: 0; + top: 0; + bottom: 0; + right:0; + margin: 0; + border: 0; + overflow: hidden; +} + +.jsroot_browser_area { + background-color: #E6E6FA; + overflow: hidden; + font-size: 12px; + font-family: Verdana; + pointer-events: all; +} + +.jsroot_browser_btns { + pointer-events: all; + opacity: 0; + display:flex; + flex-direction: column; +} + +.jsroot_browser_btns:hover { + opacity: 0.3; +} + +.jsroot_browser_hierarchy { + flex:1; + margin-top:2px; +} + +.jsroot_status_area { + background-color: #E6E6FA; + overflow: hidden; + font-size: 12px; + font-family: Verdana; + pointer-events: all; +} + +.jsroot_browser_area p { + margin-top: 5px; + margin-bottom: 5px; + white-space: nowrap; +} + +.jsroot_browser_title { + font-family: Verdana; + font-size: 20px; +} + +.jsroot_float_browser { + border: solid 3px white; +} + +.jsroot_draw_area { + background-color: #E6E6FA; + overflow: hidden; + margin: 0; + border: 0; +} + +/* separator style, used for browser and new grid layout +*/ + + +.jsroot_separator { + pointer-events: all; + border: 0; + margin: 0; + padding: 0; +} + +.jsroot_vline:after { + content:""; + position: absolute; + top: 0; + bottom: 0; + left: 50%; + border-left: 1px dotted #ff0000; +} + +.jsroot_hline:after { + content:""; + position: absolute; + left: 0; + right: 0; + top: 50%; + border-top: 1px dotted #ff0000; +} + +.jsroot_h_separator { + cursor: ns-resize; + background-color: azure; +} + +.jsroot_v_separator { + cursor: ew-resize; + background-color: azure; +} + +.jsroot_status_label { + margin: 3px; + margin-left: 5px; + font-size: 14px; + vertical-align: middle; + white-space: nowrap; +} + +.jsroot .canvas_menu { + float: left; + display: block; + text-align: center; + padding: 0px 5px; + text-decoration: none; + font-size: 17px; + margin: 2px; +} + +.jsroot .canvas_menu:hover { + background-color: #ddd; + color: black; +} diff --git a/js/style/images/ui-icons_444444_256x240.png b/js/style/images/ui-icons_444444_256x240.png new file mode 100644 index 0000000000000000000000000000000000000000..c2daae1663d47f397a01fd4166bce9b6b9ac4183 GIT binary patch literal 7006 zcmZvBWl$W<vi9!c5G1$-O9+zSut;zTu0aFAEwB)RJBu!^0Tu#_6C}U_2`-BhJi*=F zgZsz(om+M9x%d2;p04VynSQE!X8M^34K;auTxwhZ0D!NkAgcuc03WA-BW(1?Q4ZlO z`6$qBq*SE<fXX<$TQiJD9b~R7FAI>J6)kLh)UaF?Rpqdju<$Xc!K-1EZvg;m2Sr&a zZO@tgOdp7qykC!mO||mGuP|d7Wy>h`8zNQulJl2fredx2hR`Y;;>y}w?PT_8MN5ht z%y8}EASEyDqJV__?4o(>3BwohAk8Kk&8ZRCGiE!+DT9hXg&JS5v?_IepEqpNV=_Bk z_jnCv@Kv}BHMdM&40x<JUmzBn0$Q&IGp+`2UwU%UsdfiSQJ^f4N1zcWPhdQcRBvZC zUS;YLh`~IF!?aY9X~Z5#>HCnz@SWBL4=&3BQtS(^upnf_gBk$Cwk1d)ck=WS(Jomd zVU_Ed+?DU~na)4;FqtZOg}8>W0-80TNdj65D=+VmqC1_TP^g3HS12mpIa7q-S&-{9 zhGO$Sgs#{*Bce>Xu0cx2Nydf!izy!Z)qCY^vpaQh@gD)zAlJ}h!Wmc`s|N|*VDZ@Q z*Fr`Gm3jn%iWj{=4>Z`^JBC&Lwrs{@j}3lPSifie3|;^k<-5UMUj%{hZcbH6@*hgt z5$!dVHt8orKe9>)%=?~q+_O`g{@`hwV6B{t4G!i+#hdx?7rGxDy$ZyKQ9#2w@FY8y zF|wEc1&Xau6M&!AUqVv+AiKY{hqam><sc6oq~tT3BQzaq8$yWO0QWYIiuRr}zgRy< zt200is216b<Zm?E&w$TowHEvQcHYsa%>%mb08dX#mlau)npM?nyWFP<P1!SrJ$!um z+J*MlTwX97VrlrLR_^CxjG67-jao@Siy!KfRk_4-+-jxLGR`r0f!O&0-cxdtlbxJ9 zUT+psth!Uc?&DQ*{8#U?uCb@_d>jY}uoi?!AUe9kF?^U83$&t_36-%@wV%69TZzUz zJ%RrU#uz|Nzy<j4SZhN!pAtB6WZzF0|5=yN=khk8Hj8J*E@Lio#I5R~l^k4WWI)d= zTkMjM)DP4m*EvBZOPKqas&sME>R2?6qnNcL>ag+wH9L(NyQ4jXwA8%?xH)ZeyIL(M z$s~#X^#qMQ4%6}+1E{nz1nFj8e7i!l^xkjY@tMza3^9$PoZmB_XykUkFsN8yDV4w* z*;Dg<w)=^ww>ExM&!ja5>h}Tq)Ic(@1q-}&rp)o{IvN)=*qG`QXT@4OJa|L4^2|Ay zb)>%u)0%yV`AfRBZlF63_?y|gN=NpYiC{>5qY6`LJLigfgLV)vHA>ZO;_EtQ?E69! zt0&R86CCp>Mim`6?BfZbDB4GZ#MX(@73bXLo^0hh8TB7i;UDy_oNQNKyE!3m&<<IQ z-lMvh-g6-KAwTRn3*vDkot=lf=6!x*Zaph0uzFQ*hzB<sw4SJo_*1#w;dL#dqU{*S zt*0dECp6|8Hr$mfmg70`=IKbm`UbVMiGMBm$U0BL8{;>c?C!c~UolHO_?w+1^~7nm zR@CO*(G53MrX5&fn$a6v_c-VFnLS(-DrzW64QST3YJ%6PT(mbyWZ0~#+w^Ua1d(Qs zu$}3|_f(kE<NmqS5s)I+OMXbnCB5by8*IKU@gY~9#4H!lhbeXmzUsq~%)~?r2DF1m z3wRAg#{X8l0$tCsSlICfm8O~YNhp*>1cuou3BPG^lmKxJ@b&FuaSK3219@~7jfCEj zseTOCss41MRf*z+7E(htX%!%;YHj#0&mF%_F4QF_I)j!LPWJWQ!f|aHc{(fY3U-&7 z9t|yF{b>C^1;!KdA#@?CXr>3)O|4v#ogru4`3b=iluYe!!jEjJ|0%$K&)Etd1s8XW zwF|T<(<;4sZNJ>Y=ElV$lLl1Pl$fO(*8vuHn<bBjaB8al-pgkM@Ey$yr{pV7PgAjb zI~yct3)>lx(GZ6;YQ5@<AwSHzhoW@;e&5}3(lP=0ji|f!0W)Pv#HC{U$aYKCtzsJ? zDTX!TAi_OcT9uR2R~TBfIaRB=?ME3>H*+0Ctgdra^0zh%LZ@U2VxYn8H_XqAN<F&) zLa=)wUgHEBHfB2w*+nT8hT$UO;@40WfUNy{GO8Mb)xGYChCB-fTcV#~@e(?W-lI`E z!o4#Vwx=ON=$3^<$)Gq=-yieJF%GN#01AuJd9e_xX=A`y3a-njO>q1|qXIE6t0I|< z_PoX@MNwIxVHj=$rLvA$O`0oz%}kSho$9IU@vbK&&*4tB$;(yo_&usIkcNNa8gV&A zw{9wFNn?@I)4+xT8s5ufNvfOp(6gogb>=-n9=l8eoj|@$1fzKYovN+As(^DybSQG= zJk*W5F!!;{Y&C{HG<{{WZhGt0@Iv|zZ&>M0m3RmCJir*M3INwD9xR<#tZ@9T6DbMj z{8BP}AXgF~ivN4OQ@usUrNmLZZBFtLv_>B;rfS%(Q6UyO&yB|yuQVN>{A&+N!Hi5* zXT43XL)PAJD;wgupA{fLgQPSu<Js2+I5(wnt8dgcsL5`+s@D6nAlCg`&s{NmpS=LZ z^Ot?>Ck;=1S)}=(M4EXY?=qY!)q<U)-(JSAt=0GT8F2i0HD;u0p$E5l>skBRdz@!t z#DPfeIE5!|b``hIUf%1vEkM>2@_2ztM|H%$(n}IQ(E|6t>})I$qsO?U<%0T)#<(K| z%?%DzQ*qzM+Q3Gm1xrCg(_75gVdA>RI9tj&u4p9w)8;@g0u3yD(VN2{GZ&)ev>!c` z;)c*3MEn1^UZN8LDh03b-}xy%Fu+y=I>2t_feHZY)i6V=8fPWK_pk53AsGqocwekm zNO!j{+^qJB->-a*7pzBoaIZ%QCNptcaoioly^WG!2*)TK`o259&3I=v5jr|&u2d-b zE9s@ZWC++#yvIxR&vbnQ^N=lhlH8iiz)3DjT7M~HtZujdXcY1#yPsJ*`9O$ExmEor z^7Mv#vicV#Qu*uQv4sO((FxLvB((#5h?GZm;%|*eq4H+L3los3YBg?cE>XOI^@y3` zJ80$UtYcu!fW=m&+L}I7J2~U77QwEHG81=Z-t2LeMnh4^)#cad&*<<-3@JS|xUR<B zu+G`;(RbFBk4g~$NO#r>_(^4ND)g|@-l$NFHURNEOvp0485Q-KddnpdFH%@h@3Eqo zvUl#TPU_{tXjjfoZw!;IgxUqrjjUML_c7BA(9#Ew1DTSYK?vkS?G@JXXK;!e2aa#t zyfkG!b^;)pMr-tp2Kf=-DNYs`FO1L&QIO5<y~i$_v#E5Qq*k8Uke|c!4X)w6$INHS z=WKKRUR;QWrrVl;e7K-Yl0&(PmzoDu0^7b9<+hxZBwCLGBCxZ~Bt9S5vUssLXL-?X zU>(=)l8%+ut9(_>9<*98hNG=<6zhlqrpTH(I_Zzr+pELxl#TFx@foO4^CoCfd&7E1 z?By%$-E~T(FDllQ%F(sOAk*#s@FlMe_^Q{S`w&}AnpMhv<jF0Mzwo`FF6$!t;fpo5 znIFQEy>DU+mA(lKNU+~-J5ka=7+dl^$#L$e7TWaya5D}j?SMQE-OmHmn~h=dV0`X2 zaHn5@;qTjb#2=VJt?-)xLCrDc8CgCi1NEk0RiXtv@JAYV(s9kBMgf_k3)d#%Nv`y) zf;~YTs8A9IdnVJ(Lk2~Gi5y%f*NcF=%yaOS43?+-0pFtR@7ooI-B3LgB=NQQFZEGK zlBlQj<ty_*t7V^`MBYt_k#(qhvj%Q++)KCRi>UMn?SQ92L3hn6V(q2_3q4*2)(_k` z&>l%{r5ZpS?*Dvn83W$pWo?YEGxdT-oQ2?Ju>QfXj&QB_W8W|g-H$l}QZ%jwzvgjm zY?a8d{C@A>MCb}_MgCBSsja&=hN=HmEUyenw?SO3!7iz%a{Kv_<x^i<`y7sO$I!kz zMU#bgUGsp2&|dR&<;rq-Y<@DIP3=%W$-MmdWv0<ZSt3D9v@K2ASI@_nCY;>gTV1^! z9o6(>5t!Y<zUmtIx#8-<?Y(OtGo3{OU$&^k@#|W^@bTBMiOe{PBy#;#0ZjnYx%|YB zT<nm_JUzdY=?UDtlMwoKP4T|Gxqg{+%yjc$16^FO*zwjkcC6Ih+14&qqZQ2ih{cgh zAzPQUcxX~+a!WJ;<yOTJCQPV2pJlKW@H!RJ7Siw~eOB(;ybZfG-^d`-DimXAR24iI zzOiH}?3TH$6#Krj8D!VLJP0}VyN{ti%I$tB)FtAQF`4eVyL9M9Nb%7n;p>&WLy;{< zvqOHreG2b_#vYkc{Ar67vzw8f!2A&2nPb#0Edt>Cgfb4+L;hx(b}9NtddtucGea1` zo4t{O{@8P;Nr{t2-z2Y=ZY?tztQUJGW+hzxsKa#}wPQE6W2^P<m|fuLRc{C#kyB`j ze|SfF4A%+q>WTeTCj9Q#_Akfcdepbe=+hfM-x8t?R{3oJVdVg5lZi9J1xmCc3{?u8 zg+ZZ^5WM8muTv}JErULn;6pb3GLrLBpVqqA^7MDI1lA4hVP8b=N`1q7uDIh)%n)lo zx<h4YG-8&i?r{C>@=I53EIx(UxcCsg`Cj-la))IY^j^5^eFhqw^Ym$#dhU8z;5A~> zD)xjnMyJ+aBAZ||lt+ymz<0AAIa4FM$C`DIqvt|6=}f41Y?F~<n{>;4Uqcmu*kTj2 zco0@in_OXJC^kT}z4=3=X&HbA-Gmy3kNa>w*zTDm<*f@qr=m_`9N&`Wk_iS}-EnJn zo$aYFfQXA0K;7>s1iD1vED^tY@434FjOSp5V4jyM6*=dVML>7(m;8*@o{M6>{;QX< za`<9Lw0}-Hb=`MP1ufi=xRl#Tu>_UK8@;bY{_fCZb3O>WsnPU7qOITcS78<lsq2*o z9rzoM+ZLYgd56k@05bfUROg9j@Zx4EK=f^@ASojqi2U#84})zitCRF`{&{F#0`nvT zXryu@hggqo0mr}hJA)+9UdWuLhDb5ng*VLAwWh^yBSD`On)DGZ<9mj&+XKMuH`5yA z_U^m8UdLS}zWGlEP-_?aH{roXPm0BLJzSo=i7VM#<)&?+c6?uG{MY)lctR%`#+GS6 zIe$SJe+iicM?4<GUYSA`GDQ<K^{QXg0XVNml?D-AvPMRV=Qfi!qWwSW2Nc0%QS6#S z{d2#jJ)1wY()ma0v6Yh=XZi;uWwB03r+P(_%^1awCQR<^Zya^DOzKc44%%1bw2Mp) zhGPGT;oZg6YhhfKjvmX%{0LQ@fG>;E=Xb@fyck%jd;;Mee#steS2ck^npioDQ3sT$ z{+8Ha*{kYT_k5=q5P5>~v>P>f^&yzVb@UZaq&LGfR>5e_o7bH+x<8u*qTi)~%E<j$ zl2mwq#U)~;VPdDPirN^2GtW0=$)z@j^Lk5q$OMKb1?iXYj~TReHVkB9crPGQ4jBz> zgu44f=jb<90pEWE3owb*MGx2opyChlm7YE0aNbY_G*?FOuV&pkBbMKQcPOd?zQcGh z7BmaE{Tn<@O<DP%R`4yG`=TtpQhxH5vn~S>W2ix(;UPV9GrmW0A-Xm>L%(TL?6+h^ z$JY6PPNA?tu%mM)(?{m1XO!uGPjPe-Nkorj8Y-+SR5$`;oUR-*hoyt=X)dX-E-{Rk z0=FuQfbO<ks<ler+Eciq8Rx*FY0k)xP_DnQ?TgzMp|m@8OvIW+dj*!)V0@zzDp&ma z9bjR^4v<Na6L0b7Bz_W?T5^m&!J%S~cIoYs1n|;qq9JX@e$*WH4Q`bjYp$#fUe&p| zCC@66Mz0UBE@6ia!o8+Fp5oj*fA$$~SZOTejxU;o_2$q@yhr-BqSt@QGR-FtE8Ln| zZV%b<a7<pVfmq6_5t<Tee`>srJ=yv2HAjR7@)gaf2Ux!Tz8u3*McPtEa_xc1ThWfN zVE+@NKVDsDVJ?vAT%sqlDatUsMlL*js?}QIfw<on?~)ng2H4U|O<39e+|>XON)A;R zEI~3tEQF1P0z@h3%ZKl?`a^9CM3}BJVRfo+o2}k1Q{{XYaEh-8wEnSG82Mn}_{(50 zZ{P8}`K@g~y(*7~P`8?Brf9qi4w}a?v4pANtP-P?w=sjnpy)tFCEcfAUpGu#43%xj zd|0hg{jP}QVE#%E7z?zoSN25#bKkbRPNJ)6qjaJk);DpPUP?0qas@m5_k79$k6pX` z2?R(-{9i3mY!hI>?k;q3sD3Qbb!dxt+=5;TfnLsym%-H(+)jToJ(uKjIhT!hs7arT zDMWU0Z=kj=J&&l8FwD96u7&rVgnI5p3$=ZG>`$X}BA+<7w)B?C7XKSeO+X6tb2l5^ zu25NYskaCQrhJ+F>adP-u}CC74L7~ueG?eL5fVd(tEWn8AX;|SQjvfU{C0^s{Tn%3 z$0`v0(tSC?j~Q7YRLAyQ_$3?H+>o*{?=aiSwDdsr02^Xim(xzm$z{v2bh$;k5SVMc z7&!?~<zIFXJmjQWdAseQndQ5kpT&OOPa`_Extr%ey;^yLL3T%~eqw>x`0^6NRA^%J zoFD?=x^mn~GyC28Rc!kM-NW_>2AC{qKz4g~>M-(T&z9?FppA1DmC-q`8juEp1o}0k z*Z~y60KcDT@kjKQRKzkx4;>w>A*>;j)r$v_!sz5e!>{{`$S&Csm`is?V}-~BUO{^4 zrbs&rZEIix=2m{IVNe>6&vg-R`Oe24-X211QXhlF8<<LSfYiwc{{|Jov-WrSCTn-J z8+S(hmoo_G+-Nu^QuXgbk09CD;;&4pVXZ&*n9ah|<+uB4<Pb*4X*_<)iUF#jFix)- z$5P=b4)hu!ra3s@wdpd}cooE?2Gd!+beK^$je0{%sR(pxD;wyZC0>3y^y;P7pri!` z%HqXx*?*#~dh;xfH(G~jC8rp0C5wKvKM&m+PbLa(r-~xki~U?7-P4d{wkS0Lc&1w> zo&ENuD2D^?GhGX18Q6Fb_OF%NqHHcDwqjZ2(nGFBkQ_PwnTt(pe|e!_U{l2sw!LV! zQR27{2|<A;<CVZ&(J?5y!|(HInwI{WN+8{b!0aflNz`5k1NR7ojb-eq!Bg#Fpvd?4 zhkqx!lqosRe`|Q!O>isXifE5(XtG5v?iBtw%pr#gSV!v#?;^XO@V%gB*kuen8iO1t zYK^p!2Ylit_LGp-1Wd4lorx>D*!j@wNhh%3X2~gxezh5;DeC7^*@Z)ttC3^K_81%) z94~@wnwx5(YZ{C&`VCESX|Nuf`h4oq1WHuoJGDNf@IdAtChS(p^#9O&UO?{5<}*qu zOVCK<hXUgsH)@lcgv@<^{Ba8trl(Ny`7z-Eo(83twQ0*w5At@Ma%2~bs^E>~rk~@s z>8M}eN!b`IRr^NA-*`bawh4r#qsT;bZK~w-x~>+h@;d!T#rVU~v*l7%9RUZcR1<Zw zhAwZ;cnSYfm%8#(z~3%wx0Ljld+fkGgJm!RW*9%MyDhK_8R?ChOkR)1*)|?$^;xvS zKnc}bBq)r>SH>;IOa|*|Hdqij0P2C~^@9jg`?ejn1<&>u<yR!m)=!*NZ!f@O=a<h> zo+|W@1hAYjnyiLB^u-!AUxt;`E`dQA&|l~JPD?8EBK06gDj(>spV#5*YwL{w+o#j8 zfj0D)S=Fi3rb>~W%JqvhK1vrO3~A_ZFU%m$fp2W{T6h>{@ww4(tBa;?<Sl#Vwq%;X z2ltn9N1_*m>!DBS{Gf}3kG!(sztgF_K;%4@MymfS!f&Urdbi>2yYj{CZL)+WjHv^( zBIVlpv|YjG#WNcIW?m*>U1qD!h&XC;^^@B+SU%~l@S@Q_xNuUEAKeo1&}H%N8`+}l z+P23xz5a#FyhX<RxRvc^C2Inw+0wV8eU~NI(>q)#t-iPT+otK9EfJh4(u2u~y^WDN zZ-Q&;69;KK7chLKy#F+weps0u)vNDtkD<>NHziNGe1=<0x*dRyGO?fK^72OG8cC9| z%LVkFpP2(8r<QYr-4<?WyVSi1|7?}PWZ?PfAV{OtFX+@u;5w#>0olp|azgqOgZ$ZV zP3UrTp2HdG<SP=T8GLmk=tVkzru`B(&z|pPj<^$(s(?YgmT1Re&}(*MlNNK_aqT)b zKS6x+QH_S%Piu*t_jI;UTVmTrLR5@D1#-aoRy9A0%Q9zWn*zNgCN?29kuz1|wWyzV z?$nmfEK9M8e%gIdr@vb{^HUrYMlk?~leHzHcT^$^ytL_Z$`X32De9+{+!RKq8y+A< zWuhZtc-QqeH73i$SSN)*q0i(Ip1Ktw)T>)8`T@;@jfhj957!r0^p5?%50{mF-X40~ zVX9U<QWQ(X_Ipn6Zcm@ye<5Qt`fz>X3lsd<(|RAKj<Yw7=iRz1XzOitiO+}+tHlKW zFY@mHR~=D|)IsVuLYDbFkfr^S{<VW1RRia|#g+ywXs6O~GF`eEK{KY-CL?VOfIOMA znp9Aq<J&T|$R0}d2twwTEy@Hp0ipvF0xhDcwi93kV$uUNFI6a7pnfu;@`|J|XeDlO zZ{;A{*lsHr_?H#Oi`bUtVfT+%7(p&zN_!VMD#niDLKpZ?JDX|+aW7MZcmoXpI~CQT zDo=UGFPznpU6zY39|4v?c=Q7%zTsi)RIAvQc`V2hI2HMTiD!6tzIVuIBp}%<yIeur z-Yy})biUKYZPuEFc8XrbV;cqK7@VK!YITOY<0c~m{wOS-yFiVl$N@>1a2123+vIoc zyP+&{jOj#w^djH`{u0=yfR22i=nWP?4_|}+9FMlIGC-PSD38=g0A-BI|De5h;R2=0 zo}|t;X>=zk$a**}!Z85UthO%8WM7>YMcmor9c|&<)3<sXdl7gU+dck8F}up?yIPvL zT8UUVTRjQ@FE<aEgIkz`hhLkAPlS(8<R6t^gqxcYp8)i44i29zKU#bJmxCY&51%%- zfCw*GM1cQa4%{jZIgbuh|E%!tleMddnX?r@%JP%B6@#LKnT?f}m6@g2=U-N$k46AR MIW^gGY15$p2NQu<W&i*H literal 0 HcmV?d00001 diff --git a/js/style/images/ui-icons_555555_256x240.png b/js/style/images/ui-icons_555555_256x240.png new file mode 100644 index 0000000000000000000000000000000000000000..47849283f84f7026932bf50282ee8af51444c26e GIT binary patch literal 7074 zcmZvBby!sI*7lwuhRy*5iJ?KHOG=QCZs`sQ0qNFZ2n7j25NQUKa!?wiyCkGULApbF zsDS}Ke(!s}?>guD&OiIv_p|qUVqI%pYpr{|(bG{SC1M}~0Dx3oP1yhdK)0{J0Risq zQzh3&;da1vex&^f04fuSv37X380Mg6pbY>aTmXQG0)UI#Da0lK_zMBRwk-firvm_; zS9YVm?Cl4zy{4)%U{o3ZTKyJ5{M5BoAd3)EJO+uC*LNNR0K+SF<ws9~{_N(2#&f8? z?34G9sU$d@X6=5sgU+d-atEi+mVJ#;<+#5(#5K-|c=2QQBLLd?6@CD1u*$Z&S&|$2 zk$gwq%g=cl*X)n#9wV#{I$|IHj*z>3hiT*iM~4%6w9Gks)JkIiqk6Pz8>;c|<eaEX z^~8zX?y%Mk3ibDJ7qxwHwQbU2Et?r%jh_Qb?C7M<TROl^8sjRE+thOBk_9Q(n1PHl zmBX#6Z4X9tvnqUsXlz-ei8y%4TjS-Tv;beoouV793OV_UbGsL3brSKr^Xlxze2;!& zONH^YcoX$lSgG>pm=;?ZcsaaNHY#MdyI&y?Mz*Pl_9UMi5i+I-KPDKj{So6Pg<^h) zvho&g>N2-(#@=;ZXtX$bFSF`vyaj<7x$PccWfy|K+okFkXh@xD`1#B|^EFI(E#zt_ ziIt~?$^{;)HDYW0*$BxLO0@1gksavEl3wWk*SQWlK;0hiwP-ZqR4CFhq@<U8v^Y4W zbesuTFnJh1{v5n}fa~%At6|%<L^$dd1Quh=1xTa075*QbXNIu^j$#%Z-&aDsstGE1 z9sWEH1<*`8!-jp#?PX+%M-L4+c%8`?i$J0#`K{rnuB}Z)9&T`pZN3KGm)q<Pq<S@w zm^>R&UB!%JkB|obx;QxmZ{T{<%t{tzuPZl_9W>3XaAMVqG8D`sa|nBAwFA-`L0Zfo z9}|B4h5vM~hEq?4-qE0*tVs^>#<K33o43IPa#!el;IkXK&?eSXq*=Ot>45mrf1LW? zE|D#|NkYQZ2`W4KZNtZ(bK|?MvaiWWA_B=5hfEqhI!(vnX^_Q@vi*6|bPgflQyciW zE$5C&%zP+RWY4WSIrW^=i_nN|&&&X@IK+ttZ>~VdXjToPM)P*OzuVX*eMheCy;Iu} zw-w0GP{`+$m}0i)y;-JMG=Gs(`?e)Hg4ypNU!U6buFBt4n3e-X<8x5pq*ZdCCNg>y zCRv=5`U86>rhz1HheOCOD8xPAa>{I%KG1Epoz>qEr=h^27GEndPxH^IG*ACvGrp5m zwkA*Q&@A2`dUu_!Up<ZfV|Cp90fA}ijz&|w&(k!ecqVY_{c}#78p0g}C(32<d&z$B z&$Y8^8Kp<NqJfh5(6?Npi$a@>?rWDOF@H_Kcgb`Sue<)o>Rlelf*AfUOp=V|`e6Wp zG|3;pI}7nG#Xe3hPoF++nlFTkfI04dvYc%(DMifZo152VH%%hGPr4T+xTU>i+Tu+K zyAY}2`>l{Z$eB0K_-wv&>*LsSzOs|I;KrI+OQlWpzA;W?XpQfT+f1RoGiSw#!bx2b zoy6vVMVIC5=b1X&zY;NxX5&-7d76EDopZUqlF`S{5*}5$MrO~}Rm!?CPF{EGX-t0+ z`o;St(muTk*Q*?nr)>F+F}-wj?fSIk>f&<7eulud9LE>u51}nr(raLC9$ZCK^0A5_ zO6=$7=<(vMYonyKrftSfzq6N>V)Px8%(z--y7s6Ipzgis0%_6JFvjvj4MfNYAsa4C zvyd%iNU7}_qf(vq@^fapj)Ebfu`d~iv1aiiz9G7-sBgZ0ExAewktJp1;!kPEjQ6)Y zpw!x5YPNUrg3F`G55@A#0g1!2bcGY+Vxg<WAoY)z!Fg|u_SW<MP2~r;o8tJNf0QAb z<q)J?FH<$gX2ehCt{z{_;(h4ZW917SV{XSy>79L=Dl|5=>pNwOQk@$%THjp?_rEM{ z3HLwL{!C6Vt(cU~-}G%^+5S_#c-5b+g)-t{+wrMsd&nQJWuu(BiJD+BzvRX=Kf}CS zoXvQ$p$n9|ONo6Ag`8ACHE#=fB!!8Ujovb9yA^dg6DUE>DFW_~?L30?t3tkT51TxM zD-;cu)`d$G8~(;qsl9A`RkE`3iM*cxc8{pkYbqcaVKr?Y=tmO8tURaGk3><l1jiZ$ zCWR*EZ*h0C+KLaqN8uz&pZCvdCK!E^L&ViB>@j!7578=k7}%9vxKoUW(y1%ra~9gi zpzy_ChMV6l$?8SKRXvd;+<8?sIsB}0TY2Is)f-lb#eoogIoStcF)OrFM>+0*izzx3 zEXMqAe*ce_yHpXsD()vs-~@x~x2m-7WsRz%h{rxQ@s`_1o<<6Z@oWgpYtxA8v&&mi zCD+6+p&Gx82q|(SeurxT=zF!nwKBmd3%^t-!Ne<rllhjCzeqJDKk>s9&&h05T#IgS z!Wsb^J7Q<AB}R*-%r}FXqI<Zls5z~{EwS-hoQovXIi;y|U(f=&YUu6DGWLL@HKO{S zXlQetYgO`k`NOy6QVl-F``5o^jCA9tMKA<RAR7oFC>bT5p%otF62Wkis62MUax{ky zP9j(2S@%+D3{>c<Lu|hbCZ;RZ+PCe7Z@>CmNhKYu99|)ms0QtLR*v<7hpZX5f_Tuh zNk)}FxJCjvQq&*5(`ZuA+k}9Z_E6#d?z$XJi3e(|NIF{?uWrWxvonskS}~8b-~H`} z<`G8NFE(%NL<xjPK(Zlk?PR2W299LKFHPVDx!?OYW4*%(9xCD^t$wL~BhtGZmPXoG z(xRk{Q1b5a@G9}qNHiC_l8BOJH6woS(QURqv5y{@s;=Girq}i6|NF(4Uze9x$Zh!Q z+O*Nem%L?`mU?gaN_2tMqtJy3w#u4|`@>m-AiE`*Nu!)){jv7=G~1Z|sdT;Xk7(0n z^?X9R3`xyY86>fMUk8<sR5WUKccbDsG&Zzg!NGD6ywWZ$D%<JpL0YoEw5(+wc2vBp zx5J}sjII+Y(u5O&XhG-A&==Zj&1y+0JL6CG_4N#3j<Q#+WjxEj>ov~#sbS-|T18b@ z+R7xUH(=i(H@Q2T60HfEZD=V*haB$!Kyafg-i^SE2tj8wYX?of?+W=rB^;Fj1jj;> z_;ES47lt7*ha6rJ$OBiU)4pZhtL0@0rJbj_?+KFn?DF+kqYGP!7GVX@^cCAO)&6^W zHt%MF?q9(ZM95|8V-Op6eK2YG84VDz(iI$)duu!&#BLT29v%ABQBBqUvnsT+-z>=P z%OEk$sVpUYF6o-XMs)thTjc499kU<>?2|$zI&pO1C9Q8@j&QLkmO2o;Z}*t~M(m*G zpe06XeWGnxWgL5UD4PK;)9gU4kF4MU**(60DChteE}lAOSU$kG?(LBd)TA_*`XYnf zSEvuaed8-g8wJrK=%sgfNkGBc&n7*J0t5-`D3GfjuiW&}ENj8-O~CS_wkUzTDJ%wT zZL7UvGVZy8m+=*X7+iiGmOU7x!HQhtB?BdjmTut;og2-kzz07K3otv%i?&Zk4IR9Q zeDs|WlA2JXc|KuBa@U=89tCTMMu)dBCT!@(X{knR59G16Aw3g(ov~77Nz);Sk}-Co z66-D}&IT0S)Vs?kMwCMoavMh!)p2+f^Tf1bT?$bc1}kjHFvYX1x1q2ifMD2@tv&mo zWoiqWb%Vwx9G4RKrn&5a)}iIWPgj#j^rxL$WA{Lc@Hd!FK3nBC*i@Y|zdCj1Ss0e4 zGP`xH-KU2lgaewC8J4~Satco)YD0ecnebbMAa;HK={6<)r_=cny9P}38-N+7gJ%mY zd$0XJBI{VEL&U=_LJ^QT+1=_BFR9=O(rS%_i|o8Xfz~w^w)fX-{CD53uBt-MXlmCk zFJX}Lh(fq@!^ta=AS>)hJm&{f4R}m>IDg|12u(DDC7r)ht{^wS-ki=`D1GL73RVpk zHd%XLyLi2qwRyUB;5$oYlVH$fmcK8PdHu&CW*?Q9Xnan4!KT}Z+n!vohrj8CAZ%>M zox@&A^EbBZmu(P)K57VChU@^jO9o220zGl+gD-L~mBGrxEUpu=P=e{S88gGv;{zA@ zrQ#rJ<g&JGH?ub0uuqbb7L8xX@-N*<Cd;>;H-Z97s+QfNJEP|h(({$n+Qo>?rEHVJ zUWvM|1g0JpT%?76PZm#CODx(B(1#b~Mad7G#9p%4$3ERF&YH4_*<N&%^3QG1cx&Fx zZ}n_=iT?$XRL3jUA6`NtJSZzu|IYcMg6v$34lO6J8fw{jR-6B^_L%+?qgk=Q5=md} zcIN6<))Nix0`m!vB*XIAtJhsL2zlVg3O`U|I!JI3Rg?K}gi+UJvPk-io$vY!QS!>@ zk)z8O;lFv~2c0rDgbZK0!h?iw20YO$SlWeE52Dn8rtoglXXcdh?{M%j61`%t1vL%2 zHhv$;Fse-?*7XbA+yB@rjwLRqgomlyjUSQOa#uh)=I^n#Pjd7^$2K}z#X4>;akD;{ zy*%g+El@{~(C;%b94}FS4rMSRKW4HX_=eGL9UiPw*Nc@1Oy0aKrWrtL!6n*+`m3c7 z@$Neb2R+IDlJEEoTcd-%KH)2$oR>dC#HO^bZW+xKBvd2s2CKUN(06p^>EVA{p;A4Z z2a^<Udtt3FoXAQK`t|-O@PO5+K7ssz^7?I}`q6hVr(>#~Rq!t?=CjRf<L3mXqW%8k z&M`mdf-zJnhf~PvH9u}dR@yb~cRjrTGD`7^>n+`RFjdJsn9G1p{8>alPiyguq&D&O zvbVA@F^RU93_1D=C-`1>_g6q=khfk;-_RiS#%>PsLs2fYH(KXoRUoG7frgq|nt+`< z{TIQH0{(^@@*~5Y<ypj6-=X?_3kiclg-KcPu7@7z$uvQWEP0XfSm{$jgA{&3H!Xw{ z&eaG;S$4lISNFhIB}PuGDm(EniY&LRQg%rnpNU5p<EtvBOvAIedz-<Q6aPnA<-!bN ztF7G5DM~^4EbJ!z2p%X^3Y2XoWdjvW5S3gr7|h8lSk(|r?3(x08j~X97H-I)JO}z@ zUgT#7I`iLin#(CfQ8|zmn+?!L&kfsbcOPNHD+>b514)|YtT~g_uk=T!Bq|O3%3~9e z_Y>c>;OkVkt25)z_cna~Q=J~O``%+SZSs;TWoXnc6R+o^hTjHtym$6orX>e)m86$o zPim)0;ljuPQ;+#3Ve0@?)Nk2ub<L|uTGp&({~pcv^;(nE%c182%1I0ZLwuI-*IER^ z2L1s>WY#ezZxVe4Mrco4NN~8q@yZ;j((h9&;x>iPxuTJJ1z!5t&-1w#(6%Ana5P4~ z5L-Ii4;57NzgWBcUb=EJNHK}pxR2f{Q=DY4>5Yt_QK^iM;|VIfjS=!|bO09C03!pD z<Md4r6FxL+blFoKNVn&c`3!xR>tS#%V1NJlQ2{1S8bezyxxN&J;RWQ^NQt(DiwMF4 zX0bg_=e(DY4Cu^#{p*eJ;NCmVmah7v_T*kMYLymI({q6eY4iaVaheTc)%3|{_>YI> zi;kht^;RRp)ATAAC2shIo!PW}0-<gj3e%K4tOWmhC6i6bxWvfU9Y)Hu2*`|W9oKmm z`DKV$Cc_^RVBfKI+koDYImD{%bF*`NGCDlWz=IQDBdVu6zREIK{a6QBM|_@J`rqC8 zVte#TI4Y|nWsB_N2WxRv%;VXsM`Hpy&*4TmI%w|B@}`CnuRxj(w%>Qg7QG*Dft?i@ zYS9i@((#j|OCn!D-|R&Md1@}sEN&%DuYqyXG=)%CgY2M*R5!j1jg|Yli`A}=RWpi+ za`if+5G8ZJJ0a~Q-8-=`F^Zl3$5JrSAPdI`1q?PI2r+lqW{>Uya|aOwy>}_n?`A-* z5oh-`X!w4Sii=Dju1AD6AZ+4pBptpjn~Ol|sZMZe<Ep271Oh;koUB!>u%j?a{|Hf~ z2YB%ksw1OIS@(G)R8@y>NE|9X+~<iEeqxK>%zU-%3j@>fWwI<%77?0leDa(AT8j-; zOSyQ|;o5!OdA-tgxPGy7)73yB<C8TIXHBN8$y+=5zEf1u%wrK|gEQ<hrY&>LQo&v< zZZgs|*<i9EpJ^jI$Wl#v*U5dwxuL!kE2CS5`dXL-n-lb^UwpMgo{^}1w0^!}$>OVK z*9L3a8I0zUJ~q4%JlM9S3_W*S?8+<-dV{W)DKd(4Xl_&xro0D^aq<q3eol0oT)thu zjhP((A|X_Bf#{m+&i&=TTWq_(8{9_e&o)U{3m3yyd=~vJ^$E^gU0-5To0FNEy+<?7 zO2{iA^^t?1`fM4W{5_2<d5iqe$SS%ADtAJMjF-ZenY&wu#Nvtdi*Z#ZKVN(&g(!n- z5QJPjC<dFa@uiK8a@U3{*mE?3(}d|&2mbw@)V6{IXJWgQ=xmK)@mOsv+wd8GLOd{r zZtG>}c?h#OhECQ5l-C90;*xDdJic^9L;EEpb)GSd(%QdK-?Pn@so`x8Sa(R?bd@#e zr;Ye{7#86YIT=_OjM!NkU)?_<2o*0QWK)hS;ilP3mN}GuS*0!A_S`eDn*lsHJ7SUk z<TXJ9yTnOj&e=1=2RRZiGpOb2?k6+nQ77KanL7Ii_voLyiXbuf{K8rIup1mXtz{T1 zZ+W*_&!hn)y``3^Q}{&oy4dlSDGCJJ0x65D>2og6<4jTPE)9D=AIh{^z(($abO^gT zxAZgcl;spoYraJh+6J8P4b-DbnFbl<^%zOWCn{gQ-P*GG^&+iYXI#7G0J^rn7SLOt zbH?z(!!s~Beu#usN=$=2LEdxaifF6PCv>#>{jpr6b&mT!c2|eioz?v)X=0YiZA-^B z_YlP$PQuFu&NdJ+-&r?y*(fO8G3?&*YJULF+97oJj>chE2k7n}gl=Ws2)DY(3Ol?X zGX)35b2Lj-{Qs45|0jo^gnnNbBKh&(0jzgvY4rBrM%{ttE)srfcBnDhH07tSV_apn z<%WFW&|_!U)yz_iPB5Jqwfm&NngLgZ9<du}+#}ll_JRAbZ26uNW;Sb~2j!{>+vj`G zscxLASry{hnGY4@Xe(kdvIhKIszn>WvA$y8;qPac!LfSLfO|0^?PoAeUuz}J#uxDn zjJW6~ybFQ}pC+X$PM0UtA669Pu_GR~W<M6pG!-PJnJNFq^E0JA<vzogkmCp6?f+oo z6!Gxx_nHJ&_Nzxj{VIAE7~_>ERC%ai&mxYb8#t`vNNI_kpKDQ9^yBjv)h28PY-|m1 z2w|9G3gUX}KZ=P(%^4&`19MZzSEEQCA*@i~5oJ|_M)1~$sCwaU>xy=%RiRGK-xKNa zzlO*83Cqcz|2LBF9XG;t|7+iE5vve40(h}{{yzVcc<hdxP?M|UpaR!y7VW7D7MHrO z($h-y{@s$k58a@tQuWDgPjs)ERf=?E-F(o55h-U|^|jP2@r!26?~&W7kxt=ny!Yeg z0~6<|#a{j+WdyAid`P98ozXdy#XH}g+>;=C@%f%ZWKJfI)+eufHj^urGAAC{b`~AT zfPQh=Uh#-7|5|M2Pr5dZhd)BF(VaHmqQUP37N0Fz0G7n<--6^!=oo@t^JT1B+sa$b z7jhyPOaMBZikxa_C?)%b$cz+mkj`O%k2f|D?;xA)YPVg}9;1n!N#J7x%YvE}>n~!@ zGvmp;<gK1N(Q!|G($e+h^3Fg0>rm-@Niq}MrV#fLt2obcld-I7SI4)?tij=nAPp$W zDoRU#BJKU=eS38JGJctp#$R#^aa_hnzogf86E67AMq#W9e$2gzw;^#+@h3OF<1Zkt z9keE8vgAUqmGH3JVdeV%DfO|{HT;RYwVeCG=`GKS<d^(+zSR-8A_t;p(%PP8fJuXH zT%TCX?;nwxTT_0wXfGz-Sc5;7CeJIIU3V&5ID)5njvfs>xO@r(9)5^eC9>}CIy`GU znmI>DVAryd&!{i>_X9Eb{N>>;1pTr%aWh5MU(dPN1Z}hvKUhunl9L>IY;72Bs=lzm zcwi*^<oP|cCVC{l_gI!_T2Td?R6cVal`yHA-dnikySL{${3in6c<S1$k<Ez15h0Og zrptjm1qSa~@NCQLu9HhymW@NIlr(F_@7oMDGbYH!_suN_W$SYPw3ICN6!aR$xh0^? z2O0{>29cT<tWG1~-}Js-)Zd7P7pSuh<q1I}gg0rbF1wUNo7y;kS%A>%U2l(PRS=S@ ztaAdE{Nmw-OIBOLAkoQa#D!J!!>}GG%73ZoSR2Ea+oq?(tgqmH%}fFs;}{KKMr6If zOLr8x<{IcpsZi>fT#5L})yJdCn}%kgErY8hPpumL<>s|9HG`M_#BMizP*z4b7~oSe z8or=@m-cOf$lYxv`t^C;F`D<7z4a@$4x6>Skz<mYies=*F5s`O{1<Su>=^V-Hd=B- zHXcP|aysqaBbUBras5l%F~C8hY+`l2SZhf9(`!W{6O(K5<|JRktTxXB#Hef*>;L{o z;z=>?73A?>Y4?}`*vwXQm%v#GV0QOGF5JT8bs68;9cgGZB1HS!bM5^3l)FE5I+PT1 zfjWFk=Q$qTS<y{fH-#L*eOx;gtF~zTU~qh7C8&>Ha)6zjDI_YLluHZJikQpm{KOHf z)E@Ne$?DWPbX%@X0v!B4>bgIDDQoTW8{%Q!P%!9!wr!*M`QLg07HNP-8|)`>KW<6e z4_Xn;e)k3RoRf+Vu%u5Z0y^ypi+sJi^)@rie{`A=uOHWxb^5oY+EniI1*}|@8#%?e z05(<0^t|}-&*l&YuHpR+KrY;!vZnJM-+(h8VC);Vwz%FZ=X(9}F$RUiIVKVTY00&> z*0?6O`EaBQTJkb)jnj^s6beYTvEYUv?6yJO>*O^)w~N1WBiCa&WzQZE53`{D@d^5R ziyvkye$A&iiG`Dm;`GmS&3qYW9{3?1FLQ-0R@Dx=0Z99PP2vR|<KB>`zs%OyovFL+ zVga0fDyDvpc79K#9ekeN4uFV|umr!56u+?86Jb$lQBmoCpqR9f5GyGe_&)?ZJRMz~ zg8wBT$uBJWL`Ym(L_%6z?0*G>v^?@}1?d0T!O+vmFVN2CDe%bA)BY(;-NVlLslih_ W$6)X8PycD00qQC`%4LeS5&s7ix^mY5 literal 0 HcmV?d00001 diff --git a/js/style/images/ui-icons_777620_256x240.png b/js/style/images/ui-icons_777620_256x240.png new file mode 100644 index 0000000000000000000000000000000000000000..d2f58d25581c605a5538fa50408fe09c4a30740d GIT binary patch literal 4676 zcmeHLXIGO=x4!QrKte|l1W^dROD~~?UZe>q<rN6M7a_Dr2`EKS;86sT77#@gX)2)f zCMZf(h|~bmyV9g22Yucz=iB)KXRleaXU|%D_L^(WHM95Ju`n}Wpyi?k0D!^BP}dRw zz|$eH1&5yYL?h$hrwZn&WvT@L)#-G{&Qzy1udAV@DFEPv004g*01i*5@Jj#?Dh&WD z7yv*$0sxMny!ThsP8XA~FtOGP599s+_J2g6pDO#?DWI-cOEW9L)*y;c_R&mJZ@5QZ z&7Bud?agqDXtcXWf>o;iKbfws&ZYz}e_U?J)0XJg#<^GX%Rl1M9Hu8p??%RlI=_7# zbr}mHGxX(nA1I5lb9Y4!&Xva5_B<FMR&IUCC{3<v=ziJVmbH2s4s^L}pbI2ZT`)W~ zXs|}6dNd>&1}ZMaxx{n&0KgPyq^o5eF}ChN=X$=2WvU@nK%!fiQ@{&~NNE!l2(?!- za>~@^;xnX^@y=y_{K#^FLP^?~^7ZuGE1Gj#_S;<S+?&u?Z1~=kGpTNud@2`t<J`s_ zh&AMa5NcHTC9s8z@IbpyNgz8RT5SUOy>3IBGDI_^l?yP3mPBo@>YK*f^9u78oyZI= zUvPsB%r=5qD&Kjb<&?0qYRh?ATER!Yb?#=3IU}?lZH=ir)FE`+Q_cZk0i)j(WUZu1 z>JW~38kdt?8s-w8TL`^InlmYcVB!8`(W=nvVFn_6f2FuvImA4uH^!p9Sb@-YQ~UD3 znm)d;iaKf)^wTmNX})4CaRCFXqL**rloBcjjq$?ot=|U9o^v^=+b2Hov%6xX)}@C* zFw;U5Yq?t`ZHay($s^ZnnG8RVMe+NLvt#sTmv8Lv0vg)2D4N?h1`8o9|CMnarEblo z$JDEv+!5Gv;2=!wP0!@J*kfg2)q<e7<utSMj~mJE^DN2uwGwF^FZgY``4u&fmPG#5 z5Avihpb^Z#<%`J6bT+_dmUjJD5T`b5i;8#4msx7#ql=jBypZoTk1+e9Y)xOrN<<`0 zMwK1hdBSocuy}@j>^TSbT$Y?J$(-q{VE_#*(2xK!k0?%-jmOaD-T1xbD*G=svo*y> z)nC&B^j%c$ZBz^`BvIGBfPAT2Z8c^%n2W5f^H~OrIU+)Qs4C6e!)SytlT(ZNZdc!r z*LBuegHDr}rm|$7xH{p;K*^*@)=OaA>zQ^R4-M+ZW5KNXg4Un6So%h0f}-Qr^I7R! zW~v0aJS+W@&!RBqZ)Ht<O6MgNNm6}qj5=vjZg`oQjuo?s|HWRB`5EG&1dcR?HtTFQ zf`0G}<QZ<r-jxF75b4CGBxuCN)HuXzNL$zv6qaF>QBvbA`X*jyyl#R&wx)@L5n_Xw zg0i>D?cY?#jBj@9{*@gr&m*?QG}_3kBbF{rX?pc2uk5C$<km{kQolXqb?s1$%HSgp z>e8ODu;cSi>)_g(`eoIun-2==I-nKJf>7y%1eRzV0=${;fCy@tb`Xfv;AyQbaNe+a zO+Jjj^<JVrr7|Cnn!vJT*tR=Qg_^5%4f{6?qb=JCIY$h&T$Yh^;b5*vM0eFw#rM3k z>aSe{@r-xgCWYfHtx^#ZD7op)x)Rnl#Wfk^-9i9~Y;WkeKIl9s8tE#)+?2=&CXDbL zuNrVLb2zm8;aPI(y`4PG9*F>&gW8wRm5xJpHixg_Lvy=!nukaMyd@=;l_I*8iaNwW z_qf@!Pkm@bX%jymNF@wGurbb)5Kq{iI}u2CT-wH!wXo!K!q7(XEd7=&tGVbFc$HsE zNW3MV6=ciY`Of6P+Y(NfXikW@EzlcSKomg)+XCv97Q>V0Pjb@y7<pC7#pTOt&!A{* z8GCj<9ETRtBPc;8zeQqwY~T_tqJCSiW&b1Hy6hGHU`cKusU!)8)jNN}|L5#UamdaK zyS-d&k<F;DDVt(&U)0xeN>hRqoL|eVxPQ6pu8?PpMn$qrtL=5<S;CnH%Zam$IYKEf z&l<+r3le*OA%pi)rWv$p>%7{{HAiRP3<dctjqg1A<mc&IXIyzx{agnIn2Q?(+u{+p zkrA;>4xw81TwclkUvFSYH#cVdIl#RbIysxBg)hfB72kMTR11v8gxlp;1Oc~{rlaVj z!PnnEQ>YVLVaWj4KpjW0HsBCIB7{oT2u24{<h`hk8sHq{u!yT-0YG1n$EjUP=~n;) zn}4M`alx)Pgx$N49^U%{B8Xn5NC~ydi)I|=DpGGgU7=HmFm3Y&kBmdlZLEgk%d04f zz*S9q7x9<FXFnl>PEZ#ia>&5A<0-bDl*&RQ{19d3Uic(T;75GpeSsqctuyJQt6iO@ zwb>25l8z7|E5O(u@bZzKiADeNh@K(j!I+X!&jDe4Q!x?_@{o4#eB60)T+jd~FtjI8 zS=>rWN+OtM+M#PTxjzNs;A}Oy_>ME*65QxF?{?Q=?oP94>liv7T-{FCy<h>Mz70rA zV2XG5nFp-*uYfMWw-Ny#@Ow<$A-fFcS8i39t4Uh-7c0#5I?XV9K$uq^7KBrwSukBl z#DDgyEUVaok{D)yYT%IAYkTtG=S7m3?8y>!MG$7_sGeDqJ&i6CA0KzUoXJj6a-e<G zmHTnUWo6Yj_7z1$hnM8Pcc^;z`Z#%qt#Ne>sC|+S%V7-PWJ@noeQQfKZhBX}?1zz6 zE!H&5CM)4UVcC2my5ggkubI@xZp9JJUU?}0yxzroNn=dk|8Xc-lTXWgm}278V)brT z0a{Z9`R*;No?9JEWs}u=H0YHf?kVM8uwFJB7QeadfN#)^ov)XCL;j=`SnPyD<*9f; zV)$G3f|6t-3*|DWiRVkI6AoS}v$u3?uiMhP>aagM-Xr-7yd;~KRxoPMuh|6q2ldRl zd6s&wzZ(%}H^p`#L~Ll7!To@#*q}Kfd&N&B(Vq31j*u9p*bJxGPFk_i!XD*=jOuOR zsreViYkg5Zftz8H#gQ1;O{<SuqHETDxY{{B!egoos<pO4Qtd{@S02gl36iA#S=Mci zrV^~71S!L|wWtRFE~`|34QYT@F;du;^xhn{Jbbf^VfpL}6@h%EUp_BHn)<?|k?9n6 zB5r<xHAB04#kw~(q5sF|;!@{rnGbZoCHbE0xEvctE%6f4HY}g$bjH9EReC!xBJBE& zhVUMEhc0D7_qGvmpC=~RAG;oyE*9BR5fH8r=`*F?mWUQ~-QIAJ6dw;9QGEr2Ln5_a zF}+V8$k5wRy_&RZg}xwjrUF@%s9M%{iLO|aiDXsYQcp?9BMUiA1i~}sG<P#SQ_P40 zK2kL`dNH#!1MY!*;~L-xVe>Nbj*Q4B9S77qB1`>arTMsT7>q<8@+UjkJOkDHbIJRG zI*rn=uB#}!MP6KW>Ob&uu0A^xeW;avv7{<<I{RQS3fA*2ilh1X=gUeG%SvCtPz(Ne zeuSYuoGD=9#c(f?A;iwb&<$6Fn0h`fpEwwF(1~fK%(x&;+#Oum{Nvp)MorrZdyV9Z zEvEGpsic~CQM!P~SbjzKOLjJGFZ=i%x=pB6aUoSE18on3?`Cgx2HWp>o*`V9wANmB zJXT^rvu^DwrSru8db`nYf!6r8!6i(%tG|-}%teOwLWH5-JL`XZoK&q=Ws>nUK9!70 z_15L5w4D*O$u7xmxH(pwl~BHG{^i($co<-HTxP<B3_nZ#1D$BsOr+7{L{k;W7O)Z_ zLab4a(NV$0?UzmQU!4eo(w~$W*w^@Ewx3bnGVq@Cs@nF0g>4luHGkP3@2*^2h=DNv zsH9nO$}gw)gVVWz0=Vcc45baht#DT3O4IpQ>8FIBX8$Q?75j=5VTW;MAHA)0I2EO# z1b@Ea_uIAFwviH49bw3*CXpY~`tc4I5OF3-mOE`k8F62QH15Or{G7$%qP{Zj@@{xh z>ZN@WT!tWqLJvDq3xPb*)+hYbvw6_O?;k%R@-Wm(u0fOLah|iBX%z3J+B}n;_=kDm ze2cXl@FD$hbn*}qO)r)zGV=(Ed5%X^O?F7Zm`l2vVy_*6S#t3U^y07Pjb3<s>JDAe zr0fR%a&^#^@wFb}wYrS6i^e=@;;D+}R*Q|ncP<yqibYRI>#O>yQU7_0P_D`51}z6> zrZUq_#IRDu<ZR&5`I#f!$Vtrj<k-0i@z6?}_SBzuo;3TOf7C|Lagg4X!?LOxsVII> z7+UFdwb2^1_J>r;gO!iDJN>JEv%GtD+h2Wv&N?v%_pHBhw-8y8P3vTE&uaA6uJBWi zV1Ksx1xd>c$4Bj}ZN4GlSqgPVkRS8}?WJt}IS(G82-otjPJx#eo{?*xGz?=?c5h0y zG%3n{t~EqEPH#?_qRkT3T5qHbSCJJVmK|;>w-%uMd5Z8JjAE{T-|#ou1_a4HgKQb@ zYPseI=H|obpdwC>MX?bTh=?@Vc`|JfZczpEdXOuBXTx_}qfeKXg_=GFrAc+0NMchS zrp;DYe${1F&Yush%B-a9{JwT;m*;DZgxZO7ZuHWy&tIzPc5?F56h@5TS#G#p!|4>$ zg@rvQlUVu-0A99pFg9<|zKnFs-7h@^?FIXS%$$iCf3v8?JVBjmomwr339Sj_)0=1g zUF-j>4AN7B%K5D5TYAmsFc&{e!odS+X+eT5`8mq&_}q+!4W~57pK9iOkKsmstR_Yf zqUZ&Rvs5|L5!blU)w?Q~4s)=1s(QW@%~a)}$@?d-m<{frT>P$QaOebTYUp|@J<Sfr z-q8@YX)>VITv&=uyg~l@6QZ}CJJ7G`CBDyi`Jhk$O&I=|@{q+9-)#4yf3@zxQ6gJf z!hsA&_ksWFyte+Eg`>Cj|FlK%QWU!DoC69xZDb$)L`O5=R;E0@z5C4{o%F%VqI7+q z8^*?SFKcbIu#yHLaOb^6@6pQTSaN}Jw$1&Mf-@Gj_)eMTIUh$`uF?lAV7jrq(3IuI z1^q6$pp?GG9t;+qT67Cfr-VoY)6&zn-#AGbEM>5b9CJt=C2n7ijCCyNty}n;IiYSf z^Dy6EM!u*G9^ZTa2|2J2)s|J)AH5bZ?r5VDK`ClWz3PU`sChL}+f)(EymNxLc^_}D zakY8ITQJ+eJ9TIA9=$bt-;NFH<l*aRa0(k*{GfzxEH-XBd<(=v2YNyUi^mu=)Vmrw zijLLt=STnZqZZqE(}RN0kL@(qJQ4UzhTo`}C36wNaTjX1no3JL>UAVqFtopau|ncc zSaxHRqAXWhG$7BG<d!60#F*MEBE;q{?I`vjKI0P`Azn4u*V4eZGTQ^pam;a3NI}CG zvCGtEkB_xZcOvn?ULCPwbl1!h?Y>{)lP}<XguSmY>>G2vh6{R+yYm^3s{_vy|9NS} z^&V_!$=D}nzp;nwE5>yX|6;?(r}msXN$$Z-rl0%Jj-ONlz%h)?$yRGd7(JkgBL-&j z7{M>*FvE70vQ5ax4$~}>q@jK=`$Uxa-;%95Kwz<(6<!d3yZl6J^!9NyL4%(quDJpY zG)*rWQ9^BjZ~NDm1MSf_8k-J+nFrRIat^t;Ukq`CG4}X8I-FB=T#1eGBfO-_{M}zk zc90}ZtWNKWk_IU4eIV#{(x1)%lO!-?PVG{XlMCi3)<5Hg9wFnTPU~|)te!2_%^B;C zat(GrRe-FtjH0BpilmIZwTv7}P7d|Qlt)QRBN-SW|I5KY(9PQ;^1lvBk}`7E(h4Y9 zMU;a4zYfwS{zaz_oPQ!%1$tn^orB#0Ew?}ycU~iZXHR!acW1ZA8z0?Izjgq?NY6~S ILK_qRKZ>1V4FCWD literal 0 HcmV?d00001 diff --git a/js/style/images/ui-icons_777777_256x240.png b/js/style/images/ui-icons_777777_256x240.png new file mode 100644 index 0000000000000000000000000000000000000000..1d532588b989c5fd03e7a63f7e829b017c35d3cf GIT binary patch literal 7013 zcmZvBbwE^K*Y1I#krEhSXbA!77U>WM=|&h}hyjt1l7^vUkWxw-luqgH?gjx#k&-Sc zFTeNu?!Di8@B7c$XYI3|efC;sueJ7mPK1V<A^{!*4*&oHsFJ)E0H8hG0!KI)4_Ac@ zXX%Fq!&*jF1^_B!@NeOm4>G#>D@A$0-EzOL^g+UQg{mrGuVNEmLWDO$DPIBr#1$$p zqvP@Yce=lwm7-gplzY{y*?~|=xmT7bjvKi**K#wh-O&s)dY%ri7MLGb*5&9Va4bNp zxn)%uv=lHClnONdK7q<;Hj$LnDKThjG*fFDY!kguo|dhsGWn_s)%1h*=qW5-e!gGJ z3SPQ*@*i1x(RR>s_($Sqbk3{wa9KdW9Wk0B;PPuY4OcQ+@nfaqJk=2;cQYVJV**&J z5cBixtL!s31L4VLr1N(1IA=yc=!zdJ&a=KH4AzMV>G+eQp?SrAbTd69{MtIO^lp12 z?0D*FHQa7YE!m(HgXE^poP_slbC_!|8*rzA{3xWQw9fjwLVUM71c~G_Lm}H^ozwZF zY5379*xL&N(O-ErUTg$%9xxjvXuXTr)53EZbQ=_P?#E~^0bp?3po;@0uf~*+Je}Pd zRc#99JY)5-D9XS|fdEFz*Bap&0ft`_9RteP<%e+}9iNY>Q5MfK84l+0ABcVO$FE@5 z@SVZfG1Z;dp69PsIjtIj#U`I*z@_#NUA$&e7J2Mu`n$j%?Q9oPzlh)RUy$5^k;~Cy z>s8OztkJ0nc>sbi3S?*(zI4|bX4cvf`uIB!G#k-dFQm^B{Fi^2CPD(a7zw2EAv){n z+HWylc<+{ASEP33HXpJxve(hIkDw#UWF>-Fg;rowwUsN0*NB56b>FcPEVeRiUJAz{ zLyT!&0k&7mmUeu)t<P>|3KvyWQ$HUzK~B5?@8czTY1-Z&lCW7&vV1$2W8<_vZ5k@{ zyIVg7L+t%o1qxXf341-F*UUK-rE0%l<cYF5(arSg8tFiwQr<{N!yb%|q;S=Va1_R} zW?9j`kZq&OGIerizm?bcH+%l;+e7|kt|>S}QM9`OdF`FA{LA0JWgAo&4Buj?-eNG< zN)Z2UL72ViOhFttF?+a9&rl-Gjw%|f_$d{Y@1<HeAChZpSNFI+n1jSUldN6OC&}0M z`YJ#Uvw@6J(C*%Kz|<^jV9t3AXR6eq7Q&k}&MBSEB0LYN{N!JW|BkEGp(eT|K2Va) zgA}yiVv|l2{AOPoN}gHfr99bu=7~e#>hj%iXLv+<*b1=14#<|<s|<0D8@07x`p^&{ zx66vv@WrSGOGR~@#on8iY}?8NBtZV_v9hW_v2+tg>QqIcfe5+%TbbJYrbkbTJGs~2 zH+~A@hqSA@%~JowihhmI@O%`7H_Nr$&ZwfB-1No;yCAB`l+?z9@;%}E)6-|&=K=x$ zaW(woy_2o+Zo}OpvrBAArTS?kN}>9-_~H+nx%^MEPA&zgrb}D$aVecwLy0bR5Z;E* zBPC9xUoD1GPtUB93yeW<?j)p_OMxd*CQ89u)~Ve8N!F{O5usqozYaoK-o5e;-oNDw z=M8b~AO$~W&pNSSo-PF*Tt;YHDp;dV_T#0+PUi$>roV{|KFDxfBUIE~Rro||#dzN` zXb&3V92dz-CVj;YxW<dU;n6-Wj+6n<^#U;RX%e|VJ3p<Ls|*^&-pzD~sc^I!YN`Rd zI>?sm-;a%bB{I?ucb{bWUt6lEo`rqJ&HI%q6wCF~?xxWfznOQG?O}E6pq&7{IzBF2 zDhh&M8Nnm1`>%S?Dadzs3;f=tZrU%-jog#t(UA?}Aiam`=&9g?X}`OP`*ISv!%)Cy z<yd=e5x(pnqHNHGCEQf8_9gJuT_nR+k;{PP%+=Q2pL6p??eCKr;B}J=u^R15_JsB8 z4~$QmgK%Q<I{u%4YzEG#y9BNErTrw31gzc(uO^<_es9A5aNU5<`Ei*^?|nj*jfBbt zN0P7Sz;W?MLTZ)sf~JPSW(n~M2mcxY1B#VT*RiptM8puT$uh8u_ARg+j9P4keUz9m zsmYG(SkQ4O$U@8#3j|eua`+-IErG>L%fMrDs*qOEEy7r2cJqzBg(!$v-^f&By==F^ z7OnEP9UasXoq-x}$mmOMP?9|ge1_9+=Q$&+VGZAH%qqArt|NBy@p%NK0O7OM9Q<}w zy$c^o-E=J&Y=~<@W6O((@80wjJ?;N)VR;rjk7+4U<prITHx|4L#F+8|C@hMXC4#8} zDk*ApeP?lZT2Rc4LGe0#-AWB<`bHoT0!-KEoHFFSc6JGwU-E<N*$hA8Cy3F#lm{n% zjr<e`Z&L#XiQ<hr&%5S#<7Ll<Fu9*-h`2LhNs+QyP<*SP`=1Hnzw;lT7y39P0Xm6b z-~k+J?LH2$y5{W4R&O8l7tdGRF+@EYY(TjS^hC||t0&1Tz3zRd3!Al`mwSqw3*ZE{ z3~f*C+$W2SToaxU=aGKhZSjuVrB|186*~UtIFnYC>dq@doC5S8{6O{ZuZbn?pves1 zXPg)!X6Op<={7=Jss^TJ#**~OHnp8x=qE&(Ymp^`!*u2Li6y~zGdIT>9~)lw`0+XZ zxqXUS;J>C5LvJN~jHXnicUvy21oQt<`@<+-YBT@WDFc15#_$>f!ZGmkUrPLMvka^n zh3pqP*^(?Mblx2!q|{<6c%zjbb=a2QI{RJ!)N4g!I|Z8=&Du!C56IK27s43WwgaR+ z8jG0t%b&(CD|&qS=edcFm5Vdtba~=cA$NIPz(xzk!2uHl>k`Cd2b1?VqXSLLfG+Qw z%%*ANJy?J9z8nLuR_6Zidh(CEy`ezfWJ+jZz?ZhnpyQPSg7mixkC6-Y>w3whX_NU} ziGI|wqe{h?gZxgBHD@=U`7d<1j_1cxm)eCFm)cX6Ns_;9-P@>06nTbbIG}LphwoA{ zW1ZQrJaqnCy5QPWa$<~{3?Qa%T+-&4(|;EmZAKyZ4do@f#m8_tgE2>;2~COkQX^it zjcIba2hk@vXE&5Q&^97x5OoyVVzp<$T#Znc-^)tFWWsR5G<Ngwk}Z2HmHbgsXe&m0 z5d!RB$jDGUoYj@X3bNR#`;BfN(Kl}Kp}$f-SXFlR%hM7*u84NmXoo(O>_HCA)`lZ* zFQXX;7y~8=e=Xy*qAyf1Qk4^)&(4BgL1NltMQNVMgT_-~pOz;<X*y;jN5k7~vie+& zdfO#XBV-ubh-U^PM$_FJI~?QU-vr9PuB?;|cQKYRu5!q6JBo}CL&oi*iO32+ksbx# zwGBvx*HyKayoIh}*5boAIpxuL9h6k(9NP2HR#S8^WVbwCk~|>^cyhy3?L23GP$slh zJrdJEa0Rxvx^+`hP)ZNlG0;|}5G#>kg8x0_XGJ0RJoI|*%`pQFH5KfCS+R`dp*<#% z?($pD&!yd@9fF;T_7@-5?U79vH>ji%WQ|z;Fr)-+auw=I0Q2N6T-}GK37swBcPL{5 z9}vS%`?4trwLeC2#8I}+(Oa)v%v`>yT!x{;WjE02m%K`~mApYU;ylV;n{1U>8o6=H z=f`(X{cO`Q(4F)IV*h=gX>+-k<?9q=iykZ~M$?UD6wdSPKta|&wC-307_NYj6tzu& zQKE<sryx0{RIFq({Po(luLbw)5oM19GRI)2x@0x+!V}?2v!sXSpy10ug72Z^3T|Y# z??;Gtg=l$texiD<*>6<Q8KNyw%K82GQX9{A^hpp2Hgq7BXC|kE<7ht;nzoABAg24) zrAK(l1o1sD{=h%m$6}jONGfnvF#D8)Wn+@GNGRqrhe1*3c}P=oKdF2wB?2%b+x*Jd zG}EKLecw+MRu?hxfX5?D?*Z_tCYlNGU;B}NrJwd6oz_<>4LIL`Y8qk0-kS4C9(CR) z@cEmLM3~P|Cd;RLgv;5~^G4fAXmuhzEkL_E#&tfGt=;gWY>m_>@GWQdR*JRcAI4U! z+HHP<6871x@^?n!pmT;H8n_|6(l5$w6hNssz0OH`aVk>zduT2HkDrf-^6#ysX?05? z^>=y1D>HN}SUC}y_fsEv(Rg`E-GS|jPEnXyn!~+sIv8da*C#qcrE!qy5lPxUb=#Qz z{@2F97fd}*1u|s#U7S!U8#;V{Ti4XLwxQETYE9AOQ_K<D<!NkQV4i_>;?F=;^`+}V zufPu-jA$!ATa4FV-ba{DU5VPbq{JdOLQ-0z2r0LDj<K*si@rRaX#+SDN;-lYlRqyi zT<-*u_-Q_`5*y;jPs>l`tS1@i7;xQ%OeN6Ngulg{PV6$8-weB@E<Z`@Wfkp#JcR#e z*S*z4Pa=vpE^$UziuMII+%5KBhFlW)e`u7DE5}y1vaq-r7YQv7;-A~1_Gk`(CG4oa zWeb#vFqSCONM1Rgy}@j@Tnrto@vJ(v={{v;?ZxmZ0T>@&i~;_aUmKKyb<fp03T+*L zw&obuJAur;)2EDs(96ariQZ{c9a))}`}lFUkyc49NGxy(fv=b|6a4%W)xn)KTfDTZ zjEM%T#@#GVkBDW(u{7A<c~cO_p1;eEzc&$n-f`(cw6Y<AS?t#7=e9@jYeLr|vcE$` z-yk+V-~R*AiLPX~{vYBP7v&Av9D;)DqbNU2DWS=k<EmDXPVEMva9X`dErp*S712u5 z^thtYy1Bowb*5ZVsS)*!pEM3TWpq{U&X!|O!yCu@2GGqAZN?gl@!=UK2lOsNm(E<5 z&gA}s>=D8PG3$=h$L9v7J5)DgZ%&#a?r6|~lSc<on0(wF7m$IaMqGTkbeh}huN$2> z2bez_)o-NI4A(Qh`#IMok2zN*<%zG9<%LhF4x1($GNWT=mAGl6bkPr^BZkbE4`vU> z=`o`hi6AeX;)qTu-+gY|WcGim`O9$KuaWcT1_B~&9B&X3fYL$(C&29#za_u^3lYJ8 z^3J8>-am?BC!RnmhJE|wP~1+<Vt1UPWIrrr>8%-wgiQCTN6^Z~TR{9}k_Z_i9Xj~L z2{zKvw=qW_Ba;jA6k4Vj29YU@mt)(AHgo;ov(7)YX@nHnZ?~kWAy&wKi52GRTH6ZS ziZdWXZoI*yDNi$T`wO^DJlV9ny(@XI+Xbp5F#pPc-qwMaFWPf%JVtc&Rd%@Gy(IYW zV|B6UcTDcY&iHl2&e$U0_0(nkO?`pQIRUbrTH>k@>;AJZ3_EXEorDd3@*r7W7cNvK zhohbibd-2yT1N;cJs%A<*JANHdF<{aoZ&b(7Dm5j6)6y+pTDxQ`82X&oF&67ML220 zb+f^%>A862p<6<z<>}Jff(pX-E{uV$*~6bZ6CC^NiJ63~ts!PXx(LxRY?}$~{a`A| zL?pr1g0z)}>ehGCi(-|su#MvHWOrgx@Kk%h&Q#@V(lqQ|?bLhQoyRn}sdN#V)1Uz{ zwsgYZmBfp$XD()W)vWNUUtcY&@DDIcsX16e7%Zbt)2tX1T~EEh%Nq)xCP0m(c=9w9 z-CAF>NAXx^Sq?bHPcN!{@CP7WBqp5VcW_C(b`Dw%TL!1Tjan_xb|yVPxV#>sok#oz z$=%J`ppO@}#|$yU6U}wqqMbz0AAw^X>_3(UklY+<dEw!?tQ1jsyUrX24(<G?$F#zB zqxe#4I^yRvBIj3jSKOTN9ou9xPWCp&DZp|+D`Q3~D=omiXJ+TT4VkGMe8mO~4Ob46 zgb?Bk)P4n1Pm>+3v>WYj{PIY|&RxvG+Mb9kb_h`mVKJqYtLO6Im*~htYwf20vU0k& zZh28m>5+C5Y?`@6-ZiC*4z8KVL_Z4E18q0sgwVttgf(l813CBMcHTdG0THynxa~3D zzK=|sq=F?f%o54PB3U#S!u5Zj8Z{T=k!;=%>&%b}n{QdIC@}BGxOU@a#24V+SW`aL zs9hQI$q2bB@AsQGi?|8Ej(7=CINLt<Z~pM?(~GNoE<#~Kr|_ib-9pFy0y^G7_7=#! z`Mw(Cp_+D8Xm|;J_^qit5A=6j^&MBYBU;kDhK_XieSQOK@3~Ahr>uPUy{_DKlEHdY zI}h7D(GiQDXSgn1_7FN-H6U-R7vct|8k*?5-)Qh~@xAcprpQUy4c~O9Tj!@bkEaT; z4*oXV4sXT!Jdu;iai1?5SM^zOXnFtbhw&{bi1~%6EDxR9!B9hRK$B;N{=(#}mQw5i zML&@M(aE!to>wP%f994ZCk=Zb$_rMelJXPTnUnqjBG@R8r$p$Plhx~<y@ruJMLmB{ z1TaZRvmXN!scQ_g68gx8!kFt>3lQP{ccoM`0T4C!osPeZZJ}b;t`WPHC<Y?*q!i3i ziXSp-F;~V1qb)vu^C_1FM4F(qD5JlePhGMd)E6>G#(mWaF=ufI93GoS3n}$|=J5_s z@B3_~y7I=f4HU!%pxQ+@$m-nEw0d=y)6s)+XS<Hwdg6<t%{#D$`x2zeKUm|#bHh3{ zNfp5AZ(9#-En)4@R)t!jePM28^4thmy+tOj9lNl@pi(V#khJbJK55t`(xaC6l+!8x zX+r|)GuaYN<DznXaqJsp!A#xy^DPBckHvu|RA{~CHEjBYso0KgkDq5in3unAwTgxK z`?jo{%+1B-(Yoh_P&CR9e;U%|o&f3fe-C?wix(nWj@tU@X&c)^&0|y8d}(iBP8k^& z8q^;A?jx(;5}oi2tkc~n$18Q@q@MuL^0b<FMpC7{903V#0wFz*NEY>NtLPDLs0dpd zg&qLTMORc$EcVEB-evOTgkxlVym!Dw^zI+z4%Qbn(GF2cF=&)nK}YHNEB$3oVXaN_ zBIljjUraaeXg2SR1+TtmIOptB5yYlJ^0Is9E{|z3&+A;g$E!Y_*+U)GYU})(K4Kc- zP)k^*_jr(1<WcSDOW<0{li(t+(^}lJ@ea1|pYKZeXp-c2MQR45&XUfrM`K-l0qR%v z5F1tzM>xO8L4}B{O7zvrr)#DEiJs`swK(2t8={e(XTXy#sP1G6*`A9d?&_o(;`HmY z0qy8i$42p55{$!pI52E2JEtb|#^Efrg02Sa;jx^4`Q&F)TFM+GoL6mZo2!EP1V3G@ z+lGqrU;*Y78oD^~9uf!xb{&ndSaQTR)ug+(vm2vol&URjSTNSbufh(K3CvwS=`iv= z!yk<v&*ZD_%&7@Nnh;wo?AsdYe-wzYXDW?eNMlZ;R}4lSvsu&XrNBcA0ujN_Po?YM z3STm_Z=0do1m@*tkvTw#Udbl235pznHzccvn+y+0Wc00jsy~vsA0(}s&euy`2oE78 zefjvr6RlX>rsVZh1bQyfX#|8s?2WZ<M&q*w_jtM*@KwyKEQkDa?z&28|NnTs6Lhoh z-g}kUak$dY-Y0m`&b{&Zt@yqcTTmwk79kJ3cAb)NQ{3iASwe&=UXj7VKrAO)@ly>O zcxs2d%W^@MPqsPneWGu0JdxPA2?w!E)dqPMZmdSGx@mv8UMSNDKIkYtjIyx$a#dS= zfFsG~ty;dx`c!i#9_<KPo~CF*`EKQW`Zd~*Rq2k*_x+2WAL{T4=Vs34s_)O3zQ4cK z^xVJHU~mTeKB@<Zz2n-XQ!PTk(_1eewoEuKu7;~?TIybk*Q&nPm)Tdjl0I~05mJZJ z_AyczQGI7lV?O$uLedyDSW2>G{9T6N>Vw!B$ZFEpl`#sPE3+Lsh&&{#kArq=Lv`x3 z+HfXKiG;V0Kg_eUqRS*iA!F>$WJR+v3~PXaSB%Ia2!9DmeI9|fV2h;ENLJ{XZR@)j zKY%e~zckJp0S!-Ljh-T%qv)09q@fg2bWMPt!~=n9kM?i$*#p1(o=zHeT`Hb7Nv~IL zOC#tz{*zj`<w<-Uu;>Z6?Ffsw1mzJm`gG;#zhnmLPV4Z#)A|V9>m@n32tK#D&KeT2 z^CFOkNpJlzT@rRvK30{_@KYC4a8-}?%a4_eY;rG(pBoRtJ631kC?2$a)|UMD<aqAu zhc}H^tc}U|Li);24mpI`ZsT`~qQVKy53yR=mUm3AxsQMEpcn^xi8LH}@n78%hUi3| zNnxy(SDz;>wZvKP4EYqZ0pEOElF_IocHFD(4PYIOc;E8r*|c4(kP^OCz;t;gLyPGL zKhiP0{X-P6U!EC^%*6XU#8hpIA<+GMTUU$No>q4~jL^v*@r{VuM#Kqf?r%DN$ZbX^ zs(8+w)fzeXt2|j&h}=PWMKx$%@YBJcf2q(5N(<str(>_aY@;?XXTN8i?4kIk;dF^Y zpLyA*qzFwqr3W8Ka%kF}6`g<l#8aZ;uV>zNUC2U$+m6W&!sTXbjp(0hi`84Da6an` zIn!M7HBM*_rPB-dm!UG%l{EU(bDQ)b)7?Zjkx*&SbR;3ZejTIz)h#xCzvjW(-p*y? z8U2aWQey7PP?CF;<n{?cstG6#XlK#eIsS2Vz;uf{q*dQ|W_=~;I2rAKCzMGxUqyN* zljJymHh6?D3n6qQuoL|cyb>cMXo*OjUbRsXvwya|@@%n|-xb!_*PlI)Ic>3AD-`0z zHRt$ZPv9XoEmnmWUwW-)$Y4{0?EC7&$nEdwAe)$GkD?yYSPU!0h`Vl+n49pz#f~ud z@j1kmbLKIlbd?mM?bWhPZfbC26`}n>(nfzxlMeWti80&rUMr>_XrlQ&DfmCc{{NU? z-vK!iSBi0(s2^R!KZDCMGPW?_mv^8lEB5^-ENL)u;7Y)5{<VAeeJR}9h3BDT<VwJJ z{&k(TKmA$}nk*|`rZWz{zpecK3<}=qCxx|*Z)q{kikAAhs%GyRJ>xxILWTdN(#nYi z(oY5qe8fstG5qK=$i7z7nVv(einCKJuYzbh#JEOkP68Qsa>!z=0-_r<!k_a}*|@(n z@yZ}(Pt7K|IWBJar0K^U33v;1n<6I1OeJh(!N}4p0WTau{g}`5Eww;Q>*`;$*RK%7 zDM3cn55J^XTonvlE#a<KViwL;4-LT2%O}jm`<#nUP=`-IOh7>FA5l<@mzR-%5dGf( z_Kucs5T5@H5aHqz(BTyl;};ea68tX!uZn&41AywEH)uN|T;1W$R)CD9qq!9W)E;ha ZrDX-T^mH1q5`RzvpbBd8WwK_0{|mNJD+vGq literal 0 HcmV?d00001 diff --git a/js/style/images/ui-icons_cc0000_256x240.png b/js/style/images/ui-icons_cc0000_256x240.png new file mode 100644 index 0000000000000000000000000000000000000000..2825f2004d10b413a76317d47384e6139abcbe00 GIT binary patch literal 4632 zcmeHKXIGP5v%c>nKte|l1Q7@wDbjlhy%zzcyaJ(j0vM{4fKmhn9z_vp0Z~LT6ctc< z6BGpmg(xk6^sY1^BnN%oFX!9&0q0tK?b)-|%$l`l?Q8bTO&cp?CVC!v005XwO$=-S z06aMYTX5*fPBb<9eIj7Kx|X^CP@By_cBeTpkg~C`H~a_y|G)l^87PgmOFzk@C)U== z4&Y{0fWd9rlJhSJUJ66`pm{jtKQb{P1vNSKSWV0Y1o+sUg~a6Sq|hmfX}GR{zQK2@ zhP=&<t#Qv^Kfd+s=?nfkiDR(%qVOg?Ed-h^SJvgB%AIS5uMVCrH1^cNB>v-vtYGFi z2?u(Z8yf)WH0MlC6gsS_r6C=Oj){gxc`o&g5dg3xnHuQYM}J>;VemZL!#35FDJ<11 z#x3jzMPzhH2uC=pn7ZZa@d%nQ$oUtrK73%iK&7T_Oa=P-?v>7YEeCBbcJEDSFE)K^ z$)D76N<RUgK$6$E3$czebd^>;>H^qCLHMA&r=*bG5Zw-8++MGVLnWdW(#``|L(Ai~ zSB)%_odv`MN{{7+m(O{@hGv_=`)c0=pjFh!)0)eLy1L;<feqeP&H1DBJ{`@OJG56B zwx`@fz+&d0DacxRjm#k&{WvK<y&}>hxu67knKWln0>Q$ADH1giS0atY1^=R~SM{oO zXn%rDXPFXy;F_NK(3%mhq=q(b6%5if8Ew62CUp)Ct6@}Z;+7Gu0?lw@Z|z@W<j;5< zH|!Jd202|c)$B1uBUtGn%JsbM(vHNS(e%;Fjw~i0zsCs$jB}z5XP3kFcL8m^dUd)R zVV_GNZ2!f$zDlpo(nH$SP2Om16>t!F{#D=Pn?$lIuxf)>-g28+`Nxao^l_GC_ELqk zjuZJh-TH!-UstN=(mO@cC(smT?D0wbc{T^&FiXGwE0kLgwnZbb704>H@!sRS<Gg6# zWuHjr(mb6&=4wO?T~3V?+<n4!0#i1_`TZ#u@7#R_1Clk%7n2Y=7{&w-vW_ZGR*omo z7l!@b@|6EKH?wtRN3~zFLX14rZf_8V7t&}Oo<Tk}thSpm9n8hlHv}vLW?a!%18AzP zyd&wv(34Y(MP8TQjyH5S*n@79=$6WK{-g%67>sn<B>M$0>E%pkfR8q9Gg;*Rd~y5F z>udv~GokTG>qYDg9y2u}JigUI>8I7v*01F)0xIUEl}R!KaI_X_QekA7m4O|-iTlM# z$o&ZMQ2|F=B3kt~o53J>4)PQ)Wbb0J>Q&j)mNaNIUuF{GC8Q&A2@1<G%_*<*mw1(| zKi)7Qlvvlo#SC#kOhGx@751-bp~p9S4gO+>$M=Y1F^fLt(x|OROO|1yx?f()V@i89 zX=%_I^0Iz7LGAMcAKHq($Vl>8w{>vsRpYY8{cCrN8@ix`RuQOdN(x(iECRe%<bnuo zn|2Y7(dKWjFLvK>cu6@-zW!FKF{8Q&r#^vY%W>><pNg>7>=_Ae8bR51lyHxl=z1(8 z8KS@f@#x-~$I5R7X0={=h~SuSzD|pZwYAGcNU1AKZ#I;(cPOvPA#arcNMvVI*Okxi zpCw{Eg;`rtnZcA%e)6g@7b}-b+aI2#XWrf^)ajE7p*yI5{#1p0b!T(rGA^Q^XQy?T z6e3VwZd)yGP_3*_{Op}Hd-`zzy##&g#{-#^VF)(CeG=je+w&#@*{)05v6XFXMcgoy zX)@cOE!%1VstsNf)OI!5R?rTzW$k`*a_DtAw?{lTMA8xH#}pIA5#f%2R<+H@<k{o= ztRQ9qwJJ%)%KB64bdJn@JMYL5C5#AasKsyb!~h4lRGUQ5)=T;S$hI&0McrLe7)mQo zgJBKN9t-_>doo<|^I~4l7u)1>8tW>jn7kK_^xd*lAjN0batU|Ldv1yPCTJ7V<=P#u zAW!2@HQ7#_X3iJQcz)U>$ytQh{|gzumod$xN8jMrX{|Fh`)W8eU}=2k!G|E<zy`DG zYg%Wz(7;^MXRsp~5j#41K9@_hp0hwedhpjP7}Cp&6?X>kE`v_aX6fRpV%^HZ9+%bw zV+m1CMTAh`y2^AMgDm*++ea#GYC9|)0Gnu&@b<=B!bpT@`5NBzAda#Zw^0Y2fgG0d z5EcN`ImKAb3mJn-Ag1+KrW+6JN>k+RbJ<b-KOiEgWvYy5yP`zSVSzI3=HnFxrD)3z zfAGjG;>^Zs1g@%vnhIRfarTgWK63g4GW1xT52Ap?B$1~$`ZB6ZOmV~1mD^F1FySA` z&3A;45cKY(<DO0}y7pEt)Jir&oT3EdxGNw?dU8Jgmrwi*z7WQeuKpAd!?lzl;UGV0 z_vZVZXXN50IG(99jmGABT3Q<3GS>-JufzKR6AS04E5LP~`kLa!xOuC$0ex$lO;6v% z_2ANW%I-NE2<;6(RtjCVyU#jgzkd<*2)~{R1c2WXk`6iLxWDjfz&tIodOz8ruQcdH zIs;+?im=dFHM#}Mg;d<fpz2D(4wS?+1JnYC#D2%)yFd9z=jD%=XbGX{;iE=Y9nLI< zTwHR}l`0k|W$B^LF;Cuy1ano5SI&e|qRVs2-x{jbyFO0Y;b>m{4%9!&hUGIyZE|E+ zYP@!&8MnNpRr$lzt{!U{>2N>gKxx@}BcAZyFVITneXsJUPQM~lXx@<TcG`EAZ~wRy zuPJ5~-pjCXYqNVZs|2m9fqe6q*D9zDr*XL7fArZeN77d&xOlyCHZpm0*#*~RkT~Bc z{fhEI1ykl0t6r$)14$5S+Y3#Tk10{eohF_wuT434p~~6TwY~00@2SuEguF)z7Jg2# zt{^b$&96Cx2Z#2}dihrPufG|U<g~>0AjBQ$Si${}sl?DZQD@~3<?+6aI<Alemc$&l z#BTcYV<mm62RXIdz+>xA%$En^0x+AA(q%Dd*fqQNx)N*l1F`jUg7}9tIW%h>C8YX| zoG<*+-%_MWgR|`0TrK5T6Dd-TV|!^G?#=xQqcx;4O3hShTiSnf#P;yjGMepUAXFUk zg>m_;C~4{wi*~MC<gujnIrbdA+7<i$#FW7wV~b1OH{{+i{FWAcwBtcGi(3-FXKmO% z((g`yrK<IJp~X3knoZz+@Gb-Dg24?_;0}L6crbPylYKs>jSv#06caF|)sc!4@!Z~U zk(M0CjB31q!67laFIe7Y59JtcXk1F$wL_hgJ4Ha2rfO6UTwo~EVIkR7wKY;x3Mry) z6Bu~ToX&2pZ-y07I6$VZ&M;w?Zpa%WIIa!86SJ<Q?8u3K(05UPLu6}ws4}1Q6^)h} zK>p+eTW6q#e~Nq%sNXF6;)<H8R}9~(+u(tpd+q6&_(R=1zVe#f>AZu_aj?Fxaa^tB zpU<mFY%2rB!)-Y7{3ugn6idj&vypxx(^V%A6R+4(#MIMi#njKC2i@p)>Wl}{!rR4@ zBRJU$ZQ8P(ve!%@Y_Y6o$fVUJOE82y#0n{UUvP5hcs?NH(rZDh5qq`9VyNR@_^rIH z?r`Tl-&6Q2()N1Gu4EM^6#Le$N;ZGuuh$!cHYn|{8$4q8TShBIPdw!4&qbRUzOnx& zz)iz$RW2Pz7f{Wt(r90GLfaV;hrIH<rfc8J?x$4kT7M$j5D!D_$dwj6$f(n_KTxSo ztwcIQZWK+id@(x_BFY};8Xp&4)@g2u`{ITdk^P{`#JMIYxBZ0rnn~ceU&C<_Ea@P? zG=t@Tyt&A?kN{!+QBAkvR#e3p1ZVI9g=6El(9{kDuhMDli!EngWS<azn)9cEUE&K; zv=iE$bL@uh;Z&Tq3jFCt&~MLL$7X71ZL|rqrc}|@_V+h=fap_k^1NB2s)##kr11de zr)O*q7mZY7&3B_pGcW9u;Bxr$>ZlP{T2YWc-u_sKcD4|j`tALDL?N1X$uo4)I>~pI zJB#YSR9|SZlYFlboNu#N0N!OEj!hmy;u+6piqAZNqMzarHIrR3FxK*(mc+|P;C+SU z1xCpi^QO;yKJ-Sc=umetzdT(G<O1!71?<dYo#N4tTKH??c{LLgaNWzrv*+U{WQ{a} zG->~QMe3gE*2ZlIR+e(pEyTzQ<@7w@!r7Ul*wN#J@yYLJ2$B)i4xO1lZ$4@bJo})7 zk?SD4C!cLqBSu;Bpd_N&?^3fpXdeuzRs^db@^%N;{APRe<VLX85QBYce(aOM=G_t` zA&=h8__p2H^<A;YT;ahS^9$0pIj#>nS33f)M%`CxFopbJ#Op2P8O{0di$;4^eR0EF zSa?FIf7CRB&Dgyr-PWQk|FPZ#<vP7NVTrOz)oc&T7^$HsLu|XeGOjN`g$kA7eQ4!^ z;DM2^^i2qocMioi%F}i&2rMXqF+j!L9!g-N35e({`FRR`XzZdI`sHVyqMePvZS4UA zdNx|d1a%#n8$=R^>Ii+Fmg<WhyDFg~XiaW4b?5ix>%074>ZCM}-3#KEMgsm)&7hlG zh^{1h6vr0kbvahQj3F}eDTTx~SPTeooPlxpOAO>>+wOkq!|N?L7w6_r%miD-Ef$LC z*Xq~nLM-SlARk^m8SGjAXXP^^EvQ<=j=FBxdIrt+ZW0b2$jXY~9Vt)Moyccqv>mu* zL7_}5_uEWiMTt6S5s0!MD9Kji&Olt_Mb+-Ap}VZX)~VY03KUC?i;lpbzG61Ki^})S z(D={|)X_HZRe78jj=iZZ=FnnHud}cepBhH_@)KgXUNAJM<0rY#Y<^H8jKYt+&$!3t ziEDLwHn`ew_b8PkE9F3rtM?#ybzaZt)xyzh=YKll1gJ{A4elYuz7Fyaexl-;Vppbo zzP|Y_6rc9a&Zc60pBKi#fBXL0SV=V<LipxeoBpE}^F&IqS)Rk4<Kj~`j<{~Q*0}&z zN1lqiY+$yTqUe<E#yO)Nh0u(F<~}qQo>_Vw$Do490<*HSwqLo)7%$~;jFP!zj#9VH zV-j79`x_Sic24ToTlrb<EF+)QhmY^Q{eT?Whw8~|8I4^I8FzJ1i>8)#WM1-$&8d4a zQQtxcXWco*IlN7F*1ps_<1dnD?4P-_c$?9lb703o{rKL?cyJ0EQFgbS;d^4zbkr7z zg%0&ah?IS2($?x}>MA8`7R`_S=SMxZ`I-+EVU*Zyt#d5=kpd5^o2BsJqhin1@w8Nw zcQxuuwV~;M|6+$EAG7Tyrp4K=v}r@0EGaBW!H5a<7sZLKJ$iARp@L?|4x$2@urC#u z*K*rKtVyg%Q%Dh$g!AUKRu9R#CpVG0>#T)XF}-DFi}Kzt4=57$Kf>No8VO9eQpW?m z&D;Hi-_wQvQSiL1@_HXOqWt>@_n`0h)>q6L?)}Y;prGbc-ZX`~*I0h;L%V*`2m@po zhnu7Bj2LQ2CzgoG<u`@%<+H+eRq`w-WS40+Y0~f@n0G9}`tQhA8zQ{e%MLG2zEO3o zJ9dK{kJlDrOKK&cfR^b+Q)+}G@OA&nGR7Gd*4%Os&N{T#l7Gm<`)rsilDRM7!Qq^S z>q=rm5dJw$?(e~Bii<R9Vs&~~f;2?!8~{PT<H2kum^7X#cWRfKo?bjhwf~tc`T&_E zb26WcU=1CyUhY_Lb<c3`69LG}$|+0Bs!7W!+RG`ZD=4V{Q5Dr?WsywGkpJZnjPdgK ziTSUCinN@9y{wYDyt2BI;=c~E7Qv+_4%~kt*kOFIQSRa1fUXzD!&|^K*xlFL*4y1H UChWbp=7|wtYG`FZ&_gHx4-D@nX8-^I literal 0 HcmV?d00001 diff --git a/js/style/images/ui-icons_ffffff_256x240.png b/js/style/images/ui-icons_ffffff_256x240.png new file mode 100644 index 0000000000000000000000000000000000000000..136a4f97bd2e204943789c1ba9ac9bf0e997ff81 GIT binary patch literal 6313 zcmZu#cU%))v)({xL3&qu7o<sVA#{-{ib!wLdq)T)SRg1E6eJ*0q=+C@Iw%PpDbk73 zr3g|4Lx%vD_kHjEzTbE6{b$e4?#|gWXU@z#^CXy==+i(hLjVAvF}R^)4gjEwTVR_K zd~wyy4uV|_V0TSpO#rAuQxl!YE@TpCLwz0KJRaSTy^ttE42*Rt<|$~%E-Ng?vFiZ< zTZ4g)=ADSiO*=c3P<QB=wY`n3x9`Xz*%MWtj~}cO7jmU#qbQu!AAio|Ehyy)vCLIt zC$Y4bF(K))(s+%$OY(xPUByvz;zsqe)>fs*ue6Ma$@dj}C^Zvn#K8&1$q4T2+LTVr zSR)*(2;HfrMfBR8(1Xvxh>{k!pR-d%Yh!~)B~8sH7NJ@wN)9?>RZ@mgT|wA93OqDS z`c`q%h*N|gbZ57c&QU`Ul9&mM`fI4ye6ASi$3m`<K?X*p7TMo2!F~h9YJv@uXm#jv z@j<DRttXqFkLAODB84)U-~jcQ{(CUHK1IW%rZz*pNBqFBkYqA%D+oy{cmq6O*Q*qK zqqob9xypk=f!^!`H%mr#fdw(|)%TI`LSwF--ygnPbSZ0%llE}sN);%qw!rTf8w#h^ zhInU=2;CT;F3ZV~5lq@jU%D$;+bULE=i6PT>6aNay9})y*;sS`2^pZ`ee}*=UVWop zI2}$UCTEIGbm?fIlHOW%LcHi-*Za#@f!J69M&1A&67cgINE`zdy%Il&ME|chJD~oC z(XZz+`Cs4wmIEZ|Ze;p~j<;xD!4z`@_=QKL9X#PTs6GN>xTPB*o8;ED@PqNq>sZ5+ zmOq~O7U^ox+79UYH~sc!W-qY=lHr~E8FakMCMGjn4&=*C&jz0$p*+Zw@<rSSw)ysk zsiHwRP<(o{JYd2T^i{#*<%n%=lI)G3hOftPAi=i$tVr}h2nBU|%yLK;o%AM=M>bDY zDWD@Z_dk{lrsRA9{B6&h^e}QaTDi_!XTMzvlXeh!HoFOT+T?;^UpZ^S$r@cu-Yy*r zA%S81R<#CDn=Ge0C1-myXq1Dpo?h~}GF1VFzP;QLeS>;lEN0;r5Jl|Be+YjHdsy8q zf=J*U)yOQobz@qd7h@(&uk1`(u2;J3@ELr_I;UXMZD;U>T_u81{YCi)4-BUnhpJPd z*P5-E?#{=RSa4%$vsl*jr7>G!*k~q<;Gte_2Ho(%cbz6?MtEQ@E#=qy(%di}(ywo( z^&$wPV=dTLn4V(3*yU!nex$WzTgU4*TPKT$=4AHN1>ByNzy~=tJ<>)%(zkYP)bzTJ zE^L1eCjZ}#{AX9R9XPFh(p1zN4oGtZ;a<3Ifl0}1Z{He!u_QBw+<WZH)iY7e5O$u) zUqQ>$732kFZsPv76@eT5rdFK$*LSV)07oMjCq?@T6L1_+6V>1N=N9f=pT9R{)Y+*Q zE=_Onp8b?JbF*0N2a2^ixzBYlOCHGncaxb~@Khaa%wIT3l|n)Nx5V^}^1)Pc_Ce#g zaVC2ZzKzhUG<~cyBG*UjlG(0O9PfD(IEUQ0+_BdeYx@NHs~NvPH5%R-#(=Y<_z0Q- zCsW<$gH;zHOGqXoN*Q%2Dza)!ubwKrC(P_~Yu${N$FN!k#87~)p7IML=;lXkH)nXu z{1t+~2SAZ`K*uzRci_sw<_tnyUc=L)ElNxcRHCouao=DIxmDyEH-4&%Iz%mE4CO9- zc~tVHQTH*NWrK05BJwEc(C$&Qsb|V=4Wc;dgd3^*hAua61@1D^#&;1s9dGCV?=f8L zdZT_fV+UlLOtgUNZiViKn_iv?#wd|DyO(b49RZAj=*B@&ryo@|d-oi@^zoe*1j2Sl zBXQi<(FSgCl4?c+F8&_0wQs}Ya|feW7j;s<1(W4{uwh%p<gK(<Ixuxrf?G(c7-4`W zBdQ~PM`AZBN+fA~g(dDwbgTRJw#0*4@pz1!QeR<T;g<b(wG`<&HZu#SQN@5vOmczd zwANZZc=B^Z^C>IiOAb5r$5=N{G}1+Hob>(kHU+ET&jz?npUucnqg3w4TYS5wk{uD& zGMI<6QT?c+Jwu#k#?^AtL6t+FCN?x_AQXwNpZl!-IMGWI&?wX@KVIX%KWA4!nIV^2 z!Z&I1K7%sCpVvw?fXBUfQ#gS0>s_qXGhctXXg_|C5~Yf4*Pdnw#d>;1`B4M?MFLtd z3%E$a{|e>5Qqy+<n2OEpN8NY>K*OPK=_8+1v4qakc9#c?Ir~sb*+*_uohLpbS&oI; zF|@am1zFl_XFj&Hk$eVyq7EVH$sZ$lgb$b8=KRQ<8<d;s(2NN^6?a8x8xj|6nvKWD zXS=s7cBr2}1&+hELhqafOr`yzdO1zx`RMt@E^1;Afnssm^m(C@(*n)MjV;ti>ja3# zJv_ZzZz%e6@>{?E*G`!z2E6|-A3Ntb*?M&HY!El|*i|R0HMi?dIlc3Wd~ML;e!*nl zo8&p#_<bssR<;e6Z9B8i(pqKLPsjy+*V`Yq+-(yc6ou8EpxPMvw|Xm9x>sr$7=VUT z5b<s~{*>^W%S+HRY)3SHs8+~+1=0{s4`Du&N*r?UygS!Tb7H5Xc<9f=!0hG=#TE4P zIJK5C@GhjwM71DMF8`FYzjxE+1?7;GI_NZERU@{L=&|22o}s6Qbg~a@X0MyrecC>{ zMe^gFf=zBQ!^t;s>{eCPN!Ds02^P1g)W*QwEp-pFo7L#hSLmH4w-ID%H2+{R`L^`W zFnYUu5RJzTv69O1Bfi!kv!lkcP7Cer$!Zs!Xk+L|LG<-ue?fe3&$8bD3hUN`@yJ4@ zc_g4FJPqE1ph+qPmkF5ne087u?!}3w!+C%J{Pm1Q+LnhWfcf;*!I@4W@heylj$5{p zSg!H=_1ng8PdE9d?(w%nDWj|*QQyoX0mr`N=0CA7o3F*Y5h?C<2>{0tj*rK8sC;A? z=cYp*9DPcZhnvMn$+LhXk`X1N(qq@=D7LjZ6RM-r2!oju^gL|NSmZ&KL{EiB`I0z< zMfOv^nIrWUyZOT=r4$FJ!$4vw@yyVNo4fU@pwiVP!be_N^_QRCAV8sQ9-eyJZA9!d zgqf)&{-bvML!O2Ata^i5dPo+{%(5AvoEwN}E&zT&X5F-yncrt>XnVmYf)B)<O%%81 z4%GofJdMJcD$IZnN@4TBwD90=ckIP<XxA)~mV@dyN9!z<JzN$OVKM!^w(2lV(7k@N zTIfB0!q+P~!fD&1#3?JiV}noeG-^O)>_NcgbN8MBs~f(Uj3(7cOVr?^l=sT@9Rx!T zc)K1jv&EhAkgoq!q>f+|31sY3^4t{U>1vN)2k>ov%Kdb^+Y06Lkl8w;m5oI}`%>T# z0gB+jX7lvb688egALlrcUWuT5EW408BJu3c;8ldewN^4ql)voC^^v&_k!?EwCp0|( z-puh>*R>7nI*O$q87JKh0G52uk;P{%!YiWNAG(UHbgjg{!@~3n4w%pjASBN#ERUmh z`mM3TM;dGF4|AkX@;|}9pIUjwq@rVs7iD@+DR-U<BRY>8oDqqQ%B|hF1-|0rn&rGf zHIg8@z;cSu@6fHeFKTz8d}EA+<7e@>*vPQ3>DFifTTG0Z3lfmGqDSuBG~~hVUmDGL z{V|TNW&*9m!y9q!r4(--+5Z5Yzf;Y#CzgM_swq`K=JdAI)tk8^FNXJq^XR_jw-l<i zOq}{^FII(n^wiTRE3Otq_ThzjDUce$V}rn>iM=q0L#Jh6FN4=(2EApeLKAcTwc9zU zkxAY*Nr~llO1x)Q+=g_|0G!u3)9-T7_Y`05Xa!>0!WUuwNoNYJr}^A->d7fjtcpUd zbCN$%rqHaVzXY+61{EvYrr5-LWF})IT|?#s`17KiH(4JU2&m}uu2Svp$ka4N=Go^5 zN}JH~A1@NOUe`W6PBn)8ve|8a`LGYClZy}<iY7Uw{&QOxH4*%!i8o$UL)S2*mtU#` zp_AVwf6p=Vl|SCuzxo$lf`^W${LA-EkElhKx$CTb$MU|i%&W(nI`f>zBDzigv~-Gm z>*g+>H~wH)PkqLXeX`|3I@g_YsPFyW=UTLO>bgssN{syu(_Qu-tiaOw`d;|^(}mW- zI;HhMa-ijsqYzf@-66dzUBD>2@z&@-mpXE?^?M}JTW7aOXIE@W>sZHUoyU@H+Y)@t z9ou4TXmpHLjYMkE-tyZ5=~@5oH^jldgvM#+6QYe%qLYeSgG0)*n=*7XM6^C1cWWXC zM=FL_e!<W19mL~Or7IwF{+m|^DlqSe%{seT#H|W%LLR)%J3<IMpS<(ugSUU!8~+=? zs2v6(FWCILX6GHr-ffJ;aI#sD2kvn)mDvGaUIuHWmH~VsUW-O^7urRpp2b03dMv#g zZLWOybX}t~-f!Vf>Quo2;fm&MXx_pkb}9`B;7oNF*t;}%rNRG|KL<;{I$441@Pmin zsM3E>>Hlu(`5}!(_kGTV_4Z`vp$S*8zQ?F+XUc#iy}gE(FU>S1bMb_O+>rv;??hp; zIxlm4jh~f?&R8&e(KGmx9Clr%G7sjJa0)*<J+k)krdwL4weOCK0STx$1FPI8GEQKi z!8iN)&INSeCHoH~9|7)}?jqH@E}E0XeK6!QWgPhRcZmf_DTbwT)|$t-3}Q|nM%YrV z9Pnz$mJ*vOyEPwP`D|sI6PjeYNO5Q+;dWOQPjL92UAWe=l6lBUX}VxQ4~-wNhCeuY z>a^J!vzpwjb;;Y4T>$p;dno^8As@}JWU(R&#d$s&w`5tJ6PMH#?<}r6Un;e8xx6Kx z{zwkqFvEW#9D-F@o3z{2C^E7^DJ{{Q72D<oX-?8dMl7net6#b<pEN2`7#)qVuXl#a z!xV0Q($<N;D`1iWblzjl(R12gt1kc1q%?6vADzf}bJb;+-aDBu7DZlYn$wqM1dQ`I zm)rJ!;yeBLd>xEbc$Q~^G+GZ+7Vcx1zf|^<Li?iRC8=&C^00w=tjPQpd;j2BIPlt= zqCsDY#qV=OucGCJ_pUrBwTrp&>f?;|(?=pm^=L77+dr4z?*`IRg*+Dmm`S#ydsTc# z+<sNur>sn|<kDE~>kLrVk-cili!n9!Ivr0ex<smd#>H>lN0)acF;4T>$K??bmGK0i zXs5cU@7!%8@BA|3u(BbYV+9t<ko8u!=BB$x3aZ?FW&D5)j$*FgenMn5m<{AHX{^a? zu<0$VwEyk$vTRuKj|5Tk=rrfg)az>&ZfYQ@vF?tl=ThQW`&QG(W7XEz`>-VQ0sw9> zgT{?gd{Rw(hl~yFxk9BOvvdr9YjgNi##?-<O(XMKbGOfmX#+5S(VL$akCjifa*rg( z)fiSkV7gZWg(msGD${6J7x2^YKPa|1cl#dpwW@e)NIvfq*KcXU#!k($-ryS#m%2HT zRjNhoG(rwb!ET<T;F+S3;87hzWmZw8urqje8>cSzvnyy^HlUzVd#Yx@q)3ZfHJ@G| z#2Ay|j`!k=tEGi|bf{UXzMdhar|E0g0_N^2Ns#pDm((0b-H#lop7?QF#pbL!dpX%$ z%ugi6dRl78y;x+7ks<Zul3iV@2HE}d0pHa%u*}u#%!OXRYOd>rS3Vt$;J_Ik^4wKv zgZM4`%ij2dJ#^h1ATN&+gw6E_G45pB@LquS$1BvRp}*kfMHz@UK)wydZud3V&6>@! z*6Spti+IpM!cnMI+8to0a8kPm^Nvu-hL+)3L%ZKxgt~y6OV!m`8~R131@hFrgEaOz zlVkN!iyHgP$6LngicGvXE-|=?8_%|iArjB=ga9-1WpDF}c`o>S*`l0YQhC^3*|w&; z_mrTaufMm)F@TG_D1^63kT}Wd(oF2E>3eVQ2c%6}iKtai>%5|}%fy@Yx!|7i^Cx(# zEz;eGhU1mSb*@e&N8ub_a*0b)Op=SdityJ=u_+o^h$!o!N|Ayp9GE?sY8*HN&#U^| zjYf9~Sawur%wd45-%r@Z^uMj29YexMb`w0%`yOaG5fU7f&f*y3e-pspVlVbP>)*KW zpB7yuPBGTv#FPaa>>B4^2|gsx9~vk9Mq5j<uxNVDjWcdlR%^%`r#@m9kA8Y<wS=?z zj@M~ZtbUnxNHnCU&1lABQ3S{B?N|#bpD3^_bK|6>y1DBy6~(z#<p|ymr*P<?N4!Lw ztIT$27)M<SzUgrynagp}ThS}!DN6qzP6C+#dS4qt`<4-z?#mQH-?euW<@w{?wqG#7 z?pR+N0(D9pVc3M^2bL(}Qknmle~1HZ{(PPb+Jsz&^<Wf#5qynrUkTsD$$V4WM%j%a z?fPuF;CtVVL>XX7mK8rWIoy*gDlziks2rbdX#)mgs*!6WWE_ljEH85=e(=NG+SckN z$==Fk8$L<`_7D9?<m9XDdi`<I7zzYa1RG|1fEAz8-0;}2XX1;Uc~?Kv@`g~L$h6iY zn)1W$N4f;^v3o5&2SB+1E(#du&}n#v>D<><K6y5H^zeAexi2~_XU;?ggPMggk#0bQ z(+Y!8fAKN;B&2_nG5>Cd(!spToeK=0Tz=SV|5uT$?h;X(?%Mizi4jzzjwX^he)*>~ z`bV-nfn4&(dIVKGw^XWhJX>87L(is5n*O(B{5M*LQ{`BceV&hl?bK?Z*l!`*q~7M3 z1GEJ<UEeMCSF6xinA9*5cJO6CY>i7rKjXGSt=MvSiCu5~ZH-sw8LBhc{GRQ5S|)k$ zVxo=LCOu?B2?Qw7%}W5dJ^)!?8M{+kW~5k|U=smC|A5f`A@P%2^MV$Js8Fp545610 zRENu!MFgyA?40cx10dcAcdhDL7fI-6OJ1O-OJ(Dl=_bEhlNCT+pwwY!+eT~eD4s#c zT3c@(Kabl#nM?c}BqD*X<lBOT6<f=x^T#k@`q{ESSG4V$b4<ZGPG=VOj`UK}y4!=8 zXK@?R>~!0#*`4Hvia~d(L6V?En>)Uz)OB%TfwvkT;RDqX^l&EpV&8(c=HI7I>OYt; zF_MN^iXn>_2F064G`4DCM+JR~z7K4cRP44$SH;48WfeXDd9*HY(qP0{asUc>)vWOP zO$~fxIkWCl`wKggY;o1cIvlN0&yU`<rDD^&jkojo5O;^^er{C1iF~H!$#AZ$0JVf# z9*q+f(dV>`LXRa{1TBMGZ3_85#^!p-i58!ZEZgcq9+1q7Ar)(67e}|4=E@vshUH>N zVq!Vu4~?IuH4*7R0K%yZyRacVdr=^Zi@`&4x^{y|L)uR$MZmUm-I;7ktfx%FsrKkH zuFOFgc5rOayR*5(wq5RgRz*Lr6V3vGnx83BC`W-g)`E5wE;BAy8^Z~x^`Ml~7rf2L zlh;Sx4+9-Y^Z>v7Q=!}_Hvd5fJMCsk+mS8&qlQRPn`5>B2ibG>NaTj_w*1}w%R9y| z9moQx>k0lPL>eJh8TUD}0!d{Z<$I0Uh?1-e7}v1myIv&9Q=5kUkdb3rd-Y+&rObVo z)q>@$ZV)Si*KLyYR!Um9FtEx$Bl>DC_gQVO-7@A^*j4PnC1)dR=r4k?%`5@Mq;-LJ z$p1gWt3>ww?~pN>bpncY=yPn}a=m~;h~<Nh{<kqyt8PsKMR9%-ioZ(vv>q7%7!W!@ zuon|puuB@+aOu5C!U9Yp`jmk+9ej^mhg8zVDwW5{N{~`BTlz(mXeny_d3WNmkYnQ$ zR`t5lw>BrC45E2_y9Z<*FRi~>Vf1TYe=SIfp7~!q>c2y`UkVf%2=m|^q8f^RlQcx} zR^t!+pb|ZvP{as?kd*#JjK+Nkb^oc69;UzsQUUGnV1KoZH{~C7Q_gWChd!LjlU9o* z=(^df(opYoM<J_VISe&u@JVT=kki>~r#|sJPG=UkV(7O(U1V8+IbEgo>vxCV6I5H{ zU&jo_Ztn&&j}Guik+|Tl?E%BY+em-9A+FyC;c~KwK}N|u26z;55joZz@DqIixFDf? z1@WZ2ZXbgSKaDDC2&nLXrG#+qtW%@dsn2-gG|k?99p4GRp!J19bnk`ScM5S;aS3w0 z7=Y{2G71vX$`UeicVuK$WMx(U66I8+rTJ)RN&Z8@*Z;n!+k^jBP?V67y(2BJa$P}1 zUhW?SX(Qja7YZDI{o%I1TS&N5kSm~h-{0Al*TC1w-PPRH>HdSjFRp4A9{~osCOYL> Hjt~C}Fe}Pt literal 0 HcmV?d00001 diff --git a/js/style/jquery-ui.css b/js/style/jquery-ui.css new file mode 100644 index 00000000000..93707f4cbe6 --- /dev/null +++ b/js/style/jquery-ui.css @@ -0,0 +1,1312 @@ +/*! jQuery UI - v1.12.1 - 2016-09-14 +* http://jqueryui.com +* Includes: core.css, accordion.css, autocomplete.css, menu.css, button.css, controlgroup.css, checkboxradio.css, datepicker.css, dialog.css, draggable.css, resizable.css, progressbar.css, selectable.css, selectmenu.css, slider.css, sortable.css, spinner.css, tabs.css, tooltip.css, theme.css +* To view and modify this theme, visit http://jqueryui.com/themeroller/?bgShadowXPos=&bgOverlayXPos=&bgErrorXPos=&bgHighlightXPos=&bgContentXPos=&bgHeaderXPos=&bgActiveXPos=&bgHoverXPos=&bgDefaultXPos=&bgShadowYPos=&bgOverlayYPos=&bgErrorYPos=&bgHighlightYPos=&bgContentYPos=&bgHeaderYPos=&bgActiveYPos=&bgHoverYPos=&bgDefaultYPos=&bgShadowRepeat=&bgOverlayRepeat=&bgErrorRepeat=&bgHighlightRepeat=&bgContentRepeat=&bgHeaderRepeat=&bgActiveRepeat=&bgHoverRepeat=&bgDefaultRepeat=&iconsHover=url(%22images%2Fui-icons_555555_256x240.png%22)&iconsHighlight=url(%22images%2Fui-icons_777620_256x240.png%22)&iconsHeader=url(%22images%2Fui-icons_444444_256x240.png%22)&iconsError=url(%22images%2Fui-icons_cc0000_256x240.png%22)&iconsDefault=url(%22images%2Fui-icons_777777_256x240.png%22)&iconsContent=url(%22images%2Fui-icons_444444_256x240.png%22)&iconsActive=url(%22images%2Fui-icons_ffffff_256x240.png%22)&bgImgUrlShadow=&bgImgUrlOverlay=&bgImgUrlHover=&bgImgUrlHighlight=&bgImgUrlHeader=&bgImgUrlError=&bgImgUrlDefault=&bgImgUrlContent=&bgImgUrlActive=&opacityFilterShadow=Alpha(Opacity%3D30)&opacityFilterOverlay=Alpha(Opacity%3D30)&opacityShadowPerc=30&opacityOverlayPerc=30&iconColorHover=%23555555&iconColorHighlight=%23777620&iconColorHeader=%23444444&iconColorError=%23cc0000&iconColorDefault=%23777777&iconColorContent=%23444444&iconColorActive=%23ffffff&bgImgOpacityShadow=0&bgImgOpacityOverlay=0&bgImgOpacityError=95&bgImgOpacityHighlight=55&bgImgOpacityContent=75&bgImgOpacityHeader=75&bgImgOpacityActive=65&bgImgOpacityHover=75&bgImgOpacityDefault=75&bgTextureShadow=flat&bgTextureOverlay=flat&bgTextureError=flat&bgTextureHighlight=flat&bgTextureContent=flat&bgTextureHeader=flat&bgTextureActive=flat&bgTextureHover=flat&bgTextureDefault=flat&cornerRadius=3px&fwDefault=normal&ffDefault=Arial%2CHelvetica%2Csans-serif&fsDefault=1em&cornerRadiusShadow=8px&thicknessShadow=5px&offsetLeftShadow=0px&offsetTopShadow=0px&opacityShadow=.3&bgColorShadow=%23666666&opacityOverlay=.3&bgColorOverlay=%23aaaaaa&fcError=%235f3f3f&borderColorError=%23f1a899&bgColorError=%23fddfdf&fcHighlight=%23777620&borderColorHighlight=%23dad55e&bgColorHighlight=%23fffa90&fcContent=%23333333&borderColorContent=%23dddddd&bgColorContent=%23ffffff&fcHeader=%23333333&borderColorHeader=%23dddddd&bgColorHeader=%23e9e9e9&fcActive=%23ffffff&borderColorActive=%23003eff&bgColorActive=%23007fff&fcHover=%232b2b2b&borderColorHover=%23cccccc&bgColorHover=%23ededed&fcDefault=%23454545&borderColorDefault=%23c5c5c5&bgColorDefault=%23f6f6f6 +* Copyright jQuery Foundation and other contributors; Licensed MIT */ + +/* Layout helpers +----------------------------------*/ +.ui-helper-hidden { + display: none; +} +.ui-helper-hidden-accessible { + border: 0; + clip: rect(0 0 0 0); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; +} +.ui-helper-reset { + margin: 0; + padding: 0; + border: 0; + outline: 0; + line-height: 1.3; + text-decoration: none; + font-size: 100%; + list-style: none; +} +.ui-helper-clearfix:before, +.ui-helper-clearfix:after { + content: ""; + display: table; + border-collapse: collapse; +} +.ui-helper-clearfix:after { + clear: both; +} +.ui-helper-zfix { + width: 100%; + height: 100%; + top: 0; + left: 0; + position: absolute; + opacity: 0; + filter:Alpha(Opacity=0); /* support: IE8 */ +} + +.ui-front { + z-index: 100; +} + + +/* Interaction Cues +----------------------------------*/ +.ui-state-disabled { + cursor: default !important; + pointer-events: none; +} + + +/* Icons +----------------------------------*/ +.ui-icon { + display: inline-block; + vertical-align: middle; + margin-top: -.25em; + position: relative; + text-indent: -99999px; + overflow: hidden; + background-repeat: no-repeat; +} + +.ui-widget-icon-block { + left: 50%; + margin-left: -8px; + display: block; +} + +/* Misc visuals +----------------------------------*/ + +/* Overlays */ +.ui-widget-overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; +} +.ui-accordion .ui-accordion-header { + display: block; + cursor: pointer; + position: relative; + margin: 2px 0 0 0; + padding: .5em .5em .5em .7em; + font-size: 100%; +} +.ui-accordion .ui-accordion-content { + padding: 1em 2.2em; + border-top: 0; + overflow: auto; +} +.ui-autocomplete { + position: absolute; + top: 0; + left: 0; + cursor: default; +} +.ui-menu { + list-style: none; + padding: 0; + margin: 0; + display: block; + outline: 0; +} +.ui-menu .ui-menu { + position: absolute; +} +.ui-menu .ui-menu-item { + margin: 0; + cursor: pointer; + /* support: IE10, see #8844 */ + list-style-image: url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"); +} +.ui-menu .ui-menu-item-wrapper { + position: relative; + padding: 3px 1em 3px .4em; +} +.ui-menu .ui-menu-divider { + margin: 5px 0; + height: 0; + font-size: 0; + line-height: 0; + border-width: 1px 0 0 0; +} +.ui-menu .ui-state-focus, +.ui-menu .ui-state-active { + margin: -1px; +} + +/* icon support */ +.ui-menu-icons { + position: relative; +} +.ui-menu-icons .ui-menu-item-wrapper { + padding-left: 2em; +} + +/* left-aligned */ +.ui-menu .ui-icon { + position: absolute; + top: 0; + bottom: 0; + left: .2em; + margin: auto 0; +} + +/* right-aligned */ +.ui-menu .ui-menu-icon { + left: auto; + right: 0; +} +.ui-button { + padding: .4em 1em; + display: inline-block; + position: relative; + line-height: normal; + margin-right: .1em; + cursor: pointer; + vertical-align: middle; + text-align: center; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + + /* Support: IE <= 11 */ + overflow: visible; +} + +.ui-button, +.ui-button:link, +.ui-button:visited, +.ui-button:hover, +.ui-button:active { + text-decoration: none; +} + +/* to make room for the icon, a width needs to be set here */ +.ui-button-icon-only { + width: 2em; + box-sizing: border-box; + text-indent: -9999px; + white-space: nowrap; +} + +/* no icon support for input elements */ +input.ui-button.ui-button-icon-only { + text-indent: 0; +} + +/* button icon element(s) */ +.ui-button-icon-only .ui-icon { + position: absolute; + top: 50%; + left: 50%; + margin-top: -8px; + margin-left: -8px; +} + +.ui-button.ui-icon-notext .ui-icon { + padding: 0; + width: 2.1em; + height: 2.1em; + text-indent: -9999px; + white-space: nowrap; + +} + +input.ui-button.ui-icon-notext .ui-icon { + width: auto; + height: auto; + text-indent: 0; + white-space: normal; + padding: .4em 1em; +} + +/* workarounds */ +/* Support: Firefox 5 - 40 */ +input.ui-button::-moz-focus-inner, +button.ui-button::-moz-focus-inner { + border: 0; + padding: 0; +} +.ui-controlgroup { + vertical-align: middle; + display: inline-block; +} +.ui-controlgroup > .ui-controlgroup-item { + float: left; + margin-left: 0; + margin-right: 0; +} +.ui-controlgroup > .ui-controlgroup-item:focus, +.ui-controlgroup > .ui-controlgroup-item.ui-visual-focus { + z-index: 9999; +} +.ui-controlgroup-vertical > .ui-controlgroup-item { + display: block; + float: none; + width: 100%; + margin-top: 0; + margin-bottom: 0; + text-align: left; +} +.ui-controlgroup-vertical .ui-controlgroup-item { + box-sizing: border-box; +} +.ui-controlgroup .ui-controlgroup-label { + padding: .4em 1em; +} +.ui-controlgroup .ui-controlgroup-label span { + font-size: 80%; +} +.ui-controlgroup-horizontal .ui-controlgroup-label + .ui-controlgroup-item { + border-left: none; +} +.ui-controlgroup-vertical .ui-controlgroup-label + .ui-controlgroup-item { + border-top: none; +} +.ui-controlgroup-horizontal .ui-controlgroup-label.ui-widget-content { + border-right: none; +} +.ui-controlgroup-vertical .ui-controlgroup-label.ui-widget-content { + border-bottom: none; +} + +/* Spinner specific style fixes */ +.ui-controlgroup-vertical .ui-spinner-input { + + /* Support: IE8 only, Android < 4.4 only */ + width: 75%; + width: calc( 100% - 2.4em ); +} +.ui-controlgroup-vertical .ui-spinner .ui-spinner-up { + border-top-style: solid; +} + +.ui-checkboxradio-label .ui-icon-background { + box-shadow: inset 1px 1px 1px #ccc; + border-radius: .12em; + border: none; +} +.ui-checkboxradio-radio-label .ui-icon-background { + width: 16px; + height: 16px; + border-radius: 1em; + overflow: visible; + border: none; +} +.ui-checkboxradio-radio-label.ui-checkboxradio-checked .ui-icon, +.ui-checkboxradio-radio-label.ui-checkboxradio-checked:hover .ui-icon { + background-image: none; + width: 8px; + height: 8px; + border-width: 4px; + border-style: solid; +} +.ui-checkboxradio-disabled { + pointer-events: none; +} +.ui-datepicker { + width: 17em; + padding: .2em .2em 0; + display: none; +} +.ui-datepicker .ui-datepicker-header { + position: relative; + padding: .2em 0; +} +.ui-datepicker .ui-datepicker-prev, +.ui-datepicker .ui-datepicker-next { + position: absolute; + top: 2px; + width: 1.8em; + height: 1.8em; +} +.ui-datepicker .ui-datepicker-prev-hover, +.ui-datepicker .ui-datepicker-next-hover { + top: 1px; +} +.ui-datepicker .ui-datepicker-prev { + left: 2px; +} +.ui-datepicker .ui-datepicker-next { + right: 2px; +} +.ui-datepicker .ui-datepicker-prev-hover { + left: 1px; +} +.ui-datepicker .ui-datepicker-next-hover { + right: 1px; +} +.ui-datepicker .ui-datepicker-prev span, +.ui-datepicker .ui-datepicker-next span { + display: block; + position: absolute; + left: 50%; + margin-left: -8px; + top: 50%; + margin-top: -8px; +} +.ui-datepicker .ui-datepicker-title { + margin: 0 2.3em; + line-height: 1.8em; + text-align: center; +} +.ui-datepicker .ui-datepicker-title select { + font-size: 1em; + margin: 1px 0; +} +.ui-datepicker select.ui-datepicker-month, +.ui-datepicker select.ui-datepicker-year { + width: 45%; +} +.ui-datepicker table { + width: 100%; + font-size: .9em; + border-collapse: collapse; + margin: 0 0 .4em; +} +.ui-datepicker th { + padding: .7em .3em; + text-align: center; + font-weight: bold; + border: 0; +} +.ui-datepicker td { + border: 0; + padding: 1px; +} +.ui-datepicker td span, +.ui-datepicker td a { + display: block; + padding: .2em; + text-align: right; + text-decoration: none; +} +.ui-datepicker .ui-datepicker-buttonpane { + background-image: none; + margin: .7em 0 0 0; + padding: 0 .2em; + border-left: 0; + border-right: 0; + border-bottom: 0; +} +.ui-datepicker .ui-datepicker-buttonpane button { + float: right; + margin: .5em .2em .4em; + cursor: pointer; + padding: .2em .6em .3em .6em; + width: auto; + overflow: visible; +} +.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { + float: left; +} + +/* with multiple calendars */ +.ui-datepicker.ui-datepicker-multi { + width: auto; +} +.ui-datepicker-multi .ui-datepicker-group { + float: left; +} +.ui-datepicker-multi .ui-datepicker-group table { + width: 95%; + margin: 0 auto .4em; +} +.ui-datepicker-multi-2 .ui-datepicker-group { + width: 50%; +} +.ui-datepicker-multi-3 .ui-datepicker-group { + width: 33.3%; +} +.ui-datepicker-multi-4 .ui-datepicker-group { + width: 25%; +} +.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header, +.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { + border-left-width: 0; +} +.ui-datepicker-multi .ui-datepicker-buttonpane { + clear: left; +} +.ui-datepicker-row-break { + clear: both; + width: 100%; + font-size: 0; +} + +/* RTL support */ +.ui-datepicker-rtl { + direction: rtl; +} +.ui-datepicker-rtl .ui-datepicker-prev { + right: 2px; + left: auto; +} +.ui-datepicker-rtl .ui-datepicker-next { + left: 2px; + right: auto; +} +.ui-datepicker-rtl .ui-datepicker-prev:hover { + right: 1px; + left: auto; +} +.ui-datepicker-rtl .ui-datepicker-next:hover { + left: 1px; + right: auto; +} +.ui-datepicker-rtl .ui-datepicker-buttonpane { + clear: right; +} +.ui-datepicker-rtl .ui-datepicker-buttonpane button { + float: left; +} +.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current, +.ui-datepicker-rtl .ui-datepicker-group { + float: right; +} +.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header, +.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { + border-right-width: 0; + border-left-width: 1px; +} + +/* Icons */ +.ui-datepicker .ui-icon { + display: block; + text-indent: -99999px; + overflow: hidden; + background-repeat: no-repeat; + left: .5em; + top: .3em; +} +.ui-dialog { + position: absolute; + top: 0; + left: 0; + padding: .2em; + outline: 0; +} +.ui-dialog .ui-dialog-titlebar { + padding: .4em 1em; + position: relative; +} +.ui-dialog .ui-dialog-title { + float: left; + margin: .1em 0; + white-space: nowrap; + width: 90%; + overflow: hidden; + text-overflow: ellipsis; +} +.ui-dialog .ui-dialog-titlebar-close { + position: absolute; + right: .3em; + top: 50%; + width: 20px; + margin: -10px 0 0 0; + padding: 1px; + height: 20px; +} +.ui-dialog .ui-dialog-content { + position: relative; + border: 0; + padding: .5em 1em; + background: none; + overflow: auto; +} +.ui-dialog .ui-dialog-buttonpane { + text-align: left; + border-width: 1px 0 0 0; + background-image: none; + margin-top: .5em; + padding: .3em 1em .5em .4em; +} +.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { + float: right; +} +.ui-dialog .ui-dialog-buttonpane button { + margin: .5em .4em .5em 0; + cursor: pointer; +} +.ui-dialog .ui-resizable-n { + height: 2px; + top: 0; +} +.ui-dialog .ui-resizable-e { + width: 2px; + right: 0; +} +.ui-dialog .ui-resizable-s { + height: 2px; + bottom: 0; +} +.ui-dialog .ui-resizable-w { + width: 2px; + left: 0; +} +.ui-dialog .ui-resizable-se, +.ui-dialog .ui-resizable-sw, +.ui-dialog .ui-resizable-ne, +.ui-dialog .ui-resizable-nw { + width: 7px; + height: 7px; +} +.ui-dialog .ui-resizable-se { + right: 0; + bottom: 0; +} +.ui-dialog .ui-resizable-sw { + left: 0; + bottom: 0; +} +.ui-dialog .ui-resizable-ne { + right: 0; + top: 0; +} +.ui-dialog .ui-resizable-nw { + left: 0; + top: 0; +} +.ui-draggable .ui-dialog-titlebar { + cursor: move; +} +.ui-draggable-handle { + -ms-touch-action: none; + touch-action: none; +} +.ui-resizable { + position: relative; +} +.ui-resizable-handle { + position: absolute; + font-size: 0.1px; + display: block; + -ms-touch-action: none; + touch-action: none; +} +.ui-resizable-disabled .ui-resizable-handle, +.ui-resizable-autohide .ui-resizable-handle { + display: none; +} +.ui-resizable-n { + cursor: n-resize; + height: 7px; + width: 100%; + top: -5px; + left: 0; +} +.ui-resizable-s { + cursor: s-resize; + height: 7px; + width: 100%; + bottom: -5px; + left: 0; +} +.ui-resizable-e { + cursor: e-resize; + width: 7px; + right: -5px; + top: 0; + height: 100%; +} +.ui-resizable-w { + cursor: w-resize; + width: 7px; + left: -5px; + top: 0; + height: 100%; +} +.ui-resizable-se { + cursor: se-resize; + width: 12px; + height: 12px; + right: 1px; + bottom: 1px; +} +.ui-resizable-sw { + cursor: sw-resize; + width: 9px; + height: 9px; + left: -5px; + bottom: -5px; +} +.ui-resizable-nw { + cursor: nw-resize; + width: 9px; + height: 9px; + left: -5px; + top: -5px; +} +.ui-resizable-ne { + cursor: ne-resize; + width: 9px; + height: 9px; + right: -5px; + top: -5px; +} +.ui-progressbar { + height: 2em; + text-align: left; + overflow: hidden; +} +.ui-progressbar .ui-progressbar-value { + margin: -1px; + height: 100%; +} +.ui-progressbar .ui-progressbar-overlay { + background: url("data:image/gif;base64,R0lGODlhKAAoAIABAAAAAP///yH/C05FVFNDQVBFMi4wAwEAAAAh+QQJAQABACwAAAAAKAAoAAACkYwNqXrdC52DS06a7MFZI+4FHBCKoDeWKXqymPqGqxvJrXZbMx7Ttc+w9XgU2FB3lOyQRWET2IFGiU9m1frDVpxZZc6bfHwv4c1YXP6k1Vdy292Fb6UkuvFtXpvWSzA+HycXJHUXiGYIiMg2R6W459gnWGfHNdjIqDWVqemH2ekpObkpOlppWUqZiqr6edqqWQAAIfkECQEAAQAsAAAAACgAKAAAApSMgZnGfaqcg1E2uuzDmmHUBR8Qil95hiPKqWn3aqtLsS18y7G1SzNeowWBENtQd+T1JktP05nzPTdJZlR6vUxNWWjV+vUWhWNkWFwxl9VpZRedYcflIOLafaa28XdsH/ynlcc1uPVDZxQIR0K25+cICCmoqCe5mGhZOfeYSUh5yJcJyrkZWWpaR8doJ2o4NYq62lAAACH5BAkBAAEALAAAAAAoACgAAAKVDI4Yy22ZnINRNqosw0Bv7i1gyHUkFj7oSaWlu3ovC8GxNso5fluz3qLVhBVeT/Lz7ZTHyxL5dDalQWPVOsQWtRnuwXaFTj9jVVh8pma9JjZ4zYSj5ZOyma7uuolffh+IR5aW97cHuBUXKGKXlKjn+DiHWMcYJah4N0lYCMlJOXipGRr5qdgoSTrqWSq6WFl2ypoaUAAAIfkECQEAAQAsAAAAACgAKAAAApaEb6HLgd/iO7FNWtcFWe+ufODGjRfoiJ2akShbueb0wtI50zm02pbvwfWEMWBQ1zKGlLIhskiEPm9R6vRXxV4ZzWT2yHOGpWMyorblKlNp8HmHEb/lCXjcW7bmtXP8Xt229OVWR1fod2eWqNfHuMjXCPkIGNileOiImVmCOEmoSfn3yXlJWmoHGhqp6ilYuWYpmTqKUgAAIfkECQEAAQAsAAAAACgAKAAAApiEH6kb58biQ3FNWtMFWW3eNVcojuFGfqnZqSebuS06w5V80/X02pKe8zFwP6EFWOT1lDFk8rGERh1TTNOocQ61Hm4Xm2VexUHpzjymViHrFbiELsefVrn6XKfnt2Q9G/+Xdie499XHd2g4h7ioOGhXGJboGAnXSBnoBwKYyfioubZJ2Hn0RuRZaflZOil56Zp6iioKSXpUAAAh+QQJAQABACwAAAAAKAAoAAACkoQRqRvnxuI7kU1a1UU5bd5tnSeOZXhmn5lWK3qNTWvRdQxP8qvaC+/yaYQzXO7BMvaUEmJRd3TsiMAgswmNYrSgZdYrTX6tSHGZO73ezuAw2uxuQ+BbeZfMxsexY35+/Qe4J1inV0g4x3WHuMhIl2jXOKT2Q+VU5fgoSUI52VfZyfkJGkha6jmY+aaYdirq+lQAACH5BAkBAAEALAAAAAAoACgAAAKWBIKpYe0L3YNKToqswUlvznigd4wiR4KhZrKt9Upqip61i9E3vMvxRdHlbEFiEXfk9YARYxOZZD6VQ2pUunBmtRXo1Lf8hMVVcNl8JafV38aM2/Fu5V16Bn63r6xt97j09+MXSFi4BniGFae3hzbH9+hYBzkpuUh5aZmHuanZOZgIuvbGiNeomCnaxxap2upaCZsq+1kAACH5BAkBAAEALAAAAAAoACgAAAKXjI8By5zf4kOxTVrXNVlv1X0d8IGZGKLnNpYtm8Lr9cqVeuOSvfOW79D9aDHizNhDJidFZhNydEahOaDH6nomtJjp1tutKoNWkvA6JqfRVLHU/QUfau9l2x7G54d1fl995xcIGAdXqMfBNadoYrhH+Mg2KBlpVpbluCiXmMnZ2Sh4GBqJ+ckIOqqJ6LmKSllZmsoq6wpQAAAh+QQJAQABACwAAAAAKAAoAAAClYx/oLvoxuJDkU1a1YUZbJ59nSd2ZXhWqbRa2/gF8Gu2DY3iqs7yrq+xBYEkYvFSM8aSSObE+ZgRl1BHFZNr7pRCavZ5BW2142hY3AN/zWtsmf12p9XxxFl2lpLn1rseztfXZjdIWIf2s5dItwjYKBgo9yg5pHgzJXTEeGlZuenpyPmpGQoKOWkYmSpaSnqKileI2FAAACH5BAkBAAEALAAAAAAoACgAAAKVjB+gu+jG4kORTVrVhRlsnn2dJ3ZleFaptFrb+CXmO9OozeL5VfP99HvAWhpiUdcwkpBH3825AwYdU8xTqlLGhtCosArKMpvfa1mMRae9VvWZfeB2XfPkeLmm18lUcBj+p5dnN8jXZ3YIGEhYuOUn45aoCDkp16hl5IjYJvjWKcnoGQpqyPlpOhr3aElaqrq56Bq7VAAAOw=="); + height: 100%; + filter: alpha(opacity=25); /* support: IE8 */ + opacity: 0.25; +} +.ui-progressbar-indeterminate .ui-progressbar-value { + background-image: none; +} +.ui-selectable { + -ms-touch-action: none; + touch-action: none; +} +.ui-selectable-helper { + position: absolute; + z-index: 100; + border: 1px dotted black; +} +.ui-selectmenu-menu { + padding: 0; + margin: 0; + position: absolute; + top: 0; + left: 0; + display: none; +} +.ui-selectmenu-menu .ui-menu { + overflow: auto; + overflow-x: hidden; + padding-bottom: 1px; +} +.ui-selectmenu-menu .ui-menu .ui-selectmenu-optgroup { + font-size: 1em; + font-weight: bold; + line-height: 1.5; + padding: 2px 0.4em; + margin: 0.5em 0 0 0; + height: auto; + border: 0; +} +.ui-selectmenu-open { + display: block; +} +.ui-selectmenu-text { + display: block; + margin-right: 20px; + overflow: hidden; + text-overflow: ellipsis; +} +.ui-selectmenu-button.ui-button { + text-align: left; + white-space: nowrap; + width: 14em; +} +.ui-selectmenu-icon.ui-icon { + float: right; + margin-top: 0; +} +.ui-slider { + position: relative; + text-align: left; +} +.ui-slider .ui-slider-handle { + position: absolute; + z-index: 2; + width: 1.2em; + height: 1.2em; + cursor: default; + -ms-touch-action: none; + touch-action: none; +} +.ui-slider .ui-slider-range { + position: absolute; + z-index: 1; + font-size: .7em; + display: block; + border: 0; + background-position: 0 0; +} + +/* support: IE8 - See #6727 */ +.ui-slider.ui-state-disabled .ui-slider-handle, +.ui-slider.ui-state-disabled .ui-slider-range { + filter: inherit; +} + +.ui-slider-horizontal { + height: .8em; +} +.ui-slider-horizontal .ui-slider-handle { + top: -.3em; + margin-left: -.6em; +} +.ui-slider-horizontal .ui-slider-range { + top: 0; + height: 100%; +} +.ui-slider-horizontal .ui-slider-range-min { + left: 0; +} +.ui-slider-horizontal .ui-slider-range-max { + right: 0; +} + +.ui-slider-vertical { + width: .8em; + height: 100px; +} +.ui-slider-vertical .ui-slider-handle { + left: -.3em; + margin-left: 0; + margin-bottom: -.6em; +} +.ui-slider-vertical .ui-slider-range { + left: 0; + width: 100%; +} +.ui-slider-vertical .ui-slider-range-min { + bottom: 0; +} +.ui-slider-vertical .ui-slider-range-max { + top: 0; +} +.ui-sortable-handle { + -ms-touch-action: none; + touch-action: none; +} +.ui-spinner { + position: relative; + display: inline-block; + overflow: hidden; + padding: 0; + vertical-align: middle; +} +.ui-spinner-input { + border: none; + background: none; + color: inherit; + padding: .222em 0; + margin: .2em 0; + vertical-align: middle; + margin-left: .4em; + margin-right: 2em; +} +.ui-spinner-button { + width: 1.6em; + height: 50%; + font-size: .5em; + padding: 0; + margin: 0; + text-align: center; + position: absolute; + cursor: default; + display: block; + overflow: hidden; + right: 0; +} +/* more specificity required here to override default borders */ +.ui-spinner a.ui-spinner-button { + border-top-style: none; + border-bottom-style: none; + border-right-style: none; +} +.ui-spinner-up { + top: 0; +} +.ui-spinner-down { + bottom: 0; +} +.ui-tabs { + position: relative;/* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */ + padding: .2em; +} +.ui-tabs .ui-tabs-nav { + margin: 0; + padding: .2em .2em 0; +} +.ui-tabs .ui-tabs-nav li { + list-style: none; + float: left; + position: relative; + top: 0; + margin: 1px .2em 0 0; + border-bottom-width: 0; + padding: 0; + white-space: nowrap; +} +.ui-tabs .ui-tabs-nav .ui-tabs-anchor { + float: left; + padding: .5em 1em; + text-decoration: none; +} +.ui-tabs .ui-tabs-nav li.ui-tabs-active { + margin-bottom: -1px; + padding-bottom: 1px; +} +.ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor, +.ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor, +.ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor { + cursor: text; +} +.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor { + cursor: pointer; +} +.ui-tabs .ui-tabs-panel { + display: block; + border-width: 0; + padding: 1em 1.4em; + background: none; +} +.ui-tooltip { + padding: 8px; + position: absolute; + z-index: 9999; + max-width: 300px; +} +body .ui-tooltip { + border-width: 2px; +} + +/* Component containers +----------------------------------*/ +.ui-widget { + font-family: Arial,Helvetica,sans-serif; + font-size: 1em; +} +.ui-widget .ui-widget { + font-size: 1em; +} +.ui-widget input, +.ui-widget select, +.ui-widget textarea, +.ui-widget button { + font-family: Arial,Helvetica,sans-serif; + font-size: 1em; +} +.ui-widget.ui-widget-content { + border: 1px solid #c5c5c5; +} +.ui-widget-content { + border: 1px solid #dddddd; + background: #ffffff; + color: #333333; +} +.ui-widget-content a { + color: #333333; +} +.ui-widget-header { + border: 1px solid #dddddd; + background: #e9e9e9; + color: #333333; + font-weight: bold; +} +.ui-widget-header a { + color: #333333; +} + +/* Interaction states +----------------------------------*/ +.ui-state-default, +.ui-widget-content .ui-state-default, +.ui-widget-header .ui-state-default, +.ui-button, + +/* We use html here because we need a greater specificity to make sure disabled +works properly when clicked or hovered */ +html .ui-button.ui-state-disabled:hover, +html .ui-button.ui-state-disabled:active { + border: 1px solid #c5c5c5; + background: #f6f6f6; + font-weight: normal; + color: #454545; +} +.ui-state-default a, +.ui-state-default a:link, +.ui-state-default a:visited, +a.ui-button, +a:link.ui-button, +a:visited.ui-button, +.ui-button { + color: #454545; + text-decoration: none; +} +.ui-state-hover, +.ui-widget-content .ui-state-hover, +.ui-widget-header .ui-state-hover, +.ui-state-focus, +.ui-widget-content .ui-state-focus, +.ui-widget-header .ui-state-focus, +.ui-button:hover, +.ui-button:focus { + border: 1px solid #cccccc; + background: #ededed; + font-weight: normal; + color: #2b2b2b; +} +.ui-state-hover a, +.ui-state-hover a:hover, +.ui-state-hover a:link, +.ui-state-hover a:visited, +.ui-state-focus a, +.ui-state-focus a:hover, +.ui-state-focus a:link, +.ui-state-focus a:visited, +a.ui-button:hover, +a.ui-button:focus { + color: #2b2b2b; + text-decoration: none; +} + +.ui-visual-focus { + box-shadow: 0 0 3px 1px rgb(94, 158, 214); +} +.ui-state-active, +.ui-widget-content .ui-state-active, +.ui-widget-header .ui-state-active, +a.ui-button:active, +.ui-button:active, +.ui-button.ui-state-active:hover { + border: 1px solid #003eff; + background: #007fff; + font-weight: normal; + color: #ffffff; +} +.ui-icon-background, +.ui-state-active .ui-icon-background { + border: #003eff; + background-color: #ffffff; +} +.ui-state-active a, +.ui-state-active a:link, +.ui-state-active a:visited { + color: #ffffff; + text-decoration: none; +} + +/* Interaction Cues +----------------------------------*/ +.ui-state-highlight, +.ui-widget-content .ui-state-highlight, +.ui-widget-header .ui-state-highlight { + border: 1px solid #dad55e; + background: #fffa90; + color: #777620; +} +.ui-state-checked { + border: 1px solid #dad55e; + background: #fffa90; +} +.ui-state-highlight a, +.ui-widget-content .ui-state-highlight a, +.ui-widget-header .ui-state-highlight a { + color: #777620; +} +.ui-state-error, +.ui-widget-content .ui-state-error, +.ui-widget-header .ui-state-error { + border: 1px solid #f1a899; + background: #fddfdf; + color: #5f3f3f; +} +.ui-state-error a, +.ui-widget-content .ui-state-error a, +.ui-widget-header .ui-state-error a { + color: #5f3f3f; +} +.ui-state-error-text, +.ui-widget-content .ui-state-error-text, +.ui-widget-header .ui-state-error-text { + color: #5f3f3f; +} +.ui-priority-primary, +.ui-widget-content .ui-priority-primary, +.ui-widget-header .ui-priority-primary { + font-weight: bold; +} +.ui-priority-secondary, +.ui-widget-content .ui-priority-secondary, +.ui-widget-header .ui-priority-secondary { + opacity: .7; + filter:Alpha(Opacity=70); /* support: IE8 */ + font-weight: normal; +} +.ui-state-disabled, +.ui-widget-content .ui-state-disabled, +.ui-widget-header .ui-state-disabled { + opacity: .35; + filter:Alpha(Opacity=35); /* support: IE8 */ + background-image: none; +} +.ui-state-disabled .ui-icon { + filter:Alpha(Opacity=35); /* support: IE8 - See #6059 */ +} + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { + width: 16px; + height: 16px; +} +.ui-icon, +.ui-widget-content .ui-icon { + background-image: url("images/ui-icons_444444_256x240.png"); +} +.ui-widget-header .ui-icon { + background-image: url("images/ui-icons_444444_256x240.png"); +} +.ui-state-hover .ui-icon, +.ui-state-focus .ui-icon, +.ui-button:hover .ui-icon, +.ui-button:focus .ui-icon { + background-image: url("images/ui-icons_555555_256x240.png"); +} +.ui-state-active .ui-icon, +.ui-button:active .ui-icon { + background-image: url("images/ui-icons_ffffff_256x240.png"); +} +.ui-state-highlight .ui-icon, +.ui-button .ui-state-highlight.ui-icon { + background-image: url("images/ui-icons_777620_256x240.png"); +} +.ui-state-error .ui-icon, +.ui-state-error-text .ui-icon { + background-image: url("images/ui-icons_cc0000_256x240.png"); +} +.ui-button .ui-icon { + background-image: url("images/ui-icons_777777_256x240.png"); +} + +/* positioning */ +.ui-icon-blank { background-position: 16px 16px; } +.ui-icon-caret-1-n { background-position: 0 0; } +.ui-icon-caret-1-ne { background-position: -16px 0; } +.ui-icon-caret-1-e { background-position: -32px 0; } +.ui-icon-caret-1-se { background-position: -48px 0; } +.ui-icon-caret-1-s { background-position: -65px 0; } +.ui-icon-caret-1-sw { background-position: -80px 0; } +.ui-icon-caret-1-w { background-position: -96px 0; } +.ui-icon-caret-1-nw { background-position: -112px 0; } +.ui-icon-caret-2-n-s { background-position: -128px 0; } +.ui-icon-caret-2-e-w { background-position: -144px 0; } +.ui-icon-triangle-1-n { background-position: 0 -16px; } +.ui-icon-triangle-1-ne { background-position: -16px -16px; } +.ui-icon-triangle-1-e { background-position: -32px -16px; } +.ui-icon-triangle-1-se { background-position: -48px -16px; } +.ui-icon-triangle-1-s { background-position: -65px -16px; } +.ui-icon-triangle-1-sw { background-position: -80px -16px; } +.ui-icon-triangle-1-w { background-position: -96px -16px; } +.ui-icon-triangle-1-nw { background-position: -112px -16px; } +.ui-icon-triangle-2-n-s { background-position: -128px -16px; } +.ui-icon-triangle-2-e-w { background-position: -144px -16px; } +.ui-icon-arrow-1-n { background-position: 0 -32px; } +.ui-icon-arrow-1-ne { background-position: -16px -32px; } +.ui-icon-arrow-1-e { background-position: -32px -32px; } +.ui-icon-arrow-1-se { background-position: -48px -32px; } +.ui-icon-arrow-1-s { background-position: -65px -32px; } +.ui-icon-arrow-1-sw { background-position: -80px -32px; } +.ui-icon-arrow-1-w { background-position: -96px -32px; } +.ui-icon-arrow-1-nw { background-position: -112px -32px; } +.ui-icon-arrow-2-n-s { background-position: -128px -32px; } +.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } +.ui-icon-arrow-2-e-w { background-position: -160px -32px; } +.ui-icon-arrow-2-se-nw { background-position: -176px -32px; } +.ui-icon-arrowstop-1-n { background-position: -192px -32px; } +.ui-icon-arrowstop-1-e { background-position: -208px -32px; } +.ui-icon-arrowstop-1-s { background-position: -224px -32px; } +.ui-icon-arrowstop-1-w { background-position: -240px -32px; } +.ui-icon-arrowthick-1-n { background-position: 1px -48px; } +.ui-icon-arrowthick-1-ne { background-position: -16px -48px; } +.ui-icon-arrowthick-1-e { background-position: -32px -48px; } +.ui-icon-arrowthick-1-se { background-position: -48px -48px; } +.ui-icon-arrowthick-1-s { background-position: -64px -48px; } +.ui-icon-arrowthick-1-sw { background-position: -80px -48px; } +.ui-icon-arrowthick-1-w { background-position: -96px -48px; } +.ui-icon-arrowthick-1-nw { background-position: -112px -48px; } +.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } +.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } +.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } +.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } +.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } +.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } +.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } +.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } +.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } +.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } +.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } +.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } +.ui-icon-arrowreturn-1-w { background-position: -64px -64px; } +.ui-icon-arrowreturn-1-n { background-position: -80px -64px; } +.ui-icon-arrowreturn-1-e { background-position: -96px -64px; } +.ui-icon-arrowreturn-1-s { background-position: -112px -64px; } +.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } +.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } +.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } +.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } +.ui-icon-arrow-4 { background-position: 0 -80px; } +.ui-icon-arrow-4-diag { background-position: -16px -80px; } +.ui-icon-extlink { background-position: -32px -80px; } +.ui-icon-newwin { background-position: -48px -80px; } +.ui-icon-refresh { background-position: -64px -80px; } +.ui-icon-shuffle { background-position: -80px -80px; } +.ui-icon-transfer-e-w { background-position: -96px -80px; } +.ui-icon-transferthick-e-w { background-position: -112px -80px; } +.ui-icon-folder-collapsed { background-position: 0 -96px; } +.ui-icon-folder-open { background-position: -16px -96px; } +.ui-icon-document { background-position: -32px -96px; } +.ui-icon-document-b { background-position: -48px -96px; } +.ui-icon-note { background-position: -64px -96px; } +.ui-icon-mail-closed { background-position: -80px -96px; } +.ui-icon-mail-open { background-position: -96px -96px; } +.ui-icon-suitcase { background-position: -112px -96px; } +.ui-icon-comment { background-position: -128px -96px; } +.ui-icon-person { background-position: -144px -96px; } +.ui-icon-print { background-position: -160px -96px; } +.ui-icon-trash { background-position: -176px -96px; } +.ui-icon-locked { background-position: -192px -96px; } +.ui-icon-unlocked { background-position: -208px -96px; } +.ui-icon-bookmark { background-position: -224px -96px; } +.ui-icon-tag { background-position: -240px -96px; } +.ui-icon-home { background-position: 0 -112px; } +.ui-icon-flag { background-position: -16px -112px; } +.ui-icon-calendar { background-position: -32px -112px; } +.ui-icon-cart { background-position: -48px -112px; } +.ui-icon-pencil { background-position: -64px -112px; } +.ui-icon-clock { background-position: -80px -112px; } +.ui-icon-disk { background-position: -96px -112px; } +.ui-icon-calculator { background-position: -112px -112px; } +.ui-icon-zoomin { background-position: -128px -112px; } +.ui-icon-zoomout { background-position: -144px -112px; } +.ui-icon-search { background-position: -160px -112px; } +.ui-icon-wrench { background-position: -176px -112px; } +.ui-icon-gear { background-position: -192px -112px; } +.ui-icon-heart { background-position: -208px -112px; } +.ui-icon-star { background-position: -224px -112px; } +.ui-icon-link { background-position: -240px -112px; } +.ui-icon-cancel { background-position: 0 -128px; } +.ui-icon-plus { background-position: -16px -128px; } +.ui-icon-plusthick { background-position: -32px -128px; } +.ui-icon-minus { background-position: -48px -128px; } +.ui-icon-minusthick { background-position: -64px -128px; } +.ui-icon-close { background-position: -80px -128px; } +.ui-icon-closethick { background-position: -96px -128px; } +.ui-icon-key { background-position: -112px -128px; } +.ui-icon-lightbulb { background-position: -128px -128px; } +.ui-icon-scissors { background-position: -144px -128px; } +.ui-icon-clipboard { background-position: -160px -128px; } +.ui-icon-copy { background-position: -176px -128px; } +.ui-icon-contact { background-position: -192px -128px; } +.ui-icon-image { background-position: -208px -128px; } +.ui-icon-video { background-position: -224px -128px; } +.ui-icon-script { background-position: -240px -128px; } +.ui-icon-alert { background-position: 0 -144px; } +.ui-icon-info { background-position: -16px -144px; } +.ui-icon-notice { background-position: -32px -144px; } +.ui-icon-help { background-position: -48px -144px; } +.ui-icon-check { background-position: -64px -144px; } +.ui-icon-bullet { background-position: -80px -144px; } +.ui-icon-radio-on { background-position: -96px -144px; } +.ui-icon-radio-off { background-position: -112px -144px; } +.ui-icon-pin-w { background-position: -128px -144px; } +.ui-icon-pin-s { background-position: -144px -144px; } +.ui-icon-play { background-position: 0 -160px; } +.ui-icon-pause { background-position: -16px -160px; } +.ui-icon-seek-next { background-position: -32px -160px; } +.ui-icon-seek-prev { background-position: -48px -160px; } +.ui-icon-seek-end { background-position: -64px -160px; } +.ui-icon-seek-start { background-position: -80px -160px; } +/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */ +.ui-icon-seek-first { background-position: -80px -160px; } +.ui-icon-stop { background-position: -96px -160px; } +.ui-icon-eject { background-position: -112px -160px; } +.ui-icon-volume-off { background-position: -128px -160px; } +.ui-icon-volume-on { background-position: -144px -160px; } +.ui-icon-power { background-position: 0 -176px; } +.ui-icon-signal-diag { background-position: -16px -176px; } +.ui-icon-signal { background-position: -32px -176px; } +.ui-icon-battery-0 { background-position: -48px -176px; } +.ui-icon-battery-1 { background-position: -64px -176px; } +.ui-icon-battery-2 { background-position: -80px -176px; } +.ui-icon-battery-3 { background-position: -96px -176px; } +.ui-icon-circle-plus { background-position: 0 -192px; } +.ui-icon-circle-minus { background-position: -16px -192px; } +.ui-icon-circle-close { background-position: -32px -192px; } +.ui-icon-circle-triangle-e { background-position: -48px -192px; } +.ui-icon-circle-triangle-s { background-position: -64px -192px; } +.ui-icon-circle-triangle-w { background-position: -80px -192px; } +.ui-icon-circle-triangle-n { background-position: -96px -192px; } +.ui-icon-circle-arrow-e { background-position: -112px -192px; } +.ui-icon-circle-arrow-s { background-position: -128px -192px; } +.ui-icon-circle-arrow-w { background-position: -144px -192px; } +.ui-icon-circle-arrow-n { background-position: -160px -192px; } +.ui-icon-circle-zoomin { background-position: -176px -192px; } +.ui-icon-circle-zoomout { background-position: -192px -192px; } +.ui-icon-circle-check { background-position: -208px -192px; } +.ui-icon-circlesmall-plus { background-position: 0 -208px; } +.ui-icon-circlesmall-minus { background-position: -16px -208px; } +.ui-icon-circlesmall-close { background-position: -32px -208px; } +.ui-icon-squaresmall-plus { background-position: -48px -208px; } +.ui-icon-squaresmall-minus { background-position: -64px -208px; } +.ui-icon-squaresmall-close { background-position: -80px -208px; } +.ui-icon-grip-dotted-vertical { background-position: 0 -224px; } +.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } +.ui-icon-grip-solid-vertical { background-position: -32px -224px; } +.ui-icon-grip-solid-horizontal { background-position: -48px -224px; } +.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } +.ui-icon-grip-diagonal-se { background-position: -80px -224px; } + + +/* Misc visuals +----------------------------------*/ + +/* Corner radius */ +.ui-corner-all, +.ui-corner-top, +.ui-corner-left, +.ui-corner-tl { + border-top-left-radius: 3px; +} +.ui-corner-all, +.ui-corner-top, +.ui-corner-right, +.ui-corner-tr { + border-top-right-radius: 3px; +} +.ui-corner-all, +.ui-corner-bottom, +.ui-corner-left, +.ui-corner-bl { + border-bottom-left-radius: 3px; +} +.ui-corner-all, +.ui-corner-bottom, +.ui-corner-right, +.ui-corner-br { + border-bottom-right-radius: 3px; +} + +/* Overlays */ +.ui-widget-overlay { + background: #aaaaaa; + opacity: .003; + filter: Alpha(Opacity=.3); /* support: IE8 */ +} +.ui-widget-shadow { + -webkit-box-shadow: 0px 0px 5px #666666; + box-shadow: 0px 0px 5px #666666; +} -- GitLab