├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── LICENSE-BSD-glMatrix ├── LICENSE-MPL-RabbitMQ ├── Makefile ├── README.md ├── erlang.mk ├── license_info ├── priv └── www │ ├── js │ ├── tmpl │ │ └── visualiser.ejs │ └── visualiser.js │ └── visualiser │ └── js │ ├── glMatrix-min.js │ ├── glMatrix.js │ ├── model.js │ ├── octtree.js │ └── physics.js ├── rabbitmq-components.mk ├── src ├── rabbit_mgmt_wm_all.erl └── rabbit_visualiser_mgmt.erl └── test └── visualiser_http_SUITE.erl /.gitignore: -------------------------------------------------------------------------------- 1 | .sw? 2 | .*.sw? 3 | *.beam 4 | /.erlang.mk/ 5 | /cover/ 6 | /deps/ 7 | /doc/ 8 | /ebin/ 9 | /logs/ 10 | /plugins/ 11 | 12 | /rabbitmq_management_visualiser.d 13 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | As contributors and maintainers of this project, and in the interest of fostering an open 4 | and welcoming community, we pledge to respect all people who contribute through reporting 5 | issues, posting feature requests, updating documentation, submitting pull requests or 6 | patches, and other activities. 7 | 8 | We are committed to making participation in this project a harassment-free experience for 9 | everyone, regardless of level of experience, gender, gender identity and expression, 10 | sexual orientation, disability, personal appearance, body size, race, ethnicity, age, 11 | religion, or nationality. 12 | 13 | Examples of unacceptable behavior by participants include: 14 | 15 | * The use of sexualized language or imagery 16 | * Personal attacks 17 | * Trolling or insulting/derogatory comments 18 | * Public or private harassment 19 | * Publishing other's private information, such as physical or electronic addresses, 20 | without explicit permission 21 | * Other unethical or unprofessional conduct 22 | 23 | Project maintainers have the right and responsibility to remove, edit, or reject comments, 24 | commits, code, wiki edits, issues, and other contributions that are not aligned to this 25 | Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors 26 | that they deem inappropriate, threatening, offensive, or harmful. 27 | 28 | By adopting this Code of Conduct, project maintainers commit themselves to fairly and 29 | consistently applying these principles to every aspect of managing this project. Project 30 | maintainers who do not follow or enforce the Code of Conduct may be permanently removed 31 | from the project team. 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an 34 | individual is representing the project or its community. 35 | 36 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by 37 | contacting a project maintainer at [info@rabbitmq.com](mailto:info@rabbitmq.com). All complaints will 38 | be reviewed and investigated and will result in a response that is deemed necessary and 39 | appropriate to the circumstances. Maintainers are obligated to maintain confidentiality 40 | with regard to the reporter of an incident. 41 | 42 | This Code of Conduct is adapted from the 43 | [Contributor Covenant](http://contributor-covenant.org), version 1.3.0, available at 44 | [contributor-covenant.org/version/1/3/0/](http://contributor-covenant.org/version/1/3/0/) 45 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Overview 2 | 3 | RabbitMQ projects use pull requests to discuss, collaborate on and accept code contributions. 4 | Pull requests is the primary place of discussing code changes. 5 | 6 | ## How to Contribute 7 | 8 | The process is fairly standard: 9 | 10 | * Fork the repository or repositories you plan on contributing to 11 | * Clone [RabbitMQ umbrella repository](https://github.com/rabbitmq/rabbitmq-public-umbrella) 12 | * `cd umbrella`, `make co` 13 | * Create a branch with a descriptive name in the relevant repositories 14 | * Make your changes, run tests, commit with a [descriptive message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html), push to your fork 15 | * Submit pull requests with an explanation what has been changed and **why** 16 | * Submit a filled out and signed [Contributor Agreement](https://github.com/rabbitmq/ca#how-to-submit) if needed (see below) 17 | * Be patient. We will get to your pull request eventually 18 | 19 | If what you are going to work on is a substantial change, please first ask the core team 20 | of their opinion on [RabbitMQ mailing list](https://groups.google.com/forum/#!forum/rabbitmq-users). 21 | 22 | 23 | ## Code of Conduct 24 | 25 | See [CODE_OF_CONDUCT.md](./CODE_OF_CONDUCT.md). 26 | 27 | 28 | ## Contributor Agreement 29 | 30 | If you want to contribute a non-trivial change, please submit a signed copy of our 31 | [Contributor Agreement](https://github.com/rabbitmq/ca#how-to-submit) around the time 32 | you submit your pull request. This will make it much easier (in some cases, possible) 33 | for the RabbitMQ team at Pivotal to merge your contribution. 34 | 35 | 36 | ## Where to Ask Questions 37 | 38 | If something isn't clear, feel free to ask on our [mailing list](https://groups.google.com/forum/#!forum/rabbitmq-users). 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This package, the RabbitMQ Visualiser is licensed under the MPL. For 2 | the MPL, please see LICENSE-MPL-RabbitMQ. 3 | 4 | This package makes use of the following third party libraries: 5 | glMatrix - http://code.google.com/p/glmatrix/ - BSD 2-clause license, see LICENSE-BSD-glMatrix 6 | 7 | If you have any questions regarding licensing, please contact us at 8 | info@rabbitmq.com. 9 | -------------------------------------------------------------------------------- /LICENSE-BSD-glMatrix: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011, Brandon Jones 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in the 13 | documentation and/or other materials provided with the 14 | distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /LICENSE-MPL-RabbitMQ: -------------------------------------------------------------------------------- 1 | MOZILLA PUBLIC LICENSE 2 | Version 1.1 3 | 4 | --------------- 5 | 6 | 1. Definitions. 7 | 8 | 1.0.1. "Commercial Use" means distribution or otherwise making the 9 | Covered Code available to a third party. 10 | 11 | 1.1. "Contributor" means each entity that creates or contributes to 12 | the creation of Modifications. 13 | 14 | 1.2. "Contributor Version" means the combination of the Original 15 | Code, prior Modifications used by a Contributor, and the Modifications 16 | made by that particular Contributor. 17 | 18 | 1.3. "Covered Code" means the Original Code or Modifications or the 19 | combination of the Original Code and Modifications, in each case 20 | including portions thereof. 21 | 22 | 1.4. "Electronic Distribution Mechanism" means a mechanism generally 23 | accepted in the software development community for the electronic 24 | transfer of data. 25 | 26 | 1.5. "Executable" means Covered Code in any form other than Source 27 | Code. 28 | 29 | 1.6. "Initial Developer" means the individual or entity identified 30 | as the Initial Developer in the Source Code notice required by Exhibit 31 | A. 32 | 33 | 1.7. "Larger Work" means a work which combines Covered Code or 34 | portions thereof with code not governed by the terms of this License. 35 | 36 | 1.8. "License" means this document. 37 | 38 | 1.8.1. "Licensable" means having the right to grant, to the maximum 39 | extent possible, whether at the time of the initial grant or 40 | subsequently acquired, any and all of the rights conveyed herein. 41 | 42 | 1.9. "Modifications" means any addition to or deletion from the 43 | substance or structure of either the Original Code or any previous 44 | Modifications. When Covered Code is released as a series of files, a 45 | Modification is: 46 | A. Any addition to or deletion from the contents of a file 47 | containing Original Code or previous Modifications. 48 | 49 | B. Any new file that contains any part of the Original Code or 50 | previous Modifications. 51 | 52 | 1.10. "Original Code" means Source Code of computer software code 53 | which is described in the Source Code notice required by Exhibit A as 54 | Original Code, and which, at the time of its release under this 55 | License is not already Covered Code governed by this License. 56 | 57 | 1.10.1. "Patent Claims" means any patent claim(s), now owned or 58 | hereafter acquired, including without limitation, method, process, 59 | and apparatus claims, in any patent Licensable by grantor. 60 | 61 | 1.11. "Source Code" means the preferred form of the Covered Code for 62 | making modifications to it, including all modules it contains, plus 63 | any associated interface definition files, scripts used to control 64 | compilation and installation of an Executable, or source code 65 | differential comparisons against either the Original Code or another 66 | well known, available Covered Code of the Contributor's choice. The 67 | Source Code can be in a compressed or archival form, provided the 68 | appropriate decompression or de-archiving software is widely available 69 | for no charge. 70 | 71 | 1.12. "You" (or "Your") means an individual or a legal entity 72 | exercising rights under, and complying with all of the terms of, this 73 | License or a future version of this License issued under Section 6.1. 74 | For legal entities, "You" includes any entity which controls, is 75 | controlled by, or is under common control with You. For purposes of 76 | this definition, "control" means (a) the power, direct or indirect, 77 | to cause the direction or management of such entity, whether by 78 | contract or otherwise, or (b) ownership of more than fifty percent 79 | (50%) of the outstanding shares or beneficial ownership of such 80 | entity. 81 | 82 | 2. Source Code License. 83 | 84 | 2.1. The Initial Developer Grant. 85 | The Initial Developer hereby grants You a world-wide, royalty-free, 86 | non-exclusive license, subject to third party intellectual property 87 | claims: 88 | (a) under intellectual property rights (other than patent or 89 | trademark) Licensable by Initial Developer to use, reproduce, 90 | modify, display, perform, sublicense and distribute the Original 91 | Code (or portions thereof) with or without Modifications, and/or 92 | as part of a Larger Work; and 93 | 94 | (b) under Patents Claims infringed by the making, using or 95 | selling of Original Code, to make, have made, use, practice, 96 | sell, and offer for sale, and/or otherwise dispose of the 97 | Original Code (or portions thereof). 98 | 99 | (c) the licenses granted in this Section 2.1(a) and (b) are 100 | effective on the date Initial Developer first distributes 101 | Original Code under the terms of this License. 102 | 103 | (d) Notwithstanding Section 2.1(b) above, no patent license is 104 | granted: 1) for code that You delete from the Original Code; 2) 105 | separate from the Original Code; or 3) for infringements caused 106 | by: i) the modification of the Original Code or ii) the 107 | combination of the Original Code with other software or devices. 108 | 109 | 2.2. Contributor Grant. 110 | Subject to third party intellectual property claims, each Contributor 111 | hereby grants You a world-wide, royalty-free, non-exclusive license 112 | 113 | (a) under intellectual property rights (other than patent or 114 | trademark) Licensable by Contributor, to use, reproduce, modify, 115 | display, perform, sublicense and distribute the Modifications 116 | created by such Contributor (or portions thereof) either on an 117 | unmodified basis, with other Modifications, as Covered Code 118 | and/or as part of a Larger Work; and 119 | 120 | (b) under Patent Claims infringed by the making, using, or 121 | selling of Modifications made by that Contributor either alone 122 | and/or in combination with its Contributor Version (or portions 123 | of such combination), to make, use, sell, offer for sale, have 124 | made, and/or otherwise dispose of: 1) Modifications made by that 125 | Contributor (or portions thereof); and 2) the combination of 126 | Modifications made by that Contributor with its Contributor 127 | Version (or portions of such combination). 128 | 129 | (c) the licenses granted in Sections 2.2(a) and 2.2(b) are 130 | effective on the date Contributor first makes Commercial Use of 131 | the Covered Code. 132 | 133 | (d) Notwithstanding Section 2.2(b) above, no patent license is 134 | granted: 1) for any code that Contributor has deleted from the 135 | Contributor Version; 2) separate from the Contributor Version; 136 | 3) for infringements caused by: i) third party modifications of 137 | Contributor Version or ii) the combination of Modifications made 138 | by that Contributor with other software (except as part of the 139 | Contributor Version) or other devices; or 4) under Patent Claims 140 | infringed by Covered Code in the absence of Modifications made by 141 | that Contributor. 142 | 143 | 3. Distribution Obligations. 144 | 145 | 3.1. Application of License. 146 | The Modifications which You create or to which You contribute are 147 | governed by the terms of this License, including without limitation 148 | Section 2.2. The Source Code version of Covered Code may be 149 | distributed only under the terms of this License or a future version 150 | of this License released under Section 6.1, and You must include a 151 | copy of this License with every copy of the Source Code You 152 | distribute. You may not offer or impose any terms on any Source Code 153 | version that alters or restricts the applicable version of this 154 | License or the recipients' rights hereunder. However, You may include 155 | an additional document offering the additional rights described in 156 | Section 3.5. 157 | 158 | 3.2. Availability of Source Code. 159 | Any Modification which You create or to which You contribute must be 160 | made available in Source Code form under the terms of this License 161 | either on the same media as an Executable version or via an accepted 162 | Electronic Distribution Mechanism to anyone to whom you made an 163 | Executable version available; and if made available via Electronic 164 | Distribution Mechanism, must remain available for at least twelve (12) 165 | months after the date it initially became available, or at least six 166 | (6) months after a subsequent version of that particular Modification 167 | has been made available to such recipients. You are responsible for 168 | ensuring that the Source Code version remains available even if the 169 | Electronic Distribution Mechanism is maintained by a third party. 170 | 171 | 3.3. Description of Modifications. 172 | You must cause all Covered Code to which You contribute to contain a 173 | file documenting the changes You made to create that Covered Code and 174 | the date of any change. You must include a prominent statement that 175 | the Modification is derived, directly or indirectly, from Original 176 | Code provided by the Initial Developer and including the name of the 177 | Initial Developer in (a) the Source Code, and (b) in any notice in an 178 | Executable version or related documentation in which You describe the 179 | origin or ownership of the Covered Code. 180 | 181 | 3.4. Intellectual Property Matters 182 | (a) Third Party Claims. 183 | If Contributor has knowledge that a license under a third party's 184 | intellectual property rights is required to exercise the rights 185 | granted by such Contributor under Sections 2.1 or 2.2, 186 | Contributor must include a text file with the Source Code 187 | distribution titled "LEGAL" which describes the claim and the 188 | party making the claim in sufficient detail that a recipient will 189 | know whom to contact. If Contributor obtains such knowledge after 190 | the Modification is made available as described in Section 3.2, 191 | Contributor shall promptly modify the LEGAL file in all copies 192 | Contributor makes available thereafter and shall take other steps 193 | (such as notifying appropriate mailing lists or newsgroups) 194 | reasonably calculated to inform those who received the Covered 195 | Code that new knowledge has been obtained. 196 | 197 | (b) Contributor APIs. 198 | If Contributor's Modifications include an application programming 199 | interface and Contributor has knowledge of patent licenses which 200 | are reasonably necessary to implement that API, Contributor must 201 | also include this information in the LEGAL file. 202 | 203 | (c) Representations. 204 | Contributor represents that, except as disclosed pursuant to 205 | Section 3.4(a) above, Contributor believes that Contributor's 206 | Modifications are Contributor's original creation(s) and/or 207 | Contributor has sufficient rights to grant the rights conveyed by 208 | this License. 209 | 210 | 3.5. Required Notices. 211 | You must duplicate the notice in Exhibit A in each file of the Source 212 | Code. If it is not possible to put such notice in a particular Source 213 | Code file due to its structure, then You must include such notice in a 214 | location (such as a relevant directory) where a user would be likely 215 | to look for such a notice. If You created one or more Modification(s) 216 | You may add your name as a Contributor to the notice described in 217 | Exhibit A. You must also duplicate this License in any documentation 218 | for the Source Code where You describe recipients' rights or ownership 219 | rights relating to Covered Code. You may choose to offer, and to 220 | charge a fee for, warranty, support, indemnity or liability 221 | obligations to one or more recipients of Covered Code. However, You 222 | may do so only on Your own behalf, and not on behalf of the Initial 223 | Developer or any Contributor. You must make it absolutely clear than 224 | any such warranty, support, indemnity or liability obligation is 225 | offered by You alone, and You hereby agree to indemnify the Initial 226 | Developer and every Contributor for any liability incurred by the 227 | Initial Developer or such Contributor as a result of warranty, 228 | support, indemnity or liability terms You offer. 229 | 230 | 3.6. Distribution of Executable Versions. 231 | You may distribute Covered Code in Executable form only if the 232 | requirements of Section 3.1-3.5 have been met for that Covered Code, 233 | and if You include a notice stating that the Source Code version of 234 | the Covered Code is available under the terms of this License, 235 | including a description of how and where You have fulfilled the 236 | obligations of Section 3.2. The notice must be conspicuously included 237 | in any notice in an Executable version, related documentation or 238 | collateral in which You describe recipients' rights relating to the 239 | Covered Code. You may distribute the Executable version of Covered 240 | Code or ownership rights under a license of Your choice, which may 241 | contain terms different from this License, provided that You are in 242 | compliance with the terms of this License and that the license for the 243 | Executable version does not attempt to limit or alter the recipient's 244 | rights in the Source Code version from the rights set forth in this 245 | License. If You distribute the Executable version under a different 246 | license You must make it absolutely clear that any terms which differ 247 | from this License are offered by You alone, not by the Initial 248 | Developer or any Contributor. You hereby agree to indemnify the 249 | Initial Developer and every Contributor for any liability incurred by 250 | the Initial Developer or such Contributor as a result of any such 251 | terms You offer. 252 | 253 | 3.7. Larger Works. 254 | You may create a Larger Work by combining Covered Code with other code 255 | not governed by the terms of this License and distribute the Larger 256 | Work as a single product. In such a case, You must make sure the 257 | requirements of this License are fulfilled for the Covered Code. 258 | 259 | 4. Inability to Comply Due to Statute or Regulation. 260 | 261 | If it is impossible for You to comply with any of the terms of this 262 | License with respect to some or all of the Covered Code due to 263 | statute, judicial order, or regulation then You must: (a) comply with 264 | the terms of this License to the maximum extent possible; and (b) 265 | describe the limitations and the code they affect. Such description 266 | must be included in the LEGAL file described in Section 3.4 and must 267 | be included with all distributions of the Source Code. Except to the 268 | extent prohibited by statute or regulation, such description must be 269 | sufficiently detailed for a recipient of ordinary skill to be able to 270 | understand it. 271 | 272 | 5. Application of this License. 273 | 274 | This License applies to code to which the Initial Developer has 275 | attached the notice in Exhibit A and to related Covered Code. 276 | 277 | 6. Versions of the License. 278 | 279 | 6.1. New Versions. 280 | Netscape Communications Corporation ("Netscape") may publish revised 281 | and/or new versions of the License from time to time. Each version 282 | will be given a distinguishing version number. 283 | 284 | 6.2. Effect of New Versions. 285 | Once Covered Code has been published under a particular version of the 286 | License, You may always continue to use it under the terms of that 287 | version. You may also choose to use such Covered Code under the terms 288 | of any subsequent version of the License published by Netscape. No one 289 | other than Netscape has the right to modify the terms applicable to 290 | Covered Code created under this License. 291 | 292 | 6.3. Derivative Works. 293 | If You create or use a modified version of this License (which you may 294 | only do in order to apply it to code which is not already Covered Code 295 | governed by this License), You must (a) rename Your license so that 296 | the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape", 297 | "MPL", "NPL" or any confusingly similar phrase do not appear in your 298 | license (except to note that your license differs from this License) 299 | and (b) otherwise make it clear that Your version of the license 300 | contains terms which differ from the Mozilla Public License and 301 | Netscape Public License. (Filling in the name of the Initial 302 | Developer, Original Code or Contributor in the notice described in 303 | Exhibit A shall not of themselves be deemed to be modifications of 304 | this License.) 305 | 306 | 7. DISCLAIMER OF WARRANTY. 307 | 308 | COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, 309 | WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, 310 | WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF 311 | DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. 312 | THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE 313 | IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, 314 | YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE 315 | COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER 316 | OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF 317 | ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. 318 | 319 | 8. TERMINATION. 320 | 321 | 8.1. This License and the rights granted hereunder will terminate 322 | automatically if You fail to comply with terms herein and fail to cure 323 | such breach within 30 days of becoming aware of the breach. All 324 | sublicenses to the Covered Code which are properly granted shall 325 | survive any termination of this License. Provisions which, by their 326 | nature, must remain in effect beyond the termination of this License 327 | shall survive. 328 | 329 | 8.2. If You initiate litigation by asserting a patent infringement 330 | claim (excluding declatory judgment actions) against Initial Developer 331 | or a Contributor (the Initial Developer or Contributor against whom 332 | You file such action is referred to as "Participant") alleging that: 333 | 334 | (a) such Participant's Contributor Version directly or indirectly 335 | infringes any patent, then any and all rights granted by such 336 | Participant to You under Sections 2.1 and/or 2.2 of this License 337 | shall, upon 60 days notice from Participant terminate prospectively, 338 | unless if within 60 days after receipt of notice You either: (i) 339 | agree in writing to pay Participant a mutually agreeable reasonable 340 | royalty for Your past and future use of Modifications made by such 341 | Participant, or (ii) withdraw Your litigation claim with respect to 342 | the Contributor Version against such Participant. If within 60 days 343 | of notice, a reasonable royalty and payment arrangement are not 344 | mutually agreed upon in writing by the parties or the litigation claim 345 | is not withdrawn, the rights granted by Participant to You under 346 | Sections 2.1 and/or 2.2 automatically terminate at the expiration of 347 | the 60 day notice period specified above. 348 | 349 | (b) any software, hardware, or device, other than such Participant's 350 | Contributor Version, directly or indirectly infringes any patent, then 351 | any rights granted to You by such Participant under Sections 2.1(b) 352 | and 2.2(b) are revoked effective as of the date You first made, used, 353 | sold, distributed, or had made, Modifications made by that 354 | Participant. 355 | 356 | 8.3. If You assert a patent infringement claim against Participant 357 | alleging that such Participant's Contributor Version directly or 358 | indirectly infringes any patent where such claim is resolved (such as 359 | by license or settlement) prior to the initiation of patent 360 | infringement litigation, then the reasonable value of the licenses 361 | granted by such Participant under Sections 2.1 or 2.2 shall be taken 362 | into account in determining the amount or value of any payment or 363 | license. 364 | 365 | 8.4. In the event of termination under Sections 8.1 or 8.2 above, 366 | all end user license agreements (excluding distributors and resellers) 367 | which have been validly granted by You or any distributor hereunder 368 | prior to termination shall survive termination. 369 | 370 | 9. LIMITATION OF LIABILITY. 371 | 372 | UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT 373 | (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL 374 | DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE, 375 | OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR 376 | ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY 377 | CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, 378 | WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER 379 | COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN 380 | INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF 381 | LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY 382 | RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW 383 | PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE 384 | EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO 385 | THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. 386 | 387 | 10. U.S. GOVERNMENT END USERS. 388 | 389 | The Covered Code is a "commercial item," as that term is defined in 390 | 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer 391 | software" and "commercial computer software documentation," as such 392 | terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 393 | C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), 394 | all U.S. Government End Users acquire Covered Code with only those 395 | rights set forth herein. 396 | 397 | 11. MISCELLANEOUS. 398 | 399 | This License represents the complete agreement concerning subject 400 | matter hereof. If any provision of this License is held to be 401 | unenforceable, such provision shall be reformed only to the extent 402 | necessary to make it enforceable. This License shall be governed by 403 | California law provisions (except to the extent applicable law, if 404 | any, provides otherwise), excluding its conflict-of-law provisions. 405 | With respect to disputes in which at least one party is a citizen of, 406 | or an entity chartered or registered to do business in the United 407 | States of America, any litigation relating to this License shall be 408 | subject to the jurisdiction of the Federal Courts of the Northern 409 | District of California, with venue lying in Santa Clara County, 410 | California, with the losing party responsible for costs, including 411 | without limitation, court costs and reasonable attorneys' fees and 412 | expenses. The application of the United Nations Convention on 413 | Contracts for the International Sale of Goods is expressly excluded. 414 | Any law or regulation which provides that the language of a contract 415 | shall be construed against the drafter shall not apply to this 416 | License. 417 | 418 | 12. RESPONSIBILITY FOR CLAIMS. 419 | 420 | As between Initial Developer and the Contributors, each party is 421 | responsible for claims and damages arising, directly or indirectly, 422 | out of its utilization of rights under this License and You agree to 423 | work with Initial Developer and Contributors to distribute such 424 | responsibility on an equitable basis. Nothing herein is intended or 425 | shall be deemed to constitute any admission of liability. 426 | 427 | 13. MULTIPLE-LICENSED CODE. 428 | 429 | Initial Developer may designate portions of the Covered Code as 430 | "Multiple-Licensed". "Multiple-Licensed" means that the Initial 431 | Developer permits you to utilize portions of the Covered Code under 432 | Your choice of the NPL or the alternative licenses, if any, specified 433 | by the Initial Developer in the file described in Exhibit A. 434 | 435 | EXHIBIT A -Mozilla Public License. 436 | 437 | ``The contents of this file are subject to the Mozilla Public License 438 | Version 1.1 (the "License"); you may not use this file except in 439 | compliance with the License. You may obtain a copy of the License at 440 | http://www.mozilla.org/MPL/ 441 | 442 | Software distributed under the License is distributed on an "AS IS" 443 | basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the 444 | License for the specific language governing rights and limitations 445 | under the License. 446 | 447 | The Original Code is RabbitMQ Visualiser. 448 | 449 | The Initial Developer of the Original Code is GoPivotal, Inc. 450 | Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved.'' 451 | 452 | [NOTE: The text of this Exhibit A may differ slightly from the text of 453 | the notices in the Source Code files of the Original Code. You should 454 | use the text of this Exhibit A rather than the text found in the 455 | Original Code Source Code for Your Modifications.] 456 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PROJECT = rabbitmq_management_visualiser 2 | PROJECT_DESCRIPTION = RabbitMQ Visualiser 3 | 4 | define PROJECT_APP_EXTRA_KEYS 5 | {broker_version_requirements, []} 6 | endef 7 | 8 | DEPS = rabbit_common rabbit rabbitmq_management 9 | TEST_DEPS = rabbitmq_ct_helpers 10 | 11 | DEP_EARLY_PLUGINS = rabbit_common/mk/rabbitmq-early-plugin.mk 12 | DEP_PLUGINS = rabbit_common/mk/rabbitmq-plugin.mk 13 | 14 | # FIXME: Use erlang.mk patched for RabbitMQ, while waiting for PRs to be 15 | # reviewed and merged. 16 | 17 | ERLANG_MK_REPO = https://github.com/rabbitmq/erlang.mk.git 18 | ERLANG_MK_COMMIT = rabbitmq-tmp 19 | 20 | include rabbitmq-components.mk 21 | include erlang.mk 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RabbitMQ Visualiser 2 | 3 | This experimental plugin that visualizes RabbitMQ topology and message flow. 4 | It is **DEPRECATED** and will not ship with RabbitMQ as of 3.7.0. 5 | 6 | 7 | ## Project Maturity 8 | 9 | This project was an experiment because it is no longer under development. 10 | 11 | ## Usage 12 | 13 | This is a plugin for the RabbitMQ Management Plugin that provides an 14 | HTML Canvas for rendering configured broker topology. The current main 15 | purpose of this is for diagnostics and comprehension of the current 16 | routing topology of the broker. 17 | 18 | The left of the canvas displays exchanges, the right displays queues, 19 | and the top displays channels. All of these items can be dragged 20 | around the canvas. They repel one another, and snap back into their 21 | predefined areas should they be released within the boundaries of those 22 | areas. 23 | 24 | Shift-clicking on an item hides it - it will be added to the relevant 25 | select box on the left. 26 | 27 | Hovering over an item shows at the top of the screen various details 28 | about the item. Double-clicking on the item will take you to the 29 | specific page in the Management Plugin concerning that item. 30 | 31 | When hovering over an item, incoming links and/or traffic are shown in 32 | green, whilst outgoing links and/or traffic are shown in 33 | blue. Bindings are always displayed, but the consumers of a queue, and 34 | likewise the publishers to an exchange, are only drawn in when 35 | hovering over the exchange, queue or channel in question. 36 | 37 | By default, up to 10 exchanges, 10 queues and 10 channels are 38 | displayed. Additional resources are available from the left hand-side 39 | select boxes, and can be brought into the display by selecting them 40 | and clicking on the relevant 'Show' button. 41 | 42 | The 'Display' check-boxes turn off and on entire resource classes, and 43 | resets positioning. 44 | -------------------------------------------------------------------------------- /license_info: -------------------------------------------------------------------------------- 1 | glMatrix is "Copyright (c) 2011, Brandon Jones" and is covered by the 2 | BSD 2-Clause license. It was downloaded from 3 | http://code.google.com/p/glmatrix/ 4 | 5 | -------------------------------------------------------------------------------- /priv/www/js/tmpl/visualiser.ejs: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | 6 | 7 | 8 | 72 |
73 |
74 | 75 |
Vhost:
76 | 77 | 83 | 84 | 90 | 91 | 97 | 98 | 104 |
105 |
106 |
107 |
Help
108 |
109 | 110 |
111 |
112 |

RabbitMQ Visualiser

113 | 114 |

Click to hide.

115 | 116 |

117 | The left of the canvas displays exchanges, the right displays 118 | queues, and the top displays channels. All of these items can 119 | be dragged around the canvas. They repel one another, and snap 120 | back into their predefined areas should they be released within 121 | the boundaries of those areas. 122 |

123 | 124 |

125 | Shift-clicking on an item hides it - it will be added to the 126 | relevant select box on the left. 127 |

128 | 129 |

130 | Hovering over an item shows at the top of the screen various 131 | details about the item. Double-clicking on the item will take 132 | you to the specific page in the Management Plugin concerning 133 | that item. 134 |

135 | 136 |

137 | When hovering over an item, incoming links and/or traffic are 138 | shown in green, whilst outgoing links and/or traffic are shown 139 | in blue. Bindings are always displayed, but the consumers of a 140 | queue, and likewise the publishers to an exchange, are only 141 | drawn in when hovering over the exchange, queue or channel in 142 | question. 143 |

144 | 145 |

146 | By default, up to 10 exchanges, 10 queues and 10 channels are 147 | displayed. Additional resources are available from the left 148 | hand-side select boxes, and can be brought into the display by 149 | selecting them and clicking on the relevant 'Show' button. 150 |

151 | 152 |

153 | The 'Display' check-boxes turn off and on entire resource 154 | classes, and resets positioning. 155 |

156 | 157 |

Click to hide.

158 |
159 |
-------------------------------------------------------------------------------- /priv/www/js/visualiser.js: -------------------------------------------------------------------------------- 1 | var visualiser; 2 | 3 | NAVIGATION['Visualiser'] = ['#/visualiser', "management"]; 4 | 5 | dispatcher_add(function(sammy) { 6 | sammy.get('#/visualiser', function() { 7 | render({}, 'visualiser', '#/visualiser'); 8 | visualiser = new Visualiser(); 9 | visualiser.visualisationStart(); 10 | }); 11 | }); 12 | 13 | 14 | function Visualiser() { 15 | /*global octtree, vec3, Model, Channel, Exchange, Queue, Binding, Newton, Spring, window */ 16 | /*jslint browser: true, devel: true */ 17 | 18 | var tree = octtree.create(0, 10000, 0, 1000000, -0.5, 2); 19 | 20 | var configuration, detailsInFlight, mouseDragOffsetVec, hoveringOver, dragging, selectedVhost, ctx, canvas, tick, mouseMove, setCanvasMousemove, requestAnimFrame; 21 | 22 | var detailsClient = new XMLHttpRequest(); 23 | 24 | var model = new Model(); 25 | var mousePos = vec3.create(); 26 | var mouseDown = false; 27 | var highlight = "#ffffc0"; 28 | var faded = "#c0c0c0"; 29 | 30 | var eta = 0.1; 31 | var max_v = 100000; 32 | 33 | var newton = new Newton(); 34 | var spring = new Spring(); 35 | spring.octtreeRadius = 500; 36 | spring.equilibriumLength = 50; 37 | spring.dampingFactor = 0.01; 38 | spring.pull = false; 39 | spring.push = true; 40 | 41 | var rendering = true; 42 | var lastTime = 0; 43 | 44 | var fontSize = 12; 45 | Exchange.prototype.fontSize = fontSize; 46 | Queue.prototype.fontSize = fontSize; 47 | Binding.prototype.fontSize = fontSize; 48 | var canvasLeft = 0; 49 | var canvasTop = 0; 50 | var scrollLeft = 0; 51 | var scrollTop = 0; 52 | var clientWidth = 0; 53 | var clientHeight = 0; 54 | 55 | var details_timeout = null; 56 | var update_timeout = null; 57 | 58 | 59 | /****************************************************************************** 60 | * Fetching details from the broker * 61 | ******************************************************************************/ 62 | 63 | function update() { 64 | if($('#visualiser').length == 0) { 65 | visualiser.disableRendering(); 66 | return; 67 | } 68 | clear_update_timeout(); 69 | if (undefined === selectedVhost) { 70 | with_req("GET", "/all", "", updateReady); 71 | } else { 72 | with_req("GET", "/all/" + encodeURIComponent(selectedVhost), "", updateReady); 73 | } 74 | } 75 | 76 | function updateReady(resp) { 77 | var configuration = jQuery.parseJSON(resp.responseText); 78 | if(undefined === selectedVhost) { 79 | if(undefined !== configuration.vhosts[0]){ 80 | selectedVhost = configuration.vhosts[0].name; 81 | update(); 82 | return; 83 | } 84 | } 85 | model.rebuild(tree, configuration); 86 | set_update_timeout(); 87 | if (!rendering) { 88 | lastTime = 0; 89 | requestAnimFrame(tick); 90 | } 91 | } 92 | 93 | function set_update_timeout(){ 94 | if (timer_interval != null) { 95 | update_timeout = setTimeout(update, timer_interval); 96 | } 97 | } 98 | 99 | function clear_update_timeout() { 100 | if(update_timeout){ 101 | clearTimeout(update_timeout); 102 | } 103 | } 104 | 105 | Channel.prototype.getDetails = getDetails; 106 | Exchange.prototype.getDetails = getDetails; 107 | Queue.prototype.getDetails = getDetails; 108 | 109 | function repeatGetDetails() { 110 | if (undefined !== hoveringOver) { 111 | hoveringOver.getDetails(); 112 | } 113 | } 114 | 115 | function flattenAtts(a) { 116 | if ("string" === typeof a) { 117 | return a; 118 | } else { 119 | var str, e; 120 | str = "{"; 121 | for (e in a) { 122 | if (a.hasOwnProperty(e)) { 123 | str += "" + e + ": " + flattenAtts(a[e]) + ", "; 124 | } 125 | } 126 | return str.replace(/(, )?$/, "}"); 127 | } 128 | } 129 | 130 | function setDetails(elem) { 131 | var details, strAtts, visibleRows, columns, column, str, attName, i; 132 | details = document.getElementById("details"); 133 | if(details != null) { 134 | if (undefined === elem) { 135 | details.innerHTML = ""; 136 | detailsInFlight = undefined; 137 | } else { 138 | strAtts = elem.stringAttributes(); 139 | visibleRows = Math.floor(details.clientHeight / 16); // line-height + padding; 140 | columns = Math.ceil(strAtts.attributeOrder.length / visibleRows); 141 | column = 0; 142 | str = ""; 143 | for (i in strAtts.attributeOrder) { 144 | column += 1; 145 | attName = strAtts.attributeOrder[i]; 146 | if (undefined !== strAtts[attName]) { 147 | str += ""; 148 | } else { 149 | str += ""; 150 | } 151 | if (column === columns) { 152 | column = 0; 153 | str += ""; 154 | } 155 | } 156 | str += "
" + attName + "" + flattenAtts(strAtts[attName]) + "" + attName + "
"; 157 | document.getElementById("details").innerHTML = str; 158 | } 159 | } 160 | } 161 | 162 | function getDetails() { 163 | clear_details_timeout(); 164 | detailsInFlight = this; 165 | with_req("GET", this.url(), "", detailsUpdateReady); 166 | } 167 | 168 | function detailsUpdateReady(resp) { 169 | if (undefined !== hoveringOver && 170 | undefined !== detailsInFlight && 171 | hoveringOver.object_type === detailsInFlight.object_type && 172 | hoveringOver.name === detailsInFlight.name) { 173 | try { 174 | var details = JSON.parse(resp.responseText); 175 | if (undefined !== details.name && 176 | details.name === detailsInFlight.name) { 177 | model[detailsInFlight.object_type][detailsInFlight.name].details = details; 178 | setDetails(model[detailsInFlight.object_type][detailsInFlight.name]); 179 | set_details_update_timeout(); 180 | } 181 | } catch (err) { 182 | // We probably cancelled it as we were receiving data. 183 | model[detailsInFlight.object_type][detailsInFlight.name].details = undefined; 184 | window.console.info("" + err); 185 | } 186 | } 187 | } 188 | 189 | function set_details_update_timeout() { 190 | if (timer_interval != null) { 191 | details_timeout = setTimeout(repeatGetDetails, timer_interval); 192 | } 193 | } 194 | 195 | function clear_details_timeout() { 196 | if(details_timeout){ 197 | clearTimeout(details_timeout); 198 | } 199 | } 200 | 201 | 202 | /****************************************************************************** 203 | * Rendering / animation * 204 | ******************************************************************************/ 205 | 206 | requestAnimFrame = (function () { 207 | return (this.requestAnimationFrame || 208 | this.webkitRequestAnimationFrame || 209 | this.mozRequestAnimationFrame || 210 | this.oRequestAnimationFrame || 211 | this.msRequestAnimationFrame || 212 | function (/* function FrameRequestCallback */ callback, /* DOMElement Element */ element) { 213 | setTimeout(callback, 1000 / 60); 214 | }); 215 | })(); 216 | 217 | function recordMousePos(e) { 218 | var x, y; 219 | x = e.pageX; 220 | y = e.pageY; 221 | x = (x - canvasLeft) + scrollLeft; 222 | y = (y - canvasTop) + scrollTop; 223 | mousePos[octtree.x] = x; 224 | mousePos[octtree.y] = y; 225 | } 226 | 227 | mouseMove = function (e) { 228 | recordMousePos(e); 229 | canvas.onmousemove = undefined; 230 | setTimeout(setCanvasMousemove, 10); 231 | }; 232 | 233 | setCanvasMousemove = function () { 234 | if (rendering) { 235 | canvas.onmousemove = mouseMove; 236 | } 237 | }; 238 | var resizeCanvas = function() { 239 | var e; 240 | if (undefined !== canvas) { 241 | canvas.width = canvas.parentNode.offsetWidth; 242 | canvas.height = canvas.parentNode.offsetHeight; 243 | Channel.prototype.canvasResized(canvas); 244 | Exchange.prototype.canvasResized(canvas); 245 | Queue.prototype.canvasResized(canvas); 246 | clientWidth = canvas.width; 247 | clientHeight = canvas.height; 248 | e = canvas.parentNode; 249 | while (undefined !== e && null !== e) { 250 | if (undefined !== e.clientHeight && undefined !== e.clientWidth && 251 | e.clientHeight > 0 && e.clientWidth > 0) { 252 | clientHeight = Math.min(clientHeight, e.clientHeight); 253 | clientWidth = Math.min(clientWidth, e.clientWidth); 254 | } 255 | e = e.parentNode; 256 | } 257 | canvasLeft = 0; 258 | canvasTop = 0; 259 | canvasTop = canvas.offsetTop; 260 | canvasLeft = canvas.offsetLeft; 261 | // e = canvas.parentNode; 262 | // while (undefined !== e && null !== e) { 263 | // if (undefined !== e.offsetLeft && undefined !== e.offsetTop) { 264 | // canvasLeft += e.offsetLeft; 265 | // canvasTop += e.offsetTop; 266 | // } 267 | // e = e.parentNode; 268 | // } 269 | if (undefined !== hoveringOver && undefined !== hoveringOver.details) { 270 | setDetails(hoveringOver); 271 | } 272 | } 273 | } 274 | 275 | this.resizeCanvas = resizeCanvas; 276 | 277 | this.canvasScroll = function() { 278 | scrollLeft = 0; 279 | scrollTop = 0; 280 | var e = canvas.parentNode; 281 | while (undefined !== e && null !== e) { 282 | if (undefined !== e.scrollLeft && undefined !== e.scrollTop) { 283 | scrollLeft += e.scrollLeft; 284 | scrollTop += e.scrollTop; 285 | } 286 | e = e.parentNode; 287 | } 288 | } 289 | 290 | function clamp(elem) { 291 | var x_vel_abs, y_vel_abs; 292 | x_vel_abs = Math.abs(elem.velocity[octtree.x]); 293 | y_vel_abs = Math.abs(elem.velocity[octtree.y]); 294 | if (0 !== x_vel_abs && eta > x_vel_abs) { 295 | elem.velocity[octtree.x] = 0; 296 | } else if (max_v < x_vel_abs) { 297 | elem.velocity[octtree.x] = max_v * (x_vel_abs / elem.velocity[octtree.x]); 298 | } 299 | if (0 !== y_vel_abs && eta > y_vel_abs) { 300 | elem.velocity[octtree.y] = 0; 301 | } else if (max_v < y_vel_abs) { 302 | elem.velocity[octtree.y] = max_v * (y_vel_abs / elem.velocity[octtree.y]); 303 | } 304 | if (elem.next_pos[octtree.x] < 1) { 305 | elem.next_pos[octtree.x] = 1; 306 | elem.velocity[octtree.x] = 0; 307 | } 308 | if (elem.next_pos[octtree.y] < 1) { 309 | elem.next_pos[octtree.y] = 1; 310 | elem.velocity[octtree.y] = 0; 311 | } 312 | if (elem.next_pos[octtree.x] >= canvas.width) { 313 | elem.next_pos[octtree.x] = canvas.width - 1; 314 | } 315 | if (elem.next_pos[octtree.y] >= (canvas.height - 100)) { 316 | canvas.height += 100; 317 | resizeCanvas(); 318 | } 319 | } 320 | 321 | function initCanvas() { 322 | resizeCanvas(); 323 | setCanvasMousemove(); 324 | canvas.onmousedown = function (e) { 325 | recordMousePos(e); 326 | if (e.shiftKey && undefined !== hoveringOver) { 327 | model.disable(hoveringOver, tree); 328 | mouseDown = false; 329 | hoveringOver = undefined; 330 | dragging = undefined; 331 | } else { 332 | mouseDown = true; 333 | mouseDragOffsetVec = undefined; 334 | } 335 | }; 336 | canvas.ondblclick = function (e) { 337 | recordMousePos(e); 338 | if (undefined !== hoveringOver) { 339 | hoveringOver.navigateTo(); 340 | } 341 | }; 342 | canvas.onmouseup = function (e) { 343 | recordMousePos(e); 344 | mouseDown = false; 345 | mouseDragOffsetVec = undefined; 346 | dragging = undefined; 347 | }; 348 | try { 349 | ctx = canvas.getContext("2d"); 350 | } catch (e) { 351 | } 352 | if (!ctx) { 353 | alert("Could not initialise 2D canvas. Change browser?"); 354 | } 355 | } 356 | 357 | function drawScene() { 358 | ctx.font = "" + fontSize + "px sans-serif"; 359 | ctx.clearRect(scrollLeft, scrollTop, clientWidth, clientHeight); 360 | ctx.lineWidth = 1.0; 361 | ctx.lineCap = "round"; 362 | ctx.lineJoin = "round"; 363 | ctx.strokeStyle = "black"; 364 | model.render(ctx); 365 | } 366 | 367 | function animate() { 368 | var timeNow, elapsed, e, i; 369 | timeNow = new Date().getTime(); 370 | if (lastTime !== 0) { 371 | elapsed = (timeNow - lastTime) / 10000; 372 | for (i in model.exchange) { 373 | e = model.exchange[i]; 374 | if ((undefined === dragging || dragging !== e) && ! e.disabled) { 375 | e.animate(elapsed); 376 | newton.update(elapsed, e); 377 | spring.update(elapsed, tree, e); 378 | clamp(e); 379 | } 380 | } 381 | for (i in model.channel) { 382 | e = model.channel[i]; 383 | if ((undefined === dragging || dragging !== e) && ! e.disabled) { 384 | e.animate(elapsed); 385 | newton.update(elapsed, e); 386 | spring.update(elapsed, tree, e); 387 | clamp(e); 388 | } 389 | } 390 | for (i in model.queue) { 391 | e = model.queue[i]; 392 | if ((undefined === dragging || dragging !== e) && ! e.disabled) { 393 | e.animate(elapsed); 394 | newton.update(elapsed, e); 395 | spring.update(elapsed, tree, e); 396 | clamp(e); 397 | } 398 | } 399 | tree.update(); 400 | } 401 | lastTime = timeNow; 402 | } 403 | 404 | tick = function () { 405 | drawScene(); 406 | animate(); 407 | if (rendering) { 408 | requestAnimFrame(tick); 409 | } 410 | }; 411 | 412 | this.visualisationStart = function() { 413 | canvas = document.getElementById("topology_canvas"); 414 | initCanvas(); 415 | update(); 416 | this.enableRendering(); 417 | // requestAnimFrame(tick); 418 | } 419 | 420 | // Used to start/stop doing work when we gain/lose focus 421 | this.enableRendering = function() { 422 | $('#update-every').change(function() { 423 | if(rendering == true){ 424 | if (timer_interval != null) { 425 | update(); 426 | } 427 | } 428 | }); 429 | lastTime = 0; 430 | rendering = true; 431 | setCanvasMousemove(); 432 | requestAnimFrame(tick); 433 | } 434 | 435 | this.disableRendering = function() { 436 | clear_update_timeout(); 437 | clear_details_timeout(); 438 | canvas.onmousemove = undefined; 439 | rendering = false; 440 | } 441 | 442 | 443 | /****************************************************************************** 444 | * Model callbacks for rendering * 445 | ******************************************************************************/ 446 | 447 | function draggable(model, ctx) { 448 | var inPath = ctx.isPointInPath(mousePos[octtree.x], mousePos[octtree.y]); 449 | if ((inPath && undefined === hoveringOver) || dragging === this || hoveringOver === this) { 450 | ctx.fillStyle = highlight; 451 | ctx.fill(); 452 | 453 | if (hoveringOver !== this) { 454 | this.getDetails(); 455 | } 456 | 457 | hoveringOver = this; 458 | if (mouseDown) { 459 | dragging = this; 460 | if (undefined === mouseDragOffsetVec) { 461 | mouseDragOffsetVec = vec3.create(this.pos); 462 | vec3.subtract(mouseDragOffsetVec, mousePos); 463 | } 464 | vec3.set(mousePos, this.next_pos); 465 | vec3.add(this.next_pos, mouseDragOffsetVec); 466 | this.velocity = vec3.create(); 467 | clamp(this); 468 | } else if (!inPath) { 469 | if (undefined !== hoveringOver) { 470 | hoveringOver.details = undefined; 471 | } 472 | if (detailsInFlight === this) { 473 | setDetails(undefined); 474 | } 475 | dragging = undefined; 476 | hoveringOver = undefined; 477 | mouseDragOffsetVec = undefined; 478 | } 479 | } else { 480 | ctx.fillStyle = "white"; 481 | ctx.fill(); 482 | } 483 | if (undefined !== hoveringOver && hoveringOver !== this && ! model.isHighlighted(this)) { 484 | ctx.strokeStyle = faded; 485 | } 486 | ctx.stroke(); 487 | } 488 | 489 | Channel.prototype.preStroke = draggable; 490 | Exchange.prototype.preStroke = draggable; 491 | Queue.prototype.preStroke = draggable; 492 | 493 | Binding.prototype.preStroke = function (source, destination, model, ctx) { 494 | var drawBindingKeys, xMid, yMid, bindingKey, k, dim; 495 | drawBindingKeys = false; 496 | if (undefined === hoveringOver) { 497 | drawBindingKeys = ctx.isPointInPath(mousePos[octtree.x], mousePos[octtree.y]); 498 | } else { 499 | if (hoveringOver === source) { 500 | ctx.strokeStyle = "#0000a0"; 501 | drawBindingKeys = true; 502 | } else if (hoveringOver === destination) { 503 | ctx.strokeStyle = "#00a000"; 504 | drawBindingKeys = true; 505 | } else { 506 | ctx.strokeStyle = faded; 507 | } 508 | } 509 | ctx.stroke(); 510 | 511 | if (drawBindingKeys) { 512 | xMid = (source.xMax + destination.xMin) / 2; 513 | yMid = source === destination ? source.pos[octtree.y] - this.loopOffset + fontSize 514 | : (source.pos[octtree.y] + destination.pos[octtree.y]) / 2; 515 | bindingKey = ""; 516 | for (k in this.keys) { 517 | bindingKey += ", " + k; 518 | } 519 | bindingKey = bindingKey.slice(2); 520 | dim = ctx.measureText(bindingKey); 521 | 522 | ctx.textBaseline = "middle"; 523 | ctx.textAlign = "center"; 524 | ctx.fillStyle = "rgba(255, 255, 255, 0.67)"; 525 | ctx.fillRect(xMid - (dim.width / 2), yMid - (this.fontSize / 2), 526 | dim.width, this.fontSize); 527 | ctx.fillStyle = ctx.strokeStyle; 528 | ctx.fillText(bindingKey, xMid, yMid); 529 | } 530 | }; 531 | 532 | function frustumCull(xMin, yMin, width, height) { 533 | return ((yMin > (scrollTop + clientHeight)) || 534 | ((yMin + height) < scrollTop) || 535 | (xMin > (scrollLeft + clientWidth)) || 536 | ((xMin + width) < scrollLeft)); 537 | } 538 | Model.prototype.cull = frustumCull; 539 | 540 | 541 | /****************************************************************************** 542 | * Showing / hiding / removing resources * 543 | ******************************************************************************/ 544 | 545 | function selectInsertAlphabetical(selectElem, optionElem) { 546 | var preceding, i; 547 | for (i = 0; i < selectElem.options.length; i += 1) { 548 | if (optionElem.text < selectElem.options[i].text) { 549 | preceding = selectElem.options[i]; 550 | break; 551 | } 552 | } 553 | selectElem.add(optionElem, preceding); 554 | return selectElem.options; 555 | } 556 | 557 | function show(hiddenElemId, model, type) { 558 | var i, e, hidden; 559 | if (model.rendering[type].enabled) { 560 | hidden = document.getElementById(hiddenElemId); 561 | for (i = 0; i < hidden.options.length; i += 1) { 562 | e = hidden.options[i]; 563 | if (e.selected) { 564 | model.enable(model[type][e.value], tree); 565 | hidden.remove(i); 566 | i -= 1; 567 | } 568 | } 569 | } 570 | } 571 | 572 | this.showChannels = function() { 573 | show("hidden_channels", model, 'channel'); 574 | } 575 | 576 | this.showExchanges = function() { 577 | show("hidden_exchanges", model, 'exchange'); 578 | } 579 | 580 | this.showQueues = function() { 581 | show("hidden_queues", model, 'queue'); 582 | } 583 | 584 | // Called when the resource is enabled from being hidden 585 | function enable_fun(type, postFun) { 586 | return function (model, tree) { 587 | if (model.rendering[type].enabled) { 588 | delete model.rendering[type].on_enable[this.name]; 589 | } 590 | this.remove = Object.getPrototypeOf(this).remove; 591 | this.postFun = postFun; 592 | this.postFun(model, tree); 593 | }; 594 | } 595 | 596 | Channel.prototype.enable = enable_fun('channel', Channel.prototype.enable); 597 | Exchange.prototype.enable = enable_fun('exchange', Exchange.prototype.enable); 598 | Queue.prototype.enable = enable_fun('queue', Queue.prototype.enable); 599 | 600 | 601 | // Called when the item is removed and the item is disabled 602 | function remove_disabled_fun(hiddenElemId, postFun) { 603 | return function (tree, model) { 604 | var hidden, i; 605 | hidden = document.getElementById(hiddenElemId); 606 | for (i = 0; i < hidden.options.length; i += 1) { 607 | if (hidden.options[i].value === this.name) { 608 | hidden.remove(i); 609 | break; 610 | } 611 | } 612 | model.enable(this, tree); 613 | this.postFun = postFun; 614 | this.postFun(tree, model); 615 | }; 616 | } 617 | 618 | function disable_fun(hiddenElemId, type, postFun) { 619 | return function (model) { 620 | if (detailsInFlight === this) { 621 | setDetails(undefined); 622 | } 623 | var optionElem = document.createElement('option'); 624 | optionElem.text = '"' + this.name + '"'; 625 | if (undefined !== model.rendering[type].on_enable[this.name]) { 626 | optionElem.text += ' *'; 627 | } 628 | optionElem.value = this.name; 629 | selectInsertAlphabetical(document.getElementById(hiddenElemId), optionElem); 630 | this.remove = remove_disabled_fun(hiddenElemId, this.remove); 631 | this.postFun = postFun; 632 | this.postFun(model); 633 | }; 634 | } 635 | 636 | Channel.prototype.disable = 637 | disable_fun("hidden_channels", 'channel', Channel.prototype.disable); 638 | Exchange.prototype.disable = 639 | disable_fun("hidden_exchanges", 'exchange', Exchange.prototype.disable); 640 | Queue.prototype.disable = 641 | disable_fun("hidden_queues", 'queue', Queue.prototype.disable); 642 | 643 | // Called when the resource is deleted / vanishes on the broker 644 | function remove_fun(postFun, type) { 645 | return function (tree, model) { 646 | if (undefined !== hoveringOver && this === hoveringOver) { 647 | hoveringOver = undefined; 648 | dragging = undefined; 649 | } 650 | delete model.rendering[type].on_enable[this.name]; 651 | if (this === detailsInFlight) { 652 | setDetails(undefined); 653 | } 654 | this.postFun = postFun; 655 | this.postFun(tree, model); 656 | }; 657 | } 658 | 659 | Channel.prototype.remove = remove_fun(Channel.prototype.remove, 'channel'); 660 | Queue.prototype.remove = remove_fun(Queue.prototype.remove, 'queue'); 661 | Exchange.prototype.remove = remove_fun(Exchange.prototype.remove, 'exchange'); 662 | 663 | this.toggleRendering = function(hiddenElemId, showButtonElemId, type) { 664 | var hidden, i, e; 665 | model.rendering[type].enabled = !model.rendering[type].enabled; 666 | if (model.rendering[type].enabled) { 667 | hidden = document.getElementById(hiddenElemId); 668 | for (i = 0; i < hidden.options.length; i += 1) { 669 | e = hidden.options[i].value; 670 | if (undefined !== model.rendering[type].on_enable[e]) { 671 | model.enable(model[type][e], tree); 672 | hidden.remove(i); 673 | i -= 1; 674 | } 675 | } 676 | document.getElementById(showButtonElemId).disabled = false; 677 | } else { 678 | for (i in model[type]) { 679 | if (! model[type][i].disabled) { 680 | model.rendering[type].on_enable[model[type][i].name] = true; 681 | model.disable(model[type][i], tree); 682 | } 683 | } 684 | document.getElementById(showButtonElemId).disabled = true; 685 | } 686 | return true; 687 | } 688 | 689 | this.displayHelp = function() { 690 | document.getElementById('help').style.display = 'block'; 691 | } 692 | 693 | this.hideHelp = function() { 694 | document.getElementById('help').style.display = 'none'; 695 | } 696 | 697 | 698 | /****************************************************************************** 699 | * VHost * 700 | ******************************************************************************/ 701 | 702 | Model.prototype.vhost_add = function (vhost) { 703 | var optionElem, options; 704 | optionElem = document.createElement('option'); 705 | optionElem.text = vhost.name; 706 | optionElem.value = vhost.name; 707 | options = 708 | selectInsertAlphabetical(document.getElementById('vhosts'), optionElem); 709 | if (options.length === 1) { 710 | selectedVhost = options[0].value; 711 | options[0].selected = true; 712 | } 713 | }; 714 | 715 | Model.prototype.vhost_remove = function (vhost) { 716 | var elem, i; 717 | elem = document.getElementById('vhosts'); 718 | for (i = 0; i < elem.options.length; i += 1) { 719 | if (elem.options[i].value === vhost.name) { 720 | elem.remove(i); 721 | break; 722 | } 723 | } 724 | }; 725 | 726 | this.vhostChanged = function() { 727 | var elem, i, e, j; 728 | elem = document.getElementById('vhosts'); 729 | for (i = 0; i < elem.options.length; i += 1) { 730 | if (elem.options[i].selected && selectedVhost !== elem.options[i].value) { 731 | selectedVhost = elem.options[i].value; 732 | for (e in ['channel', 'exchange', 'queue']) { 733 | for (j in model[e]) { 734 | model[e][j].remove(tree, model); 735 | } 736 | } 737 | break; 738 | } 739 | } 740 | update(); 741 | } 742 | } -------------------------------------------------------------------------------- /priv/www/visualiser/js/glMatrix-min.js: -------------------------------------------------------------------------------- 1 | // glMatrix v0.9.5 2 | glMatrixArrayType=typeof Float32Array!="undefined"?Float32Array:typeof WebGLFloatArray!="undefined"?WebGLFloatArray:Array;var vec3={};vec3.create=function(a){var b=new glMatrixArrayType(3);if(a){b[0]=a[0];b[1]=a[1];b[2]=a[2]}return b};vec3.set=function(a,b){b[0]=a[0];b[1]=a[1];b[2]=a[2];return b};vec3.add=function(a,b,c){if(!c||a==c){a[0]+=b[0];a[1]+=b[1];a[2]+=b[2];return a}c[0]=a[0]+b[0];c[1]=a[1]+b[1];c[2]=a[2]+b[2];return c}; 3 | vec3.subtract=function(a,b,c){if(!c||a==c){a[0]-=b[0];a[1]-=b[1];a[2]-=b[2];return a}c[0]=a[0]-b[0];c[1]=a[1]-b[1];c[2]=a[2]-b[2];return c};vec3.negate=function(a,b){b||(b=a);b[0]=-a[0];b[1]=-a[1];b[2]=-a[2];return b};vec3.scale=function(a,b,c){if(!c||a==c){a[0]*=b;a[1]*=b;a[2]*=b;return a}c[0]=a[0]*b;c[1]=a[1]*b;c[2]=a[2]*b;return c}; 4 | vec3.normalize=function(a,b){b||(b=a);var c=a[0],d=a[1],e=a[2],g=Math.sqrt(c*c+d*d+e*e);if(g){if(g==1){b[0]=c;b[1]=d;b[2]=e;return b}}else{b[0]=0;b[1]=0;b[2]=0;return b}g=1/g;b[0]=c*g;b[1]=d*g;b[2]=e*g;return b};vec3.cross=function(a,b,c){c||(c=a);var d=a[0],e=a[1];a=a[2];var g=b[0],f=b[1];b=b[2];c[0]=e*b-a*f;c[1]=a*g-d*b;c[2]=d*f-e*g;return c};vec3.length=function(a){var b=a[0],c=a[1];a=a[2];return Math.sqrt(b*b+c*c+a*a)};vec3.dot=function(a,b){return a[0]*b[0]+a[1]*b[1]+a[2]*b[2]}; 5 | vec3.direction=function(a,b,c){c||(c=a);var d=a[0]-b[0],e=a[1]-b[1];a=a[2]-b[2];b=Math.sqrt(d*d+e*e+a*a);if(!b){c[0]=0;c[1]=0;c[2]=0;return c}b=1/b;c[0]=d*b;c[1]=e*b;c[2]=a*b;return c};vec3.lerp=function(a,b,c,d){d||(d=a);d[0]=a[0]+c*(b[0]-a[0]);d[1]=a[1]+c*(b[1]-a[1]);d[2]=a[2]+c*(b[2]-a[2]);return d};vec3.str=function(a){return"["+a[0]+", "+a[1]+", "+a[2]+"]"};var mat3={}; 6 | mat3.create=function(a){var b=new glMatrixArrayType(9);if(a){b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3];b[4]=a[4];b[5]=a[5];b[6]=a[6];b[7]=a[7];b[8]=a[8];b[9]=a[9]}return b};mat3.set=function(a,b){b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3];b[4]=a[4];b[5]=a[5];b[6]=a[6];b[7]=a[7];b[8]=a[8];return b};mat3.identity=function(a){a[0]=1;a[1]=0;a[2]=0;a[3]=0;a[4]=1;a[5]=0;a[6]=0;a[7]=0;a[8]=1;return a}; 7 | mat3.transpose=function(a,b){if(!b||a==b){var c=a[1],d=a[2],e=a[5];a[1]=a[3];a[2]=a[6];a[3]=c;a[5]=a[7];a[6]=d;a[7]=e;return a}b[0]=a[0];b[1]=a[3];b[2]=a[6];b[3]=a[1];b[4]=a[4];b[5]=a[7];b[6]=a[2];b[7]=a[5];b[8]=a[8];return b};mat3.toMat4=function(a,b){b||(b=mat4.create());b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=0;b[4]=a[3];b[5]=a[4];b[6]=a[5];b[7]=0;b[8]=a[6];b[9]=a[7];b[10]=a[8];b[11]=0;b[12]=0;b[13]=0;b[14]=0;b[15]=1;return b}; 8 | mat3.str=function(a){return"["+a[0]+", "+a[1]+", "+a[2]+", "+a[3]+", "+a[4]+", "+a[5]+", "+a[6]+", "+a[7]+", "+a[8]+"]"};var mat4={};mat4.create=function(a){var b=new glMatrixArrayType(16);if(a){b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3];b[4]=a[4];b[5]=a[5];b[6]=a[6];b[7]=a[7];b[8]=a[8];b[9]=a[9];b[10]=a[10];b[11]=a[11];b[12]=a[12];b[13]=a[13];b[14]=a[14];b[15]=a[15]}return b}; 9 | mat4.set=function(a,b){b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3];b[4]=a[4];b[5]=a[5];b[6]=a[6];b[7]=a[7];b[8]=a[8];b[9]=a[9];b[10]=a[10];b[11]=a[11];b[12]=a[12];b[13]=a[13];b[14]=a[14];b[15]=a[15];return b};mat4.identity=function(a){a[0]=1;a[1]=0;a[2]=0;a[3]=0;a[4]=0;a[5]=1;a[6]=0;a[7]=0;a[8]=0;a[9]=0;a[10]=1;a[11]=0;a[12]=0;a[13]=0;a[14]=0;a[15]=1;return a}; 10 | mat4.transpose=function(a,b){if(!b||a==b){var c=a[1],d=a[2],e=a[3],g=a[6],f=a[7],h=a[11];a[1]=a[4];a[2]=a[8];a[3]=a[12];a[4]=c;a[6]=a[9];a[7]=a[13];a[8]=d;a[9]=g;a[11]=a[14];a[12]=e;a[13]=f;a[14]=h;return a}b[0]=a[0];b[1]=a[4];b[2]=a[8];b[3]=a[12];b[4]=a[1];b[5]=a[5];b[6]=a[9];b[7]=a[13];b[8]=a[2];b[9]=a[6];b[10]=a[10];b[11]=a[14];b[12]=a[3];b[13]=a[7];b[14]=a[11];b[15]=a[15];return b}; 11 | mat4.determinant=function(a){var b=a[0],c=a[1],d=a[2],e=a[3],g=a[4],f=a[5],h=a[6],i=a[7],j=a[8],k=a[9],l=a[10],o=a[11],m=a[12],n=a[13],p=a[14];a=a[15];return m*k*h*e-j*n*h*e-m*f*l*e+g*n*l*e+j*f*p*e-g*k*p*e-m*k*d*i+j*n*d*i+m*c*l*i-b*n*l*i-j*c*p*i+b*k*p*i+m*f*d*o-g*n*d*o-m*c*h*o+b*n*h*o+g*c*p*o-b*f*p*o-j*f*d*a+g*k*d*a+j*c*h*a-b*k*h*a-g*c*l*a+b*f*l*a}; 12 | mat4.inverse=function(a,b){b||(b=a);var c=a[0],d=a[1],e=a[2],g=a[3],f=a[4],h=a[5],i=a[6],j=a[7],k=a[8],l=a[9],o=a[10],m=a[11],n=a[12],p=a[13],r=a[14],s=a[15],A=c*h-d*f,B=c*i-e*f,t=c*j-g*f,u=d*i-e*h,v=d*j-g*h,w=e*j-g*i,x=k*p-l*n,y=k*r-o*n,z=k*s-m*n,C=l*r-o*p,D=l*s-m*p,E=o*s-m*r,q=1/(A*E-B*D+t*C+u*z-v*y+w*x);b[0]=(h*E-i*D+j*C)*q;b[1]=(-d*E+e*D-g*C)*q;b[2]=(p*w-r*v+s*u)*q;b[3]=(-l*w+o*v-m*u)*q;b[4]=(-f*E+i*z-j*y)*q;b[5]=(c*E-e*z+g*y)*q;b[6]=(-n*w+r*t-s*B)*q;b[7]=(k*w-o*t+m*B)*q;b[8]=(f*D-h*z+j*x)*q; 13 | b[9]=(-c*D+d*z-g*x)*q;b[10]=(n*v-p*t+s*A)*q;b[11]=(-k*v+l*t-m*A)*q;b[12]=(-f*C+h*y-i*x)*q;b[13]=(c*C-d*y+e*x)*q;b[14]=(-n*u+p*B-r*A)*q;b[15]=(k*u-l*B+o*A)*q;return b};mat4.toRotationMat=function(a,b){b||(b=mat4.create());b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3];b[4]=a[4];b[5]=a[5];b[6]=a[6];b[7]=a[7];b[8]=a[8];b[9]=a[9];b[10]=a[10];b[11]=a[11];b[12]=0;b[13]=0;b[14]=0;b[15]=1;return b}; 14 | mat4.toMat3=function(a,b){b||(b=mat3.create());b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[4];b[4]=a[5];b[5]=a[6];b[6]=a[8];b[7]=a[9];b[8]=a[10];return b};mat4.toInverseMat3=function(a,b){var c=a[0],d=a[1],e=a[2],g=a[4],f=a[5],h=a[6],i=a[8],j=a[9],k=a[10],l=k*f-h*j,o=-k*g+h*i,m=j*g-f*i,n=c*l+d*o+e*m;if(!n)return null;n=1/n;b||(b=mat3.create());b[0]=l*n;b[1]=(-k*d+e*j)*n;b[2]=(h*d-e*f)*n;b[3]=o*n;b[4]=(k*c-e*i)*n;b[5]=(-h*c+e*g)*n;b[6]=m*n;b[7]=(-j*c+d*i)*n;b[8]=(f*c-d*g)*n;return b}; 15 | mat4.multiply=function(a,b,c){c||(c=a);var d=a[0],e=a[1],g=a[2],f=a[3],h=a[4],i=a[5],j=a[6],k=a[7],l=a[8],o=a[9],m=a[10],n=a[11],p=a[12],r=a[13],s=a[14];a=a[15];var A=b[0],B=b[1],t=b[2],u=b[3],v=b[4],w=b[5],x=b[6],y=b[7],z=b[8],C=b[9],D=b[10],E=b[11],q=b[12],F=b[13],G=b[14];b=b[15];c[0]=A*d+B*h+t*l+u*p;c[1]=A*e+B*i+t*o+u*r;c[2]=A*g+B*j+t*m+u*s;c[3]=A*f+B*k+t*n+u*a;c[4]=v*d+w*h+x*l+y*p;c[5]=v*e+w*i+x*o+y*r;c[6]=v*g+w*j+x*m+y*s;c[7]=v*f+w*k+x*n+y*a;c[8]=z*d+C*h+D*l+E*p;c[9]=z*e+C*i+D*o+E*r;c[10]=z* 16 | g+C*j+D*m+E*s;c[11]=z*f+C*k+D*n+E*a;c[12]=q*d+F*h+G*l+b*p;c[13]=q*e+F*i+G*o+b*r;c[14]=q*g+F*j+G*m+b*s;c[15]=q*f+F*k+G*n+b*a;return c};mat4.multiplyVec3=function(a,b,c){c||(c=b);var d=b[0],e=b[1];b=b[2];c[0]=a[0]*d+a[4]*e+a[8]*b+a[12];c[1]=a[1]*d+a[5]*e+a[9]*b+a[13];c[2]=a[2]*d+a[6]*e+a[10]*b+a[14];return c}; 17 | mat4.multiplyVec4=function(a,b,c){c||(c=b);var d=b[0],e=b[1],g=b[2];b=b[3];c[0]=a[0]*d+a[4]*e+a[8]*g+a[12]*b;c[1]=a[1]*d+a[5]*e+a[9]*g+a[13]*b;c[2]=a[2]*d+a[6]*e+a[10]*g+a[14]*b;c[3]=a[3]*d+a[7]*e+a[11]*g+a[15]*b;return c}; 18 | mat4.translate=function(a,b,c){var d=b[0],e=b[1];b=b[2];if(!c||a==c){a[12]=a[0]*d+a[4]*e+a[8]*b+a[12];a[13]=a[1]*d+a[5]*e+a[9]*b+a[13];a[14]=a[2]*d+a[6]*e+a[10]*b+a[14];a[15]=a[3]*d+a[7]*e+a[11]*b+a[15];return a}var g=a[0],f=a[1],h=a[2],i=a[3],j=a[4],k=a[5],l=a[6],o=a[7],m=a[8],n=a[9],p=a[10],r=a[11];c[0]=g;c[1]=f;c[2]=h;c[3]=i;c[4]=j;c[5]=k;c[6]=l;c[7]=o;c[8]=m;c[9]=n;c[10]=p;c[11]=r;c[12]=g*d+j*e+m*b+a[12];c[13]=f*d+k*e+n*b+a[13];c[14]=h*d+l*e+p*b+a[14];c[15]=i*d+o*e+r*b+a[15];return c}; 19 | mat4.scale=function(a,b,c){var d=b[0],e=b[1];b=b[2];if(!c||a==c){a[0]*=d;a[1]*=d;a[2]*=d;a[3]*=d;a[4]*=e;a[5]*=e;a[6]*=e;a[7]*=e;a[8]*=b;a[9]*=b;a[10]*=b;a[11]*=b;return a}c[0]=a[0]*d;c[1]=a[1]*d;c[2]=a[2]*d;c[3]=a[3]*d;c[4]=a[4]*e;c[5]=a[5]*e;c[6]=a[6]*e;c[7]=a[7]*e;c[8]=a[8]*b;c[9]=a[9]*b;c[10]=a[10]*b;c[11]=a[11]*b;c[12]=a[12];c[13]=a[13];c[14]=a[14];c[15]=a[15];return c}; 20 | mat4.rotate=function(a,b,c,d){var e=c[0],g=c[1];c=c[2];var f=Math.sqrt(e*e+g*g+c*c);if(!f)return null;if(f!=1){f=1/f;e*=f;g*=f;c*=f}var h=Math.sin(b),i=Math.cos(b),j=1-i;b=a[0];f=a[1];var k=a[2],l=a[3],o=a[4],m=a[5],n=a[6],p=a[7],r=a[8],s=a[9],A=a[10],B=a[11],t=e*e*j+i,u=g*e*j+c*h,v=c*e*j-g*h,w=e*g*j-c*h,x=g*g*j+i,y=c*g*j+e*h,z=e*c*j+g*h;e=g*c*j-e*h;g=c*c*j+i;if(d){if(a!=d){d[12]=a[12];d[13]=a[13];d[14]=a[14];d[15]=a[15]}}else d=a;d[0]=b*t+o*u+r*v;d[1]=f*t+m*u+s*v;d[2]=k*t+n*u+A*v;d[3]=l*t+p*u+B* 21 | v;d[4]=b*w+o*x+r*y;d[5]=f*w+m*x+s*y;d[6]=k*w+n*x+A*y;d[7]=l*w+p*x+B*y;d[8]=b*z+o*e+r*g;d[9]=f*z+m*e+s*g;d[10]=k*z+n*e+A*g;d[11]=l*z+p*e+B*g;return d};mat4.rotateX=function(a,b,c){var d=Math.sin(b);b=Math.cos(b);var e=a[4],g=a[5],f=a[6],h=a[7],i=a[8],j=a[9],k=a[10],l=a[11];if(c){if(a!=c){c[0]=a[0];c[1]=a[1];c[2]=a[2];c[3]=a[3];c[12]=a[12];c[13]=a[13];c[14]=a[14];c[15]=a[15]}}else c=a;c[4]=e*b+i*d;c[5]=g*b+j*d;c[6]=f*b+k*d;c[7]=h*b+l*d;c[8]=e*-d+i*b;c[9]=g*-d+j*b;c[10]=f*-d+k*b;c[11]=h*-d+l*b;return c}; 22 | mat4.rotateY=function(a,b,c){var d=Math.sin(b);b=Math.cos(b);var e=a[0],g=a[1],f=a[2],h=a[3],i=a[8],j=a[9],k=a[10],l=a[11];if(c){if(a!=c){c[4]=a[4];c[5]=a[5];c[6]=a[6];c[7]=a[7];c[12]=a[12];c[13]=a[13];c[14]=a[14];c[15]=a[15]}}else c=a;c[0]=e*b+i*-d;c[1]=g*b+j*-d;c[2]=f*b+k*-d;c[3]=h*b+l*-d;c[8]=e*d+i*b;c[9]=g*d+j*b;c[10]=f*d+k*b;c[11]=h*d+l*b;return c}; 23 | mat4.rotateZ=function(a,b,c){var d=Math.sin(b);b=Math.cos(b);var e=a[0],g=a[1],f=a[2],h=a[3],i=a[4],j=a[5],k=a[6],l=a[7];if(c){if(a!=c){c[8]=a[8];c[9]=a[9];c[10]=a[10];c[11]=a[11];c[12]=a[12];c[13]=a[13];c[14]=a[14];c[15]=a[15]}}else c=a;c[0]=e*b+i*d;c[1]=g*b+j*d;c[2]=f*b+k*d;c[3]=h*b+l*d;c[4]=e*-d+i*b;c[5]=g*-d+j*b;c[6]=f*-d+k*b;c[7]=h*-d+l*b;return c}; 24 | mat4.frustum=function(a,b,c,d,e,g,f){f||(f=mat4.create());var h=b-a,i=d-c,j=g-e;f[0]=e*2/h;f[1]=0;f[2]=0;f[3]=0;f[4]=0;f[5]=e*2/i;f[6]=0;f[7]=0;f[8]=(b+a)/h;f[9]=(d+c)/i;f[10]=-(g+e)/j;f[11]=-1;f[12]=0;f[13]=0;f[14]=-(g*e*2)/j;f[15]=0;return f};mat4.perspective=function(a,b,c,d,e){a=c*Math.tan(a*Math.PI/360);b=a*b;return mat4.frustum(-b,b,-a,a,c,d,e)}; 25 | mat4.ortho=function(a,b,c,d,e,g,f){f||(f=mat4.create());var h=b-a,i=d-c,j=g-e;f[0]=2/h;f[1]=0;f[2]=0;f[3]=0;f[4]=0;f[5]=2/i;f[6]=0;f[7]=0;f[8]=0;f[9]=0;f[10]=-2/j;f[11]=0;f[12]=-(a+b)/h;f[13]=-(d+c)/i;f[14]=-(g+e)/j;f[15]=1;return f}; 26 | mat4.lookAt=function(a,b,c,d){d||(d=mat4.create());var e=a[0],g=a[1];a=a[2];var f=c[0],h=c[1],i=c[2];c=b[1];var j=b[2];if(e==b[0]&&g==c&&a==j)return mat4.identity(d);var k,l,o,m;c=e-b[0];j=g-b[1];b=a-b[2];m=1/Math.sqrt(c*c+j*j+b*b);c*=m;j*=m;b*=m;k=h*b-i*j;i=i*c-f*b;f=f*j-h*c;if(m=Math.sqrt(k*k+i*i+f*f)){m=1/m;k*=m;i*=m;f*=m}else f=i=k=0;h=j*f-b*i;l=b*k-c*f;o=c*i-j*k;if(m=Math.sqrt(h*h+l*l+o*o)){m=1/m;h*=m;l*=m;o*=m}else o=l=h=0;d[0]=k;d[1]=h;d[2]=c;d[3]=0;d[4]=i;d[5]=l;d[6]=j;d[7]=0;d[8]=f;d[9]= 27 | o;d[10]=b;d[11]=0;d[12]=-(k*e+i*g+f*a);d[13]=-(h*e+l*g+o*a);d[14]=-(c*e+j*g+b*a);d[15]=1;return d};mat4.str=function(a){return"["+a[0]+", "+a[1]+", "+a[2]+", "+a[3]+", "+a[4]+", "+a[5]+", "+a[6]+", "+a[7]+", "+a[8]+", "+a[9]+", "+a[10]+", "+a[11]+", "+a[12]+", "+a[13]+", "+a[14]+", "+a[15]+"]"};quat4={};quat4.create=function(a){var b=new glMatrixArrayType(4);if(a){b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3]}return b};quat4.set=function(a,b){b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3];return b}; 28 | quat4.calculateW=function(a,b){var c=a[0],d=a[1],e=a[2];if(!b||a==b){a[3]=-Math.sqrt(Math.abs(1-c*c-d*d-e*e));return a}b[0]=c;b[1]=d;b[2]=e;b[3]=-Math.sqrt(Math.abs(1-c*c-d*d-e*e));return b};quat4.inverse=function(a,b){if(!b||a==b){a[0]*=1;a[1]*=1;a[2]*=1;return a}b[0]=-a[0];b[1]=-a[1];b[2]=-a[2];b[3]=a[3];return b};quat4.length=function(a){var b=a[0],c=a[1],d=a[2];a=a[3];return Math.sqrt(b*b+c*c+d*d+a*a)}; 29 | quat4.normalize=function(a,b){b||(b=a);var c=a[0],d=a[1],e=a[2],g=a[3],f=Math.sqrt(c*c+d*d+e*e+g*g);if(f==0){b[0]=0;b[1]=0;b[2]=0;b[3]=0;return b}f=1/f;b[0]=c*f;b[1]=d*f;b[2]=e*f;b[3]=g*f;return b};quat4.multiply=function(a,b,c){c||(c=a);var d=a[0],e=a[1],g=a[2];a=a[3];var f=b[0],h=b[1],i=b[2];b=b[3];c[0]=d*b+a*f+e*i-g*h;c[1]=e*b+a*h+g*f-d*i;c[2]=g*b+a*i+d*h-e*f;c[3]=a*b-d*f-e*h-g*i;return c}; 30 | quat4.multiplyVec3=function(a,b,c){c||(c=b);var d=b[0],e=b[1],g=b[2];b=a[0];var f=a[1],h=a[2];a=a[3];var i=a*d+f*g-h*e,j=a*e+h*d-b*g,k=a*g+b*e-f*d;d=-b*d-f*e-h*g;c[0]=i*a+d*-b+j*-h-k*-f;c[1]=j*a+d*-f+k*-b-i*-h;c[2]=k*a+d*-h+i*-f-j*-b;return c};quat4.toMat3=function(a,b){b||(b=mat3.create());var c=a[0],d=a[1],e=a[2],g=a[3],f=c+c,h=d+d,i=e+e,j=c*f,k=c*h;c=c*i;var l=d*h;d=d*i;e=e*i;f=g*f;h=g*h;g=g*i;b[0]=1-(l+e);b[1]=k-g;b[2]=c+h;b[3]=k+g;b[4]=1-(j+e);b[5]=d-f;b[6]=c-h;b[7]=d+f;b[8]=1-(j+l);return b}; 31 | quat4.toMat4=function(a,b){b||(b=mat4.create());var c=a[0],d=a[1],e=a[2],g=a[3],f=c+c,h=d+d,i=e+e,j=c*f,k=c*h;c=c*i;var l=d*h;d=d*i;e=e*i;f=g*f;h=g*h;g=g*i;b[0]=1-(l+e);b[1]=k-g;b[2]=c+h;b[3]=0;b[4]=k+g;b[5]=1-(j+e);b[6]=d-f;b[7]=0;b[8]=c-h;b[9]=d+f;b[10]=1-(j+l);b[11]=0;b[12]=0;b[13]=0;b[14]=0;b[15]=1;return b};quat4.slerp=function(a,b,c,d){d||(d=a);var e=c;if(a[0]*b[0]+a[1]*b[1]+a[2]*b[2]+a[3]*b[3]<0)e=-1*c;d[0]=1-c*a[0]+e*b[0];d[1]=1-c*a[1]+e*b[1];d[2]=1-c*a[2]+e*b[2];d[3]=1-c*a[3]+e*b[3];return d}; 32 | quat4.str=function(a){return"["+a[0]+", "+a[1]+", "+a[2]+", "+a[3]+"]"}; 33 | -------------------------------------------------------------------------------- /priv/www/visualiser/js/glMatrix.js: -------------------------------------------------------------------------------- 1 | /* 2 | * glMatrix.js - High performance matrix and vector operations for WebGL 3 | * version 0.9.5 4 | */ 5 | 6 | /* 7 | * Copyright (c) 2010 Brandon Jones 8 | * 9 | * This software is provided 'as-is', without any express or implied 10 | * warranty. In no event will the authors be held liable for any damages 11 | * arising from the use of this software. 12 | * 13 | * Permission is granted to anyone to use this software for any purpose, 14 | * including commercial applications, and to alter it and redistribute it 15 | * freely, subject to the following restrictions: 16 | * 17 | * 1. The origin of this software must not be misrepresented; you must not 18 | * claim that you wrote the original software. If you use this software 19 | * in a product, an acknowledgment in the product documentation would be 20 | * appreciated but is not required. 21 | * 22 | * 2. Altered source versions must be plainly marked as such, and must not 23 | * be misrepresented as being the original software. 24 | * 25 | * 3. This notice may not be removed or altered from any source 26 | * distribution. 27 | */ 28 | 29 | // Fallback for systems that don't support WebGL 30 | if(typeof Float32Array != 'undefined') { 31 | glMatrixArrayType = Float32Array; 32 | } else if(typeof WebGLFloatArray != 'undefined') { 33 | glMatrixArrayType = WebGLFloatArray; // This is officially deprecated and should dissapear in future revisions. 34 | } else { 35 | glMatrixArrayType = Array; 36 | } 37 | 38 | /* 39 | * vec3 - 3 Dimensional Vector 40 | */ 41 | var vec3 = {}; 42 | 43 | /* 44 | * vec3.create 45 | * Creates a new instance of a vec3 using the default array type 46 | * Any javascript array containing at least 3 numeric elements can serve as a vec3 47 | * 48 | * Params: 49 | * vec - Optional, vec3 containing values to initialize with 50 | * 51 | * Returns: 52 | * New vec3 53 | */ 54 | vec3.create = function(vec) { 55 | var dest = new glMatrixArrayType(3); 56 | 57 | if(vec) { 58 | dest[0] = vec[0]; 59 | dest[1] = vec[1]; 60 | dest[2] = vec[2]; 61 | } 62 | 63 | return dest; 64 | }; 65 | 66 | /* 67 | * vec3.set 68 | * Copies the values of one vec3 to another 69 | * 70 | * Params: 71 | * vec - vec3 containing values to copy 72 | * dest - vec3 receiving copied values 73 | * 74 | * Returns: 75 | * dest 76 | */ 77 | vec3.set = function(vec, dest) { 78 | dest[0] = vec[0]; 79 | dest[1] = vec[1]; 80 | dest[2] = vec[2]; 81 | 82 | return dest; 83 | }; 84 | 85 | /* 86 | * vec3.add 87 | * Performs a vector addition 88 | * 89 | * Params: 90 | * vec - vec3, first operand 91 | * vec2 - vec3, second operand 92 | * dest - Optional, vec3 receiving operation result. If not specified result is written to vec 93 | * 94 | * Returns: 95 | * dest if specified, vec otherwise 96 | */ 97 | vec3.add = function(vec, vec2, dest) { 98 | if(!dest || vec == dest) { 99 | vec[0] += vec2[0]; 100 | vec[1] += vec2[1]; 101 | vec[2] += vec2[2]; 102 | return vec; 103 | } 104 | 105 | dest[0] = vec[0] + vec2[0]; 106 | dest[1] = vec[1] + vec2[1]; 107 | dest[2] = vec[2] + vec2[2]; 108 | return dest; 109 | }; 110 | 111 | /* 112 | * vec3.subtract 113 | * Performs a vector subtraction 114 | * 115 | * Params: 116 | * vec - vec3, first operand 117 | * vec2 - vec3, second operand 118 | * dest - Optional, vec3 receiving operation result. If not specified result is written to vec 119 | * 120 | * Returns: 121 | * dest if specified, vec otherwise 122 | */ 123 | vec3.subtract = function(vec, vec2, dest) { 124 | if(!dest || vec == dest) { 125 | vec[0] -= vec2[0]; 126 | vec[1] -= vec2[1]; 127 | vec[2] -= vec2[2]; 128 | return vec; 129 | } 130 | 131 | dest[0] = vec[0] - vec2[0]; 132 | dest[1] = vec[1] - vec2[1]; 133 | dest[2] = vec[2] - vec2[2]; 134 | return dest; 135 | }; 136 | 137 | /* 138 | * vec3.negate 139 | * Negates the components of a vec3 140 | * 141 | * Params: 142 | * vec - vec3 to negate 143 | * dest - Optional, vec3 receiving operation result. If not specified result is written to vec 144 | * 145 | * Returns: 146 | * dest if specified, vec otherwise 147 | */ 148 | vec3.negate = function(vec, dest) { 149 | if(!dest) { dest = vec; } 150 | 151 | dest[0] = -vec[0]; 152 | dest[1] = -vec[1]; 153 | dest[2] = -vec[2]; 154 | return dest; 155 | }; 156 | 157 | /* 158 | * vec3.scale 159 | * Multiplies the components of a vec3 by a scalar value 160 | * 161 | * Params: 162 | * vec - vec3 to scale 163 | * val - Numeric value to scale by 164 | * dest - Optional, vec3 receiving operation result. If not specified result is written to vec 165 | * 166 | * Returns: 167 | * dest if specified, vec otherwise 168 | */ 169 | vec3.scale = function(vec, val, dest) { 170 | if(!dest || vec == dest) { 171 | vec[0] *= val; 172 | vec[1] *= val; 173 | vec[2] *= val; 174 | return vec; 175 | } 176 | 177 | dest[0] = vec[0]*val; 178 | dest[1] = vec[1]*val; 179 | dest[2] = vec[2]*val; 180 | return dest; 181 | }; 182 | 183 | /* 184 | * vec3.normalize 185 | * Generates a unit vector of the same direction as the provided vec3 186 | * If vector length is 0, returns [0, 0, 0] 187 | * 188 | * Params: 189 | * vec - vec3 to normalize 190 | * dest - Optional, vec3 receiving operation result. If not specified result is written to vec 191 | * 192 | * Returns: 193 | * dest if specified, vec otherwise 194 | */ 195 | vec3.normalize = function(vec, dest) { 196 | if(!dest) { dest = vec; } 197 | 198 | var x = vec[0], y = vec[1], z = vec[2]; 199 | var len = Math.sqrt(x*x + y*y + z*z); 200 | 201 | if (!len) { 202 | dest[0] = 0; 203 | dest[1] = 0; 204 | dest[2] = 0; 205 | return dest; 206 | } else if (len == 1) { 207 | dest[0] = x; 208 | dest[1] = y; 209 | dest[2] = z; 210 | return dest; 211 | } 212 | 213 | len = 1 / len; 214 | dest[0] = x*len; 215 | dest[1] = y*len; 216 | dest[2] = z*len; 217 | return dest; 218 | }; 219 | 220 | /* 221 | * vec3.cross 222 | * Generates the cross product of two vec3s 223 | * 224 | * Params: 225 | * vec - vec3, first operand 226 | * vec2 - vec3, second operand 227 | * dest - Optional, vec3 receiving operation result. If not specified result is written to vec 228 | * 229 | * Returns: 230 | * dest if specified, vec otherwise 231 | */ 232 | vec3.cross = function(vec, vec2, dest){ 233 | if(!dest) { dest = vec; } 234 | 235 | var x = vec[0], y = vec[1], z = vec[2]; 236 | var x2 = vec2[0], y2 = vec2[1], z2 = vec2[2]; 237 | 238 | dest[0] = y*z2 - z*y2; 239 | dest[1] = z*x2 - x*z2; 240 | dest[2] = x*y2 - y*x2; 241 | return dest; 242 | }; 243 | 244 | /* 245 | * vec3.length 246 | * Caclulates the length of a vec3 247 | * 248 | * Params: 249 | * vec - vec3 to calculate length of 250 | * 251 | * Returns: 252 | * Length of vec 253 | */ 254 | vec3.length = function(vec){ 255 | var x = vec[0], y = vec[1], z = vec[2]; 256 | return Math.sqrt(x*x + y*y + z*z); 257 | }; 258 | 259 | /* 260 | * vec3.dot 261 | * Caclulates the dot product of two vec3s 262 | * 263 | * Params: 264 | * vec - vec3, first operand 265 | * vec2 - vec3, second operand 266 | * 267 | * Returns: 268 | * Dot product of vec and vec2 269 | */ 270 | vec3.dot = function(vec, vec2){ 271 | return vec[0]*vec2[0] + vec[1]*vec2[1] + vec[2]*vec2[2]; 272 | }; 273 | 274 | /* 275 | * vec3.direction 276 | * Generates a unit vector pointing from one vector to another 277 | * 278 | * Params: 279 | * vec - origin vec3 280 | * vec2 - vec3 to point to 281 | * dest - Optional, vec3 receiving operation result. If not specified result is written to vec 282 | * 283 | * Returns: 284 | * dest if specified, vec otherwise 285 | */ 286 | vec3.direction = function(vec, vec2, dest) { 287 | if(!dest) { dest = vec; } 288 | 289 | var x = vec[0] - vec2[0]; 290 | var y = vec[1] - vec2[1]; 291 | var z = vec[2] - vec2[2]; 292 | 293 | var len = Math.sqrt(x*x + y*y + z*z); 294 | if (!len) { 295 | dest[0] = 0; 296 | dest[1] = 0; 297 | dest[2] = 0; 298 | return dest; 299 | } 300 | 301 | len = 1 / len; 302 | dest[0] = x * len; 303 | dest[1] = y * len; 304 | dest[2] = z * len; 305 | return dest; 306 | }; 307 | 308 | /* 309 | * vec3.lerp 310 | * Performs a linear interpolation between two vec3 311 | * 312 | * Params: 313 | * vec - vec3, first vector 314 | * vec2 - vec3, second vector 315 | * lerp - interpolation amount between the two inputs 316 | * dest - Optional, vec3 receiving operation result. If not specified result is written to vec 317 | * 318 | * Returns: 319 | * dest if specified, vec otherwise 320 | */ 321 | vec3.lerp = function(vec, vec2, lerp, dest){ 322 | if(!dest) { dest = vec; } 323 | 324 | dest[0] = vec[0] + lerp * (vec2[0] - vec[0]); 325 | dest[1] = vec[1] + lerp * (vec2[1] - vec[1]); 326 | dest[2] = vec[2] + lerp * (vec2[2] - vec[2]); 327 | 328 | return dest; 329 | } 330 | 331 | /* 332 | * vec3.str 333 | * Returns a string representation of a vector 334 | * 335 | * Params: 336 | * vec - vec3 to represent as a string 337 | * 338 | * Returns: 339 | * string representation of vec 340 | */ 341 | vec3.str = function(vec) { 342 | return '[' + vec[0] + ', ' + vec[1] + ', ' + vec[2] + ']'; 343 | }; 344 | 345 | /* 346 | * mat3 - 3x3 Matrix 347 | */ 348 | var mat3 = {}; 349 | 350 | /* 351 | * mat3.create 352 | * Creates a new instance of a mat3 using the default array type 353 | * Any javascript array containing at least 9 numeric elements can serve as a mat3 354 | * 355 | * Params: 356 | * mat - Optional, mat3 containing values to initialize with 357 | * 358 | * Returns: 359 | * New mat3 360 | */ 361 | mat3.create = function(mat) { 362 | var dest = new glMatrixArrayType(9); 363 | 364 | if(mat) { 365 | dest[0] = mat[0]; 366 | dest[1] = mat[1]; 367 | dest[2] = mat[2]; 368 | dest[3] = mat[3]; 369 | dest[4] = mat[4]; 370 | dest[5] = mat[5]; 371 | dest[6] = mat[6]; 372 | dest[7] = mat[7]; 373 | dest[8] = mat[8]; 374 | dest[9] = mat[9]; 375 | } 376 | 377 | return dest; 378 | }; 379 | 380 | /* 381 | * mat3.set 382 | * Copies the values of one mat3 to another 383 | * 384 | * Params: 385 | * mat - mat3 containing values to copy 386 | * dest - mat3 receiving copied values 387 | * 388 | * Returns: 389 | * dest 390 | */ 391 | mat3.set = function(mat, dest) { 392 | dest[0] = mat[0]; 393 | dest[1] = mat[1]; 394 | dest[2] = mat[2]; 395 | dest[3] = mat[3]; 396 | dest[4] = mat[4]; 397 | dest[5] = mat[5]; 398 | dest[6] = mat[6]; 399 | dest[7] = mat[7]; 400 | dest[8] = mat[8]; 401 | return dest; 402 | }; 403 | 404 | /* 405 | * mat3.identity 406 | * Sets a mat3 to an identity matrix 407 | * 408 | * Params: 409 | * dest - mat3 to set 410 | * 411 | * Returns: 412 | * dest 413 | */ 414 | mat3.identity = function(dest) { 415 | dest[0] = 1; 416 | dest[1] = 0; 417 | dest[2] = 0; 418 | dest[3] = 0; 419 | dest[4] = 1; 420 | dest[5] = 0; 421 | dest[6] = 0; 422 | dest[7] = 0; 423 | dest[8] = 1; 424 | return dest; 425 | }; 426 | 427 | /* 428 | * mat4.transpose 429 | * Transposes a mat3 (flips the values over the diagonal) 430 | * 431 | * Params: 432 | * mat - mat3 to transpose 433 | * dest - Optional, mat3 receiving transposed values. If not specified result is written to mat 434 | * 435 | * Returns: 436 | * dest is specified, mat otherwise 437 | */ 438 | mat3.transpose = function(mat, dest) { 439 | // If we are transposing ourselves we can skip a few steps but have to cache some values 440 | if(!dest || mat == dest) { 441 | var a01 = mat[1], a02 = mat[2]; 442 | var a12 = mat[5]; 443 | 444 | mat[1] = mat[3]; 445 | mat[2] = mat[6]; 446 | mat[3] = a01; 447 | mat[5] = mat[7]; 448 | mat[6] = a02; 449 | mat[7] = a12; 450 | return mat; 451 | } 452 | 453 | dest[0] = mat[0]; 454 | dest[1] = mat[3]; 455 | dest[2] = mat[6]; 456 | dest[3] = mat[1]; 457 | dest[4] = mat[4]; 458 | dest[5] = mat[7]; 459 | dest[6] = mat[2]; 460 | dest[7] = mat[5]; 461 | dest[8] = mat[8]; 462 | return dest; 463 | }; 464 | 465 | /* 466 | * mat3.toMat4 467 | * Copies the elements of a mat3 into the upper 3x3 elements of a mat4 468 | * 469 | * Params: 470 | * mat - mat3 containing values to copy 471 | * dest - Optional, mat4 receiving copied values 472 | * 473 | * Returns: 474 | * dest if specified, a new mat4 otherwise 475 | */ 476 | mat3.toMat4 = function(mat, dest) { 477 | if(!dest) { dest = mat4.create(); } 478 | 479 | dest[0] = mat[0]; 480 | dest[1] = mat[1]; 481 | dest[2] = mat[2]; 482 | dest[3] = 0; 483 | 484 | dest[4] = mat[3]; 485 | dest[5] = mat[4]; 486 | dest[6] = mat[5]; 487 | dest[7] = 0; 488 | 489 | dest[8] = mat[6]; 490 | dest[9] = mat[7]; 491 | dest[10] = mat[8]; 492 | dest[11] = 0; 493 | 494 | dest[12] = 0; 495 | dest[13] = 0; 496 | dest[14] = 0; 497 | dest[15] = 1; 498 | 499 | return dest; 500 | } 501 | 502 | /* 503 | * mat3.str 504 | * Returns a string representation of a mat3 505 | * 506 | * Params: 507 | * mat - mat3 to represent as a string 508 | * 509 | * Returns: 510 | * string representation of mat 511 | */ 512 | mat3.str = function(mat) { 513 | return '[' + mat[0] + ', ' + mat[1] + ', ' + mat[2] + 514 | ', ' + mat[3] + ', '+ mat[4] + ', ' + mat[5] + 515 | ', ' + mat[6] + ', ' + mat[7] + ', '+ mat[8] + ']'; 516 | }; 517 | 518 | /* 519 | * mat4 - 4x4 Matrix 520 | */ 521 | var mat4 = {}; 522 | 523 | /* 524 | * mat4.create 525 | * Creates a new instance of a mat4 using the default array type 526 | * Any javascript array containing at least 16 numeric elements can serve as a mat4 527 | * 528 | * Params: 529 | * mat - Optional, mat4 containing values to initialize with 530 | * 531 | * Returns: 532 | * New mat4 533 | */ 534 | mat4.create = function(mat) { 535 | var dest = new glMatrixArrayType(16); 536 | 537 | if(mat) { 538 | dest[0] = mat[0]; 539 | dest[1] = mat[1]; 540 | dest[2] = mat[2]; 541 | dest[3] = mat[3]; 542 | dest[4] = mat[4]; 543 | dest[5] = mat[5]; 544 | dest[6] = mat[6]; 545 | dest[7] = mat[7]; 546 | dest[8] = mat[8]; 547 | dest[9] = mat[9]; 548 | dest[10] = mat[10]; 549 | dest[11] = mat[11]; 550 | dest[12] = mat[12]; 551 | dest[13] = mat[13]; 552 | dest[14] = mat[14]; 553 | dest[15] = mat[15]; 554 | } 555 | 556 | return dest; 557 | }; 558 | 559 | /* 560 | * mat4.set 561 | * Copies the values of one mat4 to another 562 | * 563 | * Params: 564 | * mat - mat4 containing values to copy 565 | * dest - mat4 receiving copied values 566 | * 567 | * Returns: 568 | * dest 569 | */ 570 | mat4.set = function(mat, dest) { 571 | dest[0] = mat[0]; 572 | dest[1] = mat[1]; 573 | dest[2] = mat[2]; 574 | dest[3] = mat[3]; 575 | dest[4] = mat[4]; 576 | dest[5] = mat[5]; 577 | dest[6] = mat[6]; 578 | dest[7] = mat[7]; 579 | dest[8] = mat[8]; 580 | dest[9] = mat[9]; 581 | dest[10] = mat[10]; 582 | dest[11] = mat[11]; 583 | dest[12] = mat[12]; 584 | dest[13] = mat[13]; 585 | dest[14] = mat[14]; 586 | dest[15] = mat[15]; 587 | return dest; 588 | }; 589 | 590 | /* 591 | * mat4.identity 592 | * Sets a mat4 to an identity matrix 593 | * 594 | * Params: 595 | * dest - mat4 to set 596 | * 597 | * Returns: 598 | * dest 599 | */ 600 | mat4.identity = function(dest) { 601 | dest[0] = 1; 602 | dest[1] = 0; 603 | dest[2] = 0; 604 | dest[3] = 0; 605 | dest[4] = 0; 606 | dest[5] = 1; 607 | dest[6] = 0; 608 | dest[7] = 0; 609 | dest[8] = 0; 610 | dest[9] = 0; 611 | dest[10] = 1; 612 | dest[11] = 0; 613 | dest[12] = 0; 614 | dest[13] = 0; 615 | dest[14] = 0; 616 | dest[15] = 1; 617 | return dest; 618 | }; 619 | 620 | /* 621 | * mat4.transpose 622 | * Transposes a mat4 (flips the values over the diagonal) 623 | * 624 | * Params: 625 | * mat - mat4 to transpose 626 | * dest - Optional, mat4 receiving transposed values. If not specified result is written to mat 627 | * 628 | * Returns: 629 | * dest is specified, mat otherwise 630 | */ 631 | mat4.transpose = function(mat, dest) { 632 | // If we are transposing ourselves we can skip a few steps but have to cache some values 633 | if(!dest || mat == dest) { 634 | var a01 = mat[1], a02 = mat[2], a03 = mat[3]; 635 | var a12 = mat[6], a13 = mat[7]; 636 | var a23 = mat[11]; 637 | 638 | mat[1] = mat[4]; 639 | mat[2] = mat[8]; 640 | mat[3] = mat[12]; 641 | mat[4] = a01; 642 | mat[6] = mat[9]; 643 | mat[7] = mat[13]; 644 | mat[8] = a02; 645 | mat[9] = a12; 646 | mat[11] = mat[14]; 647 | mat[12] = a03; 648 | mat[13] = a13; 649 | mat[14] = a23; 650 | return mat; 651 | } 652 | 653 | dest[0] = mat[0]; 654 | dest[1] = mat[4]; 655 | dest[2] = mat[8]; 656 | dest[3] = mat[12]; 657 | dest[4] = mat[1]; 658 | dest[5] = mat[5]; 659 | dest[6] = mat[9]; 660 | dest[7] = mat[13]; 661 | dest[8] = mat[2]; 662 | dest[9] = mat[6]; 663 | dest[10] = mat[10]; 664 | dest[11] = mat[14]; 665 | dest[12] = mat[3]; 666 | dest[13] = mat[7]; 667 | dest[14] = mat[11]; 668 | dest[15] = mat[15]; 669 | return dest; 670 | }; 671 | 672 | /* 673 | * mat4.determinant 674 | * Calculates the determinant of a mat4 675 | * 676 | * Params: 677 | * mat - mat4 to calculate determinant of 678 | * 679 | * Returns: 680 | * determinant of mat 681 | */ 682 | mat4.determinant = function(mat) { 683 | // Cache the matrix values (makes for huge speed increases!) 684 | var a00 = mat[0], a01 = mat[1], a02 = mat[2], a03 = mat[3]; 685 | var a10 = mat[4], a11 = mat[5], a12 = mat[6], a13 = mat[7]; 686 | var a20 = mat[8], a21 = mat[9], a22 = mat[10], a23 = mat[11]; 687 | var a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15]; 688 | 689 | return a30*a21*a12*a03 - a20*a31*a12*a03 - a30*a11*a22*a03 + a10*a31*a22*a03 + 690 | a20*a11*a32*a03 - a10*a21*a32*a03 - a30*a21*a02*a13 + a20*a31*a02*a13 + 691 | a30*a01*a22*a13 - a00*a31*a22*a13 - a20*a01*a32*a13 + a00*a21*a32*a13 + 692 | a30*a11*a02*a23 - a10*a31*a02*a23 - a30*a01*a12*a23 + a00*a31*a12*a23 + 693 | a10*a01*a32*a23 - a00*a11*a32*a23 - a20*a11*a02*a33 + a10*a21*a02*a33 + 694 | a20*a01*a12*a33 - a00*a21*a12*a33 - a10*a01*a22*a33 + a00*a11*a22*a33; 695 | }; 696 | 697 | /* 698 | * mat4.inverse 699 | * Calculates the inverse matrix of a mat4 700 | * 701 | * Params: 702 | * mat - mat4 to calculate inverse of 703 | * dest - Optional, mat4 receiving inverse matrix. If not specified result is written to mat 704 | * 705 | * Returns: 706 | * dest is specified, mat otherwise 707 | */ 708 | mat4.inverse = function(mat, dest) { 709 | if(!dest) { dest = mat; } 710 | 711 | // Cache the matrix values (makes for huge speed increases!) 712 | var a00 = mat[0], a01 = mat[1], a02 = mat[2], a03 = mat[3]; 713 | var a10 = mat[4], a11 = mat[5], a12 = mat[6], a13 = mat[7]; 714 | var a20 = mat[8], a21 = mat[9], a22 = mat[10], a23 = mat[11]; 715 | var a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15]; 716 | 717 | var b00 = a00*a11 - a01*a10; 718 | var b01 = a00*a12 - a02*a10; 719 | var b02 = a00*a13 - a03*a10; 720 | var b03 = a01*a12 - a02*a11; 721 | var b04 = a01*a13 - a03*a11; 722 | var b05 = a02*a13 - a03*a12; 723 | var b06 = a20*a31 - a21*a30; 724 | var b07 = a20*a32 - a22*a30; 725 | var b08 = a20*a33 - a23*a30; 726 | var b09 = a21*a32 - a22*a31; 727 | var b10 = a21*a33 - a23*a31; 728 | var b11 = a22*a33 - a23*a32; 729 | 730 | // Calculate the determinant (inlined to avoid double-caching) 731 | var invDet = 1/(b00*b11 - b01*b10 + b02*b09 + b03*b08 - b04*b07 + b05*b06); 732 | 733 | dest[0] = (a11*b11 - a12*b10 + a13*b09)*invDet; 734 | dest[1] = (-a01*b11 + a02*b10 - a03*b09)*invDet; 735 | dest[2] = (a31*b05 - a32*b04 + a33*b03)*invDet; 736 | dest[3] = (-a21*b05 + a22*b04 - a23*b03)*invDet; 737 | dest[4] = (-a10*b11 + a12*b08 - a13*b07)*invDet; 738 | dest[5] = (a00*b11 - a02*b08 + a03*b07)*invDet; 739 | dest[6] = (-a30*b05 + a32*b02 - a33*b01)*invDet; 740 | dest[7] = (a20*b05 - a22*b02 + a23*b01)*invDet; 741 | dest[8] = (a10*b10 - a11*b08 + a13*b06)*invDet; 742 | dest[9] = (-a00*b10 + a01*b08 - a03*b06)*invDet; 743 | dest[10] = (a30*b04 - a31*b02 + a33*b00)*invDet; 744 | dest[11] = (-a20*b04 + a21*b02 - a23*b00)*invDet; 745 | dest[12] = (-a10*b09 + a11*b07 - a12*b06)*invDet; 746 | dest[13] = (a00*b09 - a01*b07 + a02*b06)*invDet; 747 | dest[14] = (-a30*b03 + a31*b01 - a32*b00)*invDet; 748 | dest[15] = (a20*b03 - a21*b01 + a22*b00)*invDet; 749 | 750 | return dest; 751 | }; 752 | 753 | /* 754 | * mat4.toRotationMat 755 | * Copies the upper 3x3 elements of a mat4 into another mat4 756 | * 757 | * Params: 758 | * mat - mat4 containing values to copy 759 | * dest - Optional, mat4 receiving copied values 760 | * 761 | * Returns: 762 | * dest is specified, a new mat4 otherwise 763 | */ 764 | mat4.toRotationMat = function(mat, dest) { 765 | if(!dest) { dest = mat4.create(); } 766 | 767 | dest[0] = mat[0]; 768 | dest[1] = mat[1]; 769 | dest[2] = mat[2]; 770 | dest[3] = mat[3]; 771 | dest[4] = mat[4]; 772 | dest[5] = mat[5]; 773 | dest[6] = mat[6]; 774 | dest[7] = mat[7]; 775 | dest[8] = mat[8]; 776 | dest[9] = mat[9]; 777 | dest[10] = mat[10]; 778 | dest[11] = mat[11]; 779 | dest[12] = 0; 780 | dest[13] = 0; 781 | dest[14] = 0; 782 | dest[15] = 1; 783 | 784 | return dest; 785 | }; 786 | 787 | /* 788 | * mat4.toMat3 789 | * Copies the upper 3x3 elements of a mat4 into a mat3 790 | * 791 | * Params: 792 | * mat - mat4 containing values to copy 793 | * dest - Optional, mat3 receiving copied values 794 | * 795 | * Returns: 796 | * dest is specified, a new mat3 otherwise 797 | */ 798 | mat4.toMat3 = function(mat, dest) { 799 | if(!dest) { dest = mat3.create(); } 800 | 801 | dest[0] = mat[0]; 802 | dest[1] = mat[1]; 803 | dest[2] = mat[2]; 804 | dest[3] = mat[4]; 805 | dest[4] = mat[5]; 806 | dest[5] = mat[6]; 807 | dest[6] = mat[8]; 808 | dest[7] = mat[9]; 809 | dest[8] = mat[10]; 810 | 811 | return dest; 812 | }; 813 | 814 | /* 815 | * mat4.toInverseMat3 816 | * Calculates the inverse of the upper 3x3 elements of a mat4 and copies the result into a mat3 817 | * The resulting matrix is useful for calculating transformed normals 818 | * 819 | * Params: 820 | * mat - mat4 containing values to invert and copy 821 | * dest - Optional, mat3 receiving values 822 | * 823 | * Returns: 824 | * dest is specified, a new mat3 otherwise 825 | */ 826 | mat4.toInverseMat3 = function(mat, dest) { 827 | // Cache the matrix values (makes for huge speed increases!) 828 | var a00 = mat[0], a01 = mat[1], a02 = mat[2]; 829 | var a10 = mat[4], a11 = mat[5], a12 = mat[6]; 830 | var a20 = mat[8], a21 = mat[9], a22 = mat[10]; 831 | 832 | var b01 = a22*a11-a12*a21; 833 | var b11 = -a22*a10+a12*a20; 834 | var b21 = a21*a10-a11*a20; 835 | 836 | var d = a00*b01 + a01*b11 + a02*b21; 837 | if (!d) { return null; } 838 | var id = 1/d; 839 | 840 | if(!dest) { dest = mat3.create(); } 841 | 842 | dest[0] = b01*id; 843 | dest[1] = (-a22*a01 + a02*a21)*id; 844 | dest[2] = (a12*a01 - a02*a11)*id; 845 | dest[3] = b11*id; 846 | dest[4] = (a22*a00 - a02*a20)*id; 847 | dest[5] = (-a12*a00 + a02*a10)*id; 848 | dest[6] = b21*id; 849 | dest[7] = (-a21*a00 + a01*a20)*id; 850 | dest[8] = (a11*a00 - a01*a10)*id; 851 | 852 | return dest; 853 | }; 854 | 855 | /* 856 | * mat4.multiply 857 | * Performs a matrix multiplication 858 | * 859 | * Params: 860 | * mat - mat4, first operand 861 | * mat2 - mat4, second operand 862 | * dest - Optional, mat4 receiving operation result. If not specified result is written to mat 863 | * 864 | * Returns: 865 | * dest if specified, mat otherwise 866 | */ 867 | mat4.multiply = function(mat, mat2, dest) { 868 | if(!dest) { dest = mat } 869 | 870 | // Cache the matrix values (makes for huge speed increases!) 871 | var a00 = mat[0], a01 = mat[1], a02 = mat[2], a03 = mat[3]; 872 | var a10 = mat[4], a11 = mat[5], a12 = mat[6], a13 = mat[7]; 873 | var a20 = mat[8], a21 = mat[9], a22 = mat[10], a23 = mat[11]; 874 | var a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15]; 875 | 876 | var b00 = mat2[0], b01 = mat2[1], b02 = mat2[2], b03 = mat2[3]; 877 | var b10 = mat2[4], b11 = mat2[5], b12 = mat2[6], b13 = mat2[7]; 878 | var b20 = mat2[8], b21 = mat2[9], b22 = mat2[10], b23 = mat2[11]; 879 | var b30 = mat2[12], b31 = mat2[13], b32 = mat2[14], b33 = mat2[15]; 880 | 881 | dest[0] = b00*a00 + b01*a10 + b02*a20 + b03*a30; 882 | dest[1] = b00*a01 + b01*a11 + b02*a21 + b03*a31; 883 | dest[2] = b00*a02 + b01*a12 + b02*a22 + b03*a32; 884 | dest[3] = b00*a03 + b01*a13 + b02*a23 + b03*a33; 885 | dest[4] = b10*a00 + b11*a10 + b12*a20 + b13*a30; 886 | dest[5] = b10*a01 + b11*a11 + b12*a21 + b13*a31; 887 | dest[6] = b10*a02 + b11*a12 + b12*a22 + b13*a32; 888 | dest[7] = b10*a03 + b11*a13 + b12*a23 + b13*a33; 889 | dest[8] = b20*a00 + b21*a10 + b22*a20 + b23*a30; 890 | dest[9] = b20*a01 + b21*a11 + b22*a21 + b23*a31; 891 | dest[10] = b20*a02 + b21*a12 + b22*a22 + b23*a32; 892 | dest[11] = b20*a03 + b21*a13 + b22*a23 + b23*a33; 893 | dest[12] = b30*a00 + b31*a10 + b32*a20 + b33*a30; 894 | dest[13] = b30*a01 + b31*a11 + b32*a21 + b33*a31; 895 | dest[14] = b30*a02 + b31*a12 + b32*a22 + b33*a32; 896 | dest[15] = b30*a03 + b31*a13 + b32*a23 + b33*a33; 897 | 898 | return dest; 899 | }; 900 | 901 | /* 902 | * mat4.multiplyVec3 903 | * Transforms a vec3 with the given matrix 904 | * 4th vector component is implicitly '1' 905 | * 906 | * Params: 907 | * mat - mat4 to transform the vector with 908 | * vec - vec3 to transform 909 | * dest - Optional, vec3 receiving operation result. If not specified result is written to vec 910 | * 911 | * Returns: 912 | * dest if specified, vec otherwise 913 | */ 914 | mat4.multiplyVec3 = function(mat, vec, dest) { 915 | if(!dest) { dest = vec } 916 | 917 | var x = vec[0], y = vec[1], z = vec[2]; 918 | 919 | dest[0] = mat[0]*x + mat[4]*y + mat[8]*z + mat[12]; 920 | dest[1] = mat[1]*x + mat[5]*y + mat[9]*z + mat[13]; 921 | dest[2] = mat[2]*x + mat[6]*y + mat[10]*z + mat[14]; 922 | 923 | return dest; 924 | }; 925 | 926 | /* 927 | * mat4.multiplyVec4 928 | * Transforms a vec4 with the given matrix 929 | * 930 | * Params: 931 | * mat - mat4 to transform the vector with 932 | * vec - vec4 to transform 933 | * dest - Optional, vec4 receiving operation result. If not specified result is written to vec 934 | * 935 | * Returns: 936 | * dest if specified, vec otherwise 937 | */ 938 | mat4.multiplyVec4 = function(mat, vec, dest) { 939 | if(!dest) { dest = vec } 940 | 941 | var x = vec[0], y = vec[1], z = vec[2], w = vec[3]; 942 | 943 | dest[0] = mat[0]*x + mat[4]*y + mat[8]*z + mat[12]*w; 944 | dest[1] = mat[1]*x + mat[5]*y + mat[9]*z + mat[13]*w; 945 | dest[2] = mat[2]*x + mat[6]*y + mat[10]*z + mat[14]*w; 946 | dest[3] = mat[3]*x + mat[7]*y + mat[11]*z + mat[15]*w; 947 | 948 | return dest; 949 | }; 950 | 951 | /* 952 | * mat4.translate 953 | * Translates a matrix by the given vector 954 | * 955 | * Params: 956 | * mat - mat4 to translate 957 | * vec - vec3 specifying the translation 958 | * dest - Optional, mat4 receiving operation result. If not specified result is written to mat 959 | * 960 | * Returns: 961 | * dest if specified, mat otherwise 962 | */ 963 | mat4.translate = function(mat, vec, dest) { 964 | var x = vec[0], y = vec[1], z = vec[2]; 965 | 966 | if(!dest || mat == dest) { 967 | mat[12] = mat[0]*x + mat[4]*y + mat[8]*z + mat[12]; 968 | mat[13] = mat[1]*x + mat[5]*y + mat[9]*z + mat[13]; 969 | mat[14] = mat[2]*x + mat[6]*y + mat[10]*z + mat[14]; 970 | mat[15] = mat[3]*x + mat[7]*y + mat[11]*z + mat[15]; 971 | return mat; 972 | } 973 | 974 | var a00 = mat[0], a01 = mat[1], a02 = mat[2], a03 = mat[3]; 975 | var a10 = mat[4], a11 = mat[5], a12 = mat[6], a13 = mat[7]; 976 | var a20 = mat[8], a21 = mat[9], a22 = mat[10], a23 = mat[11]; 977 | 978 | dest[0] = a00; 979 | dest[1] = a01; 980 | dest[2] = a02; 981 | dest[3] = a03; 982 | dest[4] = a10; 983 | dest[5] = a11; 984 | dest[6] = a12; 985 | dest[7] = a13; 986 | dest[8] = a20; 987 | dest[9] = a21; 988 | dest[10] = a22; 989 | dest[11] = a23; 990 | 991 | dest[12] = a00*x + a10*y + a20*z + mat[12]; 992 | dest[13] = a01*x + a11*y + a21*z + mat[13]; 993 | dest[14] = a02*x + a12*y + a22*z + mat[14]; 994 | dest[15] = a03*x + a13*y + a23*z + mat[15]; 995 | return dest; 996 | }; 997 | 998 | /* 999 | * mat4.scale 1000 | * Scales a matrix by the given vector 1001 | * 1002 | * Params: 1003 | * mat - mat4 to scale 1004 | * vec - vec3 specifying the scale for each axis 1005 | * dest - Optional, mat4 receiving operation result. If not specified result is written to mat 1006 | * 1007 | * Returns: 1008 | * dest if specified, mat otherwise 1009 | */ 1010 | mat4.scale = function(mat, vec, dest) { 1011 | var x = vec[0], y = vec[1], z = vec[2]; 1012 | 1013 | if(!dest || mat == dest) { 1014 | mat[0] *= x; 1015 | mat[1] *= x; 1016 | mat[2] *= x; 1017 | mat[3] *= x; 1018 | mat[4] *= y; 1019 | mat[5] *= y; 1020 | mat[6] *= y; 1021 | mat[7] *= y; 1022 | mat[8] *= z; 1023 | mat[9] *= z; 1024 | mat[10] *= z; 1025 | mat[11] *= z; 1026 | return mat; 1027 | } 1028 | 1029 | dest[0] = mat[0]*x; 1030 | dest[1] = mat[1]*x; 1031 | dest[2] = mat[2]*x; 1032 | dest[3] = mat[3]*x; 1033 | dest[4] = mat[4]*y; 1034 | dest[5] = mat[5]*y; 1035 | dest[6] = mat[6]*y; 1036 | dest[7] = mat[7]*y; 1037 | dest[8] = mat[8]*z; 1038 | dest[9] = mat[9]*z; 1039 | dest[10] = mat[10]*z; 1040 | dest[11] = mat[11]*z; 1041 | dest[12] = mat[12]; 1042 | dest[13] = mat[13]; 1043 | dest[14] = mat[14]; 1044 | dest[15] = mat[15]; 1045 | return dest; 1046 | }; 1047 | 1048 | /* 1049 | * mat4.rotate 1050 | * Rotates a matrix by the given angle around the specified axis 1051 | * If rotating around a primary axis (X,Y,Z) one of the specialized rotation functions should be used instead for performance 1052 | * 1053 | * Params: 1054 | * mat - mat4 to rotate 1055 | * angle - angle (in radians) to rotate 1056 | * axis - vec3 representing the axis to rotate around 1057 | * dest - Optional, mat4 receiving operation result. If not specified result is written to mat 1058 | * 1059 | * Returns: 1060 | * dest if specified, mat otherwise 1061 | */ 1062 | mat4.rotate = function(mat, angle, axis, dest) { 1063 | var x = axis[0], y = axis[1], z = axis[2]; 1064 | var len = Math.sqrt(x*x + y*y + z*z); 1065 | if (!len) { return null; } 1066 | if (len != 1) { 1067 | len = 1 / len; 1068 | x *= len; 1069 | y *= len; 1070 | z *= len; 1071 | } 1072 | 1073 | var s = Math.sin(angle); 1074 | var c = Math.cos(angle); 1075 | var t = 1-c; 1076 | 1077 | // Cache the matrix values (makes for huge speed increases!) 1078 | var a00 = mat[0], a01 = mat[1], a02 = mat[2], a03 = mat[3]; 1079 | var a10 = mat[4], a11 = mat[5], a12 = mat[6], a13 = mat[7]; 1080 | var a20 = mat[8], a21 = mat[9], a22 = mat[10], a23 = mat[11]; 1081 | 1082 | // Construct the elements of the rotation matrix 1083 | var b00 = x*x*t + c, b01 = y*x*t + z*s, b02 = z*x*t - y*s; 1084 | var b10 = x*y*t - z*s, b11 = y*y*t + c, b12 = z*y*t + x*s; 1085 | var b20 = x*z*t + y*s, b21 = y*z*t - x*s, b22 = z*z*t + c; 1086 | 1087 | if(!dest) { 1088 | dest = mat 1089 | } else if(mat != dest) { // If the source and destination differ, copy the unchanged last row 1090 | dest[12] = mat[12]; 1091 | dest[13] = mat[13]; 1092 | dest[14] = mat[14]; 1093 | dest[15] = mat[15]; 1094 | } 1095 | 1096 | // Perform rotation-specific matrix multiplication 1097 | dest[0] = a00*b00 + a10*b01 + a20*b02; 1098 | dest[1] = a01*b00 + a11*b01 + a21*b02; 1099 | dest[2] = a02*b00 + a12*b01 + a22*b02; 1100 | dest[3] = a03*b00 + a13*b01 + a23*b02; 1101 | 1102 | dest[4] = a00*b10 + a10*b11 + a20*b12; 1103 | dest[5] = a01*b10 + a11*b11 + a21*b12; 1104 | dest[6] = a02*b10 + a12*b11 + a22*b12; 1105 | dest[7] = a03*b10 + a13*b11 + a23*b12; 1106 | 1107 | dest[8] = a00*b20 + a10*b21 + a20*b22; 1108 | dest[9] = a01*b20 + a11*b21 + a21*b22; 1109 | dest[10] = a02*b20 + a12*b21 + a22*b22; 1110 | dest[11] = a03*b20 + a13*b21 + a23*b22; 1111 | return dest; 1112 | }; 1113 | 1114 | /* 1115 | * mat4.rotateX 1116 | * Rotates a matrix by the given angle around the X axis 1117 | * 1118 | * Params: 1119 | * mat - mat4 to rotate 1120 | * angle - angle (in radians) to rotate 1121 | * dest - Optional, mat4 receiving operation result. If not specified result is written to mat 1122 | * 1123 | * Returns: 1124 | * dest if specified, mat otherwise 1125 | */ 1126 | mat4.rotateX = function(mat, angle, dest) { 1127 | var s = Math.sin(angle); 1128 | var c = Math.cos(angle); 1129 | 1130 | // Cache the matrix values (makes for huge speed increases!) 1131 | var a10 = mat[4], a11 = mat[5], a12 = mat[6], a13 = mat[7]; 1132 | var a20 = mat[8], a21 = mat[9], a22 = mat[10], a23 = mat[11]; 1133 | 1134 | if(!dest) { 1135 | dest = mat 1136 | } else if(mat != dest) { // If the source and destination differ, copy the unchanged rows 1137 | dest[0] = mat[0]; 1138 | dest[1] = mat[1]; 1139 | dest[2] = mat[2]; 1140 | dest[3] = mat[3]; 1141 | 1142 | dest[12] = mat[12]; 1143 | dest[13] = mat[13]; 1144 | dest[14] = mat[14]; 1145 | dest[15] = mat[15]; 1146 | } 1147 | 1148 | // Perform axis-specific matrix multiplication 1149 | dest[4] = a10*c + a20*s; 1150 | dest[5] = a11*c + a21*s; 1151 | dest[6] = a12*c + a22*s; 1152 | dest[7] = a13*c + a23*s; 1153 | 1154 | dest[8] = a10*-s + a20*c; 1155 | dest[9] = a11*-s + a21*c; 1156 | dest[10] = a12*-s + a22*c; 1157 | dest[11] = a13*-s + a23*c; 1158 | return dest; 1159 | }; 1160 | 1161 | /* 1162 | * mat4.rotateY 1163 | * Rotates a matrix by the given angle around the Y axis 1164 | * 1165 | * Params: 1166 | * mat - mat4 to rotate 1167 | * angle - angle (in radians) to rotate 1168 | * dest - Optional, mat4 receiving operation result. If not specified result is written to mat 1169 | * 1170 | * Returns: 1171 | * dest if specified, mat otherwise 1172 | */ 1173 | mat4.rotateY = function(mat, angle, dest) { 1174 | var s = Math.sin(angle); 1175 | var c = Math.cos(angle); 1176 | 1177 | // Cache the matrix values (makes for huge speed increases!) 1178 | var a00 = mat[0], a01 = mat[1], a02 = mat[2], a03 = mat[3]; 1179 | var a20 = mat[8], a21 = mat[9], a22 = mat[10], a23 = mat[11]; 1180 | 1181 | if(!dest) { 1182 | dest = mat 1183 | } else if(mat != dest) { // If the source and destination differ, copy the unchanged rows 1184 | dest[4] = mat[4]; 1185 | dest[5] = mat[5]; 1186 | dest[6] = mat[6]; 1187 | dest[7] = mat[7]; 1188 | 1189 | dest[12] = mat[12]; 1190 | dest[13] = mat[13]; 1191 | dest[14] = mat[14]; 1192 | dest[15] = mat[15]; 1193 | } 1194 | 1195 | // Perform axis-specific matrix multiplication 1196 | dest[0] = a00*c + a20*-s; 1197 | dest[1] = a01*c + a21*-s; 1198 | dest[2] = a02*c + a22*-s; 1199 | dest[3] = a03*c + a23*-s; 1200 | 1201 | dest[8] = a00*s + a20*c; 1202 | dest[9] = a01*s + a21*c; 1203 | dest[10] = a02*s + a22*c; 1204 | dest[11] = a03*s + a23*c; 1205 | return dest; 1206 | }; 1207 | 1208 | /* 1209 | * mat4.rotateZ 1210 | * Rotates a matrix by the given angle around the Z axis 1211 | * 1212 | * Params: 1213 | * mat - mat4 to rotate 1214 | * angle - angle (in radians) to rotate 1215 | * dest - Optional, mat4 receiving operation result. If not specified result is written to mat 1216 | * 1217 | * Returns: 1218 | * dest if specified, mat otherwise 1219 | */ 1220 | mat4.rotateZ = function(mat, angle, dest) { 1221 | var s = Math.sin(angle); 1222 | var c = Math.cos(angle); 1223 | 1224 | // Cache the matrix values (makes for huge speed increases!) 1225 | var a00 = mat[0], a01 = mat[1], a02 = mat[2], a03 = mat[3]; 1226 | var a10 = mat[4], a11 = mat[5], a12 = mat[6], a13 = mat[7]; 1227 | 1228 | if(!dest) { 1229 | dest = mat 1230 | } else if(mat != dest) { // If the source and destination differ, copy the unchanged last row 1231 | dest[8] = mat[8]; 1232 | dest[9] = mat[9]; 1233 | dest[10] = mat[10]; 1234 | dest[11] = mat[11]; 1235 | 1236 | dest[12] = mat[12]; 1237 | dest[13] = mat[13]; 1238 | dest[14] = mat[14]; 1239 | dest[15] = mat[15]; 1240 | } 1241 | 1242 | // Perform axis-specific matrix multiplication 1243 | dest[0] = a00*c + a10*s; 1244 | dest[1] = a01*c + a11*s; 1245 | dest[2] = a02*c + a12*s; 1246 | dest[3] = a03*c + a13*s; 1247 | 1248 | dest[4] = a00*-s + a10*c; 1249 | dest[5] = a01*-s + a11*c; 1250 | dest[6] = a02*-s + a12*c; 1251 | dest[7] = a03*-s + a13*c; 1252 | 1253 | return dest; 1254 | }; 1255 | 1256 | /* 1257 | * mat4.frustum 1258 | * Generates a frustum matrix with the given bounds 1259 | * 1260 | * Params: 1261 | * left, right - scalar, left and right bounds of the frustum 1262 | * bottom, top - scalar, bottom and top bounds of the frustum 1263 | * near, far - scalar, near and far bounds of the frustum 1264 | * dest - Optional, mat4 frustum matrix will be written into 1265 | * 1266 | * Returns: 1267 | * dest if specified, a new mat4 otherwise 1268 | */ 1269 | mat4.frustum = function(left, right, bottom, top, near, far, dest) { 1270 | if(!dest) { dest = mat4.create(); } 1271 | var rl = (right - left); 1272 | var tb = (top - bottom); 1273 | var fn = (far - near); 1274 | dest[0] = (near*2) / rl; 1275 | dest[1] = 0; 1276 | dest[2] = 0; 1277 | dest[3] = 0; 1278 | dest[4] = 0; 1279 | dest[5] = (near*2) / tb; 1280 | dest[6] = 0; 1281 | dest[7] = 0; 1282 | dest[8] = (right + left) / rl; 1283 | dest[9] = (top + bottom) / tb; 1284 | dest[10] = -(far + near) / fn; 1285 | dest[11] = -1; 1286 | dest[12] = 0; 1287 | dest[13] = 0; 1288 | dest[14] = -(far*near*2) / fn; 1289 | dest[15] = 0; 1290 | return dest; 1291 | }; 1292 | 1293 | /* 1294 | * mat4.perspective 1295 | * Generates a perspective projection matrix with the given bounds 1296 | * 1297 | * Params: 1298 | * fovy - scalar, vertical field of view 1299 | * aspect - scalar, aspect ratio. typically viewport width/height 1300 | * near, far - scalar, near and far bounds of the frustum 1301 | * dest - Optional, mat4 frustum matrix will be written into 1302 | * 1303 | * Returns: 1304 | * dest if specified, a new mat4 otherwise 1305 | */ 1306 | mat4.perspective = function(fovy, aspect, near, far, dest) { 1307 | var top = near*Math.tan(fovy*Math.PI / 360.0); 1308 | var right = top*aspect; 1309 | return mat4.frustum(-right, right, -top, top, near, far, dest); 1310 | }; 1311 | 1312 | /* 1313 | * mat4.ortho 1314 | * Generates a orthogonal projection matrix with the given bounds 1315 | * 1316 | * Params: 1317 | * left, right - scalar, left and right bounds of the frustum 1318 | * bottom, top - scalar, bottom and top bounds of the frustum 1319 | * near, far - scalar, near and far bounds of the frustum 1320 | * dest - Optional, mat4 frustum matrix will be written into 1321 | * 1322 | * Returns: 1323 | * dest if specified, a new mat4 otherwise 1324 | */ 1325 | mat4.ortho = function(left, right, bottom, top, near, far, dest) { 1326 | if(!dest) { dest = mat4.create(); } 1327 | var rl = (right - left); 1328 | var tb = (top - bottom); 1329 | var fn = (far - near); 1330 | dest[0] = 2 / rl; 1331 | dest[1] = 0; 1332 | dest[2] = 0; 1333 | dest[3] = 0; 1334 | dest[4] = 0; 1335 | dest[5] = 2 / tb; 1336 | dest[6] = 0; 1337 | dest[7] = 0; 1338 | dest[8] = 0; 1339 | dest[9] = 0; 1340 | dest[10] = -2 / fn; 1341 | dest[11] = 0; 1342 | dest[12] = -(left + right) / rl; 1343 | dest[13] = -(top + bottom) / tb; 1344 | dest[14] = -(far + near) / fn; 1345 | dest[15] = 1; 1346 | return dest; 1347 | }; 1348 | 1349 | /* 1350 | * mat4.ortho 1351 | * Generates a look-at matrix with the given eye position, focal point, and up axis 1352 | * 1353 | * Params: 1354 | * eye - vec3, position of the viewer 1355 | * center - vec3, point the viewer is looking at 1356 | * up - vec3 pointing "up" 1357 | * dest - Optional, mat4 frustum matrix will be written into 1358 | * 1359 | * Returns: 1360 | * dest if specified, a new mat4 otherwise 1361 | */ 1362 | mat4.lookAt = function(eye, center, up, dest) { 1363 | if(!dest) { dest = mat4.create(); } 1364 | 1365 | var eyex = eye[0], 1366 | eyey = eye[1], 1367 | eyez = eye[2], 1368 | upx = up[0], 1369 | upy = up[1], 1370 | upz = up[2], 1371 | centerx = center[0], 1372 | centery = center[1], 1373 | centerz = center[2]; 1374 | 1375 | if (eyex == centerx && eyey == centery && eyez == centerz) { 1376 | return mat4.identity(dest); 1377 | } 1378 | 1379 | var z0,z1,z2,x0,x1,x2,y0,y1,y2,len; 1380 | 1381 | //vec3.direction(eye, center, z); 1382 | z0 = eyex - center[0]; 1383 | z1 = eyey - center[1]; 1384 | z2 = eyez - center[2]; 1385 | 1386 | // normalize (no check needed for 0 because of early return) 1387 | len = 1/Math.sqrt(z0*z0 + z1*z1 + z2*z2); 1388 | z0 *= len; 1389 | z1 *= len; 1390 | z2 *= len; 1391 | 1392 | //vec3.normalize(vec3.cross(up, z, x)); 1393 | x0 = upy*z2 - upz*z1; 1394 | x1 = upz*z0 - upx*z2; 1395 | x2 = upx*z1 - upy*z0; 1396 | len = Math.sqrt(x0*x0 + x1*x1 + x2*x2); 1397 | if (!len) { 1398 | x0 = 0; 1399 | x1 = 0; 1400 | x2 = 0; 1401 | } else { 1402 | len = 1/len; 1403 | x0 *= len; 1404 | x1 *= len; 1405 | x2 *= len; 1406 | }; 1407 | 1408 | //vec3.normalize(vec3.cross(z, x, y)); 1409 | y0 = z1*x2 - z2*x1; 1410 | y1 = z2*x0 - z0*x2; 1411 | y2 = z0*x1 - z1*x0; 1412 | 1413 | len = Math.sqrt(y0*y0 + y1*y1 + y2*y2); 1414 | if (!len) { 1415 | y0 = 0; 1416 | y1 = 0; 1417 | y2 = 0; 1418 | } else { 1419 | len = 1/len; 1420 | y0 *= len; 1421 | y1 *= len; 1422 | y2 *= len; 1423 | } 1424 | 1425 | dest[0] = x0; 1426 | dest[1] = y0; 1427 | dest[2] = z0; 1428 | dest[3] = 0; 1429 | dest[4] = x1; 1430 | dest[5] = y1; 1431 | dest[6] = z1; 1432 | dest[7] = 0; 1433 | dest[8] = x2; 1434 | dest[9] = y2; 1435 | dest[10] = z2; 1436 | dest[11] = 0; 1437 | dest[12] = -(x0*eyex + x1*eyey + x2*eyez); 1438 | dest[13] = -(y0*eyex + y1*eyey + y2*eyez); 1439 | dest[14] = -(z0*eyex + z1*eyey + z2*eyez); 1440 | dest[15] = 1; 1441 | 1442 | return dest; 1443 | }; 1444 | 1445 | /* 1446 | * mat4.str 1447 | * Returns a string representation of a mat4 1448 | * 1449 | * Params: 1450 | * mat - mat4 to represent as a string 1451 | * 1452 | * Returns: 1453 | * string representation of mat 1454 | */ 1455 | mat4.str = function(mat) { 1456 | return '[' + mat[0] + ', ' + mat[1] + ', ' + mat[2] + ', ' + mat[3] + 1457 | ', '+ mat[4] + ', ' + mat[5] + ', ' + mat[6] + ', ' + mat[7] + 1458 | ', '+ mat[8] + ', ' + mat[9] + ', ' + mat[10] + ', ' + mat[11] + 1459 | ', '+ mat[12] + ', ' + mat[13] + ', ' + mat[14] + ', ' + mat[15] + ']'; 1460 | }; 1461 | 1462 | /* 1463 | * quat4 - Quaternions 1464 | */ 1465 | quat4 = {}; 1466 | 1467 | /* 1468 | * quat4.create 1469 | * Creates a new instance of a quat4 using the default array type 1470 | * Any javascript array containing at least 4 numeric elements can serve as a quat4 1471 | * 1472 | * Params: 1473 | * quat - Optional, quat4 containing values to initialize with 1474 | * 1475 | * Returns: 1476 | * New quat4 1477 | */ 1478 | quat4.create = function(quat) { 1479 | var dest = new glMatrixArrayType(4); 1480 | 1481 | if(quat) { 1482 | dest[0] = quat[0]; 1483 | dest[1] = quat[1]; 1484 | dest[2] = quat[2]; 1485 | dest[3] = quat[3]; 1486 | } 1487 | 1488 | return dest; 1489 | }; 1490 | 1491 | /* 1492 | * quat4.set 1493 | * Copies the values of one quat4 to another 1494 | * 1495 | * Params: 1496 | * quat - quat4 containing values to copy 1497 | * dest - quat4 receiving copied values 1498 | * 1499 | * Returns: 1500 | * dest 1501 | */ 1502 | quat4.set = function(quat, dest) { 1503 | dest[0] = quat[0]; 1504 | dest[1] = quat[1]; 1505 | dest[2] = quat[2]; 1506 | dest[3] = quat[3]; 1507 | 1508 | return dest; 1509 | }; 1510 | 1511 | /* 1512 | * quat4.calculateW 1513 | * Calculates the W component of a quat4 from the X, Y, and Z components. 1514 | * Assumes that quaternion is 1 unit in length. 1515 | * Any existing W component will be ignored. 1516 | * 1517 | * Params: 1518 | * quat - quat4 to calculate W component of 1519 | * dest - Optional, quat4 receiving calculated values. If not specified result is written to quat 1520 | * 1521 | * Returns: 1522 | * dest if specified, quat otherwise 1523 | */ 1524 | quat4.calculateW = function(quat, dest) { 1525 | var x = quat[0], y = quat[1], z = quat[2]; 1526 | 1527 | if(!dest || quat == dest) { 1528 | quat[3] = -Math.sqrt(Math.abs(1.0 - x*x - y*y - z*z)); 1529 | return quat; 1530 | } 1531 | dest[0] = x; 1532 | dest[1] = y; 1533 | dest[2] = z; 1534 | dest[3] = -Math.sqrt(Math.abs(1.0 - x*x - y*y - z*z)); 1535 | return dest; 1536 | } 1537 | 1538 | /* 1539 | * quat4.inverse 1540 | * Calculates the inverse of a quat4 1541 | * 1542 | * Params: 1543 | * quat - quat4 to calculate inverse of 1544 | * dest - Optional, quat4 receiving inverse values. If not specified result is written to quat 1545 | * 1546 | * Returns: 1547 | * dest if specified, quat otherwise 1548 | */ 1549 | quat4.inverse = function(quat, dest) { 1550 | if(!dest || quat == dest) { 1551 | quat[0] *= 1; 1552 | quat[1] *= 1; 1553 | quat[2] *= 1; 1554 | return quat; 1555 | } 1556 | dest[0] = -quat[0]; 1557 | dest[1] = -quat[1]; 1558 | dest[2] = -quat[2]; 1559 | dest[3] = quat[3]; 1560 | return dest; 1561 | } 1562 | 1563 | /* 1564 | * quat4.length 1565 | * Calculates the length of a quat4 1566 | * 1567 | * Params: 1568 | * quat - quat4 to calculate length of 1569 | * 1570 | * Returns: 1571 | * Length of quat 1572 | */ 1573 | quat4.length = function(quat) { 1574 | var x = quat[0], y = quat[1], z = quat[2], w = quat[3]; 1575 | return Math.sqrt(x*x + y*y + z*z + w*w); 1576 | } 1577 | 1578 | /* 1579 | * quat4.normalize 1580 | * Generates a unit quaternion of the same direction as the provided quat4 1581 | * If quaternion length is 0, returns [0, 0, 0, 0] 1582 | * 1583 | * Params: 1584 | * quat - quat4 to normalize 1585 | * dest - Optional, quat4 receiving operation result. If not specified result is written to quat 1586 | * 1587 | * Returns: 1588 | * dest if specified, quat otherwise 1589 | */ 1590 | quat4.normalize = function(quat, dest) { 1591 | if(!dest) { dest = quat; } 1592 | 1593 | var x = quat[0], y = quat[1], z = quat[2], w = quat[3]; 1594 | var len = Math.sqrt(x*x + y*y + z*z + w*w); 1595 | if(len == 0) { 1596 | dest[0] = 0; 1597 | dest[1] = 0; 1598 | dest[2] = 0; 1599 | dest[3] = 0; 1600 | return dest; 1601 | } 1602 | len = 1/len; 1603 | dest[0] = x * len; 1604 | dest[1] = y * len; 1605 | dest[2] = z * len; 1606 | dest[3] = w * len; 1607 | 1608 | return dest; 1609 | } 1610 | 1611 | /* 1612 | * quat4.multiply 1613 | * Performs a quaternion multiplication 1614 | * 1615 | * Params: 1616 | * quat - quat4, first operand 1617 | * quat2 - quat4, second operand 1618 | * dest - Optional, quat4 receiving operation result. If not specified result is written to quat 1619 | * 1620 | * Returns: 1621 | * dest if specified, quat otherwise 1622 | */ 1623 | quat4.multiply = function(quat, quat2, dest) { 1624 | if(!dest) { dest = quat; } 1625 | 1626 | var qax = quat[0], qay = quat[1], qaz = quat[2], qaw = quat[3]; 1627 | var qbx = quat2[0], qby = quat2[1], qbz = quat2[2], qbw = quat2[3]; 1628 | 1629 | dest[0] = qax*qbw + qaw*qbx + qay*qbz - qaz*qby; 1630 | dest[1] = qay*qbw + qaw*qby + qaz*qbx - qax*qbz; 1631 | dest[2] = qaz*qbw + qaw*qbz + qax*qby - qay*qbx; 1632 | dest[3] = qaw*qbw - qax*qbx - qay*qby - qaz*qbz; 1633 | 1634 | return dest; 1635 | } 1636 | 1637 | /* 1638 | * quat4.multiplyVec3 1639 | * Transforms a vec3 with the given quaternion 1640 | * 1641 | * Params: 1642 | * quat - quat4 to transform the vector with 1643 | * vec - vec3 to transform 1644 | * dest - Optional, vec3 receiving operation result. If not specified result is written to vec 1645 | * 1646 | * Returns: 1647 | * dest if specified, vec otherwise 1648 | */ 1649 | quat4.multiplyVec3 = function(quat, vec, dest) { 1650 | if(!dest) { dest = vec; } 1651 | 1652 | var x = vec[0], y = vec[1], z = vec[2]; 1653 | var qx = quat[0], qy = quat[1], qz = quat[2], qw = quat[3]; 1654 | 1655 | // calculate quat * vec 1656 | var ix = qw*x + qy*z - qz*y; 1657 | var iy = qw*y + qz*x - qx*z; 1658 | var iz = qw*z + qx*y - qy*x; 1659 | var iw = -qx*x - qy*y - qz*z; 1660 | 1661 | // calculate result * inverse quat 1662 | dest[0] = ix*qw + iw*-qx + iy*-qz - iz*-qy; 1663 | dest[1] = iy*qw + iw*-qy + iz*-qx - ix*-qz; 1664 | dest[2] = iz*qw + iw*-qz + ix*-qy - iy*-qx; 1665 | 1666 | return dest; 1667 | } 1668 | 1669 | /* 1670 | * quat4.toMat3 1671 | * Calculates a 3x3 matrix from the given quat4 1672 | * 1673 | * Params: 1674 | * quat - quat4 to create matrix from 1675 | * dest - Optional, mat3 receiving operation result 1676 | * 1677 | * Returns: 1678 | * dest if specified, a new mat3 otherwise 1679 | */ 1680 | quat4.toMat3 = function(quat, dest) { 1681 | if(!dest) { dest = mat3.create(); } 1682 | 1683 | var x = quat[0], y = quat[1], z = quat[2], w = quat[3]; 1684 | 1685 | var x2 = x + x; 1686 | var y2 = y + y; 1687 | var z2 = z + z; 1688 | 1689 | var xx = x*x2; 1690 | var xy = x*y2; 1691 | var xz = x*z2; 1692 | 1693 | var yy = y*y2; 1694 | var yz = y*z2; 1695 | var zz = z*z2; 1696 | 1697 | var wx = w*x2; 1698 | var wy = w*y2; 1699 | var wz = w*z2; 1700 | 1701 | dest[0] = 1 - (yy + zz); 1702 | dest[1] = xy - wz; 1703 | dest[2] = xz + wy; 1704 | 1705 | dest[3] = xy + wz; 1706 | dest[4] = 1 - (xx + zz); 1707 | dest[5] = yz - wx; 1708 | 1709 | dest[6] = xz - wy; 1710 | dest[7] = yz + wx; 1711 | dest[8] = 1 - (xx + yy); 1712 | 1713 | return dest; 1714 | } 1715 | 1716 | /* 1717 | * quat4.toMat4 1718 | * Calculates a 4x4 matrix from the given quat4 1719 | * 1720 | * Params: 1721 | * quat - quat4 to create matrix from 1722 | * dest - Optional, mat4 receiving operation result 1723 | * 1724 | * Returns: 1725 | * dest if specified, a new mat4 otherwise 1726 | */ 1727 | quat4.toMat4 = function(quat, dest) { 1728 | if(!dest) { dest = mat4.create(); } 1729 | 1730 | var x = quat[0], y = quat[1], z = quat[2], w = quat[3]; 1731 | 1732 | var x2 = x + x; 1733 | var y2 = y + y; 1734 | var z2 = z + z; 1735 | 1736 | var xx = x*x2; 1737 | var xy = x*y2; 1738 | var xz = x*z2; 1739 | 1740 | var yy = y*y2; 1741 | var yz = y*z2; 1742 | var zz = z*z2; 1743 | 1744 | var wx = w*x2; 1745 | var wy = w*y2; 1746 | var wz = w*z2; 1747 | 1748 | dest[0] = 1 - (yy + zz); 1749 | dest[1] = xy - wz; 1750 | dest[2] = xz + wy; 1751 | dest[3] = 0; 1752 | 1753 | dest[4] = xy + wz; 1754 | dest[5] = 1 - (xx + zz); 1755 | dest[6] = yz - wx; 1756 | dest[7] = 0; 1757 | 1758 | dest[8] = xz - wy; 1759 | dest[9] = yz + wx; 1760 | dest[10] = 1 - (xx + yy); 1761 | dest[11] = 0; 1762 | 1763 | dest[12] = 0; 1764 | dest[13] = 0; 1765 | dest[14] = 0; 1766 | dest[15] = 1; 1767 | 1768 | return dest; 1769 | } 1770 | 1771 | /* 1772 | * quat4.slerp 1773 | * Performs a spherical linear interpolation between two quat4 1774 | * 1775 | * Params: 1776 | * quat - quat4, first quaternion 1777 | * quat2 - quat4, second quaternion 1778 | * lerp - interpolation amount between the two inputs 1779 | * dest - Optional, quat4 receiving operation result. If not specified result is written to quat 1780 | * 1781 | * Returns: 1782 | * dest if specified, quat otherwise 1783 | */ 1784 | quat4.slerp = function(quat, quat2, lerp, dest) { 1785 | if(!dest) { dest = quat; } 1786 | 1787 | var eps_lerp = lerp; 1788 | 1789 | var dot = quat[0]*quat2[0] + quat[1]*quat2[1] + quat[2]*quat2[2] + quat[3]*quat2[3]; 1790 | if (dot < 0.0) { 1791 | eps_lerp = -1.0 * lerp; 1792 | } 1793 | 1794 | dest[0] = 1.0 - lerp * quat[0] + eps_lerp * quat2[0]; 1795 | dest[1] = 1.0 - lerp * quat[1] + eps_lerp * quat2[1]; 1796 | dest[2] = 1.0 - lerp * quat[2] + eps_lerp * quat2[2]; 1797 | dest[3] = 1.0 - lerp * quat[3] + eps_lerp * quat2[3]; 1798 | 1799 | return dest; 1800 | } 1801 | 1802 | /* 1803 | * quat4.str 1804 | * Returns a string representation of a quaternion 1805 | * 1806 | * Params: 1807 | * quat - quat4 to represent as a string 1808 | * 1809 | * Returns: 1810 | * string representation of quat 1811 | */ 1812 | quat4.str = function(quat) { 1813 | return '[' + quat[0] + ', ' + quat[1] + ', ' + quat[2] + ', ' + quat[3] + ']'; 1814 | } 1815 | 1816 | -------------------------------------------------------------------------------- /priv/www/visualiser/js/model.js: -------------------------------------------------------------------------------- 1 | /*global octtree, vec3, Spring */ 2 | 3 | function searchX(elem, tree, xIncr, xMax) { 4 | var found = tree.findInRadius(elem.pos, xIncr / 2, 1); 5 | while (found.length > 0 && elem.pos[octtree.x] + xIncr < xMax) { 6 | elem.pos[octtree.x] += xIncr; 7 | found = tree.findInRadius(elem.pos, xIncr / 2, 1); 8 | } 9 | return (found.length === 0); 10 | } 11 | 12 | function searchY(elem, tree, yIncr) { 13 | var found = tree.findInRadius(elem.pos, yIncr / 2, 1); 14 | while (found.length > 0) { 15 | elem.pos[octtree.y] += yIncr; 16 | found = tree.findInRadius(elem.pos, yIncr / 2, 1); 17 | } 18 | } 19 | 20 | function bezierMid(startX, startY, ctl1X, ctl1Y, ctl2X, ctl2Y, endX, endY) { 21 | var start_ctl1X, start_ctl1Y, end_ctl2X, end_ctl2Y, ctl1_ctl2X, ctl1_ctl2Y, mid1X, mid1Y, mid2X, mid2Y; 22 | 23 | start_ctl1X = (startX + ctl1X) / 2; 24 | start_ctl1Y = (startY + ctl1Y) / 2; 25 | 26 | end_ctl2X = (endX + ctl2X) / 2; 27 | end_ctl2Y = (endY + ctl2Y) / 2; 28 | 29 | ctl1_ctl2X = (ctl1X + ctl2X) / 2; 30 | ctl1_ctl2Y = (ctl1Y + ctl2Y) / 2; 31 | 32 | mid1X = (start_ctl1X + ctl1_ctl2X) / 2; 33 | mid1Y = (start_ctl1Y + ctl1_ctl2Y) / 2; 34 | 35 | mid2X = (end_ctl2X + ctl1_ctl2X) / 2; 36 | mid2Y = (end_ctl2Y + ctl1_ctl2Y) / 2; 37 | 38 | return [(mid1X + mid2X) / 2, (mid1Y + mid2Y) / 2]; 39 | } 40 | 41 | function stringifyObject(a) { 42 | var b, e; 43 | b = {}; 44 | for (e in a) { 45 | if (a.hasOwnProperty(e)) { 46 | if ("object" === typeof a[e]) { 47 | b[e] = stringifyObject(a[e]); 48 | } else { 49 | b[e] = "" + a[e]; 50 | } 51 | } 52 | } 53 | return b; 54 | } 55 | 56 | String.prototype.toTitleCase = function () { 57 | return this.replace(/(^|_)([a-z])/g, 58 | function (str, g1, g2, offset, totalStr) { 59 | return g1.replace("_", " ") + g2.toUpperCase(); 60 | }); 61 | }; 62 | 63 | var Consumer = {}; 64 | Consumer.render = function (channel, queue, ctx, consumerTag) { 65 | var yMid, xCtl, dim, mid; 66 | ctx.beginPath(); 67 | yMid = (channel.yMax + queue.pos[octtree.y]) / 2; 68 | xCtl = queue.pos[octtree.x]; 69 | ctx.moveTo(channel.pos[octtree.x], channel.yMax); 70 | ctx.bezierCurveTo(channel.pos[octtree.x], yMid, 71 | xCtl, queue.pos[octtree.y] - channel.yInit, 72 | xCtl, queue.pos[octtree.y] - queue.fontSize); 73 | ctx.moveTo(channel.pos[octtree.x], channel.yMax); 74 | ctx.closePath(); 75 | ctx.stroke(); 76 | 77 | dim = ctx.measureText(consumerTag); 78 | mid = bezierMid(channel.pos[octtree.x], channel.yMax, 79 | channel.pos[octtree.x], yMid, 80 | xCtl, queue.pos[octtree.y] - channel.yInit, 81 | xCtl, queue.pos[octtree.y] - queue.fontSize); 82 | ctx.textBaseline = "middle"; 83 | ctx.textAlign = "center"; 84 | ctx.fillStyle = "rgba(255, 255, 255, 0.67)"; 85 | ctx.fillRect(mid[0] - (dim.width / 2), mid[1] - (channel.fontSize / 2), 86 | dim.width, channel.fontSize); 87 | ctx.fillStyle = ctx.strokeStyle; 88 | ctx.fillText(consumerTag, mid[0], mid[1]); 89 | 90 | ctx.beginPath(); 91 | ctx.moveTo(channel.pos[octtree.x], channel.yMax); 92 | ctx.lineTo(channel.pos[octtree.x] - (channel.fontSize / 2), 93 | channel.yMax + channel.fontSize); 94 | ctx.lineTo(channel.pos[octtree.x] + (channel.fontSize / 2), 95 | channel.yMax + channel.fontSize); 96 | ctx.closePath(); 97 | ctx.fillStyle = ctx.strokeStyle; 98 | ctx.fill(); 99 | }; 100 | 101 | var Publisher = {}; 102 | Publisher.render = function (channel, exchange, ctx) { 103 | var yMid, xCtl; 104 | ctx.beginPath(); 105 | yMid = (channel.yMax + exchange.pos[octtree.y]) / 2; 106 | xCtl = exchange.pos[octtree.x]; 107 | ctx.moveTo(channel.pos[octtree.x], channel.yMax); 108 | ctx.bezierCurveTo(channel.pos[octtree.x], yMid, 109 | xCtl, exchange.pos[octtree.y] - channel.yInit, 110 | xCtl, exchange.pos[octtree.y] - exchange.fontSize); 111 | ctx.moveTo(channel.pos[octtree.x], channel.yMax); 112 | ctx.closePath(); 113 | ctx.stroke(); 114 | 115 | ctx.beginPath(); 116 | ctx.moveTo(exchange.pos[octtree.x], 117 | exchange.pos[octtree.y] - exchange.fontSize); 118 | ctx.lineTo(exchange.pos[octtree.x] - exchange.fontSize / 2, 119 | exchange.pos[octtree.y] - 2 * exchange.fontSize); 120 | ctx.lineTo(exchange.pos[octtree.x] + exchange.fontSize / 2, 121 | exchange.pos[octtree.y] - 2 * exchange.fontSize); 122 | ctx.closePath(); 123 | ctx.fillStyle = ctx.strokeStyle; 124 | ctx.fill(); 125 | 126 | }; 127 | 128 | function Channel(tree, elem, model) { 129 | this.name = elem.name; 130 | this.pos = vec3.create(); 131 | this.findNewPosition(model, tree); 132 | 133 | this.next_pos = vec3.create(this.pos); 134 | this.mass = 0.1; 135 | this.velocity = vec3.create(); 136 | this.ideal = { pos : vec3.create() }; 137 | this.disabled = false; 138 | this.update(elem); 139 | tree.add(this); 140 | } 141 | 142 | Channel.prototype = { 143 | yInit : 120, 144 | yIncr : 50, 145 | xInit : 100, 146 | xIncr : 50, 147 | xMax : 200, 148 | yBoundary : 200, 149 | attributes : [ 'acks_uncommitted', 'client_flow_blocked', 'confirm', 'connection_details', 150 | 'consumer_count', 'message_stats', 'messages_unacknowledged', 151 | 'messages_unconfirmed', 'node', 'number', 'prefetch_count', 'transactional', 152 | 'user', 'vhost' ], 153 | pos : vec3.create(), 154 | fontSize : 12, 155 | spring : new Spring(), 156 | details : undefined, 157 | object_type : 'channel', 158 | detail_attributes : [ 'name', 'user', 'transactional', 'confirm', 'node', 'vhost', 159 | 'prefetch_count', 'messages_unacknowledged', 'messages_unconfirmed', 160 | 'consumer_count', 'client_flow_blocked' ] 161 | }; 162 | Channel.prototype.spring.octtreeLimit = 10; 163 | Channel.prototype.spring.octtreeRadius = 500; 164 | Channel.prototype.spring.equilibriumLength = 0; 165 | Channel.prototype.spring.dampingFactor = 0.1; 166 | Channel.prototype.spring.pull = true; 167 | Channel.prototype.spring.push = false; 168 | 169 | Channel.prototype.findNewPosition = function (model, tree) { 170 | this.pos[octtree.x] = this.xInit; 171 | this.pos[octtree.y] = this.yInit; 172 | this.pos[octtree.z] = 0; 173 | 174 | while (! searchX(this, tree, this.xIncr, this.xMax)) { 175 | this.pos[octtree.y] += this.yIncr; 176 | this.pos[octtree.x] = this.xInit + (this.pos[octtree.y] / 10); 177 | } 178 | 179 | this.yMin = this.pos[octtree.y]; 180 | this.yMax = this.pos[octtree.y]; 181 | }; 182 | Channel.prototype.canvasResized = function (canvas) { 183 | Channel.prototype.xMax = canvas.width; 184 | }; 185 | Channel.prototype.update = function (elem) { 186 | var attr, i; 187 | for (i = 0; i < this.attributes.length; i += 1) { 188 | attr = this.attributes[i]; 189 | this[attr] = elem[attr]; 190 | } 191 | }; 192 | Channel.prototype.remove = function (tree, model) { 193 | tree.del(this); 194 | }; 195 | Channel.prototype.render = function (model, ctx) { 196 | var i, dim, consumer, queue, publisher, exchange; 197 | if (this.disabled) { 198 | return; 199 | } 200 | dim = ctx.measureText(this.name); 201 | if (model.cull(this.pos[octtree.x] - this.fontSize, 202 | this.pos[octtree.y] - (dim.width / 2) - this.fontSize, 203 | this.fontSize * 2, 204 | dim.width + (this.fontSize * 2))) { 205 | return; 206 | } 207 | 208 | this.yMax = this.pos[octtree.y] + (dim.width / 2) + this.fontSize; 209 | this.yMin = this.pos[octtree.y] - (dim.width / 2) - this.fontSize; 210 | 211 | ctx.beginPath(); 212 | ctx.textAlign = "center"; 213 | ctx.textBaseline = "middle"; 214 | 215 | ctx.lineWidth = 2.0; 216 | ctx.strokeStyle = "black"; 217 | ctx.moveTo(this.pos[octtree.x] - this.fontSize, this.yMin); 218 | ctx.lineTo(this.pos[octtree.x] + this.fontSize, this.yMin); 219 | ctx.lineTo(this.pos[octtree.x] + this.fontSize, this.yMax); 220 | ctx.lineTo(this.pos[octtree.x] - this.fontSize, this.yMax); 221 | ctx.closePath(); 222 | this.preStroke(model, ctx); 223 | 224 | ctx.save(); 225 | ctx.translate(this.pos[octtree.x], this.pos[octtree.y]); 226 | ctx.rotate(3 * Math.PI / 2); 227 | ctx.fillStyle = ctx.strokeStyle; 228 | ctx.fillText(this.name, 0, 0); 229 | ctx.restore(); 230 | 231 | if (undefined !== this.details) { 232 | model.resetHighlighted(); 233 | ctx.lineWidth = 2.0; 234 | if (undefined !== this.details.consumer_details) { 235 | ctx.strokeStyle = "#00a000"; 236 | for (i = 0; i < this.details.consumer_details.length; i += 1) { 237 | consumer = this.details.consumer_details[i]; 238 | queue = consumer.queue_details.name; 239 | if (undefined !== model.queue[queue] && ! model.queue[queue].disabled) { 240 | model.setHighlighted(model.queue[queue]); 241 | Consumer.render(this, model.queue[queue], ctx, consumer.consumer_tag); 242 | } 243 | } 244 | } 245 | 246 | if (undefined !== this.details.publishes) { 247 | ctx.strokeStyle = "#0000a0"; 248 | for (i = 0; i < this.details.publishes.length; i += 1) { 249 | publisher = this.details.publishes[i]; 250 | exchange = publisher.exchange.name; 251 | if (undefined !== model.exchange[exchange] && 252 | ! model.exchange[exchange].disabled) { 253 | model.setHighlighted(model.exchange[exchange]); 254 | Publisher.render(this, model.exchange[exchange], ctx); 255 | } 256 | } 257 | } 258 | } 259 | }; 260 | Channel.prototype.preStroke = function (model, ctx) { 261 | }; 262 | Channel.prototype.animate = function (elapsed) { 263 | if (this.yBoundary > this.pos[octtree.y]) { 264 | this.ideal.pos[octtree.x] = this.pos[octtree.x]; 265 | this.ideal.pos[octtree.y] = this.yInit; 266 | this.spring.apply(elapsed, this, this.ideal); 267 | } 268 | }; 269 | Channel.prototype.disable = function (model) { 270 | model.channels_visible -= 1; 271 | }; 272 | Channel.prototype.enable = function (model, tree) { 273 | model.channels_visible += 1; 274 | this.findNewPosition(model, tree); 275 | }; 276 | Channel.prototype.getDetails = function () { 277 | }; 278 | Channel.prototype.stringAttributes = function () { 279 | var obj, i, attName, attNameTitle; 280 | obj = { Channel : '', 281 | attributeOrder : ['Channel'] }; 282 | for (i in this.detail_attributes) { 283 | attName = this.detail_attributes[i]; 284 | attNameTitle = attName.toTitleCase(); 285 | obj.attributeOrder.push(attNameTitle); 286 | if ("object" === typeof this[attName]) { 287 | obj[attNameTitle] = stringifyObject(this[attName]); 288 | } else { 289 | obj[attNameTitle] = "" + this[attName]; 290 | } 291 | } 292 | 293 | if (undefined !== this.message_stats) { 294 | if (undefined !== this.message_stats.publish_details) { 295 | obj.attributeOrder.push('Publish Rate (msgs/sec)'); 296 | obj['Publish Rate (msgs/sec)'] = "" + Math.round(this.message_stats.publish_details.rate); 297 | } 298 | 299 | if (undefined !== this.message_stats.deliver_get_details) { 300 | obj.attributeOrder.push('Delivery and Get Rate (msgs/sec)'); 301 | obj['Delivery and Get Rate (msgs/sec)'] = "" + Math.round(this.message_stats.deliver_get_details.rate); 302 | } 303 | 304 | if (undefined !== this.message_stats.ack_details) { 305 | obj.attributeOrder.push('Delivery Acknowledgement Rate (acks/sec)'); 306 | obj['Delivery Acknowledgement Rate (acks/sec)'] = "" + Math.round(this.message_stats.ack_details.rate); 307 | } 308 | } 309 | 310 | return obj; 311 | }; 312 | Channel.prototype.url = function () { 313 | return "/channels/" + encodeURIComponent(this.name); 314 | }; 315 | Channel.prototype.navigateTo = function () { 316 | document.location = "../#" + this.url(); 317 | }; 318 | 319 | function Exchange(tree, elem, model) { 320 | this.name = elem.name; 321 | this.pos = vec3.create(); 322 | this.findNewPosition(model, tree); 323 | this.next_pos = vec3.create(this.pos); 324 | this.mass = 0.1; 325 | this.velocity = vec3.create(); 326 | this.ideal = { pos : vec3.create() }; 327 | this.disabled = false; 328 | this.bindings_outbound = { exchange : {}, queue : {} }; 329 | this.bindings_inbound = {}; 330 | this.update(elem); 331 | tree.add(this); 332 | } 333 | 334 | Exchange.prototype = { 335 | yInit : 50, 336 | yIncr : 50, 337 | xInit : 100, 338 | xBoundary : 200, 339 | attributes : [ 'arguments', 'auto_delete', 'durable', 'internal', 'type', 340 | 'message_stats_out', 'message_stats_in', 'vhost' ], 341 | pos : vec3.create(), 342 | fontSize : 12, 343 | spring : new Spring(), 344 | details : undefined, 345 | object_type : 'exchange', 346 | detail_attributes : [ 'name', 'type', 'durable', 'auto_delete', 'internal', 'arguments', 'vhost' ] 347 | }; 348 | Exchange.prototype.spring.octtreeLimit = 10; 349 | Exchange.prototype.spring.octtreeRadius = 500; 350 | Exchange.prototype.spring.equilibriumLength = 0; 351 | Exchange.prototype.spring.dampingFactor = 0.1; 352 | Exchange.prototype.spring.pull = true; 353 | Exchange.prototype.spring.push = false; 354 | 355 | Exchange.prototype.findNewPosition = function (model, tree) { 356 | this.pos[octtree.x] = this.xInit; 357 | this.pos[octtree.y] = this.yInit; 358 | this.pos[octtree.z] = 0; 359 | 360 | searchY(this, tree, this.yIncr); 361 | 362 | this.xMin = this.pos[octtree.x]; 363 | this.xMax = this.pos[octtree.x]; 364 | }; 365 | Exchange.prototype.canvasResized = function (canvas) { 366 | Exchange.prototype.xInit = canvas.width / 6; 367 | Exchange.prototype.xBoundary = 2 * canvas.width / 6; 368 | }; 369 | Exchange.prototype.update = function (elem) { 370 | var attr, i; 371 | for (i = 0; i < this.attributes.length; i += 1) { 372 | attr = this.attributes[i]; 373 | this[attr] = elem[attr]; 374 | } 375 | }; 376 | Exchange.prototype.remove = function (tree, model) { 377 | tree.del(this); 378 | }; 379 | Exchange.prototype.render = function (model, ctx) { 380 | var i, dim, channel; 381 | if (this.disabled) { 382 | return; 383 | } 384 | for (i in this.bindings_outbound.exchange) { 385 | this.bindings_outbound.exchange[i].render(model, ctx); 386 | } 387 | if (model.rendering.queue.enabled) { 388 | for (i in this.bindings_outbound.queue) { 389 | this.bindings_outbound.queue[i].render(model, ctx); 390 | } 391 | } 392 | dim = ctx.measureText(this.name); 393 | if (model.cull(this.pos[octtree.x] - (dim.width / 2) - this.fontSize, 394 | this.pos[octtree.y] - this.fontSize, 395 | dim.width + (2 * this.fontSize), 396 | 2 * this.fontSize)) { 397 | return; 398 | } 399 | 400 | ctx.beginPath(); 401 | ctx.textAlign = "center"; 402 | ctx.textBaseline = "middle"; 403 | 404 | ctx.lineWidth = 2.0; 405 | ctx.strokeStyle = "black"; 406 | 407 | ctx.arc(this.pos[octtree.x] - (dim.width / 2), this.pos[octtree.y], 408 | this.fontSize, Math.PI / 2, 3 * Math.PI / 2, false); 409 | ctx.lineTo(this.pos[octtree.x] + (dim.width / 2), this.pos[octtree.y] - 410 | this.fontSize); 411 | 412 | ctx.arc(this.pos[octtree.x] + (dim.width / 2), this.pos[octtree.y], 413 | this.fontSize, 3 * Math.PI / 2, Math.PI / 2, false); 414 | ctx.closePath(); 415 | 416 | this.preStroke(model, ctx); 417 | 418 | ctx.fillStyle = ctx.strokeStyle; 419 | ctx.fillText(this.name, this.pos[octtree.x], this.pos[octtree.y]); 420 | 421 | this.xMin = this.pos[octtree.x] - (dim.width / 2) - this.fontSize; 422 | this.xMax = this.pos[octtree.x] + (dim.width / 2) + this.fontSize; 423 | 424 | if (undefined !== this.details) { 425 | model.resetHighlighted(); 426 | ctx.lineWidth = 2.0; 427 | ctx.strokeStyle = "#00a000"; 428 | if (undefined !== this.details.incoming) { 429 | for (i = 0; i < this.details.incoming.length; i += 1) { 430 | channel = this.details.incoming[i].channel_details.name; 431 | if (undefined !== model.channel[channel] && ! model.channel[channel].disabled) { 432 | model.setHighlighted(model.channel[channel]); 433 | Publisher.render(model.channel[channel], this, ctx); 434 | } 435 | } 436 | } 437 | 438 | for (i in this.bindings_outbound.queue) { 439 | model.setHighlighted(model.queue[this.bindings_outbound.queue[i].destination]); 440 | } 441 | for (i in this.bindings_outbound.exchange) { 442 | model.setHighlighted(model.exchange[this.bindings_outbound.exchange[i].destination]); 443 | } 444 | for (i in this.bindings_inbound) { 445 | model.setHighlighted(model.exchange[this.bindings_inbound[i].source]); 446 | } 447 | 448 | } 449 | }; 450 | Exchange.prototype.preStroke = function (model, ctx) { 451 | }; 452 | Exchange.prototype.animate = function (elapsed) { 453 | if (this.xBoundary > this.pos[octtree.x]) { 454 | this.ideal.pos[octtree.x] = this.xInit; 455 | this.ideal.pos[octtree.y] = this.pos[octtree.y]; 456 | this.spring.apply(elapsed, this, this.ideal); 457 | } 458 | }; 459 | Exchange.prototype.disable = function (model) { 460 | model.exchanges_visible -= 1; 461 | }; 462 | Exchange.prototype.enable = function (model, tree) { 463 | model.exchanges_visible += 1; 464 | this.findNewPosition(model, tree); 465 | }; 466 | Exchange.prototype.getDetails = function () { 467 | }; 468 | Exchange.prototype.stringAttributes = function () { 469 | var obj, i, attName, attNameTitle; 470 | obj = { Exchange : '', 471 | attributeOrder : ['Exchange'] }; 472 | for (i in this.detail_attributes) { 473 | attName = this.detail_attributes[i]; 474 | attNameTitle = attName.toTitleCase(); 475 | obj.attributeOrder.push(attNameTitle); 476 | if ("object" === typeof this[attName]) { 477 | obj[attNameTitle] = stringifyObject(this[attName]); 478 | } else { 479 | obj[attNameTitle] = "" + this[attName]; 480 | } 481 | } 482 | 483 | obj.attributeOrder.push('Outgoing Queue Bindings'); 484 | obj['Outgoing Queue Bindings'] = "" + Object.keys(this.bindings_outbound.queue).length; 485 | 486 | obj.attributeOrder.push('Outgoing Exchange Bindings'); 487 | obj['Outgoing Exchange Bindings'] = "" + Object.keys(this.bindings_outbound.exchange).length; 488 | 489 | obj.attributeOrder.push('Incoming Exchange Bindings'); 490 | obj['Incoming Exchange Bindings'] = "" + Object.keys(this.bindings_inbound).length; 491 | 492 | if (undefined !== this.message_stats_in && 493 | undefined !== this.message_stats_in.publish_details) { 494 | obj.attributeOrder.push('Message Incoming Rate (msgs/sec)'); 495 | obj['Message Incoming Rate (msgs/sec)'] = "" + Math.round(this.message_stats_in.publish_details.rate); 496 | } 497 | 498 | if (undefined !== this.message_stats_out && 499 | undefined !== this.message_stats_out.publish_details) { 500 | obj.attributeOrder.push('Message Outgoing Rate (msgs/sec)'); 501 | obj['Message Outgoing Rate (msgs/sec)'] = "" + Math.round(this.message_stats_out.publish_details.rate); 502 | } 503 | 504 | return obj; 505 | }; 506 | Exchange.prototype.url = function () { 507 | var name; 508 | if (this.name === "") { 509 | name = "amq.default"; 510 | } else { 511 | name = this.name; 512 | } 513 | return "/exchanges/" + encodeURIComponent(this.vhost) + 514 | "/" + encodeURIComponent(name); 515 | }; 516 | Exchange.prototype.navigateTo = function () { 517 | document.location = "../#" + this.url(); 518 | }; 519 | 520 | function Queue(tree, elem, model) { 521 | this.name = elem.name; 522 | this.pos = vec3.create(); 523 | this.findNewPosition(model, tree); 524 | this.next_pos = vec3.create(this.pos); 525 | this.mass = 0.1; 526 | this.velocity = vec3.create(); 527 | this.ideal = { pos : vec3.create() }; 528 | this.disabled = false; 529 | this.bindings_inbound = {}; 530 | this.update(elem); 531 | tree.add(this); 532 | } 533 | 534 | Queue.prototype = { 535 | yInit : 50, 536 | yIncr : 50, 537 | xInit : 400, 538 | xBoundary : 300, 539 | attributes : [ 'arguments', 'auto_delete', 'durable', 'messages', 540 | 'messages_ready', 'messages_unacknowledged', 'message_stats', 541 | 'node', 'owner_pid_details', 'vhost', 'memory', 'consumers' ], 542 | pos : vec3.create(), 543 | fontSize : 12, 544 | spring : new Spring(), 545 | details : undefined, 546 | object_type : 'queue', 547 | detail_attributes : [ 'name', 'durable', 'auto_delete', 'arguments', 'node', 'vhost', 548 | 'messages_ready', 'messages_unacknowledged', 'consumers', 'memory' ] 549 | }; 550 | Queue.prototype.spring.octtreeLimit = 10; 551 | Queue.prototype.spring.octtreeRadius = 500; 552 | Queue.prototype.spring.equilibriumLength = 0; 553 | Queue.prototype.spring.dampingFactor = 0.1; 554 | Queue.prototype.spring.pull = true; 555 | Queue.prototype.spring.push = false; 556 | 557 | Queue.prototype.findNewPosition = function (model, tree) { 558 | this.pos[octtree.x] = this.xInit; 559 | this.pos[octtree.y] = this.yInit; 560 | this.pos[octtree.z] = 0; 561 | 562 | searchY(this, tree, this.yIncr); 563 | 564 | this.xMin = this.pos[octtree.x]; 565 | this.xMax = this.pos[octtree.x]; 566 | }; 567 | Queue.prototype.canvasResized = function (canvas) { 568 | Queue.prototype.xInit = 5 * canvas.width / 6; 569 | Queue.prototype.xBoundary = 4 * canvas.width / 6; 570 | }; 571 | Queue.prototype.update = function (elem) { 572 | var attr, i; 573 | for (i = 0; i < this.attributes.length; i += 1) { 574 | attr = this.attributes[i]; 575 | this[attr] = elem[attr]; 576 | } 577 | }; 578 | Queue.prototype.remove = function (tree, model) { 579 | tree.del(this); 580 | }; 581 | Queue.prototype.render = function (model, ctx) { 582 | var text, dim, i, channel; 583 | if (this.disabled) { 584 | return; 585 | } 586 | text = this.name + " (" + this.messages_ready + ", " + 587 | this.messages_unacknowledged + ")"; 588 | dim = ctx.measureText(text); 589 | if (model.cull(this.pos[octtree.x] - (dim.width / 2) - this.fontSize, 590 | this.pos[octtree.y] - this.fontSize, 591 | dim.width + (2 * this.fontSize), 592 | 2 * this.fontSize)) { 593 | return; 594 | } 595 | ctx.beginPath(); 596 | ctx.textAlign = "center"; 597 | ctx.textBaseline = "middle"; 598 | 599 | ctx.lineWidth = 2.0; 600 | ctx.strokeStyle = "black"; 601 | ctx.moveTo(this.pos[octtree.x] - (dim.width / 2) - this.fontSize, 602 | this.pos[octtree.y] - this.fontSize); 603 | ctx.lineTo(this.pos[octtree.x] + (dim.width / 2) + this.fontSize, 604 | this.pos[octtree.y] - this.fontSize); 605 | ctx.lineTo(this.pos[octtree.x] + (dim.width / 2) + this.fontSize, 606 | this.pos[octtree.y] + this.fontSize); 607 | ctx.lineTo(this.pos[octtree.x] - (dim.width / 2) - this.fontSize, 608 | this.pos[octtree.y] + this.fontSize); 609 | ctx.closePath(); 610 | 611 | this.preStroke(model, ctx); 612 | 613 | ctx.fillStyle = ctx.strokeStyle; 614 | ctx.fillText(text, this.pos[octtree.x], this.pos[octtree.y]); 615 | 616 | this.xMin = this.pos[octtree.x] - (dim.width / 2) - this.fontSize; 617 | this.xMax = this.pos[octtree.x] + (dim.width / 2) + this.fontSize; 618 | 619 | if (undefined !== this.details && undefined !== this.details.consumer_details) { 620 | model.resetHighlighted(); 621 | ctx.lineWidth = 2.0; 622 | ctx.strokeStyle = "#0000a0"; 623 | for (i = 0; i < this.details.consumer_details.length; i += 1) { 624 | channel = this.details.consumer_details[i].channel_details.name; 625 | if (undefined !== model.channel[channel] && ! model.channel[channel].disabled) { 626 | model.setHighlighted(model.channel[channel]); 627 | Consumer.render(model.channel[channel], this, ctx, 628 | this.details.consumer_details[i].consumer_tag); 629 | } 630 | } 631 | for (i in this.bindings_inbound) { 632 | model.setHighlighted(model.exchange[this.bindings_inbound[i].source]); 633 | } 634 | } 635 | }; 636 | Queue.prototype.preStroke = function (model, ctx) { 637 | }; 638 | Queue.prototype.animate = function (elapsed) { 639 | if (this.xBoundary < this.pos[octtree.x]) { 640 | this.ideal.pos[octtree.x] = this.xInit; 641 | this.ideal.pos[octtree.y] = this.pos[octtree.y]; 642 | this.spring.apply(elapsed, this, this.ideal); 643 | } 644 | }; 645 | Queue.prototype.disable = function (model) { 646 | model.queues_visible -= 1; 647 | }; 648 | Queue.prototype.enable = function (model, tree) { 649 | model.queues_visible += 1; 650 | this.findNewPosition(model, tree); 651 | }; 652 | Queue.prototype.getDetails = function () { 653 | }; 654 | Queue.prototype.stringAttributes = function () { 655 | var obj, i, attName, attNameTitle; 656 | obj = { Queue : '', 657 | attributeOrder : ['Queue'] }; 658 | for (i in this.detail_attributes) { 659 | attName = this.detail_attributes[i]; 660 | attNameTitle = attName.toTitleCase(); 661 | obj.attributeOrder.push(attNameTitle); 662 | if ("object" === typeof this[attName]) { 663 | obj[attNameTitle] = stringifyObject(this[attName]); 664 | } else { 665 | obj[attNameTitle] = "" + this[attName]; 666 | } 667 | } 668 | 669 | obj.attributeOrder.push('Incoming Exchange Bindings'); 670 | obj['Incoming Exchange Bindings'] = "" + Object.keys(this.bindings_inbound).length; 671 | 672 | if (undefined !== this.message_stats) { 673 | if (undefined !== this.message_stats.publish_details) { 674 | obj.attributeOrder.push('Message Incoming Rate (msgs/sec)'); 675 | obj['Message Incoming Rate (msgs/sec)'] = "" + Math.round(this.message_stats.publish_details.rate); 676 | } 677 | 678 | if (undefined !== this.message_stats.deliver_get_details) { 679 | obj.attributeOrder.push('Delivery and Get Rate (msgs/sec)'); 680 | obj['Delivery and Get Rate (msgs/sec)'] = "" + Math.round(this.message_stats.deliver_get_details.rate); 681 | } 682 | 683 | if (undefined !== this.message_stats.ack_details) { 684 | obj.attributeOrder.push('Delivery Acknowledgement Rate (acks/sec)'); 685 | obj['Delivery Acknowledgement Rate (acks/sec)'] = "" + Math.round(this.message_stats.ack_details.rate); 686 | } 687 | } 688 | 689 | return obj; 690 | }; 691 | Queue.prototype.url = function () { 692 | return "/queues/" + encodeURIComponent(this.vhost) + 693 | "/" + encodeURIComponent(this.name); 694 | }; 695 | Queue.prototype.navigateTo = function () { 696 | document.location = "../#" + this.url(); 697 | }; 698 | 699 | function Binding(elems) { 700 | this.keys = {}; 701 | this.set(elems); 702 | var elem = elems.shift(); 703 | this.source = elem.source; 704 | this.destination_type = elem.destination_type; 705 | this.destination = elem.destination; 706 | } 707 | Binding.prototype = { 708 | attributes : [ 'arguments' ], 709 | offset : 150, 710 | fontSize : 12, 711 | loopOffset : 50, 712 | object_type : 'binding' 713 | }; 714 | Binding.prototype.set = function (elems) { 715 | var i, elem, attr, j; 716 | this.keys = {}; 717 | for (i = 0; i < elems.length; i += 1) { 718 | elem = elems[i]; 719 | this.keys[elem.routing_key] = {}; 720 | for (j = 0; j < this.attributes.length; j += 1) { 721 | attr = this.attributes[j]; 722 | this.keys[elem.routing_key][attr] = elem[attr]; 723 | } 724 | } 725 | }; 726 | Binding.prototype.render = function (model, ctx) { 727 | var source, destination, xMid, xCtl1, xCtl2, yCtl1, yCtl2, xMin, yMin, xMax, yMax; 728 | source = model.exchange[this.source]; 729 | if (this.destination_type === "exchange") { 730 | destination = model.exchange[this.destination]; 731 | } else { 732 | destination = model.queue[this.destination]; 733 | } 734 | if (undefined === source || undefined === destination) { 735 | return; 736 | } 737 | if (source.disabled || destination.disabled) { 738 | return; 739 | } 740 | xMid = (source.xMax + destination.xMin) / 2; 741 | xCtl1 = xMid > (source.xMax + this.offset) ? xMid : source.xMax + this.offset; 742 | xCtl2 = xMid < (destination.xMin - this.offset) ? xMid 743 | : destination.xMin - this.offset; 744 | yCtl1 = destination === source ? source.pos[octtree.y] - this.loopOffset : source.pos[octtree.y]; 745 | yCtl2 = destination === source ? destination.pos[octtree.y] - this.loopOffset : destination.pos[octtree.y]; 746 | xMin = Math.min(source.xMax, xCtl2); 747 | yMin = Math.min(yCtl1, yCtl2); 748 | xMax = Math.max(destination.xMin, xCtl1); 749 | yMax = Math.max(source.pos[octtree.y], destination.pos[octtree.y]); 750 | if (model.cull(xMin, yMin, xMax - xMin, yMax - yMin)) { 751 | return; 752 | } 753 | 754 | ctx.beginPath(); 755 | ctx.lineWidth = 1.0; 756 | ctx.strokeStyle = "black"; 757 | ctx.moveTo(source.xMax, source.pos[octtree.y]); 758 | ctx.bezierCurveTo(xCtl1, yCtl1, xCtl2, yCtl2, destination.xMin, 759 | destination.pos[octtree.y]); 760 | ctx.moveTo(destination.xMin, destination.pos[octtree.y] + 1); 761 | ctx.bezierCurveTo(xCtl2, yCtl2 + 1, xCtl1, yCtl1 + 1, source.xMax, 762 | source.pos[octtree.y] + 1); 763 | ctx.moveTo(source.xMax, source.pos[octtree.y]); 764 | this.preStroke(source, destination, model, ctx); 765 | 766 | // draw an arrow head 767 | ctx.beginPath(); 768 | ctx.moveTo(destination.xMin, destination.pos[octtree.y]); 769 | ctx.lineTo(destination.xMin - this.fontSize, destination.pos[octtree.y] + 770 | (this.fontSize / 2)); 771 | ctx.lineTo(destination.xMin - this.fontSize, destination.pos[octtree.y] - 772 | (this.fontSize / 2)); 773 | ctx.closePath(); 774 | ctx.fillStyle = ctx.strokeStyle; 775 | ctx.fill(); 776 | }; 777 | Binding.prototype.preStroke = function (source, destination, model, ctx) { 778 | }; 779 | 780 | function Model() { 781 | this.exchange = {}; 782 | this.exchanges_visible = 0; 783 | this.queue = {}; 784 | this.queues_visible = 0; 785 | this.channel = {}; 786 | this.channels_visible = 0; 787 | this.connection = {}; 788 | this.vhost = {}; 789 | this.rendering = { exchange : { enabled : true, 790 | on_enable : {} }, 791 | queue : { enabled : true, 792 | on_enable : {} }, 793 | channel : { enabled : true, 794 | on_enable : {} }, 795 | connection : { enabled : true, 796 | on_enable : {} } 797 | }; 798 | this.highlighted = { exchange : {}, 799 | queue : {}, 800 | channel : {}, 801 | connection : {} }; 802 | } 803 | 804 | Model.prototype.permitted_exchanges_visible = 10; 805 | Model.prototype.permitted_queues_visible = 10; 806 | Model.prototype.permitted_channels_visible = 10; 807 | 808 | Model.prototype.rebuild = function (tree, configuration) { 809 | var elem, matched, i, binding, bindings, source, src, destination_type, j, src1, destination, dest, dest_type; 810 | 811 | // Channels 812 | matched = {}; 813 | for (i = 0; i < configuration.channels.length; i += 1) { 814 | elem = configuration.channels[i]; 815 | if (undefined === this.channel[elem.name]) { 816 | this.channel[elem.name] = new Channel(tree, elem, this); 817 | this.channels_visible += 1; 818 | if ((this.channels_visible > 819 | this.permitted_channels_visible) || 820 | ! this.rendering.channel.enabled) { 821 | this.disable(this.channel[elem.name], tree); 822 | } 823 | } else { 824 | this.channel[elem.name].update(elem); 825 | } 826 | matched[elem.name] = true; 827 | } 828 | for (i in this.channel) { 829 | if (undefined === matched[i]) { 830 | elem = this.channel[i]; 831 | delete this.channel[i]; 832 | elem.remove(tree, this); 833 | if (! elem.disabled) { 834 | this.channels_visible -= 1; 835 | } 836 | } 837 | } 838 | 839 | // Exchanges 840 | matched = {}; 841 | for (i = 0; i < configuration.exchanges.length; i += 1) { 842 | elem = configuration.exchanges[i]; 843 | if (undefined === this.exchange[elem.name]) { 844 | this.exchange[elem.name] = new Exchange(tree, elem, this); 845 | this.exchanges_visible += 1; 846 | if (elem.name.slice(0, 4) === "amq." || 847 | (this.exchanges_visible > 848 | this.permitted_exchanges_visible) || 849 | ! this.rendering.exchange.enabled) { 850 | this.disable(this.exchange[elem.name], tree); 851 | } 852 | } else { 853 | this.exchange[elem.name].update(elem); 854 | } 855 | matched[elem.name] = true; 856 | } 857 | for (i in this.exchange) { 858 | if (undefined === matched[i]) { 859 | elem = this.exchange[i]; 860 | delete this.exchange[i]; 861 | elem.remove(tree, this); 862 | if (! elem.disabled) { 863 | this.exchanges_visible -= 1; 864 | } 865 | } 866 | } 867 | 868 | // Queues 869 | matched = {}; 870 | for (i = 0; i < configuration.queues.length; i += 1) { 871 | elem = configuration.queues[i]; 872 | if (undefined === this.queue[elem.name]) { 873 | this.queue[elem.name] = new Queue(tree, elem, this); 874 | this.queues_visible += 1; 875 | if ((this.queues_visible > 876 | this.permitted_queues_visible) || 877 | ! this.rendering.queue.enabled) { 878 | this.disable(this.queue[elem.name], tree); 879 | delete this.rendering.queue.on_enable[elem.name]; 880 | } 881 | } else { 882 | this.queue[elem.name].update(elem); 883 | } 884 | matched[elem.name] = true; 885 | } 886 | for (i in this.queue) { 887 | if (undefined === matched[i]) { 888 | elem = this.queue[i]; 889 | delete this.queue[i]; 890 | elem.remove(tree, this); 891 | if (! elem.disabled) { 892 | this.queues_visible -= 1; 893 | } 894 | } 895 | } 896 | 897 | // Bindings 898 | bindings = {}; 899 | for (i = 0; i < configuration.bindings.length; i += 1) { 900 | elem = configuration.bindings[i]; 901 | if (undefined === this.exchange[elem.source] || 902 | undefined === this[elem.destination_type][elem.destination]) { 903 | continue; 904 | } 905 | if (undefined === bindings[elem.source]) { 906 | bindings[elem.source] = { exchange : {}, queue : {} }; 907 | } 908 | source = bindings[elem.source]; 909 | if (undefined === source[elem.destination_type][elem.destination]) { 910 | source[elem.destination_type][elem.destination] = new Array(elem); 911 | } else { 912 | source[elem.destination_type][elem.destination].push(elem); 913 | } 914 | } 915 | 916 | for (source in bindings) { 917 | src = this.exchange[source].bindings_outbound; 918 | i = bindings[source]; 919 | for (destination_type in i) { 920 | j = i[destination_type]; 921 | src1 = src[destination_type]; 922 | for (destination in j) { 923 | dest = this[destination_type][destination].bindings_inbound; 924 | if (undefined === src1[destination]) { 925 | src1[destination] = new Binding(j[destination]); 926 | } else { 927 | src1[destination].set(j[destination]); 928 | } 929 | binding = src1[destination]; 930 | if (undefined === dest[source]) { 931 | dest[source] = binding; 932 | } 933 | } 934 | } 935 | } 936 | for (src in this.exchange) { 937 | for (dest_type in this.exchange[src].bindings_outbound) { 938 | for (dest in this.exchange[src].bindings_outbound[dest_type]) { 939 | binding = this.exchange[src].bindings_outbound[dest_type][dest]; 940 | if (undefined === bindings[binding.source] || 941 | undefined === bindings[binding.source][binding.destination_type] || 942 | undefined === bindings[binding.source][binding.destination_type][binding.destination]) { 943 | delete this.exchange[src].bindings_outbound[dest_type][dest]; 944 | if (undefined !== this[binding.destination_type][binding.destination]) { 945 | delete this[binding.destination_type][binding.destination].bindings_inbound[binding.source]; 946 | } 947 | } 948 | } 949 | } 950 | } 951 | bindings = undefined; 952 | 953 | // vhosts 954 | matched = {}; 955 | for (i = 0; i < configuration.vhosts.length; i += 1) { 956 | elem = configuration.vhosts[i]; 957 | if (undefined === this.vhost[elem.name]) { 958 | this.vhost[elem.name] = elem; 959 | this.vhost_add(elem); 960 | } 961 | matched[elem.name] = true; 962 | } 963 | for (i in this.vhost) { 964 | if (undefined === matched[i]) { 965 | this.vhost_remove(this.vhost[i]); 966 | delete this.vhost[i]; 967 | } 968 | } 969 | 970 | matched = undefined; 971 | }; 972 | Model.prototype.disable = function (elem, tree) { 973 | elem.disable(this); 974 | tree.del(elem); 975 | elem.disabled = true; 976 | elem.details = undefined; 977 | }; 978 | Model.prototype.enable = function (elem, tree) { 979 | elem.enable(this, tree); 980 | tree.add(elem); 981 | elem.disabled = false; 982 | elem.details = undefined; 983 | }; 984 | Model.prototype.render = function (ctx) { 985 | var i; 986 | if (this.rendering.exchange.enabled) { 987 | for (i in this.exchange) { 988 | this.exchange[i].render(this, ctx); 989 | } 990 | } 991 | if (this.rendering.queue.enabled) { 992 | for (i in this.queue) { 993 | this.queue[i].render(this, ctx); 994 | } 995 | } 996 | if (this.rendering.channel.enabled) { 997 | for (i in this.channel) { 998 | this.channel[i].render(this, ctx); 999 | } 1000 | } 1001 | }; 1002 | Model.prototype.cull = function (xMin, yMin, width, height) { 1003 | return false; 1004 | }; 1005 | Model.prototype.vhost_add = function (elem) { 1006 | }; 1007 | Model.prototype.vhost_del = function (elem) { 1008 | }; 1009 | Model.prototype.resetHighlighted = function () { 1010 | this.highlighted = { exchange : {}, 1011 | queue : {}, 1012 | channel : {}, 1013 | connection : {} }; 1014 | }; 1015 | Model.prototype.setHighlighted = function (elem) { 1016 | if (undefined !== elem) { 1017 | this.highlighted[elem.object_type][elem.name] = elem; 1018 | } 1019 | }; 1020 | Model.prototype.isHighlighted = function (elem) { 1021 | return ((undefined !== elem) && (undefined !== this.highlighted[elem.object_type][elem.name])); 1022 | }; 1023 | 1024 | -------------------------------------------------------------------------------- /priv/www/visualiser/js/octtree.js: -------------------------------------------------------------------------------- 1 | /*global vec3 */ 2 | 3 | var octtree = {}; 4 | octtree.top_nw = 0; 5 | octtree.top_ne = 1; 6 | octtree.top_se = 2; 7 | octtree.top_sw = 3; 8 | octtree.bot_nw = 4; 9 | octtree.bot_ne = 5; 10 | octtree.bot_se = 6; 11 | octtree.bot_sw = 7; 12 | octtree.children = [ octtree.top_nw, octtree.top_ne, octtree.top_se, 13 | octtree.top_sw, octtree.bot_nw, octtree.bot_ne, octtree.bot_se, 14 | octtree.bot_sw ]; 15 | octtree.firstChildId = 0; 16 | octtree.lastChildId = 7; 17 | octtree.x = 0; 18 | octtree.y = 1; 19 | octtree.z = 2; 20 | octtree.randoms = []; 21 | octtree.randomIndex = 0; 22 | octtree.i = 0; 23 | 24 | for (octtree.i = 0; octtree.i < 100; octtree.i += 1) { 25 | octtree.randoms.push(Math.random()); 26 | } 27 | 28 | function Octtree(xMin, xMax, yMin, yMax, zMin, zMax, parent, childId) { 29 | this.xMin = xMin; 30 | this.xMax = xMax; 31 | this.yMin = yMin; 32 | this.yMax = yMax; 33 | this.zMin = zMin; 34 | this.zMax = zMax; 35 | this.parent = parent; 36 | this.childId = childId; 37 | if (undefined !== childId && childId !== octtree.lastChildId && 38 | undefined !== parent) { 39 | this.nextSiblingId = childId + 1; 40 | } 41 | 42 | this.xMid = xMin + (xMax - xMin) / 2; 43 | this.yMid = yMin + (yMax - yMin) / 2; 44 | this.zMid = zMin + (zMax - zMin) / 2; 45 | } 46 | 47 | Octtree.prototype.isEmpty = function () { 48 | return (undefined === this[octtree.firstChildId]) && 49 | (undefined === this.value); 50 | }; 51 | 52 | Octtree.prototype.hasChildren = function () { 53 | return undefined !== this[octtree.firstChildId]; 54 | }; 55 | 56 | Octtree.prototype.hasValue = function () { 57 | return undefined !== this.value; 58 | }; 59 | 60 | Octtree.prototype.add = function (value) { 61 | return octtree.add(this, value); 62 | }; 63 | 64 | Octtree.prototype.del = function (value) { 65 | return octtree.del(this, value); 66 | }; 67 | 68 | Octtree.prototype.update = function () { 69 | return octtree.update(this); 70 | }; 71 | 72 | Octtree.prototype.findInRadius = function (pos, radius, limit) { 73 | return octtree.findInRadius(this, pos, radius, limit); 74 | }; 75 | 76 | Octtree.prototype.size = function () { 77 | return octtree.size(this); 78 | }; 79 | 80 | octtree.findNode = function (tree, pos) { 81 | while (true) { 82 | if (pos[octtree.x] < tree.xMin || tree.xMax <= pos[octtree.x] || 83 | pos[octtree.y] < tree.yMin || tree.yMax <= pos[octtree.y] || 84 | pos[octtree.z] < tree.zMin || tree.zMax <= pos[octtree.z]) { 85 | if (undefined === tree.parent) { 86 | return undefined; 87 | } else { 88 | tree = tree.parent; 89 | continue; 90 | } 91 | } 92 | 93 | if (tree.hasChildren()) { 94 | if (pos[octtree.x] < tree.xMid) { 95 | if (pos[octtree.y] < tree.yMid) { 96 | if (pos[octtree.z] < tree.zMid) { 97 | tree = tree[octtree.bot_sw]; 98 | } else { 99 | tree = tree[octtree.bot_nw]; 100 | } 101 | } else { 102 | if (pos[octtree.z] < tree.zMid) { 103 | tree = tree[octtree.top_sw]; 104 | } else { 105 | tree = tree[octtree.top_nw]; 106 | } 107 | } 108 | } else { 109 | if (pos[octtree.y] < tree.yMid) { 110 | if (pos[octtree.z] < tree.zMid) { 111 | tree = tree[octtree.bot_se]; 112 | } else { 113 | tree = tree[octtree.bot_ne]; 114 | } 115 | } else { 116 | if (pos[octtree.z] < tree.zMid) { 117 | tree = tree[octtree.top_se]; 118 | } else { 119 | tree = tree[octtree.top_ne]; 120 | } 121 | } 122 | } 123 | } else { 124 | return tree; 125 | } 126 | } 127 | }; 128 | 129 | octtree.add = function (tree, value) { 130 | tree = octtree.findNode(tree, value.pos); 131 | if (undefined === tree) { 132 | return undefined; 133 | } else { 134 | var displaced; 135 | while (undefined !== value) { 136 | if (tree.hasValue()) { 137 | if (tree.value.pos[octtree.x] === value.pos[octtree.x] && 138 | tree.value.pos[octtree.y] === value.pos[octtree.y] && 139 | tree.value.pos[octtree.z] === value.pos[octtree.z]) { 140 | tree.value = value; 141 | value = undefined; 142 | } else { 143 | displaced = value; // make sure we add our new value last 144 | value = tree.value; 145 | tree.value = undefined; 146 | 147 | tree[octtree.top_nw] = new Octtree(tree.xMin, tree.xMid, 148 | tree.yMid, tree.yMax, tree.zMid, tree.zMax, tree, 149 | octtree.top_nw); 150 | tree[octtree.top_ne] = new Octtree(tree.xMid, tree.xMax, 151 | tree.yMid, tree.yMax, tree.zMid, tree.zMax, tree, 152 | octtree.top_ne); 153 | tree[octtree.top_se] = new Octtree(tree.xMid, tree.xMax, 154 | tree.yMid, tree.yMax, tree.zMin, tree.zMid, tree, 155 | octtree.top_se); 156 | tree[octtree.top_sw] = new Octtree(tree.xMin, tree.xMid, 157 | tree.yMid, tree.yMax, tree.zMin, tree.zMid, tree, 158 | octtree.top_sw); 159 | 160 | tree[octtree.bot_nw] = new Octtree(tree.xMin, tree.xMid, 161 | tree.yMin, tree.yMid, tree.zMid, tree.zMax, tree, 162 | octtree.bot_nw); 163 | tree[octtree.bot_ne] = new Octtree(tree.xMid, tree.xMax, 164 | tree.yMin, tree.yMid, tree.zMid, tree.zMax, tree, 165 | octtree.bot_ne); 166 | tree[octtree.bot_se] = new Octtree(tree.xMid, tree.xMax, 167 | tree.yMin, tree.yMid, tree.zMin, tree.zMid, tree, 168 | octtree.bot_se); 169 | tree[octtree.bot_sw] = new Octtree(tree.xMin, tree.xMid, 170 | tree.yMin, tree.yMid, tree.zMin, tree.zMid, tree, 171 | octtree.bot_sw); 172 | tree = octtree.findNode(tree, value.pos); 173 | } 174 | } else { 175 | tree.value = value; 176 | value = displaced; 177 | displaced = undefined; 178 | if (undefined !== value) { 179 | tree = octtree.findNode(tree, value.pos); 180 | } 181 | } 182 | } 183 | return tree; 184 | } 185 | }; 186 | 187 | octtree.del = function (tree, value) { 188 | tree = octtree.findNode(tree, value.pos); 189 | if (undefined === tree || (!tree.hasValue())) { 190 | return tree; 191 | } 192 | if (tree.value.pos[octtree.x] === value.pos[octtree.x] && 193 | tree.value.pos[octtree.y] === value.pos[octtree.y] && 194 | tree.value.pos[octtree.z] === value.pos[octtree.z]) { 195 | tree.value = undefined; 196 | tree = tree.parent; 197 | var valCount, nonEmptyChild, child, i; 198 | while (undefined !== tree) { 199 | valCount = 0; 200 | for (i = 0; i < octtree.children.length; i += 1) { 201 | child = octtree.children[i]; 202 | if (!tree[child].isEmpty()) { 203 | valCount += 1; 204 | nonEmptyChild = tree[child]; 205 | } 206 | } 207 | if (0 === valCount) { 208 | for (i = 0; i < octtree.children.length; i += 1) { 209 | child = octtree.children[i]; 210 | tree[child] = undefined; 211 | } 212 | tree = tree.parent; 213 | } else if (1 === valCount) { 214 | if (nonEmptyChild.hasValue()) { 215 | for (i = 0; i < octtree.children.length; i += 1) { 216 | child = octtree.children[i]; 217 | tree[child] = undefined; 218 | } 219 | tree.value = nonEmptyChild.value; 220 | tree = tree.parent; 221 | } else { 222 | break; 223 | } 224 | } else { 225 | break; 226 | } 227 | } 228 | } 229 | return tree; 230 | }; 231 | 232 | octtree.next = function (tree) { 233 | while (undefined !== tree) { 234 | if (undefined !== tree.nextSiblingId) { 235 | return tree.parent[tree.nextSiblingId]; 236 | } else { 237 | tree = tree.parent; 238 | } 239 | } 240 | return undefined; 241 | }; 242 | 243 | octtree.defined = function (a, b) { 244 | if (undefined === a) { 245 | return b; 246 | } else { 247 | return a; 248 | } 249 | }; 250 | 251 | octtree.update = function (tree) { 252 | var root, parent, v, movedValues, i; 253 | root = tree; 254 | parent = root.parent; 255 | root.parent = undefined; // do this to stop next going up past tree 256 | 257 | movedValues = []; 258 | while (undefined !== tree) { 259 | if (tree.hasValue()) { 260 | v = tree.value; 261 | if (v.next_pos[octtree.x] < tree.xMin || 262 | tree.xMax <= v.next_pos[octtree.x] || 263 | v.next_pos[octtree.y] < tree.yMin || 264 | tree.yMax <= v.next_pos[octtree.y] || 265 | v.next_pos[octtree.z] < tree.zMin || 266 | tree.zMax <= v.next_pos[octtree.z]) { 267 | movedValues.push(tree.value); 268 | } else { 269 | vec3.set(v.next_pos, v.pos); 270 | } 271 | tree = octtree.next(tree); 272 | } else if (tree.hasChildren()) { 273 | tree = tree[octtree.firstChildId]; 274 | } else { 275 | tree = octtree.next(tree); 276 | } 277 | } 278 | 279 | root.parent = parent; 280 | tree = root; 281 | for (i = 0; i < movedValues.length; i += 1) { 282 | v = movedValues[i]; 283 | tree = octtree.defined(tree.del(v), tree); 284 | vec3.set(v.next_pos, v.pos); 285 | tree = octtree.defined(tree.add(v), tree); 286 | } 287 | 288 | return root; 289 | }; 290 | 291 | octtree.findInRadius = function (tree, pos, radius, limit) { 292 | var acc, radiusSq, worklist, x_p_r, x_m_r, y_p_r, y_m_r, z_p_r, z_m_r, xd, yd, zd; 293 | acc = []; 294 | radiusSq = radius * radius; 295 | worklist = [tree]; 296 | tree = undefined; 297 | 298 | x_p_r = 0; 299 | x_m_r = 0; 300 | y_p_r = 0; 301 | y_m_r = 0; 302 | z_p_r = 0; 303 | z_m_r = 0; 304 | 305 | while (0 < worklist.length && (undefined === limit || limit > acc.length)) { 306 | tree = worklist.shift(); 307 | 308 | if (tree.isEmpty()) { 309 | continue; 310 | } 311 | 312 | if (tree.hasValue()) { 313 | xd = Math.abs(tree.value.pos[octtree.x] - pos[octtree.x]); 314 | yd = Math.abs(tree.value.pos[octtree.y] - pos[octtree.y]); 315 | zd = Math.abs(tree.value.pos[octtree.z] - pos[octtree.z]); 316 | xd *= xd; 317 | yd *= yd; 318 | zd *= zd; 319 | if ((xd + yd + zd) <= radiusSq) { 320 | acc.push(tree); 321 | } 322 | continue; 323 | } 324 | 325 | x_p_r = pos[octtree.x] + radius; 326 | x_m_r = pos[octtree.x] - radius; 327 | y_p_r = pos[octtree.y] + radius; 328 | y_m_r = pos[octtree.y] - radius; 329 | z_p_r = pos[octtree.z] + radius; 330 | z_m_r = pos[octtree.z] - radius; 331 | 332 | if (x_p_r < tree.xMin || tree.xMax <= x_m_r || y_p_r < tree.yMin || 333 | tree.yMax <= y_m_r || z_p_r < tree.zMin || tree.zMax <= z_m_r) { 334 | continue; 335 | } 336 | 337 | if (x_m_r < tree.xMid) { 338 | if (y_m_r < tree.yMid) { 339 | if (z_m_r < tree.zMid) { 340 | octtree.randomPush(worklist, tree[octtree.bot_sw]); 341 | } 342 | if (tree.zMid <= z_p_r) { 343 | octtree.randomPush(worklist, tree[octtree.bot_nw]); 344 | } 345 | } 346 | if (tree.yMid <= y_p_r) { 347 | if (z_m_r < tree.zMid) { 348 | octtree.randomPush(worklist, tree[octtree.top_sw]); 349 | } 350 | if (tree.zMid <= z_p_r) { 351 | octtree.randomPush(worklist, tree[octtree.top_nw]); 352 | } 353 | } 354 | } 355 | if (tree.xMid <= x_p_r) { 356 | if (y_m_r < tree.yMid) { 357 | if (z_m_r < tree.zMid) { 358 | octtree.randomPush(worklist, tree[octtree.bot_se]); 359 | } 360 | if (tree.zMid <= z_p_r) { 361 | octtree.randomPush(worklist, tree[octtree.bot_ne]); 362 | } 363 | } 364 | if (tree.yMid <= y_p_r) { 365 | if (z_m_r < tree.zMid) { 366 | octtree.randomPush(worklist, tree[octtree.top_se]); 367 | } 368 | if (tree.zMid <= z_p_r) { 369 | octtree.randomPush(worklist, tree[octtree.top_ne]); 370 | } 371 | } 372 | } 373 | } 374 | return acc; 375 | }; 376 | 377 | octtree.size = function (tree) { 378 | var count, root, parent; 379 | root = 0; 380 | root = tree; 381 | parent = root.parent; 382 | root.parent = undefined; // stop the traversal going above us. 383 | 384 | while (undefined !== tree) { 385 | if (tree.hasValue()) { 386 | count += 1; 387 | tree = octtree.next(tree); 388 | } else if (tree.hasChildren()) { 389 | tree = tree[octtree.firstChildId]; 390 | } else { 391 | tree = octtree.next(tree); 392 | } 393 | } 394 | 395 | root.parent = parent; 396 | return count; 397 | }; 398 | 399 | octtree.create = function (xMin, xMax, yMin, yMax, zMin, zMax) { 400 | return new Octtree(xMin, xMax, yMin, yMax, zMin, zMax, undefined, undefined); 401 | }; 402 | 403 | octtree.randomPush = function (ary, e) { 404 | if (octtree.nextRandom() > 0.5) { 405 | ary.push(e); 406 | } else { 407 | ary.unshift(e); 408 | } 409 | return ary; 410 | }; 411 | 412 | octtree.nextRandom = function () { 413 | var r = octtree.randoms[octtree.randomIndex]; 414 | octtree.randomIndex += 1; 415 | if (octtree.randomIndex === octtree.randoms.length) { 416 | octtree.randomIndex = 0; 417 | } 418 | return r; 419 | }; 420 | -------------------------------------------------------------------------------- /priv/www/visualiser/js/physics.js: -------------------------------------------------------------------------------- 1 | /*global octtree, vec3 */ 2 | 3 | function Newton() { 4 | } 5 | Newton.prototype.friction = 100; 6 | 7 | Newton.prototype.update = function (elapsed, obj) { 8 | var incr; 9 | vec3.scale(obj.velocity, 1 - (this.friction * elapsed)); 10 | incr = vec3.create(obj.velocity); 11 | vec3.scale(incr, elapsed); 12 | vec3.add(obj.pos, incr, obj.next_pos); 13 | }; 14 | 15 | function Spring() { 16 | } 17 | Spring.prototype.k = 1; 18 | Spring.prototype.equilibriumLength = 2; 19 | Spring.prototype.push = true; 20 | Spring.prototype.pull = true; 21 | Spring.prototype.dampingFactor = 0.5; 22 | Spring.prototype.octtreeRadius = 4; 23 | Spring.prototype.octtreeLimit = 40; 24 | 25 | Spring.prototype.apply = function (elapsed, obj1, obj2) { 26 | var damper, vecOP, distanceOP, x; 27 | damper = this.dampingFactor * elapsed * 100000; 28 | vecOP = vec3.create(); 29 | distanceOP = 0; 30 | x = 0; 31 | vec3.subtract(obj2.pos, obj1.pos, vecOP); 32 | distanceOP = vec3.length(vecOP); 33 | if (!isNaN(distanceOP) && 0 !== distanceOP) { 34 | x = distanceOP - this.equilibriumLength; 35 | if (distanceOP > this.equilibriumLength && !this.pull) { 36 | return; 37 | } 38 | if (distanceOP < this.equilibriumLength && !this.push) { 39 | return; 40 | } 41 | vec3.scale(vecOP, (damper * (((1 / distanceOP) * x) / obj1.mass))); 42 | vec3.add(obj1.velocity, vecOP); 43 | } 44 | }; 45 | Spring.prototype.update = function (elapsed, tree, obj) { 46 | var damper, vecOP, distanceOP, x, found, i, obj1; 47 | damper = this.dampingFactor * elapsed * 100000; 48 | vecOP = vec3.create(); 49 | distanceOP = 0; 50 | x = 0; 51 | found = tree.findInRadius(obj.pos, this.octtreeRadius, this.octtreeLimit); 52 | for (i = 0; i < found.length; i += 1) { 53 | obj1 = found[i].value; 54 | if (obj1 !== obj) { 55 | // F = -k x where x is difference from equilibriumLength 56 | // a = F / m 57 | vec3.subtract(obj1.pos, obj.pos, vecOP); 58 | distanceOP = vec3.length(vecOP); 59 | if (!isNaN(distanceOP) && 0 !== distanceOP) { 60 | x = distanceOP - this.equilibriumLength; 61 | if (distanceOP > this.equilibriumLength && !this.pull) { 62 | continue; 63 | } 64 | if (distanceOP < this.equilibriumLength && !this.push) { 65 | continue; 66 | } 67 | vec3.scale(vecOP, 68 | (damper * (((1 / distanceOP) * x) / obj.mass))); 69 | vec3.add(obj.velocity, vecOP); 70 | } 71 | } 72 | } 73 | }; 74 | 75 | function Gravity() { 76 | } 77 | Gravity.prototype.bigG = 1 / 20; 78 | Gravity.prototype.octtreeRadius = 5; 79 | Gravity.prototype.octtreeLimit = 20; 80 | Gravity.prototype.repel = false; 81 | 82 | Gravity.prototype.update = function (elapsed, tree, obj) { 83 | var vecOP, distanceOP, found, i, obj1; 84 | vecOP = vec3.create(); 85 | distanceOP = 0; 86 | found = tree.findInRadius(obj.pos, this.octtreeRadius, this.octtreeLimit); 87 | for (i = 0; i < found.length; i += 1) { 88 | obj1 = found[i].value; 89 | if (obj1 !== obj) { 90 | // F = G.m1.m2 / (d.d) 91 | // a = F / m1 92 | // thus a = G.m2/(d.d) 93 | vec3.subtract(obj1.pos, obj.pos, vecOP); 94 | distanceOP = vec3.length(vecOP); 95 | if ((!(isNaN(distanceOP))) && 0 !== distanceOP) { 96 | vec3.scale(vecOP, (this.bigG * obj1.mass) / 97 | (distanceOP * distanceOP)); 98 | if (this.repel) { 99 | vec3.subtract(obj.velocity, vecOP); 100 | } else { 101 | vec3.add(obj.velocity, vecOP); 102 | } 103 | } 104 | } 105 | } 106 | }; 107 | -------------------------------------------------------------------------------- /rabbitmq-components.mk: -------------------------------------------------------------------------------- 1 | ifeq ($(.DEFAULT_GOAL),) 2 | # Define default goal to `all` because this file defines some targets 3 | # before the inclusion of erlang.mk leading to the wrong target becoming 4 | # the default. 5 | .DEFAULT_GOAL = all 6 | endif 7 | 8 | # PROJECT_VERSION defaults to: 9 | # 1. the version exported by rabbitmq-server-release; 10 | # 2. the version stored in `git-revisions.txt`, if it exists; 11 | # 3. a version based on git-describe(1), if it is a Git clone; 12 | # 4. 0.0.0 13 | 14 | PROJECT_VERSION := $(RABBITMQ_VERSION) 15 | 16 | ifeq ($(PROJECT_VERSION),) 17 | PROJECT_VERSION := $(shell \ 18 | if test -f git-revisions.txt; then \ 19 | head -n1 git-revisions.txt | \ 20 | awk '{print $$$(words $(PROJECT_DESCRIPTION) version);}'; \ 21 | else \ 22 | (git describe --dirty --abbrev=7 --tags --always --first-parent \ 23 | 2>/dev/null || echo rabbitmq_v0_0_0) | \ 24 | sed -e 's/^rabbitmq_v//' -e 's/^v//' -e 's/_/./g' -e 's/-/+/' \ 25 | -e 's/-/./g'; \ 26 | fi) 27 | endif 28 | 29 | # -------------------------------------------------------------------- 30 | # RabbitMQ components. 31 | # -------------------------------------------------------------------- 32 | 33 | # For RabbitMQ repositories, we want to checkout branches which match 34 | # the parent project. For instance, if the parent project is on a 35 | # release tag, dependencies must be on the same release tag. If the 36 | # parent project is on a topic branch, dependencies must be on the same 37 | # topic branch or fallback to `stable` or `master` whichever was the 38 | # base of the topic branch. 39 | 40 | dep_amqp_client = git_rmq rabbitmq-erlang-client $(current_rmq_ref) $(base_rmq_ref) master 41 | dep_amqp10_client = git_rmq rabbitmq-amqp1.0-client $(current_rmq_ref) $(base_rmq_ref) master 42 | dep_amqp10_common = git_rmq rabbitmq-amqp1.0-common $(current_rmq_ref) $(base_rmq_ref) master 43 | dep_rabbit = git_rmq rabbitmq-server $(current_rmq_ref) $(base_rmq_ref) master 44 | dep_rabbit_common = git_rmq rabbitmq-common $(current_rmq_ref) $(base_rmq_ref) master 45 | dep_rabbitmq_amqp1_0 = git_rmq rabbitmq-amqp1.0 $(current_rmq_ref) $(base_rmq_ref) master 46 | dep_rabbitmq_auth_backend_amqp = git_rmq rabbitmq-auth-backend-amqp $(current_rmq_ref) $(base_rmq_ref) master 47 | dep_rabbitmq_auth_backend_cache = git_rmq rabbitmq-auth-backend-cache $(current_rmq_ref) $(base_rmq_ref) master 48 | dep_rabbitmq_auth_backend_http = git_rmq rabbitmq-auth-backend-http $(current_rmq_ref) $(base_rmq_ref) master 49 | dep_rabbitmq_auth_backend_ldap = git_rmq rabbitmq-auth-backend-ldap $(current_rmq_ref) $(base_rmq_ref) master 50 | dep_rabbitmq_auth_mechanism_ssl = git_rmq rabbitmq-auth-mechanism-ssl $(current_rmq_ref) $(base_rmq_ref) master 51 | dep_rabbitmq_aws = git_rmq rabbitmq-aws $(current_rmq_ref) $(base_rmq_ref) master 52 | dep_rabbitmq_boot_steps_visualiser = git_rmq rabbitmq-boot-steps-visualiser $(current_rmq_ref) $(base_rmq_ref) master 53 | dep_rabbitmq_clusterer = git_rmq rabbitmq-clusterer $(current_rmq_ref) $(base_rmq_ref) master 54 | dep_rabbitmq_cli = git_rmq rabbitmq-cli $(current_rmq_ref) $(base_rmq_ref) master 55 | dep_rabbitmq_codegen = git_rmq rabbitmq-codegen $(current_rmq_ref) $(base_rmq_ref) master 56 | dep_rabbitmq_consistent_hash_exchange = git_rmq rabbitmq-consistent-hash-exchange $(current_rmq_ref) $(base_rmq_ref) master 57 | dep_rabbitmq_ct_client_helpers = git_rmq rabbitmq-ct-client-helpers $(current_rmq_ref) $(base_rmq_ref) master 58 | dep_rabbitmq_ct_helpers = git_rmq rabbitmq-ct-helpers $(current_rmq_ref) $(base_rmq_ref) master 59 | dep_rabbitmq_delayed_message_exchange = git_rmq rabbitmq-delayed-message-exchange $(current_rmq_ref) $(base_rmq_ref) master 60 | dep_rabbitmq_dotnet_client = git_rmq rabbitmq-dotnet-client $(current_rmq_ref) $(base_rmq_ref) master 61 | dep_rabbitmq_event_exchange = git_rmq rabbitmq-event-exchange $(current_rmq_ref) $(base_rmq_ref) master 62 | dep_rabbitmq_federation = git_rmq rabbitmq-federation $(current_rmq_ref) $(base_rmq_ref) master 63 | dep_rabbitmq_federation_management = git_rmq rabbitmq-federation-management $(current_rmq_ref) $(base_rmq_ref) master 64 | dep_rabbitmq_java_client = git_rmq rabbitmq-java-client $(current_rmq_ref) $(base_rmq_ref) master 65 | dep_rabbitmq_jms_client = git_rmq rabbitmq-jms-client $(current_rmq_ref) $(base_rmq_ref) master 66 | dep_rabbitmq_jms_cts = git_rmq rabbitmq-jms-cts $(current_rmq_ref) $(base_rmq_ref) master 67 | dep_rabbitmq_jms_topic_exchange = git_rmq rabbitmq-jms-topic-exchange $(current_rmq_ref) $(base_rmq_ref) master 68 | dep_rabbitmq_lvc_exchange = git_rmq rabbitmq-lvc-exchange $(current_rmq_ref) $(base_rmq_ref) master 69 | dep_rabbitmq_management = git_rmq rabbitmq-management $(current_rmq_ref) $(base_rmq_ref) master 70 | dep_rabbitmq_management_agent = git_rmq rabbitmq-management-agent $(current_rmq_ref) $(base_rmq_ref) master 71 | dep_rabbitmq_management_exchange = git_rmq rabbitmq-management-exchange $(current_rmq_ref) $(base_rmq_ref) master 72 | dep_rabbitmq_management_themes = git_rmq rabbitmq-management-themes $(current_rmq_ref) $(base_rmq_ref) master 73 | dep_rabbitmq_management_visualiser = git_rmq rabbitmq-management-visualiser $(current_rmq_ref) $(base_rmq_ref) master 74 | dep_rabbitmq_message_timestamp = git_rmq rabbitmq-message-timestamp $(current_rmq_ref) $(base_rmq_ref) master 75 | dep_rabbitmq_metronome = git_rmq rabbitmq-metronome $(current_rmq_ref) $(base_rmq_ref) master 76 | dep_rabbitmq_mqtt = git_rmq rabbitmq-mqtt $(current_rmq_ref) $(base_rmq_ref) master 77 | dep_rabbitmq_objc_client = git_rmq rabbitmq-objc-client $(current_rmq_ref) $(base_rmq_ref) master 78 | dep_rabbitmq_peer_discovery_aws = git_rmq rabbitmq-peer-discovery-aws $(current_rmq_ref) $(base_rmq_ref) master 79 | dep_rabbitmq_peer_discovery_common = git_rmq rabbitmq-peer-discovery-common $(current_rmq_ref) $(base_rmq_ref) master 80 | dep_rabbitmq_peer_discovery_consul = git_rmq rabbitmq-peer-discovery-consul $(current_rmq_ref) $(base_rmq_ref) master 81 | dep_rabbitmq_peer_discovery_etcd = git_rmq rabbitmq-peer-discovery-etcd $(current_rmq_ref) $(base_rmq_ref) master 82 | dep_rabbitmq_peer_discovery_k8s = git_rmq rabbitmq-peer-discovery-k8s $(current_rmq_ref) $(base_rmq_ref) master 83 | dep_rabbitmq_random_exchange = git_rmq rabbitmq-random-exchange $(current_rmq_ref) $(base_rmq_ref) master 84 | dep_rabbitmq_recent_history_exchange = git_rmq rabbitmq-recent-history-exchange $(current_rmq_ref) $(base_rmq_ref) master 85 | dep_rabbitmq_routing_node_stamp = git_rmq rabbitmq-routing-node-stamp $(current_rmq_ref) $(base_rmq_ref) master 86 | dep_rabbitmq_rtopic_exchange = git_rmq rabbitmq-rtopic-exchange $(current_rmq_ref) $(base_rmq_ref) master 87 | dep_rabbitmq_server_release = git_rmq rabbitmq-server-release $(current_rmq_ref) $(base_rmq_ref) master 88 | dep_rabbitmq_sharding = git_rmq rabbitmq-sharding $(current_rmq_ref) $(base_rmq_ref) master 89 | dep_rabbitmq_shovel = git_rmq rabbitmq-shovel $(current_rmq_ref) $(base_rmq_ref) master 90 | dep_rabbitmq_shovel_management = git_rmq rabbitmq-shovel-management $(current_rmq_ref) $(base_rmq_ref) master 91 | dep_rabbitmq_stomp = git_rmq rabbitmq-stomp $(current_rmq_ref) $(base_rmq_ref) master 92 | dep_rabbitmq_toke = git_rmq rabbitmq-toke $(current_rmq_ref) $(base_rmq_ref) master 93 | dep_rabbitmq_top = git_rmq rabbitmq-top $(current_rmq_ref) $(base_rmq_ref) master 94 | dep_rabbitmq_tracing = git_rmq rabbitmq-tracing $(current_rmq_ref) $(base_rmq_ref) master 95 | dep_rabbitmq_trust_store = git_rmq rabbitmq-trust-store $(current_rmq_ref) $(base_rmq_ref) master 96 | dep_rabbitmq_test = git_rmq rabbitmq-test $(current_rmq_ref) $(base_rmq_ref) master 97 | dep_rabbitmq_web_dispatch = git_rmq rabbitmq-web-dispatch $(current_rmq_ref) $(base_rmq_ref) master 98 | dep_rabbitmq_web_stomp = git_rmq rabbitmq-web-stomp $(current_rmq_ref) $(base_rmq_ref) master 99 | dep_rabbitmq_web_stomp_examples = git_rmq rabbitmq-web-stomp-examples $(current_rmq_ref) $(base_rmq_ref) master 100 | dep_rabbitmq_web_mqtt = git_rmq rabbitmq-web-mqtt $(current_rmq_ref) $(base_rmq_ref) master 101 | dep_rabbitmq_web_mqtt_examples = git_rmq rabbitmq-web-mqtt-examples $(current_rmq_ref) $(base_rmq_ref) master 102 | dep_rabbitmq_website = git_rmq rabbitmq-website $(current_rmq_ref) $(base_rmq_ref) live master 103 | dep_toke = git_rmq toke $(current_rmq_ref) $(base_rmq_ref) master 104 | 105 | dep_rabbitmq_public_umbrella = git_rmq rabbitmq-public-umbrella $(current_rmq_ref) $(base_rmq_ref) master 106 | 107 | # Third-party dependencies version pinning. 108 | # 109 | # We do that in this file, which is copied in all projects, to ensure 110 | # all projects use the same versions. It avoids conflicts and makes it 111 | # possible to work with rabbitmq-public-umbrella. 112 | 113 | dep_cowboy = hex 2.6.1 114 | dep_cowlib = hex 2.7.0 115 | dep_jsx = hex 2.9.0 116 | dep_lager = hex 3.6.5 117 | dep_ra = git https://github.com/rabbitmq/ra.git master 118 | dep_ranch = hex 1.7.1 119 | dep_recon = hex 2.3.6 120 | 121 | dep_sockjs = git https://github.com/rabbitmq/sockjs-erlang.git 405990ea62353d98d36dbf5e1e64942d9b0a1daf 122 | 123 | RABBITMQ_COMPONENTS = amqp_client \ 124 | amqp10_common \ 125 | amqp10_client \ 126 | rabbit \ 127 | rabbit_common \ 128 | rabbitmq_amqp1_0 \ 129 | rabbitmq_auth_backend_amqp \ 130 | rabbitmq_auth_backend_cache \ 131 | rabbitmq_auth_backend_http \ 132 | rabbitmq_auth_backend_ldap \ 133 | rabbitmq_auth_mechanism_ssl \ 134 | rabbitmq_aws \ 135 | rabbitmq_boot_steps_visualiser \ 136 | rabbitmq_clusterer \ 137 | rabbitmq_cli \ 138 | rabbitmq_codegen \ 139 | rabbitmq_consistent_hash_exchange \ 140 | rabbitmq_ct_client_helpers \ 141 | rabbitmq_ct_helpers \ 142 | rabbitmq_delayed_message_exchange \ 143 | rabbitmq_dotnet_client \ 144 | rabbitmq_event_exchange \ 145 | rabbitmq_federation \ 146 | rabbitmq_federation_management \ 147 | rabbitmq_java_client \ 148 | rabbitmq_jms_client \ 149 | rabbitmq_jms_cts \ 150 | rabbitmq_jms_topic_exchange \ 151 | rabbitmq_lvc_exchange \ 152 | rabbitmq_management \ 153 | rabbitmq_management_agent \ 154 | rabbitmq_management_exchange \ 155 | rabbitmq_management_themes \ 156 | rabbitmq_management_visualiser \ 157 | rabbitmq_message_timestamp \ 158 | rabbitmq_metronome \ 159 | rabbitmq_mqtt \ 160 | rabbitmq_objc_client \ 161 | rabbitmq_peer_discovery_aws \ 162 | rabbitmq_peer_discovery_common \ 163 | rabbitmq_peer_discovery_consul \ 164 | rabbitmq_peer_discovery_etcd \ 165 | rabbitmq_peer_discovery_k8s \ 166 | rabbitmq_random_exchange \ 167 | rabbitmq_recent_history_exchange \ 168 | rabbitmq_routing_node_stamp \ 169 | rabbitmq_rtopic_exchange \ 170 | rabbitmq_server_release \ 171 | rabbitmq_sharding \ 172 | rabbitmq_shovel \ 173 | rabbitmq_shovel_management \ 174 | rabbitmq_stomp \ 175 | rabbitmq_toke \ 176 | rabbitmq_top \ 177 | rabbitmq_tracing \ 178 | rabbitmq_trust_store \ 179 | rabbitmq_web_dispatch \ 180 | rabbitmq_web_mqtt \ 181 | rabbitmq_web_mqtt_examples \ 182 | rabbitmq_web_stomp \ 183 | rabbitmq_web_stomp_examples \ 184 | rabbitmq_website 185 | 186 | # Several components have a custom erlang.mk/build.config, mainly 187 | # to disable eunit. Therefore, we can't use the top-level project's 188 | # erlang.mk copy. 189 | NO_AUTOPATCH += $(RABBITMQ_COMPONENTS) 190 | 191 | ifeq ($(origin current_rmq_ref),undefined) 192 | ifneq ($(wildcard .git),) 193 | current_rmq_ref := $(shell (\ 194 | ref=$$(LANG=C git branch --list | awk '/^\* \(.*detached / {ref=$$0; sub(/.*detached [^ ]+ /, "", ref); sub(/\)$$/, "", ref); print ref; exit;} /^\* / {ref=$$0; sub(/^\* /, "", ref); print ref; exit}');\ 195 | if test "$$(git rev-parse --short HEAD)" != "$$ref"; then echo "$$ref"; fi)) 196 | else 197 | current_rmq_ref := master 198 | endif 199 | endif 200 | export current_rmq_ref 201 | 202 | ifeq ($(origin base_rmq_ref),undefined) 203 | ifneq ($(wildcard .git),) 204 | possible_base_rmq_ref := master 205 | ifeq ($(possible_base_rmq_ref),$(current_rmq_ref)) 206 | base_rmq_ref := $(current_rmq_ref) 207 | else 208 | base_rmq_ref := $(shell \ 209 | (git rev-parse --verify -q master >/dev/null && \ 210 | git rev-parse --verify -q $(possible_base_rmq_ref) >/dev/null && \ 211 | git merge-base --is-ancestor $$(git merge-base master HEAD) $(possible_base_rmq_ref) && \ 212 | echo $(possible_base_rmq_ref)) || \ 213 | echo master) 214 | endif 215 | else 216 | base_rmq_ref := master 217 | endif 218 | endif 219 | export base_rmq_ref 220 | 221 | # Repository URL selection. 222 | # 223 | # First, we infer other components' location from the current project 224 | # repository URL, if it's a Git repository: 225 | # - We take the "origin" remote URL as the base 226 | # - The current project name and repository name is replaced by the 227 | # target's properties: 228 | # eg. rabbitmq-common is replaced by rabbitmq-codegen 229 | # eg. rabbit_common is replaced by rabbitmq_codegen 230 | # 231 | # If cloning from this computed location fails, we fallback to RabbitMQ 232 | # upstream which is GitHub. 233 | 234 | # Maccro to transform eg. "rabbit_common" to "rabbitmq-common". 235 | rmq_cmp_repo_name = $(word 2,$(dep_$(1))) 236 | 237 | # Upstream URL for the current project. 238 | RABBITMQ_COMPONENT_REPO_NAME := $(call rmq_cmp_repo_name,$(PROJECT)) 239 | RABBITMQ_UPSTREAM_FETCH_URL ?= https://github.com/rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git 240 | RABBITMQ_UPSTREAM_PUSH_URL ?= git@github.com:rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git 241 | 242 | # Current URL for the current project. If this is not a Git clone, 243 | # default to the upstream Git repository. 244 | ifneq ($(wildcard .git),) 245 | git_origin_fetch_url := $(shell git config remote.origin.url) 246 | git_origin_push_url := $(shell git config remote.origin.pushurl || git config remote.origin.url) 247 | RABBITMQ_CURRENT_FETCH_URL ?= $(git_origin_fetch_url) 248 | RABBITMQ_CURRENT_PUSH_URL ?= $(git_origin_push_url) 249 | else 250 | RABBITMQ_CURRENT_FETCH_URL ?= $(RABBITMQ_UPSTREAM_FETCH_URL) 251 | RABBITMQ_CURRENT_PUSH_URL ?= $(RABBITMQ_UPSTREAM_PUSH_URL) 252 | endif 253 | 254 | # Macro to replace the following pattern: 255 | # 1. /foo.git -> /bar.git 256 | # 2. /foo -> /bar 257 | # 3. /foo/ -> /bar/ 258 | subst_repo_name = $(patsubst %/$(1)/%,%/$(2)/%,$(patsubst %/$(1),%/$(2),$(patsubst %/$(1).git,%/$(2).git,$(3)))) 259 | 260 | # Macro to replace both the project's name (eg. "rabbit_common") and 261 | # repository name (eg. "rabbitmq-common") by the target's equivalent. 262 | # 263 | # This macro is kept on one line because we don't want whitespaces in 264 | # the returned value, as it's used in $(dep_fetch_git_rmq) in a shell 265 | # single-quoted string. 266 | dep_rmq_repo = $(if $(dep_$(2)),$(call subst_repo_name,$(PROJECT),$(2),$(call subst_repo_name,$(RABBITMQ_COMPONENT_REPO_NAME),$(call rmq_cmp_repo_name,$(2)),$(1))),$(pkg_$(1)_repo)) 267 | 268 | dep_rmq_commits = $(if $(dep_$(1)), \ 269 | $(wordlist 3,$(words $(dep_$(1))),$(dep_$(1))), \ 270 | $(pkg_$(1)_commit)) 271 | 272 | define dep_fetch_git_rmq 273 | fetch_url1='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_FETCH_URL),$(1))'; \ 274 | fetch_url2='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_FETCH_URL),$(1))'; \ 275 | if test "$$$$fetch_url1" != '$(RABBITMQ_CURRENT_FETCH_URL)' && \ 276 | git clone -q -n -- "$$$$fetch_url1" $(DEPS_DIR)/$(call dep_name,$(1)); then \ 277 | fetch_url="$$$$fetch_url1"; \ 278 | push_url='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_PUSH_URL),$(1))'; \ 279 | elif git clone -q -n -- "$$$$fetch_url2" $(DEPS_DIR)/$(call dep_name,$(1)); then \ 280 | fetch_url="$$$$fetch_url2"; \ 281 | push_url='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_PUSH_URL),$(1))'; \ 282 | fi; \ 283 | cd $(DEPS_DIR)/$(call dep_name,$(1)) && ( \ 284 | $(foreach ref,$(call dep_rmq_commits,$(1)), \ 285 | git checkout -q $(ref) >/dev/null 2>&1 || \ 286 | ) \ 287 | (echo "error: no valid pathspec among: $(call dep_rmq_commits,$(1))" \ 288 | 1>&2 && false) ) && \ 289 | (test "$$$$fetch_url" = "$$$$push_url" || \ 290 | git remote set-url --push origin "$$$$push_url") 291 | endef 292 | 293 | # -------------------------------------------------------------------- 294 | # Component distribution. 295 | # -------------------------------------------------------------------- 296 | 297 | list-dist-deps:: 298 | @: 299 | 300 | prepare-dist:: 301 | @: 302 | 303 | # -------------------------------------------------------------------- 304 | # Umbrella-specific settings. 305 | # -------------------------------------------------------------------- 306 | 307 | # If this project is under the Umbrella project, we override $(DEPS_DIR) 308 | # to point to the Umbrella's one. We also disable `make distclean` so 309 | # $(DEPS_DIR) is not accidentally removed. 310 | 311 | ifneq ($(wildcard ../../UMBRELLA.md),) 312 | UNDER_UMBRELLA = 1 313 | else ifneq ($(wildcard UMBRELLA.md),) 314 | UNDER_UMBRELLA = 1 315 | endif 316 | 317 | ifeq ($(UNDER_UMBRELLA),1) 318 | ifneq ($(PROJECT),rabbitmq_public_umbrella) 319 | DEPS_DIR ?= $(abspath ..) 320 | endif 321 | 322 | ifneq ($(filter distclean distclean-deps,$(MAKECMDGOALS)),) 323 | SKIP_DEPS = 1 324 | endif 325 | endif 326 | -------------------------------------------------------------------------------- /src/rabbit_mgmt_wm_all.erl: -------------------------------------------------------------------------------- 1 | %% The contents of this file are subject to the Mozilla Public License 2 | %% Version 1.1 (the "License"); you may not use this file except in 3 | %% compliance with the License. You may obtain a copy of the License at 4 | %% http://www.mozilla.org/MPL/ 5 | %% 6 | %% Software distributed under the License is distributed on an "AS IS" 7 | %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the 8 | %% License for the specific language governing rights and limitations 9 | %% under the License. 10 | %% 11 | %% The Original Code is RabbitMQ Visualiser. 12 | %% 13 | %% The Initial Developer of the Original Code is GoPivotal, Inc. 14 | %% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. 15 | -module(rabbit_mgmt_wm_all). 16 | 17 | -export([init/2]). 18 | -export([to_json/2, content_types_provided/2, is_authorized/2, 19 | resource_exists/2]). 20 | 21 | -import(rabbit_misc, [pget/2]). 22 | 23 | -include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). 24 | -include_lib("amqp_client/include/amqp_client.hrl"). 25 | 26 | %%-------------------------------------------------------------------- 27 | init(Req, _State) -> 28 | {cowboy_rest, rabbit_mgmt_cors:set_headers(Req, ?MODULE), #context{}}. 29 | 30 | content_types_provided(ReqData, Context) -> 31 | {[{<<"application/json">>, to_json}], ReqData, Context}. 32 | 33 | resource_exists(ReqData, Context) -> 34 | {case rabbit_mgmt_util:vhost(ReqData) of 35 | not_found -> false; 36 | _ -> true 37 | end, ReqData, Context}. 38 | 39 | to_json(ReqData, Context) -> 40 | rabbit_mgmt_util:reply( 41 | rabbit_mgmt_format:strip_pids( 42 | [{Key, Mod:augmented(ReqData, Context)} 43 | || {Key, Mod} <- [{queues, rabbit_mgmt_wm_queues}, 44 | {exchanges, rabbit_mgmt_wm_exchanges}, 45 | {bindings, rabbit_mgmt_wm_bindings}, 46 | {channels, rabbit_mgmt_wm_channels}, 47 | {connections, rabbit_mgmt_wm_connections}, 48 | {vhosts, rabbit_mgmt_wm_vhosts}] 49 | ]), 50 | ReqData, Context). 51 | 52 | is_authorized(ReqData, Context) -> 53 | rabbit_mgmt_util:is_authorized(ReqData, Context). 54 | -------------------------------------------------------------------------------- /src/rabbit_visualiser_mgmt.erl: -------------------------------------------------------------------------------- 1 | %% The contents of this file are subject to the Mozilla Public License 2 | %% Version 1.1 (the "License"); you may not use this file except in 3 | %% compliance with the License. You may obtain a copy of the License at 4 | %% http://www.mozilla.org/MPL/ 5 | %% 6 | %% Software distributed under the License is distributed on an "AS IS" 7 | %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the 8 | %% License for the specific language governing rights and limitations 9 | %% under the License. 10 | %% 11 | %% The Original Code is RabbitMQ Visualiser. 12 | %% 13 | %% The Initial Developer of the Original Code is GoPivotal, Inc. 14 | %% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. 15 | %% 16 | 17 | -module(rabbit_visualiser_mgmt). 18 | 19 | -behaviour(rabbit_mgmt_extension). 20 | 21 | -export([dispatcher/0, web_ui/0]). 22 | 23 | dispatcher() -> [{"/all", rabbit_mgmt_wm_all, []}, 24 | {"/all/:vhost", rabbit_mgmt_wm_all, []}]. 25 | web_ui() -> [{javascript, <<"visualiser.js">>}]. 26 | -------------------------------------------------------------------------------- /test/visualiser_http_SUITE.erl: -------------------------------------------------------------------------------- 1 | %% The contents of this file are subject to the Mozilla Public License 2 | %% Version 1.1 (the "License"); you may not use this file except in 3 | %% compliance with the License. You may obtain a copy of the License at 4 | %% http://www.mozilla.org/MPL/ 5 | %% 6 | %% Software distributed under the License is distributed on an "AS IS" 7 | %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the 8 | %% License for the specific language governing rights and limitations 9 | %% under the License. 10 | %% 11 | %% The Original Code is RabbitMQ. 12 | %% 13 | %% The Initial Developer of the Original Code is GoPivotal, Inc. 14 | %% Copyright (c) 2016 Pivotal Software, Inc. All rights reserved. 15 | %% 16 | 17 | -module(visualiser_http_SUITE). 18 | 19 | -compile(export_all). 20 | 21 | -include_lib("common_test/include/ct.hrl"). 22 | -include_lib("rabbitmq_ct_helpers/include/rabbit_mgmt_test.hrl"). 23 | 24 | -import(rabbit_mgmt_test_util, [http_get/2, http_put/4, http_post/4, assert_list/2]). 25 | 26 | -define(COLLECT_INTERVAL, 1000). 27 | 28 | all() -> [all_request]. 29 | 30 | 31 | init_per_suite(Config) -> 32 | rabbit_ct_helpers:log_environment(), 33 | inets:start(), 34 | Config1 = rabbit_ct_helpers:set_config(Config, [ 35 | {rmq_nodename_suffix, ?MODULE} 36 | ]), 37 | Config2 = merge_app_env(Config1), 38 | rabbit_ct_helpers:run_setup_steps(Config2, 39 | rabbit_ct_broker_helpers:setup_steps()). 40 | end_per_suite(Config) -> 41 | rabbit_ct_helpers:run_teardown_steps( 42 | Config, rabbit_ct_broker_helpers:teardown_steps()). 43 | 44 | merge_app_env(Config) -> 45 | Config1 = rabbit_ct_helpers:merge_app_env(Config, 46 | {rabbit, [ 47 | {collect_statistics_interval, ?COLLECT_INTERVAL} 48 | ]}), 49 | rabbit_ct_helpers:merge_app_env(Config1, 50 | {rabbitmq_management_agent, [ 51 | {sample_retention_policies, 52 | [{global, [{605, 1}]}, 53 | {basic, [{605, 1}]}, 54 | {detailed, [{10, 1}]}] }]}). 55 | 56 | init_per_testcase(all_request, Config) -> 57 | Config1 = prepare_topology(Config), 58 | rabbit_ct_helpers:testcase_started(Config1, all_request). 59 | 60 | end_per_testcase(all_request, Config) -> 61 | Config1 = drop_topology(Config), 62 | rabbit_ct_helpers:testcase_finished(Config1, all_request). 63 | 64 | prepare_topology(Config) -> 65 | Vhosts = [<<"/">>, <<"test_vhost1">>, <<"test_vhost2">>], 66 | Queues = [{<<"test_vhost1">>, <<"queue1">>}, {<<"test_vhost1">>, <<"queue2">>}, 67 | {<<"test_vhost2">>, <<"queue3">>}, {<<"test_vhost2">>, <<"queue4">>}], 68 | Exchanges = [{<<"test_vhost1">>, <<"exchange_direct">>, <<"direct">>}, 69 | {<<"test_vhost2">>, <<"exchange_fanout">>, <<"fanout">>}], 70 | Bindings = [{<<"test_vhost1">>, <<"exchange_direct">>, <<"queue1">>, <<"rk">>, <<"rk">>}, 71 | {<<"test_vhost2">>, <<"exchange_fanout">>, <<"queue3">>, <<>>, <<$~>>}], 72 | Topology = #{vhosts => Vhosts, 73 | queues => top_queues(Queues), 74 | exchanges => top_exchanges(Vhosts, Exchanges), 75 | bindings => top_bindings(Queues, Bindings)}, 76 | create_vhosts(Config, Vhosts), 77 | create_queues(Config, Queues), 78 | create_exchanges(Config, Exchanges), 79 | create_bindings(Config, Bindings), 80 | rabbit_ct_helpers:set_config(Config, [{topology, Topology}]). 81 | 82 | drop_topology(Config) -> 83 | Topology = ?config(topology, Config), 84 | Vhosts = maps:get(vhosts, Topology), 85 | drop_vhosts(Config, Vhosts), 86 | Config. 87 | 88 | create_vhosts(Config, Vhosts) -> 89 | lists:foreach(fun(Vhost) -> 90 | rabbit_ct_broker_helpers:add_vhost(Config, Vhost), 91 | rabbit_ct_broker_helpers:set_full_permissions(Config, Vhost) 92 | end, 93 | Vhosts). 94 | 95 | create_queues(Config, Queues) -> 96 | lists:foreach(fun({Vhost, Queue}) -> 97 | http_put(Config, binary_to_list(<<"/queues/", Vhost/binary, "/", Queue/binary>>), 98 | [{durable, true}], [?CREATED, ?NO_CONTENT]) 99 | end, 100 | Queues). 101 | 102 | create_exchanges(Config, Exchanges) -> 103 | lists:foreach(fun({Vhost, Exchange, Type}) -> 104 | http_put(Config, binary_to_list(<<"/exchanges/", Vhost/binary, "/", Exchange/binary>>), 105 | [{type, Type}, {durable, true}], [?CREATED, ?NO_CONTENT]) 106 | end, 107 | Exchanges). 108 | 109 | create_bindings(Config, Bindings) -> 110 | lists:foreach(fun({Vhost, Exchange, Queue, RoutingKey, _}) -> 111 | http_post(Config, binary_to_list(<<"/bindings/", Vhost/binary, "/e/", Exchange/binary, "/q/", Queue/binary>>), 112 | [{routing_key, RoutingKey}, {arguments, []}], 113 | [?CREATED, ?NO_CONTENT]) 114 | end, 115 | Bindings). 116 | 117 | drop_vhosts(Config, Vhosts) -> 118 | lists:foreach(fun(Vhost) -> 119 | rabbit_ct_broker_helpers:delete_vhost(Config, Vhost) 120 | end, Vhosts). 121 | 122 | top_queues(Queues) -> 123 | [ #{name => Queue, 124 | vhost => Vhost, 125 | durable => true, 126 | auto_delete => false, 127 | exclusive => false, 128 | arguments => #{}} || {Vhost, Queue} <- Queues ]. 129 | 130 | top_exchanges(Vhosts, Exchanges) -> 131 | default_exchanges(Vhosts) ++ 132 | [#{name => Exchange, 133 | vhost => Vhost, 134 | type => Type, 135 | durable => true, 136 | auto_delete => false, 137 | internal => false, 138 | arguments => #{}} || {Vhost, Exchange, Type} <- Exchanges ]. 139 | 140 | default_exchanges(Vhosts) -> 141 | [#{name => Exchange, 142 | vhost => Vhost, 143 | type => Type, 144 | durable => true, 145 | auto_delete => false, 146 | internal => false, 147 | arguments => #{}} 148 | || {Exchange, Type} <- default_exchanges(), 149 | Vhost <- Vhosts] ++ 150 | [#{name => <<"amq.rabbitmq.trace">>, 151 | vhost => Vhost, 152 | type => <<"topic">>, 153 | durable => true, 154 | auto_delete => false, 155 | internal => true, 156 | arguments => #{}} 157 | || Vhost <- Vhosts ] ++ 158 | [#{name => <<"amq.rabbitmq.log">>, 159 | vhost => <<"/">>, 160 | type => <<"topic">>, 161 | durable => true, 162 | auto_delete => false, 163 | internal => true, 164 | arguments => #{}}]. 165 | 166 | default_exchanges() -> 167 | [{<<>>, <<"direct">>}, 168 | {<<"amq.direct">>, <<"direct">>}, 169 | {<<"amq.fanout">>, <<"fanout">>}, 170 | {<<"amq.headers">>, <<"headers">>}, 171 | {<<"amq.match">>, <<"headers">>}, 172 | {<<"amq.topic">>, <<"topic">>}]. 173 | 174 | top_bindings(Queues, Bindings) -> 175 | default_bindings(Queues) ++ 176 | [#{source => Exchange, 177 | vhost => Vhost, 178 | destination => Queue, 179 | destination_type => <<"queue">>, 180 | routing_key => RoutingKey, 181 | arguments => #{}, 182 | properties_key => PropKey} 183 | || {Vhost, Exchange, Queue, RoutingKey, PropKey} <- Bindings]. 184 | 185 | default_bindings(Queues) -> 186 | [#{source => <<>>, 187 | vhost => Vhost, 188 | destination => Queue, 189 | destination_type => <<"queue">>, 190 | routing_key => Queue, 191 | arguments => #{}, 192 | properties_key => Queue} 193 | || {Vhost, Queue} <- Queues]. 194 | 195 | all_request(Config) -> 196 | Topology = ?config(topology, Config), 197 | All = http_get(Config, "/all"), 198 | Queues = maps:get(queues, All), 199 | Exchanges = maps:get(exchanges, All), 200 | Bindings = maps:get(bindings, All), 201 | assert_list(maps:get(queues, Topology), Queues), 202 | assert_list(maps:get(exchanges, Topology), Exchanges), 203 | assert_list(maps:get(bindings, Topology), Bindings). 204 | --------------------------------------------------------------------------------