├── LICENSE ├── README.md ├── changelog.md ├── contents ├── c-0-1-1.xhtml ├── c-0-1-1.xml ├── c-0-1.xhtml ├── c-0-1.xml ├── c-0-2-1.xhtml ├── c-0-2-1.xml ├── c-0-2-2.xhtml ├── c-0-2-2.xml ├── c-0-2.xhtml ├── c-0-2.xml ├── c-0-3-1.xhtml ├── c-0-3-1.xml ├── c-0-3-2.xhtml ├── c-0-3-2.xml ├── c-0-3-3.xhtml ├── c-0-3-3.xml ├── c-0-3.xhtml ├── c-0-3.xml ├── c-0-4.xhtml ├── c-0-4.xml ├── c-0.html ├── c-0.xml ├── image1.jpg └── style.css ├── index.html ├── init.json ├── media ├── icon-192.png └── socmedia.png └── src ├── buttons.js ├── init.js ├── loader.js ├── orbital.html └── orbital.js /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 tearflake 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FlakeUI (v0.7-update) 2 | 3 | tags: user-interface, graph-visualization, zooming-elements-based, parent-children-orbiting, fractal-structure-inspired 4 | 5 | > ## promotional material 6 | > 7 | > ![](contents/image1.jpg) 8 | > 9 | > Would you like to bring a touch of adventurous spirit to your contents? Presenting your contents, FlakeUI does things a bit differently. As an original graph content navigating environment, it provides unusual experience in discovering information among your content selection. Possible applications are surely endless, and they are waiting to be discovered by that awesome child of creativity in you. 10 | 11 | ## 1. about flake-ui 12 | 13 | FlakeUI is a fractal-structure inspired, parent-child orbiting, and zooming-elements based graph user interface. Javascript based FlakeUI is best used in HTML pages where visitors often return, like in a curated selection of web links, searchable hierarchical catalog of arbitrary items, or maybe even some cool mobile content start pages if someone decides to go in PWA (progressive web application) direction. 14 | 15 | ## 2. contents creation 16 | 17 | Composing contents in FlakeUI consists of editing external content XHTML pages and arranging them using parent-children structure described in a set of XML files. Supported interaction includes navigating graph content nodes and following hyperlinks inside nodes. 18 | 19 | ## 3. contents navigation 20 | 21 | The final result brings all the imported content pages to be shown inside orbitable and zoomable ovals that form a seamless dynamic asymptotic fractal. We navigate the entire fractal structure using only five kinds of gestures: 22 | 23 | 1. dragging inside the central oval area to pan its contents 24 | 2. dragging orbiting ovals around the central oval to rotate them 25 | 3. dragging orbiting ovals towards center to zoom them in 26 | 4. dragging central oval out towards orbit to zoom it out 27 | 5. using mouse wheel to switch between navigating and panning mode 28 | 29 | ## 4. giving it a try 30 | 31 | To get started with site creation using FlakeUI, please refer to the [example site](https://tearflake.github.io/flake-ui/) containing use instructions. 32 | 33 | ## 5. licensing 34 | 35 | This software is released under [MIT license](LICENSE). 36 | 37 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | - v 0.1 - beta 2 | - the first official testing version 3 | 4 | - v 0.1 - release 5 | - initial release version 6 | 7 | - v 0.1 - update 8 | - SEO friendly implementation 9 | - gradual oval transparency 10 | - changed responsive mode scaling policy 11 | - HTML pages rendering support 12 | - user defined foreground/background color 13 | - optional hiding help pictograms 14 | 15 | - - - 16 | 17 | - v 0.3 - beta 18 | - improved device-pixel-ratio consistency for mobile platforms 19 | - new HTML renderer 20 | - progressive page loading for supporting bigger sites 21 | - cast shadow effect 22 | 23 | - v 0.3 - release 24 | - bug fixes 25 | 26 | - v 0.3 - update 27 | - slower processor friendly implementation & energy consumption optimisation 28 | - minimalistic visual design 29 | - user interface scaling 30 | - pinch-zoom support 31 | 32 | - - - 33 | 34 | - v 0.5 - beta 35 | - UX improvement 36 | - halign, valign, hlock, vlock, backcolor for each oval. 37 | - native HTML renderer, improved loading speed at the expense of rendering speed 38 | - CSS animations support 39 | - responsive mode matches native appearance in scale 40 | 41 | - v 0.5 - release 42 | - bug fixes 43 | 44 | - v 0.5 - update 45 | - only top two levels navigation 46 | - each oval structure stored into separate XML - scallable dynamic loading of each XML 47 | - mouse wheel event resembles pinch-zoom 48 | - updated scaling policy 49 | - directional shift for larger scaling 50 | 51 | - - - 52 | 53 | - v 0.7 - beta 54 | - mobile UX improvement 55 | - Safari support 56 | - fixed font blur on zoom 57 | - navigation buttons 58 | - command button 59 | 60 | - v 0.7 - release 61 | - orbital orientation 62 | - bug fixes 63 | - removed unnecessary features 64 | 65 | - v 0.7 - update 66 | - compacting designer experience 67 | - revised necessary features 68 | - updated scaling policy 69 | - bug fixes 70 | 71 | -------------------------------------------------------------------------------- /contents/c-0-1-1.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |

8 | 1.1. possible use cases 9 |

10 |
C
11 |

12 | onsidering FlakeUI static limitations, what kind of content can we build with it? Let's overview a 13 | few examples of static content pages: 14 |

15 |

16 |

24 |

25 |

26 | As the list goes on, we strenghten our belief that FlakeUI could still find a use in various 27 | cases, especially in a combination with server side scripting technologies. 28 |

29 | 30 | 31 | -------------------------------------------------------------------------------- /contents/c-0-1-1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /contents/c-0-1.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |

