├── .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 |
Exchanges
78 |
79 | Display
80 |
81 |
Show
82 |
83 |
84 |
Queues
85 |
86 | Display
87 |
88 |
Show
89 |
90 |
91 |
Channels
92 |
93 | Display
94 |
95 |
Show
96 |
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 += "" + attName + " " + flattenAtts(strAtts[attName]) + " ";
148 | } else {
149 | str += "" + attName + " ";
150 | }
151 | if (column === columns) {
152 | column = 0;
153 | str += " ";
154 | }
155 | }
156 | str += "
";
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 |
--------------------------------------------------------------------------------