├── LICENSE ├── README.md ├── examples ├── nginx.controller.json └── nginx.service.json ├── index.html ├── jsplumb ├── LICENSE ├── OpenSans-Bold.ttf ├── OpenSans-BoldItalic.ttf ├── OpenSans-ExtraBold.ttf ├── OpenSans-ExtraBoldItalic.ttf ├── OpenSans-Italic.ttf ├── OpenSans-Light.ttf ├── OpenSans-LightItalic.ttf ├── OpenSans-Regular.ttf ├── OpenSans-Semibold.ttf ├── OpenSans-SemiboldItalic.ttf ├── flowchart-style.css ├── jquery.jsPlumb-1.6.4.js ├── jsplumb-doc.css └── jsplumb.css ├── logotext.svg ├── script.js ├── style.css └── titlelogo.svg /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Kubernetes/Container Engine Visualizer 2 | 3 | This is a simple visualizer for use with the Kubernetes API. 4 | 5 | ### Usage: 6 | * First install a Kubernetes or Container Engine Cluster 7 | * ```git clone https://github.com/brendandburns/gcp-live-k8s-visualizer.git``` 8 | * ```kubectl proxy --www=path/to/gcp-live-k8s-visualizer --www-prefix=/my-mountpoint/ --api-prefix=/api/``` 9 | 10 | Then 11 | 12 | http://127.0.0.1:8001/my-mountpoint/ 13 | 14 | That's it. The visualizer uses labels to organize the visualization. In particular it expects that 15 | 16 | * pods, replicationcontrollers, and services have a ```name``` label, and pods and their associated replication controller share the same ```name```, and 17 | * the pods in your cluster will have a ```uses``` label which contains a comma separated list of services that the pod uses. 18 | -------------------------------------------------------------------------------- /examples/nginx.controller.json: -------------------------------------------------------------------------------- 1 | { 2 | "kind":"ReplicationController", 3 | "apiVersion":"v1", 4 | "metadata":{ 5 | "name":"nginx", 6 | "labels":{ 7 | "name":"nginx" 8 | } 9 | }, 10 | "spec":{ 11 | "replicas": 2, 12 | "selector":{ 13 | "name":"nginx" 14 | }, 15 | "template":{ 16 | "metadata":{ 17 | "labels":{ 18 | "name":"nginx", 19 | "app": "sample", 20 | "version": "0.0.1", 21 | "uses": "nginx" 22 | } 23 | }, 24 | "spec":{ 25 | "containers":[ 26 | { 27 | "name":"nginx", 28 | "image":"nginx" 29 | } 30 | ] 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /examples/nginx.service.json: -------------------------------------------------------------------------------- 1 | { 2 | "kind": "Service", 3 | "apiVersion": "v1", 4 | "metadata": { 5 | "name": "nginx", 6 | "labels": { 7 | "name": "nginx", 8 | "app": "sample" 9 | } 10 | }, 11 | "spec": { 12 | "ports": [ 13 | { 14 | "name": "http", 15 | "port": 9001, 16 | "targetPort": 80, 17 | "protocol": "TCP" 18 | } 19 | ], 20 | "publicIPs": [ 21 | "10.145.1.3", 22 | "10.145.1.4" 23 | ], 24 | "selector": { 25 | "name": "frontend" 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 34 |
35 |
36 |
37 | 38 | 39 | -------------------------------------------------------------------------------- /jsplumb/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010 - 2014 jsPlumb, http://jsplumbtoolkit.com/ 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /jsplumb/OpenSans-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendandburns/gcp-live-k8s-visualizer/5934f067a7d2449cb9fffa0b20bb27356ea66f24/jsplumb/OpenSans-Bold.ttf -------------------------------------------------------------------------------- /jsplumb/OpenSans-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendandburns/gcp-live-k8s-visualizer/5934f067a7d2449cb9fffa0b20bb27356ea66f24/jsplumb/OpenSans-BoldItalic.ttf -------------------------------------------------------------------------------- /jsplumb/OpenSans-ExtraBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendandburns/gcp-live-k8s-visualizer/5934f067a7d2449cb9fffa0b20bb27356ea66f24/jsplumb/OpenSans-ExtraBold.ttf -------------------------------------------------------------------------------- /jsplumb/OpenSans-ExtraBoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendandburns/gcp-live-k8s-visualizer/5934f067a7d2449cb9fffa0b20bb27356ea66f24/jsplumb/OpenSans-ExtraBoldItalic.ttf -------------------------------------------------------------------------------- /jsplumb/OpenSans-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendandburns/gcp-live-k8s-visualizer/5934f067a7d2449cb9fffa0b20bb27356ea66f24/jsplumb/OpenSans-Italic.ttf -------------------------------------------------------------------------------- /jsplumb/OpenSans-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendandburns/gcp-live-k8s-visualizer/5934f067a7d2449cb9fffa0b20bb27356ea66f24/jsplumb/OpenSans-Light.ttf -------------------------------------------------------------------------------- /jsplumb/OpenSans-LightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendandburns/gcp-live-k8s-visualizer/5934f067a7d2449cb9fffa0b20bb27356ea66f24/jsplumb/OpenSans-LightItalic.ttf -------------------------------------------------------------------------------- /jsplumb/OpenSans-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendandburns/gcp-live-k8s-visualizer/5934f067a7d2449cb9fffa0b20bb27356ea66f24/jsplumb/OpenSans-Regular.ttf -------------------------------------------------------------------------------- /jsplumb/OpenSans-Semibold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendandburns/gcp-live-k8s-visualizer/5934f067a7d2449cb9fffa0b20bb27356ea66f24/jsplumb/OpenSans-Semibold.ttf -------------------------------------------------------------------------------- /jsplumb/OpenSans-SemiboldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendandburns/gcp-live-k8s-visualizer/5934f067a7d2449cb9fffa0b20bb27356ea66f24/jsplumb/OpenSans-SemiboldItalic.ttf -------------------------------------------------------------------------------- /jsplumb/flowchart-style.css: -------------------------------------------------------------------------------- 1 | /** 2 | The following are adapted from https://github.com/sporritt/jsPlumb/blob/master/demo/flowchart/demo.css 3 | 4 | Copyright (c) 2010 - 2014 jsPlumb, http://jsplumbtoolkit.com/ 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining 7 | a copy of this software and associated documentation files (the 8 | "Software"), to deal in the Software without restriction, including 9 | without limitation the rights to use, copy, modify, merge, publish, 10 | distribute, sublicense, and/or sell copies of the Software, and to 11 | permit persons to whom the Software is furnished to do so, subject to 12 | the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be 15 | included in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 21 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 22 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 23 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | .flowchart-demo .window { border:1px solid #346789; 26 | box-shadow: 2px 2px 19px #aaa; 27 | -o-box-shadow: 2px 2px 19px #aaa; 28 | -webkit-box-shadow: 2px 2px 19px #aaa; 29 | -moz-box-shadow: 2px 2px 19px #aaa; 30 | -moz-border-radius:0.5em; 31 | border-radius:0.5em; 32 | opacity:0.8; 33 | filter:alpha(opacity=80); 34 | text-align:center; 35 | z-index:20; position:absolute; 36 | font-family:helvetica;padding:0.5em; 37 | font-size:1.2em; 38 | } 39 | 40 | .flowchart-demo .window:hover { 41 | box-shadow: 2px 2px 19px #444; 42 | -o-box-shadow: 2px 2px 19px #444; 43 | -webkit-box-shadow: 2px 2px 19px #444; 44 | -moz-box-shadow: 2px 2px 19px #444; 45 | opacity:0.6; 46 | filter:alpha(opacity=60); 47 | } 48 | 49 | .flowchart-demo ._jsPlumb_endpoint { 50 | z-index:21; 51 | } 52 | -------------------------------------------------------------------------------- /jsplumb/jsplumb-doc.css: -------------------------------------------------------------------------------- 1 | /* 2 | Gollum v3 Template 3 | */ 4 | 5 | /* jsplumb */ 6 | 7 | .markdown-body { 8 | font-size: 12.5px; 9 | line-height: 1.6; 10 | background-color: white; 11 | padding-left: 10px; 12 | margin-left: 265px; 13 | margin-top: 65px; 14 | padding-right: 20px; 15 | margin-right: 10px; 16 | } 17 | 18 | li { 19 | list-style-type: disc; 20 | } 21 | 22 | .apis li { 23 | list-style-type: none; 24 | } 25 | 26 | 27 | 28 | @font-face { 29 | font-family: 'Open Sans'; 30 | font-style: normal; 31 | font-weight: 400; 32 | src:local('Open Sans'), 33 | local('OpenSans'), 34 | url("OpenSans-Regular.ttf") format('truetype'), 35 | url("OpenSans.woff") format('woff'); 36 | } 37 | html { background-color: white; } 38 | body { 39 | font-family:'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif !important; 40 | background-color:white; 41 | text-align:left; 42 | } 43 | 44 | a[name]:before { 45 | display:block; 46 | content:" "; 47 | height:50px; 48 | margin-bottom:-18px; 49 | margin-top:-79px; 50 | visibility: hidden; 51 | } 52 | 53 | /* corrections for jsdoc (move these out) */ 54 | #main { 55 | height:auto; 56 | background-color: white; 57 | border:none; 58 | font-size: 85%; 59 | text-align: left; 60 | width: 90%; 61 | max-width: none; 62 | } 63 | nav { 64 | padding-bottom: 10px; 65 | overflow-x: hidden; 66 | overflow-y:auto; 67 | height:100%; 68 | background-color: white; 69 | margin-top: 40px; 70 | position: fixed; 71 | left: 0; 72 | border: none; 73 | float: none; 74 | margin-left: 0; 75 | width:210px; 76 | } 77 | 78 | nav a:visited { 79 | color:#01a3c6; 80 | } 81 | 82 | nav h2 { 83 | display:none; 84 | } 85 | 86 | #main article dd { 87 | border-bottom: 1px solid #ccc; 88 | padding-bottom: 26px; 89 | } 90 | 91 | /* this is the location in source links */ 92 | .details { 93 | display:none; 94 | } 95 | 96 | /* constructors */ 97 | .container-overview { 98 | /*display:none;*/ 99 | } 100 | 101 | .apidoc-main { 102 | margin-left: 255px !important; 103 | height: auto; 104 | width: auto; 105 | background-color: white; 106 | border: none; 107 | } 108 | 109 | .apidoc-summary { 110 | width:150px; 111 | } 112 | .apidoc-detail { 113 | margin-left:160px; 114 | } 115 | 116 | #qunit-tests li, #qunit-testresult { 117 | background-color: white !important; 118 | } 119 | 120 | #qunit-userAgent { 121 | text-shadow:none; 122 | } 123 | 124 | /* / jsplumb */ 125 | 126 | /* added by SP */ 127 | 128 | #headerWrapper { 129 | background-color:#eaedef; 130 | } 131 | 132 | .menu { 133 | background-color: #eaedef; 134 | } 135 | 136 | .nav { 137 | width: 240px; 138 | margin-left: 15px; 139 | font-size: 12px; 140 | position: fixed; 141 | height: 88%; 142 | overflow-y: auto; 143 | overflow-x: hidden; 144 | background-color: white; 145 | padding-left: 5px; 146 | } 147 | 148 | .nav ul { 149 | padding-left: 25px; 150 | margin-top:8px; 151 | } 152 | 153 | .nav ul li { 154 | margin-bottom:5px; 155 | } 156 | 157 | html, body { 158 | color: #333; 159 | } 160 | 161 | body { 162 | font: 13.34px helvetica,arial,freesans,clean,sans-serif; 163 | line-height: 1.4; 164 | } 165 | 166 | img { 167 | border: 0; 168 | } 169 | 170 | a, a:visited { 171 | color: #4183C4; 172 | text-decoration: none; 173 | padding:0.3em; 174 | } 175 | 176 | a.absent { 177 | color: #c00; 178 | } 179 | 180 | .markdown-body a[id].wiki-toc-anchor { 181 | color: inherit; 182 | text-decoration: none; 183 | } 184 | 185 | .markdown-body>*:first-child { 186 | margin-top: 0!important; 187 | } 188 | .markdown-body>*:last-child { 189 | margin-bottom: 0!important; 190 | } 191 | .markdown-body a.absent { 192 | color: #c00; 193 | } 194 | .markdown-body a.anchor { 195 | display: block; 196 | padding-left: 30px; 197 | margin-left: -30px; 198 | cursor: pointer; 199 | position: absolute; 200 | top: 0; 201 | left: 0; 202 | bottom: 0; 203 | } 204 | .markdown-body h1, 205 | .markdown-body h2, 206 | .markdown-body h3, 207 | .markdown-body h4, 208 | .markdown-body h5, 209 | .markdown-body h6 { 210 | margin: 20px 0 10px; 211 | padding: 0; 212 | font-weight: bold; 213 | -webkit-font-smoothing: antialiased; 214 | cursor: text; 215 | position: relative; 216 | } 217 | .markdown-body h1:hover a.anchor, 218 | .markdown-body h2:hover a.anchor, 219 | .markdown-body h3:hover a.anchor, 220 | .markdown-body h4:hover a.anchor, 221 | .markdown-body h5:hover a.anchor, 222 | .markdown-body h6:hover a.anchor { 223 | background: url(../images/pin-20.png) no-repeat left center; 224 | text-decoration: none; 225 | } 226 | .markdown-body h1 tt, 227 | .markdown-body h1 code, 228 | .markdown-body h2 tt, 229 | .markdown-body h2 code, 230 | .markdown-body h3 tt, 231 | .markdown-body h3 code, 232 | .markdown-body h4 tt, 233 | .markdown-body h4 code, 234 | .markdown-body h5 tt, 235 | .markdown-body h5 code, 236 | .markdown-body h6 tt, 237 | .markdown-body h6 code { 238 | font-size: inherit; 239 | } 240 | .markdown-body h1 { 241 | font-size: 28px; 242 | color: #000; 243 | margin-top: 50px; 244 | margin-bottom: 20px; 245 | } 246 | .markdown-body h2 { 247 | font-size: 24px; 248 | border-bottom: 1px solid #ccc; 249 | color: #000; 250 | margin-top: 40px; 251 | margin-bottom: 20px; 252 | } 253 | .markdown-body h3 { 254 | font-size: 18px; 255 | margin-top: 30px; 256 | margin-bottom: 15px; 257 | } 258 | .markdown-body h4 { 259 | font-size: 16px; 260 | } 261 | .markdown-body h5 { 262 | font-size: 14px; 263 | } 264 | .markdown-body h6 { 265 | color: #777; 266 | font-size: 14px; 267 | } 268 | .markdown-body p, 269 | .markdown-body blockquote, 270 | .markdown-body ul, 271 | .markdown-body ol, 272 | .markdown-body dl, 273 | .markdown-body li, 274 | .markdown-body table, 275 | .markdown-body pre { 276 | margin: 15px 0; 277 | } 278 | .markdown-body hr { 279 | background: transparent url(../images/dirty-shade.png) repeat-x 0 0; 280 | border: 0 none; 281 | color: #ccc; 282 | height: 4px; 283 | padding: 0; 284 | } 285 | .markdown-body>h1:first-child, 286 | .markdown-body>h2:first-child, 287 | .markdown-body>h3:first-child, 288 | .markdown-body>h4:first-child, 289 | .markdown-body>h5:first-child, 290 | .markdown-body>h6:first-child { 291 | } 292 | .markdown-body h1+h2{ 293 | margin-top: 30px; 294 | } 295 | .markdown-body h2+h3{ 296 | margin-top: 10px; 297 | } 298 | .markdown-body a:first-child h1, 299 | .markdown-body a:first-child h2, 300 | .markdown-body a:first-child h3, 301 | .markdown-body a:first-child h4, 302 | .markdown-body a:first-child h5, 303 | .markdown-body a:first-child h6 { 304 | margin-top: 0; 305 | padding-top: 0; 306 | } 307 | .markdown-body h1+p, 308 | .markdown-body h2+p, 309 | .markdown-body h3+p, 310 | .markdown-body h4+p, 311 | .markdown-body h5+p, 312 | .markdown-body h6+p { 313 | margin-top: 0; 314 | } 315 | .markdown-body li p.first { 316 | display: inline-block; 317 | } 318 | .markdown-body ul, 319 | .markdown-body ol { 320 | padding-left: 30px; 321 | } 322 | .markdown-body ul li>:first-child, 323 | .markdown-body ol li>:first-child { 324 | margin-top: 0; 325 | } 326 | .markdown-body ul li>:last-child, 327 | .markdown-body ol li>:last-child { 328 | margin-bottom: 0; 329 | } 330 | .markdown-body dl { 331 | padding: 0; 332 | } 333 | .markdown-body dl dt { 334 | font-size: 14px; 335 | font-weight: bold; 336 | font-style: italic; 337 | padding: 0; 338 | margin: 15px 0 5px; 339 | } 340 | .markdown-body dl dt:first-child { 341 | padding: 0; 342 | } 343 | .markdown-body dl dt>:first-child { 344 | margin-top: 0; 345 | } 346 | .markdown-body dl dt>:last-child { 347 | margin-bottom: 0; 348 | } 349 | .markdown-body dl dd { 350 | margin: 0 0 15px; 351 | padding: 0 15px; 352 | } 353 | .markdown-body dl dd>:first-child { 354 | margin-top: 0; 355 | } 356 | .markdown-body dl dd>:last-child { 357 | margin-bottom: 0; 358 | } 359 | .markdown-body blockquote { 360 | border-left: 4px solid #DDD; 361 | padding: 0 15px; 362 | color: #777; 363 | } 364 | .markdown-body blockquote>:first-child { 365 | margin-top: 0; 366 | } 367 | .markdown-body blockquote>:last-child { 368 | margin-bottom: 0; 369 | } 370 | .markdown-body table { 371 | padding: 0; 372 | border-collapse: collapse; 373 | border-spacing: 0; 374 | } 375 | .markdown-body table tr { 376 | border-top: 1px solid #ccc; 377 | background-color: #fff; 378 | margin: 0; 379 | padding: 0; 380 | } 381 | .markdown-body table tr:nth-child(2n) { 382 | background-color: #f8f8f8; 383 | } 384 | .markdown-body table tr th { 385 | font-weight: bold; 386 | } 387 | .markdown-body table tr th, 388 | .markdown-body table tr td { 389 | border: 1px solid #ccc; 390 | text-align: left; 391 | margin: 0; 392 | padding: 6px 13px; 393 | } 394 | .markdown-body table tr th>:first-child, 395 | .markdown-body table tr td>:first-child { 396 | margin-top: 0; 397 | } 398 | .markdown-body table tr th>:last-child, 399 | .markdown-body table tr td>:last-child { 400 | margin-bottom: 0; 401 | } 402 | .markdown-body img { 403 | max-width: 100%; 404 | } 405 | .markdown-body span.frame { 406 | display: block; 407 | overflow: hidden; 408 | } 409 | .markdown-body span.frame>span { 410 | border: 1px solid #ddd; 411 | display: block; 412 | float: left; 413 | overflow: hidden; 414 | margin: 13px 0 0; 415 | padding: 7px; 416 | width: auto; 417 | } 418 | .markdown-body span.frame span img { 419 | display: block; 420 | float: left; 421 | } 422 | .markdown-body span.frame span span { 423 | clear: both; 424 | color: #333; 425 | display: block; 426 | padding: 5px 0 0; 427 | } 428 | .markdown-body span.align-center { 429 | display: block; 430 | overflow: hidden; 431 | clear: both; 432 | } 433 | .markdown-body span.align-center>span { 434 | display: block; 435 | overflow: hidden; 436 | margin: 13px auto 0; 437 | text-align: center; 438 | } 439 | .markdown-body span.align-center span img { 440 | margin: 0 auto; 441 | text-align: center; 442 | } 443 | .markdown-body span.align-right { 444 | display: block; 445 | overflow: hidden; 446 | clear: both; 447 | } 448 | .markdown-body span.align-right>span { 449 | display: block; 450 | overflow: hidden; 451 | margin: 13px 0 0; 452 | text-align: right; 453 | } 454 | .markdown-body span.align-right span img { 455 | margin: 0; 456 | text-align: right; 457 | } 458 | .markdown-body span.float-left { 459 | display: block; 460 | margin-right: 13px; 461 | overflow: hidden; 462 | float: left; 463 | } 464 | .markdown-body span.float-left span { 465 | margin: 13px 0 0; 466 | } 467 | .markdown-body span.float-right { 468 | display: block; 469 | margin-left: 13px; 470 | overflow: hidden; 471 | float: right; 472 | } 473 | .markdown-body span.float-right>span { 474 | display: block; 475 | overflow: hidden; 476 | margin: 13px auto 0; 477 | text-align: right; 478 | } 479 | .markdown-body code, 480 | .markdown-body tt { 481 | margin: 0 2px; 482 | padding: 0 5px; 483 | white-space: nowrap; 484 | border: 1px solid #ddd; 485 | background-color: #f8f8f8; 486 | border-radius: 3px; 487 | } 488 | .markdown-body pre>tt, 489 | .markdown-body pre>code { 490 | margin: 0; 491 | padding: 0; 492 | white-space: pre; 493 | border: none; 494 | background: transparent; 495 | } 496 | .markdown-body pre { 497 | background-color: #f8f8f8; 498 | border: 1px solid #ccc; 499 | font-size: 11.5px; 500 | line-height: 18px; 501 | overflow: auto; 502 | padding: 6px 10px; 503 | border-radius: 3px; 504 | } 505 | .markdown-body pre pre, 506 | .markdown-body pre code, 507 | .markdown-body pre tt { 508 | background-color: transparent; 509 | border: none; 510 | } 511 | .markdown-body pre pre { 512 | margin: 0; 513 | padding: 0; 514 | } 515 | .toc { 516 | background-color: #F7F7F7; 517 | border: 1px solid #ddd; 518 | padding: 5px 10px; 519 | margin: 0; 520 | border-radius: 3px; 521 | } 522 | .toc-title { 523 | color: #888; 524 | font-size: 14px; 525 | line-height: 1.6; 526 | padding: 2px; 527 | border-bottom: 1px solid #ddd; 528 | margin-bottom: 3px; 529 | } 530 | .toc ul { 531 | padding-left: 10px; 532 | margin: 0; 533 | } 534 | .toc>ul { 535 | margin-left: 10px; 536 | font-size: 17px; 537 | } 538 | .toc ul ul { 539 | font-size: 15px; 540 | } 541 | .toc ul ul ul { 542 | font-size: 14px; 543 | } 544 | .toc ul li{ 545 | margin: 0; 546 | } 547 | #header-content .toc, 548 | #footer-content .toc, 549 | #sidebar-content .toc { 550 | border: none; 551 | } 552 | .highlight { 553 | background: #fff; 554 | } 555 | .highlight .c { 556 | color: #998; 557 | font-style: italic; 558 | } 559 | .highlight .err { 560 | color: #a61717; 561 | background-color: #e3d2d2; 562 | } 563 | .highlight .k { 564 | font-weight: bold; 565 | } 566 | .highlight .o { 567 | font-weight: bold; 568 | } 569 | .highlight .cm { 570 | color: #998; 571 | font-style: italic; 572 | } 573 | .highlight .cp { 574 | color: #999; 575 | font-weight: bold; 576 | } 577 | .highlight .c1 { 578 | color: #998; 579 | font-style: italic; 580 | } 581 | .highlight .cs { 582 | color: #999; 583 | font-weight: bold; 584 | font-style: italic; 585 | } 586 | .highlight .gd { 587 | color: #000; 588 | background-color: #fdd; 589 | } 590 | .highlight .gd .x { 591 | color: #000; 592 | background-color: #faa; 593 | } 594 | .highlight .ge { 595 | font-style: italic; 596 | } 597 | .highlight .gr { 598 | color: #a00; 599 | } 600 | .highlight .gh { 601 | color: #999; 602 | } 603 | .highlight .gi { 604 | color: #000; 605 | background-color: #dfd; 606 | } 607 | .highlight .gi .x { 608 | color: #000; 609 | background-color: #afa; 610 | } 611 | .highlight .go { 612 | color: #888; 613 | } 614 | .highlight .gp { 615 | color: #555; 616 | } 617 | .highlight .gs { 618 | font-weight: bold; 619 | } 620 | .highlight .gu { 621 | color: #800080; 622 | font-weight: bold; 623 | } 624 | .highlight .gt { 625 | color: #a00; 626 | } 627 | .highlight .kc { 628 | font-weight: bold; 629 | } 630 | .highlight .kd { 631 | font-weight: bold; 632 | } 633 | .highlight .kn { 634 | font-weight: bold; 635 | } 636 | .highlight .kp { 637 | font-weight: bold; 638 | } 639 | .highlight .kr { 640 | font-weight: bold; 641 | } 642 | .highlight .kt { 643 | color: #458; 644 | font-weight: bold; 645 | } 646 | .highlight .m { 647 | color: #099; 648 | } 649 | .highlight .s { 650 | color: #d14; 651 | } 652 | .highlight .na { 653 | color: #008080; 654 | } 655 | .highlight .nb { 656 | color: #0086B3; 657 | } 658 | .highlight .nc { 659 | color: #458; 660 | font-weight: bold; 661 | } 662 | .highlight .no { 663 | color: #008080; 664 | } 665 | .highlight .ni { 666 | color: #800080; 667 | } 668 | .highlight .ne { 669 | color: #900; 670 | font-weight: bold; 671 | } 672 | .highlight .nf { 673 | color: #900; 674 | font-weight: bold; 675 | } 676 | .highlight .nn { 677 | color: #555; 678 | } 679 | .highlight .nt { 680 | color: #000080; 681 | } 682 | .highlight .nv { 683 | color: #008080; 684 | } 685 | .highlight .ow { 686 | font-weight: bold; 687 | } 688 | .highlight .w { 689 | color: #bbb; 690 | } 691 | .highlight .mf { 692 | color: #099; 693 | } 694 | .highlight .mh { 695 | color: #099; 696 | } 697 | .highlight .mi { 698 | color: #099; 699 | } 700 | .highlight .mo { 701 | color: #099; 702 | } 703 | .highlight .sb { 704 | color: #d14; 705 | } 706 | .highlight .sc { 707 | color: #d14; 708 | } 709 | .highlight .sd { 710 | color: #d14; 711 | } 712 | .highlight .s2 { 713 | color: #d14; 714 | } 715 | .highlight .se { 716 | color: #d14; 717 | } 718 | .highlight .sh { 719 | color: #d14; 720 | } 721 | .highlight .si { 722 | color: #d14; 723 | } 724 | .highlight .sx { 725 | color: #d14; 726 | } 727 | .highlight .sr { 728 | color: #009926; 729 | } 730 | .highlight .s1 { 731 | color: #d14; 732 | } 733 | .highlight .ss { 734 | color: #990073; 735 | } 736 | .highlight .bp { 737 | color: #999; 738 | } 739 | .highlight .vc { 740 | color: #008080; 741 | } 742 | .highlight .vg { 743 | color: #008080; 744 | } 745 | .highlight .vi { 746 | color: #008080; 747 | } 748 | .highlight .il { 749 | color: #099; 750 | } 751 | .highlight .gc { 752 | color: #999; 753 | background-color: #EAF2F5; 754 | } 755 | .type-csharp .highlight .k { 756 | color: #00F; 757 | } 758 | .type-csharp .highlight .kt { 759 | color: #00F; 760 | } 761 | .type-csharp .highlight .nf { 762 | color: #000; 763 | font-weight: normal; 764 | } 765 | .type-csharp .highlight .nc { 766 | color: #2B91AF; 767 | } 768 | .type-csharp .highlight .nn { 769 | color: #000; 770 | } 771 | .type-csharp .highlight .s { 772 | color: #A31515; 773 | } 774 | .type-csharp .highlight .sc { 775 | color: #A31515; 776 | } 777 | 778 | /* api docs */ 779 | .apidocs { 780 | margin-top: 20px !important; 781 | } 782 | 783 | .apidoc-intro { 784 | padding-top:30px !important; 785 | } -------------------------------------------------------------------------------- /jsplumb/jsplumb.css: -------------------------------------------------------------------------------- 1 | /** DISABLE TEXT SELECTION (SET ON BODY WHEN DRAGGING IS OCCURRING) **/ 2 | ._jsPlumb_drag_select * { 3 | -webkit-touch-callout: none; 4 | -webkit-user-select: none; 5 | -khtml-user-select: none; 6 | -moz-user-select: none; 7 | -ms-user-select: none; 8 | user-select: none; 9 | } 10 | 11 | /** OPEN SANS FONT **/ 12 | @font-face { 13 | font-family: 'Open Sans'; 14 | font-style: normal; 15 | font-weight: 400; 16 | src:local('Open Sans'), 17 | local('OpenSans'), 18 | url("OpenSans-Regular.ttf") format('truetype'), 19 | url("OpenSans.woff") format('woff'); 20 | } 21 | 22 | /** FB **/ 23 | #like { 24 | position: fixed; 25 | width: 77px; 26 | height: 70px; 27 | border: 0; 28 | right: 11px; 29 | bottom: -40px; 30 | } 31 | 32 | #retweet_button { 33 | position: fixed; 34 | bottom: 30px; 35 | right: -7px; 36 | } 37 | 38 | body { 39 | padding:0; 40 | margin:0; 41 | font-family:'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; 42 | background-color: whitesmoke; 43 | } 44 | 45 | #headerWrapper { 46 | width:100%; 47 | background-color:white; 48 | position:fixed; 49 | top:0;left:0; 50 | z-index:100001; 51 | height:44px; 52 | padding:0; 53 | opacity:0.8; 54 | text-align: center; 55 | border-bottom: 1px solid #e5e5e5; 56 | box-shadow: 0px 1px #eee; 57 | } 58 | 59 | #header { 60 | margin-top:0; 61 | 62 | height:44px; 63 | font-size:13px; 64 | margin-left:auto; 65 | margin-right:auto; 66 | 67 | line-height: 44px; 68 | max-width:1000px; 69 | width:80%; 70 | } 71 | 72 | @media screen and (max-width:1000px) { 73 | #header { 74 | width:100%; 75 | } 76 | } 77 | 78 | @media screen and (max-width:800px) { 79 | #header select { 80 | display:none; 81 | } 82 | } 83 | 84 | @media screen and (max-width:700px) { 85 | .library-links { 86 | right:330px; 87 | } 88 | } 89 | 90 | @media screen and (max-width:640px) { 91 | .logo { 92 | display:none; 93 | } 94 | #header { 95 | text-align:center; 96 | overflow:hidden; 97 | } 98 | } 99 | 100 | .explanation i { 101 | float: right; 102 | margin-right: 25px; 103 | margin-top: 13px; 104 | font-size: 25px; 105 | cursor:pointer; 106 | } 107 | 108 | .explanation i:hover { 109 | color:orange; 110 | } 111 | 112 | .words { 113 | text-align: left; 114 | padding:50px; 115 | background-color:white; 116 | } 117 | 118 | .code { 119 | border:1px solid #456; 120 | } 121 | 122 | .logo { 123 | font-size:30px; 124 | color:#1f1f1f; 125 | text-shadow: 1px 1px #ccc; 126 | float:left; 127 | width:154px; 128 | height:44px; 129 | background-position:0px 5px; 130 | } 131 | 132 | #main { 133 | margin-top: 106px; 134 | font-size: 80%; 135 | width: 80%; 136 | margin-left:auto; 137 | margin-right: auto; 138 | height: 600px; 139 | text-align: center; 140 | position: relative; 141 | max-width: 1200px; 142 | max-height: 1000px; 143 | } 144 | 145 | .demo { 146 | position: relative; 147 | width:100%; 148 | background-color:white; 149 | overflow:auto; 150 | margin-bottom:25px; 151 | height: 600px; 152 | } 153 | 154 | .explanation { 155 | position: absolute; 156 | text-align: center; 157 | background-color: #7AB02C; 158 | opacity: 0.8; 159 | filter: alpha(opacity=80); 160 | color: white; 161 | width: 100%; 162 | height: 54px; 163 | z-index: 10000; 164 | overflow: hidden; 165 | box-shadow: 0px 0px 10px gray; 166 | } 167 | 168 | .explanation.expanded { 169 | height:auto; 170 | min-height:54px; 171 | 172 | -webkit-transition: max-height 0.8s; 173 | max-height:100%; 174 | } 175 | 176 | .commands { 177 | margin-bottom:10px; 178 | } 179 | 180 | .commands:hover { 181 | z-index:10000; 182 | } 183 | 184 | /* demo elements */ 185 | 186 | a, a:visited { 187 | text-decoration:none; 188 | color:black; 189 | border-radius:0.2em; 190 | -webkit-transition: color 0.15s ease-in; 191 | -moz-transition: color 0.15s ease-in; 192 | -o-transition: color 0.15s ease-in; 193 | transition: color 0.15s ease-in; 194 | } 195 | 196 | a:hover { 197 | color:#7AB02C; 198 | } 199 | 200 | a:active { 201 | color:#FF2300; 202 | } 203 | 204 | .menu, #render, #explanation { 205 | background-color:#fff; 206 | } 207 | 208 | .menu { 209 | float:right; 210 | font-size:12px; 211 | } 212 | 213 | .menu a { 214 | margin-right: 19px; 215 | } 216 | 217 | .otherLibraries { 218 | display:inline; 219 | } 220 | 221 | #render a { 222 | margin-right:10px; 223 | } 224 | 225 | .selected { 226 | color:orange !important; 227 | } 228 | 229 | .window, .label { 230 | text-align:center; 231 | z-index:24; 232 | cursor:pointer; 233 | box-shadow: 2px 2px 19px #aaa; 234 | -o-box-shadow: 2px 2px 19px #aaa; 235 | -webkit-box-shadow: 2px 2px 19px #aaa; 236 | -moz-box-shadow: 2px 2px 19px #aaa; 237 | 238 | } 239 | path, ._jsPlumb_endpoint { cursor:pointer; } 240 | 241 | .cmd { 242 | color:white; 243 | margin-right:25px; 244 | } 245 | 246 | .cmd:hover { 247 | color:#FF2300; 248 | text-decoration: underline; 249 | } 250 | .cmd:active { 251 | color:#FF2300; 252 | } 253 | 254 | .label { 255 | font-size:13px; 256 | padding:8px; 257 | padding:8px; 258 | } 259 | 260 | .component { 261 | border:1px solid #346789; 262 | border-radius:0.5em; 263 | opacity:0.8; 264 | filter:alpha(opacity=80); 265 | background-color:white; 266 | color:black; 267 | padding:0.5em; 268 | font-size:0.8em; 269 | } 270 | 271 | .component:hover { 272 | border:1px solid #123456; 273 | box-shadow: 2px 2px 19px #444; 274 | -o-box-shadow: 2px 2px 19px #444; 275 | -webkit-box-shadow: 2px 2px 19px #444; 276 | -moz-box-shadow: 2px 2px 19px #fff; 277 | opacity:0.9; 278 | filter:alpha(opacity=90); 279 | } 280 | 281 | .window { 282 | background-color:white; 283 | border:1px solid #346789; 284 | box-shadow: 2px 2px 19px #e0e0e0; 285 | -o-box-shadow: 2px 2px 19px #e0e0e0; 286 | -webkit-box-shadow: 2px 2px 19px #e0e0e0; 287 | -moz-box-shadow: 2px 2px 19px #e0e0e0; 288 | -moz-border-radius:0.5em; 289 | border-radius:0.5em; 290 | width:5em; height:5em; 291 | position:absolute; 292 | color:black; 293 | padding:0.5em; 294 | width:80px; 295 | height:80px; 296 | line-height: 80px; 297 | -webkit-transition: -webkit-box-shadow 0.15s ease-in; 298 | -moz-transition: -moz-box-shadow 0.15s ease-in; 299 | -o-transition: -o-box-shadow 0.15s ease-in; 300 | transition: box-shadow 0.15s ease-in; 301 | } 302 | 303 | .window:hover { 304 | border:1px solid #123456; 305 | box-shadow: 2px 2px 19px #444; 306 | -o-box-shadow: 2px 2px 19px #444; 307 | -webkit-box-shadow: 2px 2px 19px #444; 308 | -moz-box-shadow: 2px 2px 19px #fff; 309 | opacity:0.9; 310 | filter:alpha(opacity=90); 311 | } 312 | 313 | .window a { 314 | font-family:helvetica; 315 | } 316 | 317 | .demo-links, .library-links { 318 | position: fixed; 319 | right: 0; 320 | top: 44px; 321 | font-size: 11px; 322 | background-color: white; 323 | opacity: 0.8; 324 | padding-right: 10px; 325 | padding-left: 5px; 326 | text-transform: uppercase; 327 | z-index:100001; 328 | } 329 | 330 | .demo-links div, .library-links a { 331 | display:inline; 332 | margin-right:7px; 333 | margin-left:7px; 334 | } 335 | 336 | .demo-links i, .library-links i { 337 | padding:4px; 338 | } 339 | 340 | .library-links { 341 | right: 515px; 342 | height: 19px; 343 | line-height: 19px; 344 | } 345 | 346 | .current-library { 347 | color:#7AB02C !important; 348 | } 349 | 350 | /** Z-INDEX **/ 351 | 352 | ._jsPlumb_connector { z-index:18; } 353 | ._jsPlumb_endpoint { z-index:19; } 354 | ._jsPlumb_overlay { z-index:20; } 355 | 356 | .aLabel { 357 | background-color:white; 358 | padding:0.4em; 359 | font:12px sans-serif; 360 | color:#444; 361 | z-index:21; 362 | border:1px dotted gray; 363 | opacity:0.8; 364 | filter:alpha(opacity=80); 365 | cursor: pointer; 366 | } 367 | .aLabel._jsPlumb_hover { 368 | background-color:#5C96BC; 369 | color:white; 370 | border:1px solid white; 371 | } 372 | 373 | /* ---------------------- bootstrap dropdowns ------------------------- */ 374 | .clearfix { 375 | *zoom: 1; 376 | } 377 | 378 | .clearfix:before, 379 | .clearfix:after { 380 | display: table; 381 | line-height: 0; 382 | content: ""; 383 | } 384 | 385 | .clearfix:after { 386 | clear: both; 387 | } 388 | 389 | .hide-text { 390 | font: 0/0 a; 391 | color: transparent; 392 | text-shadow: none; 393 | background-color: transparent; 394 | border: 0; 395 | } 396 | 397 | .input-block-level { 398 | display: block; 399 | width: 100%; 400 | min-height: 30px; 401 | -webkit-box-sizing: border-box; 402 | -moz-box-sizing: border-box; 403 | box-sizing: border-box; 404 | } 405 | 406 | /* load test */ 407 | 408 | 409 | #iframe { 410 | width: 98%; 411 | height: 1000px; 412 | position: absolute; 413 | top: 8px; 414 | left: 1%; 415 | border: 0; 416 | } 417 | #render { height:20px;} 418 | #links { 419 | width: 143px; 420 | font-size: 14px; 421 | padding-left: 0px; 422 | position: fixed; 423 | left: 9px; 424 | top: 52px; 425 | z-index: 20; 426 | background-color: white; 427 | } 428 | ul { padding:0; } 429 | li { 430 | list-style-type:none; 431 | } 432 | .current-tests { 433 | color:orange !important; 434 | } 435 | #qunit-tests li.pass, #qunit-tests li.fail { 436 | background-color:transparent; 437 | } 438 | .loadtest #main, #main.test { 439 | max-width: none; 440 | margin-top: 52px; 441 | background-color: white; 442 | 443 | margin-left: 162px; 444 | } 445 | 446 | 447 | .loadtest ._jsPlumb_connection { z-index:3; } 448 | .loadtest .jspLoad { 449 | z-index:4; 450 | position:absolute; 451 | width:70px; 452 | height:70px; 453 | cursor:pointer; 454 | } 455 | 456 | .loadtest #header { 457 | height:11em; 458 | border:2px solid #824563; 459 | } 460 | 461 | .loadtest #setup { 462 | float:left; 463 | } 464 | .loadtest #demo { 465 | margin-top:10em; 466 | position:relative; 467 | } 468 | .loadtest #setup, .loadtest #output { 469 | font-size:12px; 470 | } 471 | -------------------------------------------------------------------------------- /logotext.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | image/svg+xml -------------------------------------------------------------------------------- /script.js: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright 2014 Google Inc. All rights reserved. 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 truncate = function (str, width) { 18 | if (str && str.length > width) { 19 | return str.slice(0, width) + "..."; 20 | } 21 | return str; 22 | }; 23 | 24 | var pods = []; 25 | var services = []; 26 | var controllers = []; 27 | var uses = {}; 28 | 29 | var groups = {}; 30 | 31 | var insertByName = function (index, value) { 32 | 33 | if (!value || !value.metadata.labels || value.metadata.name == 'kubernetes') { 34 | return; 35 | } 36 | var list = groups[value.metadata.labels.run]; 37 | if (!list) { 38 | list = []; 39 | groups[value.metadata.labels.run] = list; 40 | } 41 | list.push(value); 42 | }; 43 | 44 | var groupByName = function () { 45 | $.each(pods.items, insertByName); 46 | $.each(controllers.items, insertByName); 47 | $.each(services.items, insertByName); 48 | }; 49 | 50 | var matchesLabelQuery = function (labels, selector) { 51 | var match = true; 52 | 53 | if(!labels) { return false; } 54 | 55 | $.each(selector, function (key, value) { 56 | if (labels[key] !== value) { 57 | match = false; 58 | } 59 | }); 60 | return match; 61 | }; 62 | 63 | var connectControllers = function () { 64 | connectUses(); 65 | for (var i = 0; i < controllers.items.length; i++) { 66 | var controller = controllers.items[i]; 67 | for (var j = 0; j < pods.items.length; j++) { 68 | var pod = pods.items[j]; 69 | if (pod.metadata && controller.spec && 70 | matchesLabelQuery(pod.metadata.labels, controller.spec.selector)) { 71 | jsPlumb.connect({ 72 | source: controller.metadata.uid, 73 | target: pod.metadata.uid, 74 | anchors: ["Bottom", "Bottom"], 75 | paintStyle: {lineWidth: 5, strokeStyle: 'rgb(51,105,232)'}, 76 | joinStyle: "round", 77 | endpointStyle: {fillStyle: 'rgb(51,105,232)', radius: 7}, 78 | connector: ["Flowchart", {cornerRadius: 5}] 79 | }); 80 | } 81 | } 82 | } 83 | 84 | 85 | for (var i = 0; i < services.items.length; i++) { 86 | var service = services.items[i]; 87 | if (service.metadata.name == 'kubernetes') { 88 | continue; 89 | } 90 | 91 | for (var j = 0; j < pods.items.length; j++) { 92 | 93 | var pod = pods.items[j]; 94 | 95 | if (matchesLabelQuery(pod.metadata.labels, service.spec.selector)) { 96 | jsPlumb.connect( 97 | { 98 | source: service.metadata.uid, 99 | target: pod.metadata.uid, 100 | anchors: ["Bottom", "Top"], 101 | paintStyle: {lineWidth: 5, strokeStyle: 'rgb(0,153,57)'}, 102 | endpointStyle: {fillStyle: 'rgb(0,153,57)', radius: 7}, 103 | joinStyle: "round", 104 | connector: ["Flowchart", {cornerRadius: 5}] 105 | }); 106 | } 107 | } 108 | } 109 | }; 110 | 111 | var colors = [ 112 | 'rgb(213,15,37)', 113 | 'rgba(238,178,17,1.0)' 114 | ]; 115 | 116 | var connectUses = function () { 117 | var colorIx = 0; 118 | 119 | $.each(uses, function (key, list) { 120 | 121 | var color = colors[colorIx]; 122 | colorIx++; 123 | $.each(pods.items, function (i, pod) { 124 | if (pod.metadata.labels && pod.metadata.labels.run == key) { 125 | $.each(list, function (j, serviceKey) { 126 | $.each(services.items, function (j, service) { 127 | if (service.metadata.labels && service.metadata.labels.run == serviceKey) { 128 | jsPlumb.connect( 129 | { 130 | source: pod.metadata.uid, 131 | target: service.metadata.uid, 132 | endpoint: "Blank", 133 | anchors: ["Bottom", "Top"], 134 | connector: "Straight", 135 | paintStyle: {lineWidth: 5, strokeStyle: color}, 136 | overlays: [ 137 | ["Arrow", {width: 15, length: 30, location: 0.3}], 138 | ["Arrow", {width: 15, length: 30, location: 0.6}], 139 | ["Arrow", {width: 15, length: 30, location: 1}], 140 | ], 141 | }); 142 | } 143 | }); 144 | }); 145 | } 146 | }); 147 | }); 148 | }; 149 | 150 | var makeGroupOrder = function () { 151 | var groupScores = {}; 152 | $.each(uses, function (key, value) { 153 | if (!groupScores[key]) { 154 | groupScores[key] = 0; 155 | } 156 | $.each(value, function (ix, uses) { 157 | if (!groupScores[uses]) { 158 | groupScores[uses] = 1; 159 | } else { 160 | groupScores[uses]++; 161 | } 162 | }); 163 | }); 164 | $.each(groups, function(key, value) { 165 | if (!groupScores[key]) { 166 | groupScores[key] = 0; 167 | } 168 | }); 169 | var groupOrder = []; 170 | $.each(groupScores, function (key, value) { 171 | groupOrder.push(key); 172 | }); 173 | groupOrder.sort(function (a, b) { 174 | return groupScores[a] - groupScores[b]; 175 | }); 176 | return groupOrder; 177 | }; 178 | 179 | 180 | var renderGroups = function () { 181 | var elt = $('#sheet'); 182 | var y = 10; 183 | var serviceLeft = 0; 184 | var groupOrder = makeGroupOrder(); 185 | $.each(groupOrder, function (ix, key) { 186 | list = groups[key]; 187 | if (!list) { 188 | return; 189 | } 190 | var div = $('
'); 191 | var x = 100; 192 | var controllersCount = 0; 193 | $.each(list, function (index, value) { 194 | var eltDiv = null; 195 | if (value.type == "pod") { 196 | eltDiv = $('
'); 198 | } else if (value.type == "service") { 199 | eltDiv = $('
'); 201 | } else { 202 | eltDiv = $('
'); 205 | controllersCount += 1; 206 | } 207 | span = $(''); 208 | span.text(truncate(value.metadata.name, 17)); 209 | eltDiv.append(span) 210 | div.append(eltDiv); 211 | x += 180; 212 | }); 213 | y += 400; 214 | serviceLeft += 200; 215 | elt.append(div); 216 | }); 217 | }; 218 | 219 | var insertUse = function (name, use) { 220 | for (var i = 0; i < uses[name].length; i++) { 221 | if (uses[name][i] == use) { 222 | return; 223 | } 224 | } 225 | uses[name].push(use); 226 | }; 227 | 228 | var loadData = function () { 229 | var deferred = new $.Deferred(); 230 | var req1 = $.getJSON("/api/v1/namespaces/default/pods", function (data) { 231 | pods = data; 232 | $.each(data.items, function (key, val) { 233 | val.type = 'pod'; 234 | 235 | if (val.metadata.labels) { 236 | if (val.metadata.labels.uses) { 237 | if (!uses[val.metadata.labels.run]) { 238 | uses[val.metadata.labels.run] = val.metadata.labels.uses.split(","); 239 | } else { 240 | $.each(val.metadata.labels.uses.split(","), function (ix, use) { 241 | insertUse(val.metadata.labels.run, use); 242 | }); 243 | } 244 | } 245 | } 246 | }); 247 | }); 248 | 249 | var req2 = $.getJSON("/api/v1/namespaces/default/replicationcontrollers", function (data) { 250 | controllers = data; 251 | $.each(data.items, function (key, val) { 252 | val.type = 'replicationController'; 253 | }); 254 | }); 255 | 256 | 257 | var req3 = $.getJSON("/api/v1/namespaces/default/services", function (data) { 258 | services = data; 259 | $.each(data.items, function (key, val) { 260 | val.type = 'service'; 261 | }); 262 | }); 263 | $.when(req1, req2, req3).then(function () { 264 | deferred.resolve(); 265 | }); 266 | return deferred; 267 | } 268 | 269 | jsPlumb.bind("ready", function () { 270 | reload() 271 | }); 272 | 273 | var reload = function () { 274 | $('#sheet').empty() 275 | jsPlumb.reset() 276 | 277 | pods = []; 278 | services = []; 279 | controllers = []; 280 | uses = {}; 281 | groups = {}; 282 | 283 | var instance = jsPlumb.getInstance({ 284 | // default drag options 285 | DragOptions: {cursor: 'pointer', zIndex: 2000}, 286 | // the overlays to decorate each connection with. note that the label overlay uses a function to generate the label text; in this 287 | // case it returns the 'labelText' member that we set on each connection in the 'init' method below. 288 | ConnectionOverlays: [ 289 | ["Arrow", {location: 1}], 290 | //[ "Label", { 291 | // location:0.1, 292 | // id:"label", 293 | // cssClass:"aLabel" 294 | //}] 295 | ], 296 | Container: "flowchart-demo" 297 | }); 298 | var promise = loadData(); 299 | $.when(promise).then(function () { 300 | groupByName(); 301 | renderGroups(); 302 | connectControllers(); 303 | }) 304 | jsPlumb.fire("jsPlumbDemoLoaded", instance); 305 | 306 | setTimeout(reload, 6000); 307 | }; 308 | -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | .wide { 2 | width: 150px; 3 | } 4 | 5 | .service { 6 | background-color: rgb(0,153,57); 7 | color: white; 8 | } 9 | 10 | .controller { 11 | background-color:rgb(51,105,232); 12 | color: white; 13 | } 14 | 15 | .pod { 16 | width: 150px; 17 | background-color:#eeeeef; 18 | } 19 | 20 | .logo { 21 | background: url('titlelogo.svg'); 22 | background-repeat: no-repeat; 23 | height: 150px; 24 | width: 600px; 25 | } 26 | 27 | .navbar-logo { 28 | margin-left: 10px; 29 | text-align: left; 30 | } 31 | 32 | #nav-logo-img { 33 | height: 42px; 34 | } 35 | 36 | .navbar { 37 | background-color: #447AE8; 38 | border: 0px; 39 | border-radius: 0; 40 | } 41 | 42 | .window span { 43 | vertical-align: middle; 44 | } 45 | 46 | #main { 47 | margin-top: 0; 48 | width: auto; 49 | height: 100%; 50 | max-width: none; 51 | max-height: none; 52 | } 53 | 54 | .demo { 55 | position: absolute; 56 | top: 42px; 57 | bottom: 0; 58 | height: auto; 59 | margin-bottom: 0; 60 | } 61 | -------------------------------------------------------------------------------- /titlelogo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | image/svg+xml --------------------------------------------------------------------------------