8 | 1. strengths and weaknesses 9 |

10 |
F
11 |

12 | lakeUI is intended to display static contents arranged within zoomable oval system. 13 | The latest version of FlakeUI loads content element pages on display demand, thus it is 14 | scallable as long as all the visible ovals together with their parent ovals fit into RAM. 15 |

16 |

17 | However, interaction with pages is reduced only to page panning and following hyperlinks. 18 | This limitation entails having no fancy event dependent animations or dynamic content tree 19 | structure. Still, FlakeUI could be used in a various scenarios where these limitations 20 | meet our expectations. 21 |

22 | 23 | 24 | -------------------------------------------------------------------------------- /contents/c-0-1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /contents/c-0-2-1.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |

8 | 2.1. panning the content elements 9 |

10 |
T
11 |

12 | he center oval of the FlakeUI content pages serves for reading the content. By dragging its content, 13 | the content scrolls in dragging direction. Content size isn't restricted, but it is recommended to 14 | keep it within oval bounds. Scroll bars are not present as they could put graphical appearance 15 | of the content out of the balance. 16 |

17 |

18 | On mobile platforms, it is possible to pinch-zoom the content of the central oval for clearer view. Desktop 19 | platforms provide the same functionality with mouse wheel. 20 |

21 | 22 | 23 | -------------------------------------------------------------------------------- /contents/c-0-2-1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /contents/c-0-2-2.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |

8 | 2.2. orbiting the content elements 9 |

10 |
T
11 |

12 | he structure of content in FlakeUI is visualized in a distinctive way, resembling a form of a fractal 13 | arranged ovals where child ovals orbit around each parent oval recursively. Ovals themselves store 14 | textual or graphic information fitting into hierarchical parent-children relations. Dragging ovals 15 | around their parents enables walking horizontally through the tree (navigating through siblings), while 16 | dragging in or out of oval parent or children positions enables walking vertically through the 17 | hierarchical structure of data (focusing a parent or a child oval at central browsing area). 18 |

19 | 20 | 21 | -------------------------------------------------------------------------------- /contents/c-0-2-2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /contents/c-0-2.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |

8 | 2. browsing the contents 9 |

10 |
F
11 |

12 | lakeUI brings a simple and minimalistic kind of content structuring and organization. All the pages are 13 | displayed inside a number of ovals that hierarchically relate between each other. Central oval is supposed 14 | to be used for reading and viewing content, while orbiting ovals are supposed to be used for content 15 | navigation. All the actions of browsing content are performed by dragging displayed elements by mouse 16 | (click-drag-release cycles), or by touch screen interaction (touch-drag-release cycles). Of course, 17 | hyperlinking is also supported by usual click or touch interaction. 18 |

19 | 20 | 21 | -------------------------------------------------------------------------------- /contents/c-0-2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /contents/c-0-3-1.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |

8 | 3.1. making a local copy 9 |

10 |
F
11 |

12 | irst, we need to make sure we have installed a local web server like 13 | Apache HTTP Server 14 | or similar software. We also need to make sure to have an access to a file manager and 15 | a text editor which we will use to access and edit FlakeUI content files. 16 |

17 |

18 | To install FlakeUI, we have to download the FlakeUI software bundle from 19 | dedicated github pages. After 20 | downloading the software, we have to unpack the downloaded zip archive to a local server folder. 21 | Unpacking the archive will produce the following file-folder structure: 22 |

23 |

24 |


25 |  !
26 |  +-+ flakeUI-home-folder
27 |    +-+ contents
28 |    ! +-- ...
29 |    !
30 |    +-+ media
31 |    ! +-- ...
32 |    !
33 |    +-+ src
34 |    ! +-- ...
35 |    !
36 |    +-- changelog.md
37 |    +-- index.html
38 |    +-- init.json
39 |    +-- README.md
40 |    +-- LICENSE
41 |   
42 | 
43 |

44 |

45 | Now that we have unpacked the archive, we can test it by entering the local HTTP server address 46 | into a web browser (usually localhost). We should be able to see the exact copy of 47 | these instructions in the browser. 48 |

49 | 50 | 51 | -------------------------------------------------------------------------------- /contents/c-0-3-1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /contents/c-0-3-2.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 |

13 | 3.2. customizing our contents 14 |

15 |
N
16 |

17 | ext, we have to modify the example content to adjust it to our own requirements and introduce 18 | our own contents instead of the existing one. Freshly unpacked files represent an example content 19 | containing these instructions we are currently reading. There are several files and folders 20 | of our interest: 21 |

22 |

23 |

53 |

54 |

55 | Hopefully, examining the default content example (that is, files containing these instructions) should 56 | be descriptive enough to compose our own contents. This is the steep part where we will be using 57 | file manager 58 | and 59 | text editor 60 | to arrange and edit files of our interest. Please refer to provided links if you need to get more 61 | familiar with mentioned notions. This procedure is what makes FlakeUI content creating experience 62 | "slack", and requires a bit more advanced knowledge from the content creators, especially considering 63 | possible use of server side scripting or other technologies. 64 |

65 |

66 | Upon each edit, we would want to test if changes we made reflect what we want them to be. Again, we 67 | can test them by entering the local HTTP server address into a web browser.
68 |

69 | 70 | 71 | -------------------------------------------------------------------------------- /contents/c-0-3-2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /contents/c-0-3-3.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |

8 | 3.3. publishing our content 9 |

10 |
F
11 |

12 | inally, when we are done testing our site, we would want to publish it to a remote online server. To do 13 | this, we have to copy the entire file and folder structure from below the flakeUI-home-folder, to the 14 | remote online server home folder. We can usually do this by using control panel pages provided by the 15 | remote server, or using a custom 16 | FTP client software 17 | if we have an access to remote site FTP user name and password. If everything goes well, our new content 18 | should be happily spinning on the world wide web. 19 |

