├── .gitignore ├── LICENSE ├── README.md ├── example-images ├── iosched.sketch ├── iosched_body.png ├── iosched_navbar.png ├── iosched_session.png ├── iosched_statusbar.png ├── notes_1.png ├── notes_2.png ├── notes_3.png ├── notes_4.png ├── notes_5.png ├── notes_6.png └── notes_appbar.png ├── example-iosched.html ├── examples.gif ├── examples.html ├── keyboardhelper.css ├── keyboardhelper.js ├── layervis.css ├── layervis.js ├── old-layout-playground ├── interactive.html └── layout.html ├── template.html └── treevis ├── example1.html ├── template.html ├── treevis-example.gif ├── treevis.css └── treevis.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | _sandbox 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![No Maintenance Intended](http://unmaintained.tech/badge.svg)](http://unmaintained.tech/) 2 | 3 | # Layer Visualizer 4 | 5 | A simple web-based 3D layer visualizer (useful for visualizing material UIs and other things involving depth/shadows) 6 | 7 | ![Layer Visualizer Examples](https://raw.githubusercontent.com/romannurik/LayerVisualizer/master/examples.gif) 8 | 9 | Check the [example code](https://github.com/romannurik/LayerVisualizer/blob/master/examples.html) ([live demo](https://cdn.rawgit.com/romannurik/LayerVisualizer/d3691d20005ba8a86494a1419d5187f5edf8af0d/examples.html)) or [template code](https://github.com/romannurik/LayerVisualizer/blob/master/template.html) ([live demo](https://cdn.rawgit.com/romannurik/LayerVisualizer/d3691d20005ba8a86494a1419d5187f5edf8af0d/template.html)) to get started. 10 | 11 | ## Tree Visualizer 12 | 13 | Also included is a layout XML tree visualizer, useful for teaching layouts. 14 | 15 | ![Tree Visualizer Examples](https://raw.githubusercontent.com/romannurik/LayerVisualizer/master/treevis/treevis-example.gif) 16 | 17 | Check the [example code](https://github.com/romannurik/LayerVisualizer/blob/master/treevis/example1.html) ([live demo](https://cdn.rawgit.com/romannurik/LayerVisualizer/d3691d20005ba8a86494a1419d5187f5edf8af0d/treevis/example1.html)) or [template code](https://github.com/romannurik/LayerVisualizer/blob/master/treevis/template.html) ([live demo](https://cdn.rawgit.com/romannurik/LayerVisualizer/d3691d20005ba8a86494a1419d5187f5edf8af0d/treevis/template.html)) to get started. 18 | -------------------------------------------------------------------------------- /example-images/iosched.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/romannurik/LayerVisualizer/86b19516c10e5afb52fe1364ca6f0f1182f4461f/example-images/iosched.sketch -------------------------------------------------------------------------------- /example-images/iosched_body.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/romannurik/LayerVisualizer/86b19516c10e5afb52fe1364ca6f0f1182f4461f/example-images/iosched_body.png -------------------------------------------------------------------------------- /example-images/iosched_navbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/romannurik/LayerVisualizer/86b19516c10e5afb52fe1364ca6f0f1182f4461f/example-images/iosched_navbar.png -------------------------------------------------------------------------------- /example-images/iosched_session.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/romannurik/LayerVisualizer/86b19516c10e5afb52fe1364ca6f0f1182f4461f/example-images/iosched_session.png -------------------------------------------------------------------------------- /example-images/iosched_statusbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/romannurik/LayerVisualizer/86b19516c10e5afb52fe1364ca6f0f1182f4461f/example-images/iosched_statusbar.png -------------------------------------------------------------------------------- /example-images/notes_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/romannurik/LayerVisualizer/86b19516c10e5afb52fe1364ca6f0f1182f4461f/example-images/notes_1.png -------------------------------------------------------------------------------- /example-images/notes_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/romannurik/LayerVisualizer/86b19516c10e5afb52fe1364ca6f0f1182f4461f/example-images/notes_2.png -------------------------------------------------------------------------------- /example-images/notes_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/romannurik/LayerVisualizer/86b19516c10e5afb52fe1364ca6f0f1182f4461f/example-images/notes_3.png -------------------------------------------------------------------------------- /example-images/notes_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/romannurik/LayerVisualizer/86b19516c10e5afb52fe1364ca6f0f1182f4461f/example-images/notes_4.png -------------------------------------------------------------------------------- /example-images/notes_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/romannurik/LayerVisualizer/86b19516c10e5afb52fe1364ca6f0f1182f4461f/example-images/notes_5.png -------------------------------------------------------------------------------- /example-images/notes_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/romannurik/LayerVisualizer/86b19516c10e5afb52fe1364ca6f0f1182f4461f/example-images/notes_6.png -------------------------------------------------------------------------------- /example-images/notes_appbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/romannurik/LayerVisualizer/86b19516c10e5afb52fe1364ca6f0f1182f4461f/example-images/notes_appbar.png -------------------------------------------------------------------------------- /example-iosched.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 | 30 |
31 | 32 | 33 | 34 | 35 |
36 | 37 |
38 | 39 | Material Now 40 | Wed 11:30 AM – 1:00 PM, Room 1 41 | 42 |
43 | 44 |
45 |
46 | 47 |
48 |
49 | 50 | 51 | 52 | 53 | 54 | 55 | 142 | 143 | 273 | 274 | 275 | 276 | -------------------------------------------------------------------------------- /examples.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/romannurik/LayerVisualizer/86b19516c10e5afb52fe1364ca6f0f1182f4461f/examples.gif -------------------------------------------------------------------------------- /examples.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 |
31 | 32 |
33 |
34 | 35 | Bacon 36 | Bacon ipsum dolor amet pork belly meatball kevin spare ribs. Frankfurter swine corned beef meatloaf, strip steak. 37 |
38 |
39 | 40 | Ribs 41 | Bacon ipsum dolor amet pork belly meatball kevin spare ribs. Frankfurter swine corned beef meatloaf, strip steak. 42 |
43 |
44 | 45 |
46 | 47 | Screen Title 48 | 49 |
50 | 51 |
52 | 53 |
54 | 55 |
56 |
57 | 58 | 59 | 60 | 61 |
62 |
63 | 64 |
65 | 66 |
67 | 68 | 69 |
70 | 71 |
72 |
73 | 74 |
75 |
76 | 77 |
78 |
79 | 80 |
81 |
82 | 83 |
84 |
85 | 86 |
87 | 88 |
89 | 90 |
91 | 92 |
93 |
94 | 95 | 96 | 97 | 98 |
99 |
100 | 101 |
102 |
103 | Bacon 104 | Bacon ipsum dolor amet pork belly meatball kevin spare ribs. Frankfurter swine corned beef meatloaf, strip steak. 105 |
106 |
107 | Bacon 108 | Bacon ipsum dolor amet pork belly meatball kevin spare ribs. Frankfurter swine corned beef meatloaf, strip steak. 109 |
110 |
111 | Bacon 112 | Bacon ipsum dolor amet pork belly meatball kevin spare ribs. Frankfurter swine corned beef meatloaf, strip steak. 113 |
114 |
115 | Bacon 116 | Bacon ipsum dolor amet pork belly meatball kevin spare ribs. Frankfurter swine corned beef meatloaf, strip steak. 117 |
118 |
119 | Bacon 120 | Bacon ipsum dolor amet pork belly meatball kevin spare ribs. Frankfurter swine corned beef meatloaf, strip steak. 121 |
122 |
123 | 124 |
125 | 126 | Screen Title 127 | 128 |
129 | 130 |
131 |
132 | 133 | 134 | 216 | 217 | 406 | 407 | 408 | 409 | -------------------------------------------------------------------------------- /keyboardhelper.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | .keyboardhelp { 18 | font-family: Roboto; 19 | background-color: rgba(0,0,0,0.8); 20 | color: #ccc; 21 | position: fixed; 22 | right: 20px; 23 | bottom: 20px; 24 | padding: 8px; 25 | border-radius: 8px; 26 | z-index: 1000; 27 | } 28 | 29 | .keyboardhelp code { 30 | color: #fff; 31 | } -------------------------------------------------------------------------------- /keyboardhelper.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | (function() { 18 | 19 | window.KEYS = [ 20 | { 21 | key: '?', 22 | info: 'Show help', 23 | press: function() { 24 | toggleKeyboardHelp(); 25 | } 26 | } 27 | ]; 28 | 29 | function createKeyboardHelp() { 30 | var html = ''; 31 | 32 | for (var i = 0; i < KEYS.length; i++) { 33 | html += '' + KEYS[i].key + ' - ' + KEYS[i].info + '
'; 34 | } 35 | 36 | $('
') 37 | .attr('class', 'keyboardhelp') 38 | .html(html) 39 | .hide() 40 | .appendTo('body'); 41 | } 42 | 43 | function toggleKeyboardHelp(toggle) { 44 | if (toggle === false || toggle === true) { 45 | $('.keyboardhelp').toggle(!!toggle); 46 | } else { 47 | $('.keyboardhelp').toggle(); 48 | } 49 | } 50 | 51 | $(function() { 52 | $(document).on('keypress', function(e) { 53 | for (var i = 0; i < KEYS.length; i++) { 54 | if (KEYS[i].key.charCodeAt(0) == e.keyCode) { 55 | KEYS[i].press(); 56 | e.preventDefault(); 57 | e.stopPropagation(); 58 | return false; 59 | } 60 | } 61 | }); 62 | 63 | createKeyboardHelp(); 64 | toggleKeyboardHelp(true); 65 | setTimeout(function() { toggleKeyboardHelp(false); }, 2000); 66 | }); 67 | 68 | })(); -------------------------------------------------------------------------------- /layervis.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | .layervis { 18 | overflow: hidden; 19 | font-family: roboto; 20 | display: flex; 21 | align-items: center; 22 | justify-content: center; 23 | -webkit-font-smoothing: antialiased; 24 | cursor: move; 25 | } 26 | 27 | .layervis > .layervis-root { 28 | overflow: hidden; 29 | position: absolute; 30 | visibility: hidden; 31 | } 32 | 33 | .layervis-processed-root-positioner { 34 | transform: scale(0.75); 35 | flex: 0 0 auto; 36 | } 37 | 38 | .layervis._processed div[data-elevation] { 39 | /*box-shadow: 0 2px 4px rgba(0,0,0,0.25);*/ 40 | } 41 | 42 | .layervis-processed-root { 43 | width: 100%; 44 | height: 100%; 45 | transition: transform 1s ease; 46 | transform-style: preserve-3d; 47 | -webkit-user-select: none; 48 | -moz-user-select: none; 49 | user-select: none; 50 | } 51 | 52 | .layervis-processed-root img { 53 | -webkit-user-drag: none; 54 | -moz-user-drag: none; 55 | user-drag: none; 56 | } 57 | 58 | .layervis-processed-root.view-3d { 59 | transform: 60 | perspective(1000px) 61 | rotateX(45deg) 62 | rotateZ(-45deg); 63 | } 64 | 65 | .layervis-processed-root.view-flat { 66 | transform: 67 | perspective(1000px); 68 | } 69 | 70 | .layervis-processed-root.noanimate { 71 | transition: none; 72 | } 73 | 74 | .layervis-processed-root .layer { 75 | position: absolute; 76 | left: 0; 77 | top: 0; 78 | overflow: hidden; 79 | } 80 | 81 | .layervis .layer-holder { 82 | position: absolute; 83 | left: 0; 84 | top: 0; 85 | right: 0; 86 | bottom: 0; 87 | overflow: hidden; 88 | } 89 | 90 | .layervis .layer .shadow { 91 | position: absolute; 92 | background-color: #000; 93 | z-index: 1000; 94 | } 95 | 96 | .layervis .linearlayout { 97 | display: flex; 98 | } 99 | 100 | .layervis .linearlayout.vertical { 101 | flex-direction: column; 102 | } 103 | 104 | .layervis .linearlayout > div { 105 | flex-shrink: 0; 106 | } 107 | 108 | .layervis .flex { 109 | flex: 1 0 0; 110 | } 111 | 112 | .layervis .framelayout > div { 113 | position: absolute; 114 | } -------------------------------------------------------------------------------- /layervis.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | var LAYERVIS_DISABLE_3D_PANNING = false; 18 | var LAYERVIS_ELEVATION_SCALE = 6; 19 | var LAYERVIS_PERSPECTIVE = 1000; 20 | 21 | (function() { 22 | /** 23 | * Constants 24 | */ 25 | var MAX_SHADOW_DARK = 0.3; 26 | var MAX_SHADOW_DARK_AT = 0; // distance 27 | var MIN_SHADOW_DARK = 0; 28 | var MIN_SHADOW_DARK_AT = 20; // distance 29 | 30 | var MIN_SHADOW_BLUR = 0; 31 | var MAX_SHADOW_BLUR = 10; 32 | 33 | var SHADOW_DX = 0; 34 | var SHADOW_DY = 2; 35 | 36 | /** 37 | * Main behavior 38 | */ 39 | 40 | $(document).ready(function() { 41 | LayerVis.make($('.layervis')); 42 | }); 43 | 44 | /** 45 | * Main API 46 | */ 47 | 48 | var LayerVis = {}; 49 | window.LayerVis = LayerVis; 50 | 51 | LayerVis.make = function($elements) { 52 | $elements.each(function() { 53 | var $container = $(this); 54 | 55 | var first = !$container.hasClass('_processed'); 56 | makeOnce($container); 57 | 58 | if (first) { 59 | if (!LAYERVIS_DISABLE_3D_PANNING) { 60 | setup3dPan($container); 61 | } 62 | 63 | LayerVis.changeView($container, 'flat', true); 64 | 65 | setupRescale($container); 66 | 67 | var target = $container.children('.layervis-root').get(0); 68 | 69 | var observer = new MutationObserver(function(mutations) { 70 | mutations.forEach(function(mutation) { 71 | if (mutation.target == target) { 72 | return; 73 | } 74 | makeOnce($container); 75 | }); 76 | }); 77 | 78 | // configuration of the observer: 79 | var config = { attributes: true, childList: true, characterData: true, subtree: true }; 80 | 81 | // pass in the target node, as well as the observer options 82 | observer.observe(target, config); 83 | } 84 | }); 85 | } 86 | 87 | LayerVis.changeView = function($layervis, view, noAnimate) { 88 | $layervis.find('.layervis-processed-root') 89 | .css('transform', '') 90 | .toggleClass('noanimate', !!noAnimate) 91 | .each(function() { 92 | var $pr = $(this); 93 | var classList = this.className.split(/\s+/); 94 | $.each(classList, function(index, cls) { 95 | if (cls.indexOf('view-') >= 0) { 96 | $pr.removeClass(cls); 97 | } 98 | }); 99 | }) 100 | .addClass('view-' + view); 101 | }; 102 | 103 | /** 104 | * LayerVis subroutines 105 | */ 106 | function makeOnce($container) { 107 | $container.removeClass('_processed'); 108 | var $root = $container.children('.layervis-root'); 109 | var rootWidth = $root.width(); 110 | var rootHeight = $root.height(); 111 | 112 | var rootOffset = $root.offset(); 113 | 114 | var layers = []; 115 | 116 | layers.push({ 117 | $src: $root, 118 | elevation: 0, 119 | left: 0, 120 | top: 0, 121 | width: rootWidth, 122 | height: rootHeight 123 | }); 124 | 125 | $root.find('div').each(function() { 126 | var $layer = $(this); 127 | if ($layer.hasClass('nolayer')) { 128 | return; 129 | } 130 | 131 | var position = $layer.offset(); 132 | position.left -= rootOffset.left; 133 | position.top -= rootOffset.top; 134 | 135 | var elevation = parseFloat($layer.attr('data-elevation') || 0, 10); 136 | 137 | layers.push({ 138 | $src: $layer, 139 | elevation: elevation, 140 | left: position.left, 141 | top: position.top, 142 | width: $layer.width(), 143 | height: $layer.height(), 144 | noshadow: !!$layer.hasClass('noshadow') 145 | }); 146 | }); 147 | 148 | // sort by elevation 149 | layers.sort(function(a,b) { 150 | return a.elevation - b.elevation; 151 | }); 152 | 153 | var $processedRoot = $container.find('.layervis-processed-root'); 154 | if (!$processedRoot.length) { 155 | $processedRoot = $('
') 156 | .attr('class', 'layervis-processed-root') 157 | .appendTo($('
') 158 | .attr('class', 'layervis-processed-root-positioner') 159 | .css({ 160 | width: rootWidth, 161 | height: rootHeight 162 | }) 163 | .appendTo($container)); 164 | } 165 | $processedRoot.empty(); 166 | 167 | // arrange layers orthographically 168 | layers.forEach(function(layer) { 169 | var $layerHolder = $('
') 170 | .addClass('layer-holder') 171 | .css({ 172 | transform: 'translate3d(0,0,' + (layer.elevation * LAYERVIS_ELEVATION_SCALE) + 'px)' 173 | }) 174 | .appendTo($processedRoot); 175 | layer.$ = layer.$src.clone() 176 | .css({ 177 | // resets 178 | position: 'absolute', 179 | left: 'auto', 180 | top: 'auto', 181 | right: 'auto', 182 | bottom: 'auto', 183 | 'margin-left': 0, 184 | 'margin-top': 0, 185 | 'margin-right': 0, 186 | 'margin-bottom': 0, 187 | 188 | // ortho position 189 | width: layer.width + 'px', 190 | height: layer.height + 'px', 191 | transform: 'translate3d(' + layer.left + 'px, ' + layer.top + 'px, 0)' 192 | }) 193 | .addClass('layer') 194 | .appendTo($layerHolder); 195 | 196 | layer.$.find('div:not(.nolayer)').remove(); 197 | }); 198 | 199 | // create shadows (highest elevation first) 200 | for (var i = layers.length - 1; i >= 0; i--) { 201 | for (var j = i - 1; j >= 0; j--) { 202 | var topLayer = layers[i]; 203 | var bottomLayer = layers[j]; 204 | if (topLayer.elevation == bottomLayer.elevation || topLayer.noshadow) { 205 | continue; 206 | } 207 | 208 | // create a shadow (already ortho'd since it'll be inside bottomLayer) 209 | var distance = topLayer.elevation - bottomLayer.elevation; 210 | var filter = 'blur(' + interpolateCap(progress(distance, 0, 5), MIN_SHADOW_BLUR, MAX_SHADOW_BLUR) + 'px)'; 211 | var $shadow = $('
') 212 | .addClass('shadow') 213 | .css({ 214 | left: (topLayer.left - bottomLayer.left + distance * SHADOW_DX) + 'px', 215 | top: (topLayer.top - bottomLayer.top + distance * SHADOW_DY) + 'px', 216 | width: topLayer.width + 'px', 217 | height: topLayer.height + 'px', 218 | opacity: interpolateCap( 219 | progress(distance, MAX_SHADOW_DARK_AT, MIN_SHADOW_DARK_AT), 220 | MAX_SHADOW_DARK, MIN_SHADOW_DARK), 221 | '-webkit-filter': filter, 222 | 'filter': filter, 223 | }); 224 | 225 | var computedStyle = getComputedStyle(topLayer.$.get(0)); 226 | $shadow.css('border-radius', computedStyle.borderRadius || computedStyle.borderTopLeftRadius); 227 | $shadow.appendTo(bottomLayer.$); 228 | } 229 | } 230 | 231 | $container.addClass('_processed'); 232 | } 233 | 234 | function setup3dPan($layervis) { 235 | var ox, oy; 236 | var cx = 0.5, cy = 0; 237 | var sx, sy; 238 | var down; 239 | 240 | var width, height; 241 | 242 | $layervis 243 | .on('mousedown', function(e) { 244 | $(this).find('.layervis-processed-root').addClass('noanimate'); 245 | sx = e.clientX; 246 | sy = e.clientY; 247 | width = $(this).width() / 5; 248 | height = $(this).height() / 5; 249 | ox = cx; 250 | oy = cy; 251 | down = true; 252 | }); 253 | 254 | $(document) 255 | .on('mousemove', function(e) { 256 | if (!down) { 257 | return; 258 | } 259 | 260 | var dx = (e.clientX - sx) / width; 261 | var dy = (e.clientY - sy) / height; 262 | 263 | cx = interpolate(constrain(ox + dx, 0, 1), 0, 1); 264 | cy = interpolate(constrain(oy - dy, 0, 1), 0, 1); 265 | 266 | var tx = interpolate(cy, 0, -23); 267 | var ty = interpolate(cy, 0, 150); 268 | var rx = interpolate(cy, 0, 70); 269 | var ry = 0;//interpolate(fx, 0, 30); 270 | var rz = interpolate(cx, 45, -45); 271 | var scalePre = interpolate(cy, 0.75, 1); 272 | var scalePost = interpolate(cy, 1, 0.8); 273 | 274 | var transform = ''; 275 | 276 | transform += 'perspective(' + (LAYERVIS_PERSPECTIVE || Number.MAX_SAFE_INTEGER || 999999999) + 'px) '; 277 | transform += 'rotateX(' + rx + 'deg) '; 278 | transform += 'rotateY(' + ry + 'deg) '; 279 | transform += 'rotateZ(' + rz + 'deg) '; 280 | console.log(transform); 281 | 282 | $layervis.find('.layervis-processed-root').css('transform', transform); 283 | }) 284 | .on('mouseup', function(e) { 285 | down = false; 286 | }); 287 | } 288 | 289 | function setupRescale($container) { 290 | function _rescale() { 291 | var $inner = $container.find('.layervis-processed-root-positioner'); 292 | 293 | var ow = $inner.width(); 294 | var oh = $inner.height(); 295 | 296 | var ww = $container.width(); 297 | var wh = $container.height(); 298 | 299 | var scale = 1; 300 | 301 | if (ow / oh > ww / wh) { 302 | scale = ww / ow; 303 | } else { 304 | scale = wh / oh; 305 | } 306 | 307 | scale *= 0.7; 308 | 309 | $inner.css('transform', 'scale(' + scale + ')'); 310 | } 311 | 312 | _rescale(); 313 | $(window).resize(_rescale); 314 | } 315 | 316 | /** 317 | * Utilities 318 | */ 319 | 320 | function progress(f, min, max) { 321 | return (f - min) / (max - min); 322 | } 323 | 324 | function interpolate(f, min, max) { 325 | return min + f * (max - min); 326 | } 327 | 328 | function interpolateCap(f, min, max) { 329 | if (max < min) { 330 | return interpolateCap(1 - f, max, min); 331 | } 332 | return constrain(interpolate(f, min, max), min, max); 333 | } 334 | 335 | function constrain(f, min, max) { 336 | if (f < min) { 337 | return min; 338 | } else if (f > max) { 339 | return max; 340 | } else { 341 | return f; 342 | } 343 | } 344 | })(); -------------------------------------------------------------------------------- /old-layout-playground/interactive.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 134 | 184 | 185 | 186 | 187 |
188 | 213 |
214 | 215 | 344 | 345 |
346 | 347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 | 357 |
358 |
359 |
360 |
361 | 362 |
363 |
364 |
365 | 366 |
367 |
368 |
369 |
370 | 371 | 372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 | 380 |
381 |
382 |
383 |
384 | 385 |
386 | 387 | 388 | -------------------------------------------------------------------------------- /old-layout-playground/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 174 | 244 | 245 | 246 | 247 |
248 | 249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 | 259 |
260 |
261 |
262 |
263 | 264 |
265 |
266 |
267 | 268 |
269 |
270 |
271 |
272 | 273 | 274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 | 282 |
283 |
284 |
285 |
286 | 287 |
288 | 289 |
290 | 291 | -------------------------------------------------------------------------------- /template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 | 15 |
16 | Hi there! 17 |
18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | Screen Title 26 | 27 |
28 | 29 |
30 | 31 | 32 | 33 | 34 | 35 |
36 | 37 |
38 |
39 | 40 | 41 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /treevis/example1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 |
28 | 29 |
30 |
31 | 32 | Bacon 33 | Bacon ipsum dolor amet pork belly meatball kevin spare ribs. Frankfurter swine corned beef meatloaf, strip steak. 34 |
35 |
36 | 37 | Ribs 38 | Bacon ipsum dolor amet pork belly meatball kevin spare ribs. Frankfurter swine corned beef meatloaf, strip steak. 39 |
40 |
41 | 42 | Ribs 43 | Bacon ipsum dolor amet pork belly meatball kevin spare ribs. Frankfurter swine corned beef meatloaf, strip steak. 44 |
45 |
46 | 47 |
48 | 49 | Screen Title 50 | 51 |
52 | 53 |
54 | 55 |
56 | 57 |
58 |
59 | 60 |
61 | CoordinatorLayout %.treevis-root 62 | AppBarLayout %.appbar 63 | Toolbar app:layout_scrollFlags=scroll|enterAlways layout_height=?actionBarSize %.appbar 64 | RecyclerView app:layout_behavior=@string/appbar_scrolling_view_behavior %.cardlist 65 | CardView %.card-1 66 | CardView %.card-2 67 | ... 68 | FloatingActionButton layout_gravity=bottom|right %.fab 69 |
70 | 71 | 84 | 85 | 217 | 218 | 219 | 220 | -------------------------------------------------------------------------------- /treevis/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 |
13 | 14 |
15 | Hi there! 16 |
17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | Screen Title 25 | 26 |
27 | 28 |
29 | 30 | 31 | 32 | 33 | 34 |
35 | 36 |
37 |
38 | 39 |
40 | FrameLayout %.treevis-root 41 | LinearLayout orientation=vertical %.treevis-root 42 | Toolbar layout_height=?actionBarSize %.appbar 43 | TextView layout_weight=1 %.textview 44 | FloatingActionButton layout_gravity=bottom|right %.fab 45 |
46 | 47 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /treevis/treevis-example.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/romannurik/LayerVisualizer/86b19516c10e5afb52fe1364ca6f0f1182f4461f/treevis/treevis-example.gif -------------------------------------------------------------------------------- /treevis/treevis.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | .treevis { 18 | cursor: se-resize; 19 | -webkit-user-select: none; 20 | display: flex; 21 | align-items: center; 22 | justify-content: center; 23 | } 24 | 25 | .treevis-highlight { 26 | outline: 2000px solid rgba(0, 0, 0, 0.5); 27 | border: 10px solid rgba(233, 30, 99, 0.5); 28 | margin-left: -10px; 29 | margin-top: -10px; 30 | opacity: 1; 31 | position: absolute; 32 | z-index: 1000; 33 | transition: opacity 0.25s ease, left 0.25s ease, top 0.25s ease, width 0.25s ease, height 0.25s ease; 34 | pointer-events: none; 35 | } 36 | 37 | .treevis-highlight.noanimate { 38 | transition: none; 39 | } 40 | 41 | .treevis-highlight.inactive { 42 | opacity: 0; 43 | left: 0 !important; 44 | top: 0 !important; 45 | width: 100% !important; 46 | height: 100% !important; 47 | } 48 | 49 | .treevis .linearlayout { 50 | display: flex; 51 | } 52 | 53 | .treevis .linearlayout.vertical { 54 | flex-direction: column; 55 | } 56 | 57 | .treevis .linearlayout > div { 58 | flex-shrink: 0; 59 | } 60 | 61 | .treevis .flex { 62 | flex: 1 0 0; 63 | } 64 | 65 | .treevis .framelayout > div { 66 | position: absolute; 67 | } 68 | 69 | .treevis-root { 70 | position: relative; 71 | overflow: hidden; 72 | } 73 | 74 | /* elevations */ 75 | 76 | [data-elevation="2"] { 77 | box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 78 | 0 3px 1px -2px rgba(0, 0, 0, 0.2), 79 | 0 1px 5px 0 rgba(0, 0, 0, 0.12); 80 | } 81 | 82 | [data-elevation="3"] { 83 | box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.14), 84 | 0 3px 3px -2px rgba(0, 0, 0, 0.2), 85 | 0 1px 8px 0 rgba(0, 0, 0, 0.12); 86 | } 87 | 88 | [data-elevation="4"] { 89 | box-shadow: 0 4px 5px 0 rgba(0, 0, 0, 0.14), 90 | 0 1px 10px 0 rgba(0, 0, 0, 0.12), 91 | 0 2px 4px -1px rgba(0, 0, 0, 0.2) 92 | } 93 | 94 | [data-elevation="6"] { 95 | box-shadow: 0 6px 10px 0 rgba(0, 0, 0, 0.14), 96 | 0 1px 18px 0 rgba(0, 0, 0, 0.12), 97 | 0 3px 5px -1px rgba(0, 0, 0, 0.2); 98 | } 99 | 100 | [data-elevation="8"] { 101 | box-shadow: 0 8px 10px 1px rgba(0, 0, 0, 0.14), 102 | 0 3px 14px 2px rgba(0, 0, 0, 0.12), 103 | 0 5px 5px -3px rgba(0, 0, 0, 0.2) 104 | } 105 | 106 | [data-elevation="16"] { 107 | box-shadow: 0 16px 24px 2px rgba(0, 0, 0, 0.14), 108 | 0 6px 30px 5px rgba(0, 0, 0, 0.12), 109 | 0 8px 10px -5px rgba(0, 0, 0, 0.2); 110 | } 111 | 112 | /* XML tree */ 113 | 114 | .xmltree { 115 | padding: 16px; 116 | z-index: 10000; 117 | font-family: roboto mono, monospace; 118 | display: flex; 119 | align-items: center; 120 | justify-content: center; 121 | } 122 | 123 | .xmltree .node-meta { 124 | background: #333; 125 | color: #fff; 126 | display: inline-block; 127 | padding: 8px 16px; 128 | border-radius: 2px; 129 | margin-top: 8px; 130 | } 131 | 132 | .xmltree .node.ellipsis > .node-meta { 133 | background: #eee; 134 | color: #888; 135 | font-family: Roboto; 136 | } 137 | 138 | .xmltree .has-highlight { 139 | cursor: pointer; 140 | } 141 | 142 | .xmltree .node-meta.has-highlight:hover { 143 | background-color: #880E4F; 144 | } 145 | 146 | .xmltree .node-meta.has-highlight.active { 147 | background: #E91E63; 148 | } 149 | 150 | .xmltree .node-tagname { 151 | font-size: 14px; 152 | font-weight: 700; 153 | } 154 | 155 | .xmltree .node-attr-name, 156 | .xmltree .node-attr-value { 157 | font-size: 12px; 158 | } 159 | 160 | .xmltree .node-attr-name { 161 | color: rgba(255, 255, 255, 0.7); 162 | margin-right: 8px; 163 | } 164 | 165 | .xmltree .node-attr-value { 166 | color: #fff; 167 | } 168 | 169 | .xmltree .node-attr-name:after { 170 | content: ':'; 171 | } 172 | 173 | .xmltree .node .node { 174 | position: relative; 175 | margin-left: 16px; 176 | padding-left: 16px; 177 | /*border-left: 1px dotted #ccc;*/ 178 | } 179 | 180 | .xmltree .node .node:before { 181 | content: ''; 182 | position: absolute; 183 | border-bottom: 1px solid #888; 184 | border-left: 1px solid #888; 185 | left: 0; 186 | top: 0; 187 | width: 16px; 188 | height: 32px; 189 | z-index: -1; 190 | } 191 | 192 | .xmltree .node .node:not(:last-child):after { 193 | content: ''; 194 | position: absolute; 195 | border-left: 1px solid #888; 196 | left: 0; 197 | top: 0; 198 | width: 16px; 199 | height: 100%; 200 | z-index: -1; 201 | } -------------------------------------------------------------------------------- /treevis/treevis.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | (function() { 18 | 19 | var MIN_WIDTH = 200; 20 | var MIN_HEIGHT = 200; 21 | 22 | var preview = {}; 23 | 24 | $(document).ready(function() { 25 | preview.width = $('.treevis-root').width(); 26 | preview.height = $('.treevis-root').height(); 27 | 28 | $('.treevis') 29 | .bind('mousedown', function(evt) { 30 | preview.dragging = true; 31 | preview.startWidth = preview.width; 32 | preview.startHeight = preview.height; 33 | preview.startX = evt.pageX; 34 | preview.startY = evt.pageY; 35 | }) 36 | .bind('mousemove', function(evt) { 37 | if (preview.dragging) { 38 | preview.width = Math.max(MIN_WIDTH, preview.startWidth + (evt.pageX - preview.startX) * 2); 39 | preview.height = Math.max(MIN_HEIGHT, preview.startHeight + (evt.pageY - preview.startY) * 2); 40 | updatePreview(); 41 | } 42 | }) 43 | .bind('mouseup', function() { 44 | preview.dragging = false; 45 | }); 46 | 47 | 48 | $('.scrollable').on('scroll', updateHighlight); 49 | $(window).resize(updateHighlight); 50 | 51 | updatePreview(); 52 | createXmlTree(); 53 | }); 54 | 55 | function updatePreview() { 56 | var breakpoints = [400, 600, 800]; 57 | var $body = $('body'); 58 | for (var i = 0; i < breakpoints.length; i++) { 59 | var b = breakpoints[i]; 60 | $body.toggleClass('bp-' + b, preview.width >= b); 61 | } 62 | var classList = document.body.className.split(/\s+/); 63 | for (var i = 0; i < classList.length; i++) { 64 | if (classList[i].startsWith('size-')) { 65 | //do something 66 | } 67 | } 68 | 69 | $('.treevis > .treevis-root').css({ 70 | width: preview.width + 'px', 71 | height: preview.height + 'px' 72 | }); 73 | updateHighlight(); 74 | } 75 | 76 | function updateHighlight() { 77 | if (window.hlNode) { 78 | $('.treevis-highlight').addClass('noanimate'); 79 | highlight(window.hlNode); 80 | $('.treevis-highlight').removeClass('noanimate'); 81 | } 82 | } 83 | 84 | function highlight($node) { 85 | window.hlNode = $node; 86 | var $hl = $('.treevis-highlight'); 87 | if (!$hl.length) { 88 | $hl = $('
').addClass('treevis-highlight inactive').appendTo('body'); 89 | } 90 | 91 | if (!$node) { 92 | $hl.addClass('inactive'); 93 | return; 94 | } 95 | 96 | $hl.css({ 97 | left: $node.offset().left + 'px', 98 | top: $node.offset().top + 'px', 99 | width: $node.get(0).offsetWidth + 'px', 100 | height: $node.get(0).offsetHeight + 'px' 101 | }) 102 | .removeClass('inactive'); 103 | } 104 | 105 | function createXmlTree() { 106 | var $xmlTree = $('.xmltree'); 107 | var text = $xmlTree.text(); 108 | $xmlTree.empty(); 109 | 110 | var $root = $('
').addClass('node-root').appendTo($xmlTree); 111 | 112 | lines = text.split('\n').filter(function(x){ return !!x.replace(/\s+/g, ''); }); 113 | 114 | var $lastNode = null; 115 | var nodeStack = [$root]; 116 | var indentStack = [0]; 117 | 118 | lines.forEach(function(line) { 119 | var nodeSpec = line.split(/\%/g); 120 | var nodeXml = nodeSpec[0]; 121 | var indent = nodeXml.match(/^\s*/)[0].length; 122 | 123 | var currentIndent = indentStack[indentStack.length - 1]; 124 | if (indent > currentIndent) { 125 | // further indented 126 | nodeStack.push($lastNode); 127 | indentStack.push(indent); 128 | } else if (indent < currentIndent) { 129 | // unindented 130 | do { 131 | nodeStack.pop(); 132 | indentStack.pop(); 133 | } while (indentStack[indentStack.length - 1] != indent && indentStack.length > 0); 134 | } 135 | 136 | var components = nodeXml.substring(indent).split(/\s+/g); 137 | var tagName = components[0]; 138 | 139 | var $node = $('
') 140 | .addClass('node') 141 | .appendTo(nodeStack[nodeStack.length - 1]); 142 | 143 | var $nodeMeta = $('
') 144 | .addClass('node-meta') 145 | .appendTo($node); 146 | 147 | var $tagName = $('') 148 | .addClass('node-tagname') 149 | .text(tagName) 150 | .appendTo($nodeMeta); 151 | if (tagName == '...') { 152 | $node.addClass('ellipsis'); 153 | } 154 | 155 | for (var i = 1; i < components.length; i++) { 156 | // add attributes 157 | if (!components[i].length) { 158 | continue; 159 | } 160 | var attr = components[i].split(/=/g); 161 | $('
') 162 | .addClass('node-attr') 163 | .append($('').addClass('node-attr-name').text(attr[0])) 164 | .append($('').addClass('node-attr-value').text(attr[1])) 165 | .appendTo($nodeMeta); 166 | } 167 | 168 | $lastNode = $node; 169 | 170 | var nodeHighlight = nodeSpec.length > 1 ? nodeSpec[1] : null; 171 | if (nodeHighlight) { 172 | var $nodeHighlight = $(nodeHighlight); 173 | $nodeMeta.addClass('has-highlight'); 174 | $nodeMeta 175 | .on('click', function() { 176 | $('.node-meta').removeClass('active'); 177 | $(this).addClass('active'); 178 | highlight($nodeHighlight); 179 | return false; 180 | }); 181 | } 182 | }); 183 | 184 | $('.xmltree').click(function() { 185 | $('.node-meta').removeClass('active'); 186 | highlight(); 187 | }); 188 | } 189 | 190 | })(); --------------------------------------------------------------------------------