20 | 21 | 22 | -------------------------------------------------------------------------------- /contents/c-0-3-3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /contents/c-0-3.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |

8 | 3. building a custom site 9 |

10 |
T
11 |

12 | o populate FlakeUI interface with custom content, it is necessary to prepare XHTML files 13 | representing our pages, to have an access to arbitrary textual editor, and it may be a good practice 14 | to have a local web server at disposition for testing our new site. FlakeUI represents a so-called flat 15 | file interface, meaning there is no basic information stored in remote databases, yet all the information 16 | needed for basic functioning is extracted only from file and folder structure accessed over HTTP interface. 17 |

18 |

19 | To corroborate flat file data system, it is possible to pair it with server side scripting technologies 20 | like ASP, PHP, Node.js, and others. FlakeUI should collaborate very well with such technologies, as long 21 | as the outcome conforms FlakeUI file and folder structures. 22 |

23 | 24 | 25 | -------------------------------------------------------------------------------- /contents/c-0-3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /contents/c-0-4.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 |

11 | licensing 12 |

13 |

14 | MIT License 15 |

16 |

17 | Copyright (c) 2025 tearflake 18 |

19 |

20 | Permission is hereby granted, free of charge, to any person obtaining a copy 21 | of this software and associated documentation files (the "Software"), to deal 22 | in the Software without restriction, including without limitation the rights 23 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 24 | copies of the Software, and to permit persons to whom the Software is 25 | furnished to do so, subject to the following conditions: 26 |

27 |

28 | The above copyright notice and this permission notice shall be included in all 29 | copies or substantial portions of the Software. 30 |

31 |

32 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 33 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 34 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 35 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 36 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 37 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 38 | SOFTWARE. 39 |

40 | 41 | 42 | -------------------------------------------------------------------------------- /contents/c-0-4.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /contents/c-0.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |

9 | FlakeUI use instructions 10 |

11 |

12 |

T
13 | hese pages are displayed with FlakeUI, and they contain FlakeUI use and content building instructions. 14 | The current version of FlakeUI represents an innovative graph based user interface hosting a digital 15 | content. 16 |

17 |

18 | When creating a FlakeUI based content, one should possess a basic knowledge about editing XML, XHTML, 19 | and JSON files in text editor. XML files in FlakeUI define a hierarchical structure of XHTML content files. 20 | Some graph styling parameters can be adjusted by editing main JSON file placed in the FlakeUI root folder. 21 | The structured content is then spanned within asymptotic dynamically orbitable and zoomable fractal which can 22 | be navigated using mouse or touch gestures. 23 |

24 |

25 | Finally, the entire FlakeUI folder tree may be hosted as a standalone or embedded content at any HTTP address 26 | space. 27 |

28 | 29 | 30 | -------------------------------------------------------------------------------- /contents/c-0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /contents/image1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tearflake/flake-ui/90b0d12e5f1f691da9165ae25135f645f7d2034c/contents/image1.jpg -------------------------------------------------------------------------------- /contents/style.css: -------------------------------------------------------------------------------- 1 | @media (max-device-width: 1919px) { 2 | body { 3 | width: 512px; 4 | font-size: 1em; 5 | } 6 | 7 | h1 { 8 | font-size: 3.2em; 9 | } 10 | } 11 | 12 | @media (min-device-width: 1920px) { 13 | @media (max-device-width: 2879px) { 14 | body { 15 | width: 640px; 16 | font-size: 1.2em; 17 | } 18 | 19 | h1 { 20 | font-size: 3.2em; 21 | } 22 | } 23 | } 24 | 25 | @media (min-device-width: 2880px) { 26 | @media (max-device-width: 3839px) { 27 | body { 28 | width: 960px; 29 | font-size: 1.8em; 30 | } 31 | 32 | h1 { 33 | font-size: 3.2em; 34 | } 35 | } 36 | } 37 | 38 | @media (min-device-width: 3840px) { 39 | body { 40 | width: 1280px; 41 | font-size: 2.4em; 42 | } 43 | 44 | h1 { 45 | font-size: 3.2em; 46 | } 47 | } 48 | 49 | @media (min-resolution: 2dppx) { 50 | body { 51 | width: 50%; 52 | font-size: 0.8em; 53 | } 54 | 55 | h1 { 56 | font-size: 2em; 57 | } 58 | 59 | @media (min-device-width: 800px) and (min-device-height: 600px) { 60 | body { 61 | width: 50%; 62 | font-size: 1.2em; 63 | } 64 | 65 | h1 { 66 | font-size: 2em; 67 | } 68 | } 69 | 70 | @media (min-device-width: 600px) and (min-device-height: 800px) { 71 | body { 72 | width: 50%; 73 | font-size: 1.2em; 74 | } 75 | 76 | h1 { 77 | font-size: 2em; 78 | } 79 | } 80 | } 81 | 82 | body { 83 | color: rgb(48,48,48); 84 | font-family: Times New Roman, Georgia, Garamond; 85 | margin: 0 auto; 86 | padding: 0; 87 | } 88 | 89 | h1 { 90 | padding: 0.1em; 91 | border-bottom: 1px solid rgb(48,48,48); 92 | margin-top: 0em; 93 | font-weight: bold; 94 | } 95 | 96 | body { 97 | animation: fadein 0.5s; 98 | } 99 | 100 | @keyframes fadein { 101 | from { opacity: 0; } 102 | to { opacity: 1; } 103 | } 104 | 105 | .float-left { 106 | float:left; 107 | font-size: 4.15em; 108 | margin-top: -0.165em; 109 | margin-bottom: -0.3em; 110 | margin-right: 0.1em; 111 | font-weight: normal; 112 | } 113 | 114 | code, pre { 115 | color: white; 116 | background-color: rgb(48,48,48); 117 | border-radius: 0.25em; 118 | padding: 0.1em; 119 | padding-left: 0.25em; 120 | padding-right: 0.25em; 121 | } 122 | 123 | a { 124 | color: rgb(48,48,48); 125 | text-decoration: underline; 126 | font-weight: bold; 127 | } 128 | 129 | img { 130 | border-radius: 0.25em; 131 | } 132 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | FlakeUI 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 60 | 61 | 62 | 67 | 68 | 98 | 99 | 153 | 154 | 155 | 156 | 226 | 227 | 237 | 238 | 276 | 277 | 278 | 279 | 280 | 298 | 299 | 300 | 301 | 460 | 461 | 481 | 482 | 508 | 509 | 510 | -------------------------------------------------------------------------------- /init.json: -------------------------------------------------------------------------------- 1 | { 2 | "home": "contents/c-0.xml", 3 | "top-bar-visible": "true", 4 | "buttons-visible": "true", 5 | "ovals-border": "true", 6 | "ovals-spacing": "1%", 7 | "ovals-scale": "128%", 8 | "contents-scale": "100%" 9 | } 10 | 11 | -------------------------------------------------------------------------------- /media/icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tearflake/flake-ui/90b0d12e5f1f691da9165ae25135f645f7d2034c/media/icon-192.png -------------------------------------------------------------------------------- /media/socmedia.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tearflake/flake-ui/90b0d12e5f1f691da9165ae25135f645f7d2034c/media/socmedia.png -------------------------------------------------------------------------------- /src/buttons.js: -------------------------------------------------------------------------------- 1 | var magnFactorBut, butsBorderWidth, envButtons; 2 | 3 | function setSizeBut () { 4 | //if (document.body.clientWidth > document.body.clientHeight) { 5 | // magnFactorBut = 1.25 * document.body.clientWidth / 1920; 6 | //} 7 | //else { 8 | // magnFactorBut = 1.25 * document.body.clientHeight / 1080; 9 | //} 10 | 11 | //if (window.devicePixelRatio > 1) { 12 | // magnFactorBut *= 0.8; 13 | //} 14 | 15 | magnFactorBut = document.body.clientHeight / 1080; 16 | 17 | //if (magnFactorBut > 1) { 18 | // magnFactorBut = 1; 19 | //} 20 | 21 | if (magnFactorBut < 0.5) { 22 | magnFactorBut = 0.5; 23 | } 24 | 25 | rescaleLftBut (); 26 | rescaleRgtBut (); 27 | } 28 | 29 | function initButtons (env) { 30 | envButtons = env; 31 | document.getElementById("rgtbut").style.transform = document.getElementById("rgtbut").style.transform + " " + (env.orientation === "north" ? "rotate(" + Math.PI + "rad) " : "") 32 | 33 | if (envButtons.butVisibility === "false") { 34 | document.getElementById("lftbut").style.visibility = "hidden"; 35 | document.getElementById("rgtbut").style.visibility = "hidden"; 36 | } else { 37 | document.getElementById("lftbut").style.visibility = "visible"; 38 | document.getElementById("rgtbut").style.visibility = "visible"; 39 | } 40 | 41 | butsBorderWidth = 4; 42 | if (envButtons.butVisibility !== "false") { 43 | /* 44 | if (envButtons.butsBorderColor && envButtons.butsBorderColor !== envButtons.butsBackColor) { 45 | document.getElementById("lftbutsvg").style.stroke = envButtons.butsBorderColor; 46 | document.getElementById("lftbutsvg").style.strokeWidth = butsBorderWidth + "px"; 47 | 48 | document.getElementById("rgtbutsvg").style.stroke = envButtons.butsBorderColor; 49 | document.getElementById("rgtbutsvg").style.strokeWidth = butsBorderWidth + "px"; 50 | } 51 | */ 52 | 53 | if (envButtons.butShadowRadius > 0) { 54 | document.getElementById("lftbut").style.filter += " drop-shadow(0px 0px " + envButtons.butShadowRadius + "px " + envButtons.butShadowColor + ")"; 55 | document.getElementById("rgtbut").style.filter += " drop-shadow(0px 0px " + envButtons.butShadowRadius + "px " + envButtons.butShadowColor + ")"; 56 | } 57 | } 58 | 59 | 60 | //document.getElementById("lb1").style.stroke = envButtons.butsColor; 61 | document.getElementById("lb1").style.fill = envButtons.butsColor; 62 | 63 | document.getElementById("rb1").style.fill = envButtons.butsColor; 64 | document.getElementById("rb2").style.fill = envButtons.butsColor; 65 | document.getElementById("rb3").style.stroke = envButtons.butsColor; 66 | document.getElementById("rb3").style.fill = envButtons.butsColor; 67 | document.getElementById("rb4").style.stroke = envButtons.butsColor; 68 | document.getElementById("rb4").style.fill = envButtons.butsColor; 69 | document.getElementById("rb5").style.stroke = envButtons.butsColor; 70 | document.getElementById("rb5").style.fill = envButtons.butsColor; 71 | document.getElementById("rb6").style.stroke = envButtons.butsColor; 72 | document.getElementById("rb6").style.fill = envButtons.butsColor; 73 | 74 | var ngonsides = 4 * Math.round (8 / (envButtons.quant / 100) * 0.7); 75 | if (ngonsides > 100) ngonsides = 100; 76 | round (72, 72, 72, 72, ngonsides, document.getElementById("rgtbutsvg"), envButtons.butsBackColor); 77 | round (72, 72, 72, 72, ngonsides, document.getElementById("lftbutsvg"), envButtons.butsBackColor); 78 | 79 | window.addEventListener('resize', function () { 80 | setSizeBut (); 81 | }); 82 | 83 | setSizeBut (); 84 | } 85 | 86 | function round (x, y, r1, r2, s, svg, backcolor) { 87 | /* 88 | if (envButtons.butsBorderColor && envButtons.butsBorderColor !== envButtons.butsBackColor) { 89 | r1 -= butsBorderWidth; 90 | r2 -= butsBorderWidth; 91 | } 92 | */ 93 | var polygon = document.createElementNS("http://www.w3.org/2000/svg", "polygon"); 94 | svg.appendChild(polygon); 95 | 96 | var p = []; 97 | for (var i = 0.5; i < s; i++) { 98 | p.push ([x + Math.cos (2 * Math.PI / s * i) * r1, y + Math.sin (2 * Math.PI / s * i) * r2]); 99 | } 100 | 101 | for (value of p) { 102 | var point = svg.createSVGPoint(); 103 | point.x = value[0]; 104 | point.y = value[1]; 105 | polygon.points.appendItem(point); 106 | } 107 | 108 | polygon.style.fill = backcolor; 109 | } 110 | 111 | // --- home button --- // 112 | function rescaleLftBut () { 113 | var lb = document.getElementById("lftbut"); 114 | 115 | 116 | if (envButtons["orientation"] === "south") { 117 | lb.style.transform = "translateX(" + Math.floor (-144 / 2 + 144 * magnFactorBut / 2) + "px)" + " translateY(" + Math.floor (144 / 2 - 144 * magnFactorBut / 2) + "px)" + " scale(" + magnFactorBut + ") "; 118 | lb.style.right = ""; 119 | lb.style.top = ""; 120 | lb.style.left = 0.5 * magnFactorBut + "em"; 121 | lb.style.bottom = 0.5 * magnFactorBut + "em"; 122 | } else { 123 | lb.style.transform = "translateX(" + Math.floor (144 / 2 - 144 * magnFactorBut / 2) + "px)" + " translateY(" + Math.floor (-144 / 2 + 144 * magnFactorBut / 2) + "px)" + " scale(" + magnFactorBut + ") "; 124 | lb.style.left = ""; 125 | lb.style.bottom = ""; 126 | lb.style.right = 0.5 * magnFactorBut + "em"; 127 | lb.style.top = 0.5 * magnFactorBut + "em"; 128 | } 129 | } 130 | 131 | document.getElementById("lftbuta").addEventListener("click", function (evt) { 132 | document.getElementById ("body").contentWindow.postMessage({msg: "lftbutaClick"}, "*"); 133 | }, false); 134 | 135 | document.getElementById("lftbuta").onmousedown = function (evt) { 136 | document.getElementById ("body").contentWindow.postMessage({msg: "lftbutaMouseDown"}, "*"); 137 | }; 138 | 139 | document.getElementById("lftbuta").addEventListener("touchstart", function (evt) { 140 | document.getElementById("lftbuta").dispatchEvent(new CustomEvent('click')); 141 | evt.preventDefault (); 142 | }, false); 143 | 144 | document.getElementById("lftbuta").ondragstart = function (evt) { 145 | evt.preventDefault (); 146 | }; 147 | 148 | /* 149 | document.getElementById("lftbuta").addEventListener("click", function (evt) { 150 | reload (envButtons["topNode"]); 151 | }, false); 152 | 153 | document.getElementById("lftbuta").onmousedown = function (evt) { 154 | objOrbit.setMouseOff (); 155 | }; 156 | 157 | document.getElementById("lftbuta").addEventListener("touchstart", function (evt) { 158 | objOrbit.setMouseOff (); 159 | document.getElementById("lftbuta").dispatchEvent(new CustomEvent('click')); 160 | evt.preventDefault (); 161 | }, false); 162 | 163 | document.getElementById("lftbut").ondragstart = function (evt) { 164 | evt.preventDefault (); 165 | }; 166 | */ 167 | 168 | // --- home button end --- // 169 | 170 | // --- navigator --- // 171 | 172 | function rescaleRgtBut () { 173 | var rb = document.getElementById("rgtbut"); 174 | 175 | if (envButtons["orientation"] === "south") { 176 | rb.style.transform = "translateX(" + Math.floor (144 / 2 - 144 * magnFactorBut / 2) + "px)" + " translateY(" + Math.floor (144 / 2 - 144 * magnFactorBut / 2) + "px)" + " scale(" + magnFactorBut + ") " + (envButtons["orientation"] === "north" ? " rotate(180deg)" : ""); 177 | 178 | rb.style.left = ""; 179 | rb.style.top = ""; 180 | rb.style.right = 0.5 * magnFactorBut + "em"; 181 | rb.style.bottom = 0.5 * magnFactorBut + "em"; 182 | } else { 183 | rb.style.transform = "translateX(" + Math.floor (-144 / 2 + 144 * magnFactorBut / 2) + "px)" + " translateY(" + Math.floor (-144 / 2 + 144 * magnFactorBut / 2) + "px)" + " scale(" + magnFactorBut + ") " + (envButtons["orientation"] === "north" ? " rotate(180deg)" : ""); 184 | 185 | rb.style.right = ""; 186 | rb.style.bottom = ""; 187 | rb.style.left = 0.5 * magnFactorBut + "em"; 188 | rb.style.top = 0.5 * magnFactorBut + "em"; 189 | } 190 | } 191 | 192 | // --- zooming start --- // 193 | /* 194 | document.getElementById("zoominr").addEventListener("touchstart", function (evt) { 195 | document.getElementById("zoominr").dispatchEvent(new CustomEvent('click')); 196 | evt.preventDefault (); 197 | }, false); 198 | 199 | document.getElementById("zoomoutr").addEventListener("touchstart", function (evt) { 200 | document.getElementById("zoomoutr").dispatchEvent(new CustomEvent('click')); 201 | evt.preventDefault (); 202 | }, false); 203 | 204 | document.getElementById("zoominr").addEventListener('click', () => { 205 | objOrbit.zoomIn (); 206 | }, false); 207 | 208 | document.getElementById("zoomoutr").addEventListener('click', () => { 209 | objOrbit.zoomOut (); 210 | }, false); 211 | */ 212 | 213 | document.getElementById("zoominr").addEventListener("touchstart", function (evt) { 214 | document.getElementById("zoominr").dispatchEvent(new CustomEvent('click')); 215 | evt.preventDefault (); 216 | }, false); 217 | 218 | document.getElementById("zoomoutr").addEventListener("touchstart", function (evt) { 219 | document.getElementById("zoomoutr").dispatchEvent(new CustomEvent('click')); 220 | evt.preventDefault (); 221 | }, false); 222 | 223 | document.getElementById("zoominr").addEventListener('click', () => { 224 | document.getElementById ("body").contentWindow.postMessage({msg: "zoominrClick"}, "*"); 225 | }, false); 226 | 227 | document.getElementById("zoomoutr").addEventListener('click', () => { 228 | document.getElementById ("body").contentWindow.postMessage({msg: "zoomoutrClick"}, "*"); 229 | }, false); 230 | 231 | function zoomedInR () { 232 | document.getElementById("zoominr").style.display = "none"; 233 | document.getElementById("zoomoutr").style.display = "block"; 234 | } 235 | 236 | function zoomedOutR () { 237 | document.getElementById("zoomoutr").style.display = "none"; 238 | document.getElementById("zoominr").style.display = "block"; 239 | } 240 | 241 | function zoomingOutR () { 242 | } 243 | 244 | function zoomingInR () { 245 | } 246 | 247 | // --- zooming end --- // 248 | 249 | // --- movement --- // 250 | /* 251 | document.getElementById("northr").addEventListener("touchstart", function (evt) { 252 | document.getElementById("northr").dispatchEvent(new CustomEvent('click')); 253 | evt.preventDefault (); 254 | }, false); 255 | 256 | document.getElementById("southr").addEventListener("touchstart", function (evt) { 257 | document.getElementById("southr").dispatchEvent(new CustomEvent('click')); 258 | evt.preventDefault (); 259 | }, false); 260 | 261 | document.getElementById("eastr").addEventListener("touchstart", function (evt) { 262 | document.getElementById("eastr").dispatchEvent(new CustomEvent('click')); 263 | evt.preventDefault (); 264 | }, false); 265 | 266 | document.getElementById("westr").addEventListener("touchstart", function (evt) { 267 | document.getElementById("westr").dispatchEvent(new CustomEvent('click')); 268 | evt.preventDefault (); 269 | }, false); 270 | 271 | document.getElementById("northr").addEventListener('click', () => { 272 | if (objOrbit.getMagn() === 1) 273 | objOrbit.levelUp (); 274 | else 275 | objOrbit.slideUp (); 276 | }, false); 277 | 278 | document.getElementById("southr").addEventListener('click', () => { 279 | if (objOrbit.getMagn() === 1) 280 | objOrbit.levelDown (); 281 | else 282 | objOrbit.slideDown () 283 | }, false); 284 | 285 | document.getElementById("eastr").addEventListener('click', () => { 286 | if (objOrbit.getMagn() === 1) 287 | objOrbit.rotCounterClockwise (); 288 | else 289 | objOrbit.slideRight (); 290 | }, false); 291 | 292 | document.getElementById("westr").addEventListener('click', () => { 293 | if (objOrbit.getMagn() === 1) 294 | objOrbit.rotClockwise (); 295 | else 296 | objOrbit.slideLeft (); 297 | }, false); 298 | */ 299 | 300 | document.getElementById("northr").addEventListener("touchstart", function (evt) { 301 | document.getElementById("northr").dispatchEvent(new CustomEvent('click')); 302 | evt.preventDefault (); 303 | }, false); 304 | 305 | document.getElementById("southr").addEventListener("touchstart", function (evt) { 306 | document.getElementById("southr").dispatchEvent(new CustomEvent('click')); 307 | evt.preventDefault (); 308 | }, false); 309 | 310 | document.getElementById("eastr").addEventListener("touchstart", function (evt) { 311 | document.getElementById("eastr").dispatchEvent(new CustomEvent('click')); 312 | evt.preventDefault (); 313 | }, false); 314 | 315 | document.getElementById("westr").addEventListener("touchstart", function (evt) { 316 | document.getElementById("westr").dispatchEvent(new CustomEvent('click')); 317 | evt.preventDefault (); 318 | }, false); 319 | 320 | document.getElementById("northr").addEventListener('click', () => { 321 | document.getElementById ("body").contentWindow.postMessage({msg: "northrClick"}, "*"); 322 | }, false); 323 | 324 | document.getElementById("southr").addEventListener('click', () => { 325 | document.getElementById ("body").contentWindow.postMessage({msg: "southrClick"}, "*"); 326 | }, false); 327 | 328 | document.getElementById("eastr").addEventListener('click', () => { 329 | document.getElementById ("body").contentWindow.postMessage({msg: "eastrClick"}, "*"); 330 | }, false); 331 | 332 | document.getElementById("westr").addEventListener('click', () => { 333 | document.getElementById ("body").contentWindow.postMessage({msg: "westrClick"}, "*"); 334 | }, false); 335 | // --- movement end --- // 336 | /* 337 | document.getElementById("rgtbut").onmousedown = function (evt) { 338 | objOrbit.setMouseOff (); 339 | }; 340 | 341 | document.getElementById("rgtbut").addEventListener("touchstart", function (evt) { 342 | objOrbit.setMouseOff (); 343 | }, false); 344 | */ 345 | document.getElementById("rgtbut").onmousedown = function (evt) { 346 | document.getElementById ("body").contentWindow.postMessage({msg: "rgtbutMouseDown"}, "*"); 347 | }; 348 | 349 | document.getElementById("rgtbut").addEventListener("touchstart", function (evt) { 350 | document.getElementById ("body").contentWindow.postMessage({msg: "rgtbutTouchstart"}, "*"); 351 | }, false); 352 | // --- navigator end --- // 353 | 354 | window.addEventListener("touchend", function (evt) { 355 | document.getElementById ("body").contentWindow.postMessage({msg: "windowTouchend"}, "*"); 356 | }, false); 357 | 358 | window.addEventListener("mouseup", function (evt) { 359 | document.getElementById ("body").contentWindow.postMessage({msg: "windowMouseup"}, "*"); 360 | }, false); 361 | 362 | -------------------------------------------------------------------------------- /src/init.js: -------------------------------------------------------------------------------- 1 | function initProps (callback) { 2 | var xhttp = new XMLHttpRequest (); 3 | xhttp.onreadystatechange = function () { 4 | if (this.readyState == 4 && this.status == 200) { 5 | try { 6 | fileJSON = JSON.parse (this.responseText); 7 | } catch (e) { 8 | alert ('Error:\n' + e.message); 9 | throw e; 10 | } 11 | callback (fileJSON, new URL(fileJSON["home"], xhttp.responseURL).href); 12 | } 13 | }; 14 | xhttp.open("GET", "init.json"/* + "?" + Date.now()*/, true); 15 | xhttp.overrideMimeType("text/plain"); 16 | xhttp.send(); 17 | } 18 | 19 | -------------------------------------------------------------------------------- /src/loader.js: -------------------------------------------------------------------------------- 1 | var loadedOvals = []; 2 | var loadedOvalsIndex = 0; 3 | async function loadOval(node) { 4 | return new Promise(async function(resolve, reject) { 5 | if (node.ifr) 6 | resolve(); 7 | 8 | var idiv = document.createElement ('div'); 9 | var ifr = document.createElement ('iframe'); 10 | ifr.addEventListener('load', function () { 11 | if (!ifr.firstOnLoad) { 12 | ifr.firstOnLoad = true; 13 | allOvals.push (node); 14 | } 15 | resolve (); 16 | }); 17 | 18 | ifr.addEventListener('error', function () { 19 | reject (); 20 | }); 21 | 22 | loadNode (node.xml, node).then ((loaded) => { 23 | node.children = loaded.children; 24 | 25 | idiv.style.position = "absolute"; 26 | idiv.style.visibility = "hidden"; 27 | idiv.style.border = "none"; 28 | idiv.style.overflow = "hidden"; 29 | idiv.scrolling = "no"; 30 | idiv.disabled = true; 31 | idiv.tabIndex = -1; 32 | //idiv.width = objOrbit.getOvalWidth ();//objOrbit.getRadius () * 1.2; 33 | 34 | ifr.style.border = "none"; 35 | ifr.style.overflow = "hidden"; 36 | ifr.scrolling = "no"; 37 | ifr.disabled = true; 38 | ifr.tabIndex = -1; 39 | //ifr.width = objOrbit.getOvalWidth ();//objOrbit.getRadius () * 1.2; 40 | 41 | idiv.appendChild (ifr); 42 | node.ifr = idiv; 43 | node.wrappedifr = ifr; 44 | //document.body.appendChild (idiv); 45 | //divContainer.appendChild (idiv); 46 | 47 | var xhr = new XMLHttpRequest(); 48 | 49 | xhr.onload = function() { 50 | if (this.readyState == 4 && this.status == 200) { 51 | 52 | var parser = new DOMParser(); 53 | var xmlDoc = parser.parseFromString(xhr.responseText, "application/xml"); 54 | if (xmlDoc) { 55 | var base = document.createElement('base'); 56 | base.href = xhr.responseURL; 57 | 58 | var head = xmlDoc.documentElement.getElementsByTagName('head')[0]; 59 | if (!head) { 60 | head = document.createElement('head'); 61 | xmlDoc.documentElement.insertBefore (head, xhr.responseXML.documentElement.childNodes[0]); 62 | } 63 | head.insertBefore(base, head.childNodes[0]); 64 | 65 | var body = xmlDoc.documentElement.getElementsByTagName('body')[0]; 66 | if (!body) { 67 | body = document.createElement('body'); 68 | xmlDoc.documentElement.insertAfter (body, head.childNodes[0]); 69 | } 70 | loadedOvals[loadedOvalsIndex] = node; 71 | 72 | var html = ` 73 | window.addEventListener("unload", function (event) { 74 | window.parent.postMessage({msg: "unload", index: ${loadedOvalsIndex}}, "*"); 75 | }); 76 | 77 | function extractLinks_fract_123 (node) { 78 | var hyperlinks; 79 | var links = node.getElementsByTagName("a"); 80 | //for (var i = 0; i < links.length; i++) { 81 | for (var i in links) { 82 | try { 83 | //alert (i); 84 | var tg = links[i].getAttribute('target'); 85 | var hr = links[i].href; 86 | if (hr.baseVal) hr = hr.baseVal; 87 | 88 | if (!hr) 89 | hr = links[i].getAttributeNS('http://www.w3.org/1999/xlink', 'href'); 90 | 91 | if (hr) { 92 | if (!hyperlinks) 93 | hyperlinks = []; 94 | 95 | if (links[i].children) 96 | if (links[i].children.length !== 0) { 97 | (function traverseChildren(link, node) { 98 | if (link.children) 99 | if (link.children.length !== 0) { 100 | //for (var j = 0; j < link.children.length; j++) { 101 | for (var j in link.children) { 102 | traverseChildren(link.children[j], node); 103 | } 104 | } 105 | 106 | var rects = link.getClientRects(); 107 | for (var j in rects) { 108 | try { 109 | if (rects[j].right) 110 | hyperlinks.push ( 111 | { 112 | "type": "rect", 113 | "target": tg, 114 | "href": hr, 115 | "left": rects[j].left, 116 | "top": rects[j].top, 117 | "right": rects[j].right, 118 | "bottom": rects[j].bottom 119 | } 120 | ); 121 | } catch (e) {} 122 | } 123 | }) (links[i], node); 124 | } else { 125 | var rects = links[i].getClientRects(); 126 | for (var j in rects) { 127 | try { 128 | hyperlinks.push ( 129 | { 130 | "type": "rect", 131 | "target": tg, 132 | "href": hr, 133 | "left": rects[j].left, 134 | "top": rects[j].top, 135 | "right": rects[j].right, 136 | "bottom": rects[j].bottom 137 | } 138 | ); 139 | } catch (e) {} 140 | } 141 | } 142 | } 143 | } catch (e) {} 144 | } 145 | 146 | if (hyperlinks) 147 | window.parent.postMessage({msg: "relink", index: ${loadedOvalsIndex}, hyperlinks: hyperlinks}, "*"); 148 | } 149 | 150 | 151 | extractLinks_fract_123 (document); 152 | 153 | setInterval (function () { 154 | extractLinks_fract_123 (document); 155 | }, 500); 156 | 157 | var ro_fract_123 = new ResizeObserver(function (entries) { 158 | for (let entry of entries) { 159 | const cr = entry.contentRect; 160 | window.parent.postMessage({msg: "resize", index: ${loadedOvalsIndex}, width: cr.width, height: cr.height}, "*"); 161 | } 162 | }) 163 | ro_fract_123.observe(document.body); 164 | 165 | `; 166 | loadedOvalsIndex++; 167 | 168 | var script= document.createElement("script"); 169 | script.type = "text/javascript"; 170 | script.innerHTML = ` ${html} `; 171 | body.appendChild( script ); 172 | ifr.srcdoc = xmlDoc.documentElement.innerHTML; 173 | node.ifr = idiv; 174 | 175 | divContainer.appendChild (idiv); 176 | 177 | //resolve (getNode (xhr.responseXML)); 178 | 179 | } else { 180 | alert (`Error processing '${loaded.src}'`); 181 | reject (); 182 | } 183 | } 184 | } 185 | 186 | xhr.onerror = function() { 187 | alert (`Error while getting '${loaded.src}'`); 188 | reject (); 189 | } 190 | 191 | xhr.open("GET", loaded.src /*+ "?" + Date.now()*/, true); 192 | xhr.send(); 193 | dispatchDraw(); 194 | }); 195 | }); 196 | } 197 | 198 | async function loadNode (fileName, node) { 199 | return new Promise(async function(resolve, reject) { 200 | function getNode (topNode) { 201 | 202 | var xmlNode = topNode.children[0].children[0]; 203 | 204 | var url = new URL(xmlNode.attributes.getNamedItem("src").nodeValue, xhr.responseURL).href 205 | var att = xmlNode.attributes.getNamedItem("type"); 206 | if (att) 207 | var type = att.nodeValue; 208 | else 209 | var type = "html"; 210 | 211 | node.type = type; 212 | node.src = url; 213 | 214 | att = xmlNode.attributes.getNamedItem("vlock"); 215 | if (att) 216 | node.vLock = att.nodeValue; 217 | 218 | att = xmlNode.attributes.getNamedItem("hlock"); 219 | if (att) 220 | node.hLock = att.nodeValue; 221 | 222 | att = xmlNode.attributes.getNamedItem("valign"); 223 | if (att) 224 | node.vAlign = att.nodeValue; 225 | 226 | att = xmlNode.attributes.getNamedItem("halign"); 227 | if (att) 228 | node.hAlign = att.nodeValue; 229 | 230 | att = xmlNode.attributes.getNamedItem("backcolor"); 231 | if (att) 232 | node.backColor = att.nodeValue; 233 | 234 | node.children = []; 235 | xmlNode = topNode.children[0].children[1]; 236 | if (xmlNode) 237 | for (var i = 0; i < xmlNode.children.length; i++) { 238 | var fn = new URL (xmlNode.children[i].attributes.getNamedItem("src").nodeValue, xhr.responseURL).href; 239 | node.children.push ({parent: node, children: [], index: i, xml: fn}); 240 | } 241 | 242 | return node; 243 | } 244 | 245 | var xhr = new XMLHttpRequest(); 246 | 247 | xhr.onload = function() { 248 | if (this.readyState == 4 && this.status == 200) { 249 | 250 | if (xhr.responseXML) { 251 | resolve (getNode (xhr.responseXML)); 252 | 253 | } else { 254 | alert (`Error processing '${fileName}'`); 255 | reject (); 256 | } 257 | } 258 | } 259 | 260 | xhr.onerror = function() { 261 | alert (`Error while getting '${fileName}'`); 262 | reject (); 263 | } 264 | 265 | xhr.open("GET", fileName /*+ "?" + Date.now()*/, true); 266 | xhr.responseType = "document"; 267 | xhr.overrideMimeType('text/xml'); 268 | xhr.send(); 269 | }); 270 | } 271 | 272 | 273 | -------------------------------------------------------------------------------- /src/orbital.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 25 | 26 | 27 | 28 | 29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | 39 | 262 | 263 | 292 | 293 | 313 | 314 | 395 | 396 | 417 |
418 | 419 | 420 | --------------------------------------------------------------------------------