├── README.md
├── css
├── PoseEditor.css
├── clean.css
├── gamepad.css
└── web-bluetooth.css
├── images
├── child-back-gray.png
├── child-face-gray.png
├── child-left-gray.png
├── child-profile-gray.png
├── child-right-gray.png
├── clear.cache.gif
├── corner.png
├── crosshair_ball.png
├── crosshair_ball2.png
├── crosshair_ball3.png
├── crosshair_mine.png
├── crosshair_mine2.png
├── crosshair_star.png
├── crosshair_thick.png
├── crosshair_thin.png
├── dpad.png
├── green-circle.png
├── grid.png
├── hand-gray-left.png
├── hand-gray-right.png
├── hand-green-left.png
├── hand-green-right.png
├── hand-left-button.png
├── hand-left-yellow-button.png
├── hand-right-button.png
├── hand-right-yellow-button.png
├── hand-rotate-button.png
├── hand-yellow-left.png
├── hand-yellow-right.png
├── hborder.png
├── icon.png
├── left-arrow-dark.png
├── left-arrow.png
├── pause_button.png
├── pause_button_gray.png
├── record_button.png
├── record_button_gray.png
├── right-arrow-dark.png
├── right-arrow.png
├── trigger_meter.png
├── trigger_meter_fill.png
├── vborder.png
└── yellow-circle.png
├── index.html
└── js
├── bootstrap.min.js
├── main.js
├── smoothie.js
├── synaptic.js
├── threejs
├── Detector.js
├── build
│ └── three.min.js
├── controls
│ └── OrbitControls.js
├── libs
│ ├── dat.gui.min.js
│ └── stats.min.js
└── loaders
│ └── OBJLoader.js
└── util.js
/README.md:
--------------------------------------------------------------------------------
1 | # web-bluetooth-neural-network
2 | Train LSTM MLP neural networks for gesture recognition using sensor data streamed into a website with Web Bluetooth
3 |
4 | # LIVE SITE URL: https://curtpw.github.io/web-bluetooth-neural-network/
5 |
--------------------------------------------------------------------------------
/css/PoseEditor.css:
--------------------------------------------------------------------------------
1 | /** Add css rules here for your application. */
2 |
3 |
4 | /** Example rules used by the template application (remove for your app) */
5 | h1 {
6 | font-size: 2em;
7 | font-weight: bold;
8 | color: #777777;
9 | margin: 40px 0px 70px;
10 | text-align: center;
11 | }
12 |
13 | .sendButton {
14 | display: block;
15 | font-size: 16pt;
16 | }
17 |
18 | /** Most GWT widgets already have a style name defined */
19 | .gwt-DialogBox {
20 | width: 400px;
21 | }
22 |
23 | .dialogVPanel {
24 | margin: 5px;
25 | }
26 |
27 | .serverResponseLabelError {
28 | color: red;
29 | }
30 |
31 | /** Set ids using widget.getElement().setId("idOfElement") */
32 | #closeButton {
33 | margin: 15px 6px 6px;
34 | }
35 |
36 | .text{
37 | font-size:12px;
38 | color:#ccc;
39 | }
40 | .debug{
41 | background-color: #ccc;
42 | }
--------------------------------------------------------------------------------
/css/clean.css:
--------------------------------------------------------------------------------
1 | /**
2 | * The file contains styles for GWT widgets in the Clean theme.
3 | *
4 | * In order to maintain cross-browser compatibility, the following syntax is
5 | * used to create IE6 specific style rules:
6 | * .gwt-Widget {
7 | * property: rule applies to all browsers
8 | * -property: rule applies only to IE6 (overrides previous rule)
9 | * }
10 | * * html .gwt-Widget {
11 | * property: rule applies to all versions of IE
12 | * }
13 | */
14 |
15 | body, table td, select, button {
16 | font-family: Arial Unicode MS, Arial, sans-serif;
17 | font-size: small;
18 | }
19 | pre {
20 | font-family: "courier new", courier;
21 | font-size: small;
22 | }
23 | body {
24 | color: black;
25 | margin: 10px;
26 | border: 0px;
27 | padding: 0px;
28 | background: #fff;
29 | direction: ltr;
30 | }
31 | a, a:visited {
32 | color: #0066cc;
33 | text-decoration:none;
34 | }
35 |
36 | a:hover {
37 | color: #0066cc;
38 | text-decoration:underline;
39 | }
40 |
41 | select {
42 | background: white;
43 | }
44 |
45 | /**
46 | * The reference theme can be used to determine when this style sheet has
47 | * loaded. Create a hidden div element with absolute position, assign the style
48 | * name below, and attach it to the DOM. Use a timer to detect when the
49 | * element's height and width are set to 5px.
50 | */
51 | .gwt-Reference-clean {
52 | height: 5px;
53 | width: 5px;
54 | zoom: 1;
55 | }
56 |
57 | .gwt-Button {
58 | margin: 0;
59 | padding: 2px 5px;
60 | text-decoration: none;
61 | cursor: pointer;
62 | cursor: hand;
63 | font-size:small;
64 | background: url("images/hborder.png") repeat-x 0px -2077px;
65 | border:1px solid #bbb;
66 | border-bottom: 1px solid #a0a0a0;
67 | border-radius: 3px;
68 | -moz-border-radius: 3px;
69 | }
70 | .gwt-Button:active {
71 | border: 1px inset #ccc;
72 | }
73 | .gwt-Button:hover {
74 | border-color: #939393;
75 | }
76 | .gwt-Button[disabled] {
77 | cursor: default;
78 | color: #888;
79 | }
80 | .gwt-Button[disabled]:hover {
81 | border: 1px outset #ccc;
82 | }
83 |
84 | .gwt-CheckBox {
85 | }
86 | .gwt-CheckBox-disabled {
87 | color: #888;
88 | }
89 |
90 | .gwt-DecoratorPanel {
91 | }
92 | .gwt-DecoratorPanel .topCenter {
93 | border-top: 1px solid #bbb;
94 | line-height: 0px;
95 | }
96 | .gwt-DecoratorPanel .bottomCenter {
97 | border-bottom: 1px solid #bbb;
98 | line-height: 0px;
99 | }
100 | .gwt-DecoratorPanel .topCenterInner,
101 | .gwt-DecoratorPanel .bottomCenterInner {
102 | height: 1px;
103 | line-height: 0px;
104 | font-size: 1px;
105 | }
106 | .gwt-DecoratorPanel .middleLeft {
107 | border-left: 1px solid #bbb;
108 | }
109 | .gwt-DecoratorPanel .middleRight {
110 | border-right: 1px solid #bbb;
111 | }
112 | .gwt-DecoratorPanel .middleLeftInner,
113 | .gwt-DecoratorPanel .middleRightInner {
114 | width: 1px;
115 | line-height: 1px;
116 | }
117 | .gwt-DecoratorPanel .topLeftInner,
118 | .gwt-DecoratorPanel .topRightInner,
119 | .gwt-DecoratorPanel .bottomLeftInner,
120 | .gwt-DecoratorPanel .bottomRightInner {
121 | width: 5px;
122 | height: 5px;
123 | zoom: 1;
124 | font-size: 1px;
125 | overflow: hidden;
126 | }
127 | .gwt-DecoratorPanel .topLeft {
128 | line-height: 0px;
129 | background: url(images/circles.png) no-repeat 0px -6px;
130 | -background: url(images/circles_ie6.png) no-repeat 0px -6px;
131 | }
132 | .gwt-DecoratorPanel .topRight {
133 | line-height: 0px;
134 | background: url(images/circles.png) no-repeat -5px -6px;
135 | -background: url(images/circles_ie6.png) no-repeat -5px -6px;
136 | }
137 | .gwt-DecoratorPanel .bottomLeft {
138 | line-height: 0px;
139 | background: url(images/circles.png) no-repeat 0px -11px;
140 | -background: url(images/circles_ie6.png) no-repeat 0px -11px;
141 | }
142 | .gwt-DecoratorPanel .bottomRight {
143 | line-height: 0px;
144 | background: url(images/circles.png) no-repeat -5px -11px;
145 | -background: url(images/circles_ie6.png) no-repeat -5px -11px;
146 | }
147 | * html .gwt-DecoratorPanel .topLeftInner,
148 | * html .gwt-DecoratorPanel .topRightInner,
149 | * html .gwt-DecoratorPanel .bottomLeftInner,
150 | * html .gwt-DecoratorPanel .bottomRightInner {
151 | width: 5px;
152 | height: 5px;
153 | overflow: hidden;
154 | }
155 |
156 | .gwt-DialogBox .Caption {
157 | background: #F1F1F1;
158 | padding: 4px 8px 4px 4px;
159 | cursor: default;
160 | font-family: Arial Unicode MS, Arial, sans-serif;
161 | font-weight: bold;
162 | border-bottom: 1px solid #bbbbbb;
163 | border-top: 1px solid #D2D2D2;
164 | }
165 | .gwt-DialogBox .dialogContent {
166 | }
167 | .gwt-DialogBox .dialogMiddleCenter {
168 | padding: 3px;
169 | background: white;
170 | }
171 | .gwt-DialogBox .dialogBottomCenter {
172 | background: url(images/hborder.png) repeat-x 0px -2945px;
173 | -background: url(images/hborder_ie6.png) repeat-x 0px -2144px;
174 | }
175 | .gwt-DialogBox .dialogMiddleLeft {
176 | background: url(images/vborder.png) repeat-y -31px 0px;
177 | }
178 | .gwt-DialogBox .dialogMiddleRight {
179 | background: url(images/vborder.png) repeat-y -32px 0px;
180 | -background: url(images/vborder_ie6.png) repeat-y -32px 0px;
181 | }
182 | .gwt-DialogBox .dialogTopLeftInner {
183 | width: 10px;
184 | height: 8px;
185 | zoom: 1;
186 | }
187 | .gwt-DialogBox .dialogTopRightInner {
188 | width: 12px;
189 | zoom: 1;
190 | }
191 | .gwt-DialogBox .dialogBottomLeftInner {
192 | width: 10px;
193 | height: 12px;
194 | zoom: 1;
195 | }
196 | .gwt-DialogBox .dialogBottomRightInner {
197 | width: 12px;
198 | height: 12px;
199 | zoom: 1;
200 | }
201 | .gwt-DialogBox .dialogTopLeft {
202 | background: url(images/circles.png) no-repeat -20px 0px;
203 | -background: url(images/circles_ie6.png) no-repeat -20px 0px;
204 | }
205 | .gwt-DialogBox .dialogTopRight {
206 | background: url(images/circles.png) no-repeat -28px 0px;
207 | -background: url(images/circles_ie6.png) no-repeat -28px 0px;
208 | }
209 | .gwt-DialogBox .dialogBottomLeft {
210 | background: url(images/circles.png) no-repeat 0px -36px;
211 | -background: url(images/circles_ie6.png) no-repeat 0px -36px;
212 | }
213 | .gwt-DialogBox .dialogBottomRight {
214 | background: url(images/circles.png) no-repeat -8px -36px;
215 | -background: url(images/circles_ie6.png) no-repeat -8px -36px;
216 | }
217 | * html .gwt-DialogBox .dialogTopLeftInner {
218 | width: 10px;
219 | overflow: hidden;
220 | }
221 | * html .gwt-DialogBox .dialogTopRightInner {
222 | width: 12px;
223 | overflow: hidden;
224 | }
225 | * html .gwt-DialogBox .dialogBottomLeftInner {
226 | width: 10px;
227 | height: 12px;
228 | overflow: hidden;
229 | }
230 | * html .gwt-DialogBox .dialogBottomRightInner {
231 | width: 12px;
232 | height: 12px;
233 | overflow: hidden;
234 | }
235 |
236 | .gwt-DisclosurePanel {
237 | }
238 | .gwt-DisclosurePanel-open {
239 | }
240 | .gwt-DisclosurePanel-closed {
241 | }
242 | .gwt-DisclosurePanel .header,
243 | .gwt-DisclosurePanel .header a,
244 | .gwt-DisclosurePanel .header td {
245 | text-decoration: none; /* Remove underline from header */
246 | color: black;
247 | cursor: pointer;
248 | cursor: hand;
249 | }
250 | .gwt-DisclosurePanel .content {
251 | border-left: 3px solid #e7e7e7;
252 | padding: 4px 0px 4px 8px;
253 | margin-left: 6px;
254 | }
255 |
256 | .gwt-FileUpload {
257 | }
258 |
259 | .gwt-Frame {
260 | border-top: 2px solid #666;
261 | border-left: 2px solid #666;
262 | border-right: 2px solid #bbb;
263 | border-bottom: 2px solid #bbb;
264 | }
265 |
266 | .gwt-HorizontalSplitPanel {
267 | }
268 | .gwt-HorizontalSplitPanel .hsplitter {
269 | cursor: move;
270 | border: 0px;
271 | background: #e7e7e7;
272 | line-height: 0px;
273 | }
274 | .gwt-VerticalSplitPanel {
275 | }
276 | .gwt-VerticalSplitPanel .vsplitter {
277 | cursor: move;
278 | border: 0px;
279 | background: #e7e7e7;
280 | line-height: 0px;
281 | }
282 |
283 | .gwt-HTML {
284 | padding: 0 0px;
285 | }
286 |
287 | .gwt-Hyperlink {
288 | cursor: pointer;
289 | }
290 |
291 | .gwt-Image {
292 | }
293 |
294 | .gwt-Label {
295 | }
296 |
297 | .gwt-ListBox {
298 | }
299 |
300 | .gwt-MenuBar {
301 | cursor: default;
302 | }
303 | .gwt-MenuBar .gwt-MenuItem {
304 | cursor: default;
305 | font-family: Arial Unicode MS, Arial, sans-serif;
306 | }
307 | .gwt-MenuBar .gwt-MenuItem-selected {
308 | background: #E3E8F3;
309 | }
310 | .gwt-MenuBar-horizontal {
311 | background: #e3e8f3 url(images/hborder.png) repeat-x 0px -2003px;
312 | border: 1px solid #e0e0e0;
313 | }
314 | .gwt-MenuBar-horizontal .gwt-MenuItem {
315 | padding: 5px 10px;
316 | vertical-align: bottom;
317 | color: #000;
318 | font-weight: bold;
319 | }
320 | .gwt-MenuBar-horizontal .gwt-MenuItemSeparator {
321 | width: 1px;
322 | padding: 0px;
323 | margin: 0px;
324 | border: 0px;
325 | border-left: 1px solid #ccc;
326 | background: white;
327 | }
328 | .gwt-MenuBar-horizontal .gwt-MenuItemSeparator .menuSeparatorInner {
329 | width: 1px;
330 | height: 1px;
331 | background: white;
332 | }
333 | .gwt-MenuBar-vertical {
334 | margin-top: 0px;
335 | margin-left: 0px;
336 | background: white;
337 | }
338 | .gwt-MenuBar-vertical table {
339 | border-collapse: collapse;
340 | }
341 | .gwt-MenuBar-vertical .gwt-MenuItem {
342 | padding: 2px 40px 2px 1px;
343 | }
344 | .gwt-MenuBar-vertical .gwt-MenuItemSeparator {
345 | padding: 2px 0px;
346 | }
347 | .gwt-MenuBar-vertical .gwt-MenuItemSeparator .menuSeparatorInner {
348 | height: 1px;
349 | padding: 0px;
350 | border: 0px;
351 | border-top: 1px solid #ccc;
352 | overflow: hidden;
353 | }
354 | .gwt-MenuBar-vertical .subMenuIcon {
355 | padding-right: 4px;
356 | }
357 | .gwt-MenuBar-vertical .subMenuIcon-selected {
358 | background: #E3E8F3;
359 | }
360 | .gwt-MenuBarPopup {
361 | margin: 0px 0px 0px 3px;
362 | }
363 | .gwt-MenuBarPopup .menuPopupTopCenter {
364 | background: url(images/hborder.png) 0px -12px repeat-x;
365 | }
366 | .gwt-MenuBarPopup .menuPopupBottomCenter {
367 | background: url(images/hborder.png) 0px -13px repeat-x;
368 | -background: url(images/hborder_ie6.png) 0px -13px repeat-x;
369 | }
370 | .gwt-MenuBarPopup .menuPopupMiddleLeft {
371 | background: url(images/vborder.png) -12px 0px repeat-y;
372 | -background: url(images/vborder_ie6.png) -12px 0px repeat-y;
373 | }
374 | .gwt-MenuBarPopup .menuPopupMiddleRight {
375 | background: url(images/vborder.png) -13px 0px repeat-y;
376 | -background: url(images/vborder_ie6.png) -13px 0px repeat-y;
377 | }
378 | .gwt-MenuBarPopup .menuPopupTopLeftInner {
379 | width: 5px;
380 | height: 5px;
381 | zoom: 1;
382 | }
383 | .gwt-MenuBarPopup .menuPopupTopRightInner {
384 | width: 8px;
385 | height: 5px;
386 | zoom: 1;
387 | }
388 | .gwt-MenuBarPopup .menuPopupBottomLeftInner {
389 | width: 5px;
390 | height: 8px;
391 | zoom: 1;
392 | }
393 | .gwt-MenuBarPopup .menuPopupBottomRightInner {
394 | width: 8px;
395 | height: 8px;
396 | zoom: 1;
397 | }
398 | .gwt-MenuBarPopup .menuPopupTopLeft {
399 | background: url(images/corner.png) no-repeat 0px -36px;
400 | -background: url(images/corner_ie6.png) no-repeat 0px -36px;
401 | }
402 | .gwt-MenuBarPopup .menuPopupTopRight {
403 | background: url(images/corner.png) no-repeat -5px -36px;
404 | -background: url(images/corner_ie6.png) no-repeat -5px -36px;
405 | }
406 | .gwt-MenuBarPopup .menuPopupBottomLeft {
407 | background: url(images/corner.png) no-repeat 0px -41px;
408 | -background: url(images/corner_ie6.png) no-repeat 0px -41px;
409 | }
410 | .gwt-MenuBarPopup .menuPopupBottomRight {
411 | background: url(images/corner.png) no-repeat -5px -41px;
412 | -background: url(images/corner_ie6.png) no-repeat -5px -41px;
413 | }
414 | * html .gwt-MenuBarPopup .menuPopupTopLeftInner {
415 | width: 5px;
416 | height: 5px;
417 | overflow: hidden;
418 | }
419 | * html .gwt-MenuBarPopup .menuPopupTopRightInner {
420 | width: 8px;
421 | height: 5px;
422 | overflow: hidden;
423 | }
424 | * html .gwt-MenuBarPopup .menuPopupBottomLeftInner {
425 | width: 5px;
426 | height: 8px;
427 | overflow: hidden;
428 | }
429 | * html .gwt-MenuBarPopup .menuPopupBottomRightInner {
430 | width: 8px;
431 | height: 8px;
432 | overflow: hidden;
433 | }
434 |
435 | .gwt-PasswordTextBox {
436 | padding: 5px 4px;
437 | border: 1px solid #ccc;
438 | border-top: 1px solid #999;
439 | font-size: 100%;
440 | }
441 | .gwt-PasswordTextBox-readonly {
442 | color: #888;
443 | }
444 |
445 | .gwt-PopupPanel {
446 | border: 3px solid #e7e7e7;
447 | padding: 3px;
448 | background: white;
449 | }
450 |
451 | .gwt-DecoratedPopupPanel .popupContent {
452 | }
453 | .gwt-DecoratedPopupPanel .popupMiddleCenter {
454 | padding: 3px;
455 | background: #f1f1f1;
456 | }
457 | .gwt-DecoratedPopupPanel .popupTopCenter {
458 | background: url(images/hborder.png) 0px -2937px repeat-x;
459 | }
460 | .gwt-DecoratedPopupPanel .popupBottomCenter {
461 | background: url(images/hborder.png) repeat-x 0px -2938px;
462 | -background: url(images/hborder_ie6.png) repeat-x 0px -2138px;
463 | }
464 | .gwt-DecoratedPopupPanel .popupMiddleLeft {
465 | background: url(images/vborder.png) -21px 0px repeat-y;
466 | }
467 | .gwt-DecoratedPopupPanel .popupMiddleRight {
468 | background: url(images/vborder.png) repeat-y -24px 0px;
469 | -background: url(images/vborder_ie6.png) repeat-y -24px 0px;
470 | }
471 | .gwt-DecoratedPopupPanel .popupTopLeftInner {
472 | width: 6px;
473 | height: 5px;
474 | zoom: 1;
475 | }
476 | .gwt-DecoratedPopupPanel .popupTopRightInner {
477 | width: 6px;
478 | height: 5px;
479 | zoom: 1;
480 | }
481 | .gwt-DecoratedPopupPanel .popupBottomLeftInner {
482 | width: 6px;
483 | height: 6px;
484 | zoom: 1;
485 | }
486 | .gwt-DecoratedPopupPanel .popupBottomRightInner {
487 | width: 6px;
488 | height: 6px;
489 | zoom: 1;
490 | }
491 | .gwt-DecoratedPopupPanel .popupTopLeft {
492 | background: url(images/circles.png) no-repeat 0px -16px;
493 | -background: url(images/circles_ie6.png) no-repeat 0px -16px;
494 | }
495 | .gwt-DecoratedPopupPanel .popupTopRight {
496 | background: url(images/circles.png) no-repeat -6px -16px;
497 | -background: url(images/circles_ie6.png) no-repeat -6px -16px;
498 | }
499 | .gwt-DecoratedPopupPanel .popupBottomLeft {
500 | background: url(images/circles.png) no-repeat 0px -21px;
501 | -background: url(images/circles_ie6.png) no-repeat 0px -21px;
502 | }
503 | .gwt-DecoratedPopupPanel .popupBottomRight {
504 | background: url(images/circles.png) no-repeat -6px -21px;
505 | -background: url(images/circles_ie6.png) no-repeat -6px -21px;
506 | }
507 | * html .gwt-DecoratedPopupPanel .popupTopLeftInner {
508 | width: 6px;
509 | height: 5px;
510 | overflow: hidden;
511 | }
512 | * html .gwt-DecoratedPopupPanel .popupTopRightInner {
513 | width: 6px;
514 | height: 5px;
515 | overflow: hidden;
516 | }
517 | * html .gwt-DecoratedPopupPanel .popupBottomLeftInner {
518 | width: 6px;
519 | height: 6px;
520 | overflow: hidden;
521 | }
522 | * html .gwt-DecoratedPopupPanel .popupBottomRightInner {
523 | width: 6px;
524 | height: 6px;
525 | overflow: hidden;
526 | }
527 |
528 | .gwt-PopupPanelGlass {
529 | background-color: #000;
530 | opacity: 0.3;
531 | filter: alpha(opacity=30);
532 | }
533 |
534 | .gwt-PushButton-up,
535 | .gwt-PushButton-up-hovering,
536 | .gwt-PushButton-up-disabled,
537 | .gwt-PushButton-down,
538 | .gwt-PushButton-down-hovering,
539 | .gwt-PushButton-down-disabled {
540 | margin: 0;
541 | text-decoration: none;
542 | background: url("images/hborder.png") repeat-x 0px -27px;
543 | border-radius: 2px;
544 | -moz-border-radius: 2px;
545 | }
546 | .gwt-PushButton-up,
547 | .gwt-PushButton-up-hovering,
548 | .gwt-PushButton-up-disabled {
549 | padding: 3px 5px 3px 5px;
550 | }
551 | .gwt-PushButton-up {
552 | border:1px solid #bbb;
553 | border-bottom: 1px solid #a0a0a0;
554 | cursor: pointer;
555 | cursor: hand;
556 | }
557 | .gwt-PushButton-up-hovering {
558 | border: 1px solid;
559 | border-color: #939393;
560 | cursor: pointer;
561 | cursor: hand;
562 | }
563 | .gwt-PushButton-up-disabled {
564 | border: 1px solid #bbb;
565 | cursor: default;
566 | opacity: .5;
567 | filter: alpha(opacity=45);
568 | zoom: 1;
569 | }
570 | .gwt-PushButton-down,
571 | .gwt-PushButton-down-hovering,
572 | .gwt-PushButton-down-disabled {
573 | padding: 4px 4px 2px 6px;
574 | outline:none;
575 | }
576 | .gwt-PushButton-down {
577 | border: 1px inset #666;
578 | cursor: pointer;
579 | cursor: hand;
580 | }
581 | .gwt-PushButton-down-hovering {
582 | border: 1px solid #939393;
583 | border-top: 1px solid #333333;
584 | cursor: pointer;
585 | cursor: hand;
586 | }
587 | .gwt-PushButton-down-disabled {
588 | border: 1px outset #ccc;
589 | cursor: default;
590 | opacity: 0.5;
591 | filter: alpha(opacity=45);
592 | zoom: 1;
593 | }
594 |
595 | .gwt-RadioButton {
596 | }
597 | .gwt-RadioButton-disabled {
598 | color: #888;
599 | }
600 |
601 | .gwt-RichTextArea {
602 | }
603 | .hasRichTextToolbar {
604 | border: 0px;
605 | }
606 | .gwt-RichTextToolbar {
607 | background: #e3e8f3 url(images/hborder.png) repeat-x 0px -2003px;
608 | border-bottom: 1px solid #BBBBBB;
609 | padding: 3px;
610 | margin: 0px;
611 | }
612 | .gwt-RichTextToolbar .gwt-PushButton-up {
613 | padding: 0px 1px 0px 0px;
614 | margin-right: 4px;
615 | margin-bottom: 4px;
616 | border-width: 1px;
617 | }
618 | .gwt-RichTextToolbar .gwt-PushButton-up-hovering {
619 | margin-right: 4px;
620 | margin-bottom: 4px;
621 | padding: 0px 1px 0px 0px;
622 | border-width: 1px;
623 | }
624 | .gwt-RichTextToolbar .gwt-PushButton-down {
625 | margin-right: 4px;
626 | margin-bottom: 4px;
627 | padding: 0px 0px 0px 1px;
628 | border-width: 1px;
629 | }
630 | .gwt-RichTextToolbar .gwt-PushButton-down-hovering {
631 | margin-right: 4px;
632 | margin-bottom: 4px;
633 | padding: 0px 0px 0px 1px;
634 | border-width: 1px;
635 | }
636 | .gwt-RichTextToolbar .gwt-ToggleButton-up {
637 | margin-right: 4px;
638 | margin-bottom: 4px;
639 | padding: 0px 1px 0px 0px;
640 | border:1px solid #bbb;
641 | border-bottom: 1px solid #a0a0a0;
642 | }
643 | .gwt-RichTextToolbar .gwt-ToggleButton-up-hovering {
644 | margin-right: 4px;
645 | margin-bottom: 4px;
646 | padding: 0px 1px 0px 0px;
647 | border-width: 1px;
648 | }
649 | .gwt-RichTextToolbar .gwt-ToggleButton-down {
650 | margin-right: 4px;
651 | margin-bottom: 4px;
652 | padding: 0px 0px 0px 1px;
653 | border-width: 1px;
654 | }
655 | .gwt-RichTextToolbar .gwt-ToggleButton-down-hovering {
656 | margin-right: 4px;
657 | margin-bottom: 4px;
658 | padding: 0px 0px 0px 1px;
659 | border-width: 1px;
660 | }
661 |
662 | .gwt-StackPanel {
663 | border-bottom: 1px solid #bbbbbb;
664 | }
665 | .gwt-StackPanel .gwt-StackPanelItem {
666 | cursor: pointer;
667 | cursor: hand;
668 | font-weight: bold;
669 | font-size: 1.3em;
670 | padding: 3px;
671 | border: 1px solid #bbbbbb;
672 | border-bottom: 0px;
673 | background: #d3def6 url(images/hborder.png) repeat-x 0px -989px;
674 | }
675 | .gwt-StackPanel .gwt-StackPanelContent {
676 | border: 1px solid #bbbbbb;
677 | border-bottom: 0px;
678 | background: white;
679 | padding: 2px 2px 10px 5px;
680 | }
681 |
682 | .gwt-DecoratedStackPanel {
683 | border-bottom: 1px solid #bbbbbb;
684 | }
685 | .gwt-DecoratedStackPanel .gwt-StackPanelContent {
686 | border: 1px solid #bbbbbb;
687 | border-bottom: 0px;
688 | background: white;
689 | padding: 2px 2px 10px 5px;
690 | }
691 | .gwt-DecoratedStackPanel .gwt-StackPanelItem {
692 | cursor: pointer;
693 | cursor: hand;
694 | }
695 | .gwt-DecoratedStackPanel .stackItemTopLeft,
696 | .gwt-DecoratedStackPanel .stackItemTopRight {
697 | height: 6px;
698 | width: 6px;
699 | zoom: 1;
700 | }
701 | .gwt-DecoratedStackPanel .stackItemTopLeft {
702 | border-left: 1px solid #bbbbbb;
703 | background: #d3def6 url(images/corner.png) no-repeat 0px -49px;
704 | -background: #d3def6 url(images/corner_ie6.png) no-repeat 0px -49px;
705 | }
706 | .gwt-DecoratedStackPanel .stackItemTopRight {
707 | border-right: 1px solid #bbbbbb;
708 | background: #d3def6 url(images/corner.png) no-repeat -6px -49px;
709 | -background: #d3def6 url(images/corner_ie6.png) no-repeat -6px -49px;
710 | }
711 | .gwt-DecoratedStackPanel .stackItemTopLeftInner,
712 | .gwt-DecoratedStackPanel .stackItemTopRightInner {
713 | width: 1px;
714 | height: 1px;
715 | }
716 | * html .gwt-DecoratedStackPanel .stackItemTopLeftInner,
717 | * html .gwt-DecoratedStackPanel .stackItemTopRightInner {
718 | width: 6px;
719 | height: 6px;
720 | overflow: hidden;
721 | }
722 | .gwt-DecoratedStackPanel .stackItemTopCenter {
723 | background: url(images/hborder.png) 0px -21px repeat-x;
724 | }
725 | .gwt-DecoratedStackPanel .stackItemMiddleLeft {
726 | background: #d3def6 url(images/hborder.png) repeat-x 0px -989px;
727 | border-left: 1px solid #bbbbbb;
728 | }
729 | .gwt-DecoratedStackPanel .stackItemMiddleLeftInner,
730 | .gwt-DecoratedStackPanel .stackItemMiddleRightInner {
731 | width: 1px;
732 | height: 1px;
733 | }
734 | .gwt-DecoratedStackPanel .stackItemMiddleRight {
735 | background: #d3def6 url(images/hborder.png) repeat-x 0px -989px;
736 | border-right: 1px solid #bbbbbb;
737 | }
738 | .gwt-DecoratedStackPanel .stackItemMiddleCenter {
739 | font-weight: bold;
740 | font-size: 1.3em;
741 | background: #d3def6 url(images/hborder.png) repeat-x 0px -989px;
742 | }
743 | .gwt-DecoratedStackPanel .gwt-StackPanelItem-first .stackItemTopRight,
744 | .gwt-DecoratedStackPanel .gwt-StackPanelItem-first .stackItemTopLeft {
745 | border: 0px;
746 | background-color: white;
747 | }
748 | .gwt-DecoratedStackPanel .gwt-StackPanelItem-below-selected .stackItemTopLeft,
749 | .gwt-DecoratedStackPanel .gwt-StackPanelItem-below-selected .stackItemTopRight {
750 | background-color: white;
751 | }
752 |
753 | .gwt-SuggestBox {
754 | padding: 5px 4px;
755 | border: 1px solid #ccc;
756 | border-top: 1px solid #999;
757 | font-size: 100%;
758 | font-family: Arial Unicode MS, Arial, sans-serif;
759 | }
760 |
761 | .gwt-SuggestBoxPopup {
762 | }
763 |
764 | .gwt-SuggestBoxPopup .item {
765 | padding: 2px 6px;
766 | color: #000;
767 | cursor: default;
768 | font-size: 110%;
769 | }
770 | .gwt-SuggestBoxPopup .item-selected {
771 | background: #D5E2FF;
772 | }
773 | .gwt-SuggestBoxPopup .suggestPopupContent {
774 | background: white;
775 | }
776 | .gwt-SuggestBoxPopup .suggestPopupTopCenter {
777 | border-top: 1px solid #bbb;
778 | }
779 | .gwt-SuggestBoxPopup .suggestPopupBottomCenter {
780 | border-bottom: 1px solid #bbb;
781 | }
782 | .gwt-SuggestBoxPopup .suggestPopupTopCenterInner,
783 | .gwt-SuggestBoxPopup .suggestPopupBottomCenterInner {
784 | height: 1px;
785 | line-height: 1px;
786 | }
787 | .gwt-SuggestBoxPopup .suggestPopupMiddleLeft {
788 | border-left: 1px solid #bbb;
789 | }
790 | .gwt-SuggestBoxPopup .suggestPopupMiddleRight {
791 | border-right: 1px solid #bbb;
792 | }
793 | .gwt-SuggestBoxPopup .suggestPopupMiddleLeftInner,
794 | .gwt-SuggestBoxPopup .suggestPopupMiddleRightInner {
795 | width: 1px;
796 | line-height: 1px;
797 | }
798 | .gwt-SuggestBoxPopup .suggestPopupTopLeftInner {
799 | width: 0px;
800 | height: 0px;
801 | zoom: 1;
802 | }
803 | .gwt-SuggestBoxPopup .suggestPopupTopRightInner {
804 | width: 0px;
805 | height: 0px;
806 | zoom: 1;
807 | }
808 | .gwt-SuggestBoxPopup .suggestPopupBottomLeftInner {
809 | width: 0px;
810 | height: 0px;
811 | zoom: 1;
812 | }
813 | .gwt-SuggestBoxPopup .suggestPopupBottomRightInner {
814 | width: 0px;
815 | height: 0px;
816 | zoom: 1;
817 | }
818 | .gwt-SuggestBoxPopup .suggestPopupTopLeft {
819 | background: url(images/circles.png) no-repeat 0px -6px;
820 | -background: url(images/circles_ie6.png) no-repeat 0px -6px;
821 | width:5px;
822 | height:5px;
823 | }
824 | .gwt-SuggestBoxPopup .suggestPopupTopRight {
825 | background: url(images/circles.png) no-repeat -5px -6px;
826 | -background: url(images/circles_ie6.png) no-repeat -5px -6px;
827 | width:5px;
828 | height:5px;
829 | }
830 | .gwt-SuggestBoxPopup .suggestPopupBottomLeft {
831 | background: url(images/circles.png) no-repeat 0px -11px;
832 | -background: url(images/circles_ie6.png) no-repeat 0px -11px;
833 | width:5px;
834 | height:5px;
835 | }
836 | .gwt-SuggestBoxPopup .suggestPopupBottomRight {
837 | background: url(images/circles.png) no-repeat -5px -11px;
838 | -background: url(images/circles_ie6.png) no-repeat -5px -11px;
839 | width:5px;
840 | height:5px;
841 | }
842 | * html .gwt-SuggestBoxPopup .suggestPopupTopLeftInner {
843 | width: 0px;
844 | height: 0px;
845 | overflow: hidden;
846 | }
847 | * html .gwt-SuggestBoxPopup .suggestPopupTopRightInner {
848 | width: 0px;
849 | height: 0px;
850 | overflow: hidden;
851 | }
852 | * html .gwt-SuggestBoxPopup .suggestPopupBottomLeftInner {
853 | width: 0px;
854 | height: 0px;
855 | overflow: hidden;
856 | }
857 | * html .gwt-SuggestBoxPopup .suggestPopupBottomRightInner {
858 | width: 0px;
859 | height: 0px;
860 | overflow: hidden;
861 | }
862 |
863 | .gwt-TabBar {
864 | background: #ccc;
865 | padding-top: 6px;
866 | }
867 | .gwt-TabBar .gwt-TabBarFirst {
868 | width: 5px; /* first tab distance from the left */
869 | }
870 | .gwt-TabBar .gwt-TabBarRest {
871 | }
872 | .gwt-TabBar .gwt-TabBarItem {
873 | margin-left: 4px;
874 | padding: 4px 8px 4px 8px;
875 | cursor: pointer;
876 | cursor: hand;
877 | color: white;
878 | font-weight: normal;
879 | text-align: center;
880 | background: #8E8E8E;
881 | -moz-border-radius: 3px 3px 0px 0px;
882 | border-radius: 3px 3px 0px 0px;
883 | }
884 | .gwt-TabBar .gwt-TabBarItem-selected {
885 | cursor: default;
886 | background: white;
887 | color: #333;
888 | font-weight: bold;
889 | }
890 | .gwt-TabBar .gwt-TabBarItem-disabled {
891 | cursor: default;
892 | color: #999999;
893 | }
894 | .gwt-TabPanel {
895 | }
896 | .gwt-TabPanelBottom {
897 | border-color: #ccc;
898 | border-style: solid;
899 | border-width: 0px 1px 1px;
900 | overflow: hidden;
901 | padding: 6px;
902 | }
903 | .gwt-DecoratedTabBar {
904 | background: #ccc;
905 | padding-top: 6px;
906 | }
907 | .gwt-DecoratedTabBar .gwt-TabBarFirst {
908 | width: 5px; /* first tab distance from the left */
909 | }
910 | .gwt-DecoratedTabBar .gwt-TabBarRest {
911 | }
912 | .gwt-DecoratedTabBar .gwt-TabBarItem {
913 | border-collapse: collapse;
914 | margin-left: 4px;
915 | }
916 | .gwt-DecoratedTabBar .tabTopCenter {
917 | padding: 0px;
918 | background: #8E8E8E;
919 | }
920 | .gwt-DecoratedTabBar .tabTopLeft,
921 | .gwt-DecoratedTabBar .tabTopRight {
922 | padding: 0px;
923 | zoom: 1;
924 | }
925 | .gwt-DecoratedTabBar .tabTopLeftInner,
926 | .gwt-DecoratedTabBar .tabTopRightInner {
927 | width: 3px;
928 | height: 3px;
929 | }
930 | .gwt-DecoratedTabBar .tabTopLeft {
931 | background: url(images/circles.png) no-repeat 0px 0px;
932 | -background: url(images/circles_ie6.png) no-repeat 0px 0px;
933 | }
934 | .gwt-DecoratedTabBar .tabTopRight {
935 | background: url(images/circles.png) no-repeat -3px 0px;
936 | -background: url(images/circles_ie6.png) no-repeat -3px 0px;
937 | }
938 | * html .gwt-DecoratedTabBar .tabTopLeftInner,
939 | * html .gwt-DecoratedTabBar .tabTopRightInner {
940 | width: 3px;
941 | height: 3px;
942 | overflow: hidden;
943 | }
944 | .gwt-DecoratedTabBar .tabMiddleLeft,
945 | .gwt-DecoratedTabBar .tabMiddleRight {
946 | width: 3px;
947 | padding: 0px;
948 | background: #8E8E8E;
949 | }
950 | .gwt-DecoratedTabBar .tabMiddleLeftInner,
951 | .gwt-DecoratedTabBar .tabMiddleRightInner {
952 | width: 1px;
953 | height: 1px;
954 | }
955 | .gwt-DecoratedTabBar .tabMiddleCenter {
956 | padding: 0px 5px 4px 5px;
957 | cursor: pointer;
958 | cursor: hand;
959 | color: #fff;
960 | font-weight: normal;
961 | text-align: center;
962 | background: #8E8E8E;
963 | }
964 | .gwt-DecoratedTabBar .gwt-TabBarItem-selected .tabTopCenter {
965 | background:#fff;
966 | }
967 | .gwt-DecoratedTabBar .gwt-TabBarItem-selected .tabTopLeft {
968 | background: url(images/circles.png) no-repeat -6px 0px;
969 | -background: url(images/circles_ie6.png) no-repeat -6px 0px;
970 | }
971 | .gwt-DecoratedTabBar .gwt-TabBarItem-selected .tabTopRight {
972 | background: url(images/circles.png) no-repeat -9px 0px;
973 | -background: url(images/circles_ie6.png) no-repeat -9px 0px;
974 | }
975 | .gwt-DecoratedTabBar .gwt-TabBarItem-selected .tabMiddleLeft,
976 | .gwt-DecoratedTabBar .gwt-TabBarItem-selected .tabMiddleRight {
977 | background: #fff;
978 | }
979 | .gwt-DecoratedTabBar .gwt-TabBarItem-selected .tabMiddleCenter {
980 | cursor: default;
981 | background: #fff;
982 | color:#333;
983 | font-weight:bold;
984 | }
985 | .gwt-DecoratedTabBar .gwt-TabBarItem-disabled .tabMiddleCenter {
986 | cursor: default;
987 | color: #999999;
988 | }
989 |
990 | .gwt-TextArea {
991 | padding: 4px;
992 | border: 1px solid #ccc;
993 | border-top: 1px solid #666;
994 | font-size: 100%;
995 | font-family: Arial Unicode MS, Arial, sans-serif;
996 | }
997 | .gwt-TextArea-readonly {
998 | color: #888;
999 | }
1000 |
1001 | .gwt-TextBox {
1002 | padding: 5px 4px;
1003 | border: 1px solid #ccc;
1004 | border-top: 1px solid #999;
1005 | font-size: small;
1006 | font-family: Arial Unicode MS, Arial, sans-serif;
1007 | }
1008 | .gwt-TextBox-readonly {
1009 | color: #888;
1010 | }
1011 | .gwt-ToggleButton-up,
1012 | .gwt-ToggleButton-up-hovering,
1013 | .gwt-ToggleButton-up-disabled,
1014 | .gwt-ToggleButton-down,
1015 | .gwt-ToggleButton-down-hovering,
1016 | .gwt-ToggleButton-down-disabled {
1017 | margin: 0;
1018 | text-decoration: none;
1019 | background: url("images/hborder.png") repeat-x 0px -27px;
1020 | -moz-border-radius: 2px;
1021 | border-radius: 2px;
1022 | }
1023 | .gwt-ToggleButton-up,
1024 | .gwt-ToggleButton-up-hovering,
1025 | .gwt-ToggleButton-up-disabled {
1026 | padding: 3px 5px 3px 5px;
1027 | }
1028 | .gwt-ToggleButton-up {
1029 | border:1px solid #bbb;
1030 | border-bottom: 1px solid #a0a0a0;
1031 | cursor: pointer;
1032 | cursor: hand;
1033 | }
1034 | .gwt-ToggleButton-up-hovering {
1035 | border: 1px solid;
1036 | border-color: #939393;
1037 | cursor: pointer;
1038 | cursor: hand;
1039 | }
1040 | .gwt-ToggleButton-up-disabled {
1041 | border: 1px solid #bbb;
1042 | cursor: default;
1043 | opacity: .5;
1044 | zoom: 1;
1045 | filter: alpha(opacity=45);
1046 | }
1047 | .gwt-ToggleButton-down,
1048 | .gwt-ToggleButton-down-hovering,
1049 | .gwt-ToggleButton-down-disabled {
1050 | padding: 4px 4px 2px 6px;
1051 | }
1052 | .gwt-ToggleButton-down {
1053 | background-position: 0 -513px;
1054 | border: 1px inset #666;
1055 | cursor: pointer;
1056 | cursor: hand;
1057 | }
1058 | .gwt-ToggleButton-down-hovering {
1059 | background-position: 0 -513px;
1060 | border: 1px inset;
1061 | border-color: #9cf #69e #69e #7af;
1062 | cursor: pointer;
1063 | cursor: hand;
1064 | }
1065 | .gwt-ToggleButton-down-disabled {
1066 | background-position: 0 -513px;
1067 | border: 1px inset #ccc;
1068 | cursor: default;
1069 | opacity: .5;
1070 | zoom: 1;
1071 | filter: alpha(opacity=45);
1072 | }
1073 |
1074 | .gwt-Tree .gwt-TreeItem {
1075 | padding: 1px 0px;
1076 | margin: 0px;
1077 | white-space: nowrap;
1078 | cursor: hand;
1079 | cursor: pointer;
1080 | }
1081 | .gwt-Tree .gwt-TreeItem-selected {
1082 | background: #ebeff9;
1083 | }
1084 | .gwt-TreeItem .gwt-RadioButton input,
1085 | .gwt-TreeItem .gwt-CheckBox input {
1086 | margin-left: 0px;
1087 | }
1088 | * html .gwt-TreeItem .gwt-RadioButton input,
1089 | * html .gwt-TreeItem .gwt-CheckBox input {
1090 | margin-left: -4px;
1091 | }
1092 |
1093 | .gwt-DateBox {
1094 | padding: 5px 4px;
1095 | border: 1px solid #ccc;
1096 | border-top: 1px solid #999;
1097 | font-size: 100%;
1098 | }
1099 | .gwt-DateBox input {
1100 | width: 8em;
1101 | }
1102 | .dateBoxFormatError {
1103 | background: #ffcccc;
1104 | }
1105 | .dateBoxPopup {
1106 | }
1107 |
1108 | .gwt-DatePicker {
1109 | border: 1px solid #ccc;
1110 | border-top:1px solid #999;
1111 | cursor: default;
1112 | }
1113 | .gwt-DatePicker td,
1114 | .datePickerMonthSelector td:focus {
1115 | outline: none;
1116 | }
1117 | .datePickerDays {
1118 | width: 100%;
1119 | background: white;
1120 | }
1121 | .datePickerDay,
1122 | .datePickerWeekdayLabel,
1123 | .datePickerWeekendLabel {
1124 | font-size: 85%;
1125 | text-align: center;
1126 | padding: 4px;
1127 | outline: none;
1128 | font-weight:bold;
1129 | color:#333;
1130 | border-right: 1px solid #EDEDED;
1131 | border-bottom: 1px solid #EDEDED;
1132 | }
1133 | .datePickerWeekdayLabel,
1134 | .datePickerWeekendLabel {
1135 | background: #fff;
1136 | padding: 0px 4px 2px;
1137 | cursor: default;
1138 | color:#666;
1139 | font-size:70%;
1140 | font-weight:normal;
1141 | }
1142 | .datePickerDay {
1143 | padding: 4px 7px;
1144 | cursor: hand;
1145 | cursor: pointer;
1146 | }
1147 | .datePickerDayIsWeekend {
1148 | background: #f7f7f7;
1149 | }
1150 | .datePickerDayIsFiller {
1151 | color: #999;
1152 | font-weight:normal;
1153 | }
1154 | .datePickerDayIsValue {
1155 | background: #d7dfe8;
1156 | }
1157 | .datePickerDayIsDisabled {
1158 | color: #AAAAAA;
1159 | font-style: italic;
1160 | }
1161 | .datePickerDayIsHighlighted {
1162 | background: #F0E68C;
1163 | }
1164 | .datePickerDayIsValueAndHighlighted {
1165 | background: #d7dfe8;
1166 | }
1167 | .datePickerDayIsToday {
1168 | padding: 3px;
1169 | color: #fff;
1170 | background: url(images/hborder.png) repeat-x 0px -2607px;
1171 | }
1172 |
1173 | .datePickerMonthSelector {
1174 | width: 100%;
1175 | padding: 1px 0 5px 0;
1176 | background: #fff;
1177 | }
1178 | td.datePickerMonth {
1179 | text-align: center;
1180 | vertical-align: middle;
1181 | white-space: nowrap;
1182 | font-size: 100%;
1183 | font-weight: bold;
1184 | color: #333;
1185 | }
1186 | .datePickerPreviousButton,
1187 | .datePickerNextButton {
1188 | font-size: 120%;
1189 | line-height: 1em;
1190 | color: #3a6aad;
1191 | cursor: hand;
1192 | cursor: pointer;
1193 | font-weight: bold;
1194 | padding: 0px 4px;
1195 | outline: none;
1196 | }
1197 |
1198 | .gwt-StackLayoutPanel {
1199 | border-bottom: 1px solid #bbbbbb;
1200 | }
1201 | .gwt-StackLayoutPanel .gwt-StackLayoutPanelHeader {
1202 | cursor: pointer;
1203 | cursor: hand;
1204 | font-weight: bold;
1205 | font-size: 1.3em;
1206 | padding: 3px;
1207 | border: 1px solid #bbbbbb;
1208 | border-bottom: 0px;
1209 | background: #d3def6 url(images/hborder.png) repeat-x 0px -989px;
1210 | }
1211 | .gwt-StackLayoutPanel .gwt-StackLayoutPanelHeader-hovering {
1212 | background: #d3def6;
1213 | }
1214 | .gwt-StackLayoutPanel .gwt-StackLayoutPanelContent {
1215 | border: 1px solid #bbbbbb;
1216 | border-bottom: 0px;
1217 | background: white;
1218 | padding: 2px 2px 10px 5px;
1219 | }
1220 |
1221 | .gwt-TabLayoutPanel {
1222 | }
1223 | .gwt-TabLayoutPanel .gwt-TabLayoutPanelTabs {
1224 | background: #ccc;
1225 | padding-top: 6px;
1226 | padding-left: 5px;
1227 | }
1228 | .gwt-TabLayoutPanel .gwt-TabLayoutPanelContentContainer {
1229 | border-color: #ccc;
1230 | border-style: solid;
1231 | border-width: 0px 1px 1px;
1232 | }
1233 | .gwt-TabLayoutPanel .gwt-TabLayoutPanelContent {
1234 | overflow: hidden;
1235 | padding: 6px;
1236 | }
1237 | .gwt-TabLayoutPanel .gwt-TabLayoutPanelTab {
1238 | margin-left: 4px;
1239 | padding: 4px 8px 4px 8px;
1240 | cursor: pointer;
1241 | cursor: hand;
1242 | color: white;
1243 | font-weight: normal;
1244 | text-align: center;
1245 | background: #8E8E8E;
1246 | -moz-border-radius: 3px 3px 0px 0px;
1247 | border-radius: 3px 3px 0px 0px;
1248 | }
1249 | .gwt-TabLayoutPanel .gwt-TabLayoutPanelTab-selected {
1250 | cursor: default;
1251 | background: white;
1252 | color: #333;
1253 | font-weight: bold;
1254 | }
1255 |
1256 | .gwt-SplitLayoutPanel-HDragger {
1257 | background: #e7e7e7 url(images/thumb_vertical.png) center center no-repeat;
1258 | cursor: col-resize;
1259 | }
1260 |
1261 | .gwt-SplitLayoutPanel-VDragger {
1262 | background: #e7e7e7 url(images/thumb_horz.png) center center no-repeat;
1263 | cursor: row-resize;
1264 | }
--------------------------------------------------------------------------------
/css/gamepad.css:
--------------------------------------------------------------------------------
1 | .gpTableCell {
2 | border: solid 2px gray;
3 | border-radius: 6px;
4 | }
5 |
6 | .gpTableCellUnConnected {
7 | border-color: lightgray;
8 | color: gray;
9 | }
10 |
11 | .gpNotConnectedText {
12 | font-size: 26pt;
13 | text-align: center;
14 | }
15 |
16 | #gamepadStateTable, #gamepadStateTable th {
17 | border-collapse: collapse;
18 | }
19 |
20 | #gamepadStateTable th {
21 | font-weight: bold;
22 | text-align:left;
23 | }
24 |
25 | #gamepadStateTable td, #gamepadStateTable th {
26 | border: solid 1px #0094FF;
27 | padding: 1px 5px 1px 5px;
28 | color: white;
29 | }
30 |
31 | .AxisVisualizer {
32 | width: 108px;
33 | height: 108px;
34 | background-image: url(../images/crosshair_ball3.png), url(../images/grid.png);
35 | background-position: 10px 10px, 4px 4px;
36 | background-repeat: no-repeat;
37 | }
38 |
39 | .AnalogButtonVisualizer {
40 | width: 30px;
41 | height: 100px;
42 | background-image: url(../images/trigger_meter_fill.png), url(../images/trigger_meter.png);
43 | background-repeat: no-repeat;
44 | font-weight: bold;
45 | text-align: center;
46 | }
47 |
48 | .VisualizerGeneric {
49 | float: left;
50 | margin: 5px;
51 | }
52 |
53 | .AnalogButtonVisualizer #val {
54 | font-size: 9pt;
55 | font-weight: normal;
56 | }
57 |
58 | .oval {
59 | border: solid 1px #0094FF;
60 | border-radius: 3px 3px;
61 | background-clip: border-box;
62 | font-weight: bold;
63 | text-align: center;
64 | }
65 |
66 | .circle {
67 | width: 20px;
68 | height: 20px;
69 | border: solid 1px #0094FF;
70 | border-radius: 100%;
71 | background-clip: border-box;
72 | font-weight: bold;
73 | text-align: center;
74 | line-height: 20px;
75 | }
76 |
77 | .DPad {
78 | position: relative;
79 | left: 10px;
80 | width: 65px;
81 | height: 64px;
82 | background-image: url(../images/dpad.png);
83 | }
84 |
85 | .btnDU, .btnDL, .btnDR, .btnDD {
86 | width: 20px;
87 | height: 20px;
88 | position: absolute;
89 | }
90 |
91 | .btnDU {
92 | left: 23px;
93 | top: 1px;
94 | border-radius: 3px 3px 0px 0px;
95 | }
96 |
97 | .btnDL {
98 | left: 1px;
99 | top: 22px;
100 | border-radius: 3px 0px 0px 3px;
101 | }
102 |
103 | .btnDR {
104 | left: 44px;
105 | top: 23px;
106 | border-radius: 0px 3px 3px 0px;
107 | }
108 |
109 | .btnDD {
110 | left: 23px;
111 | top: 43px;
112 | border-radius: 0px 0px 3px 3px;
113 | }
114 |
115 | .selOrStart {
116 | width: 45px;
117 | }
118 |
119 | .bumper {
120 | width: 80px;
121 | }
122 |
123 | #gamepadDisplayDiv{
124 | margin-top: 4px;
125 | }
126 |
127 | #gamepadSupportedDiv {
128 | font-size: 4em;
129 | color: white;
130 |
131 | }
132 |
133 | #buttonNeverPressedDiv {
134 | font-size: 3em;
135 | }
136 |
137 | #gamepadSupportedDiv .gpTable tr, .gpTableCell {
138 | background: gray;
139 | }
140 |
141 | td.gpTableCellUnConnected{
142 | display:none;
143 | }
144 |
145 | #gamepadStateTable{
146 | font-size: 0.75rem;
147 | }
148 |
149 | #gamepadDisplayDiv table #gp1Axis4{
150 | display:none;
151 | }
152 |
153 |
--------------------------------------------------------------------------------
/css/web-bluetooth.css:
--------------------------------------------------------------------------------
1 | body{
2 | font-family: 'Open Sans', sans-serif;
3 | }
4 |
5 | .intro{
6 | display: block;
7 | width: 90%;
8 | margin: 0 auto 1rem auto;
9 | }
10 |
11 | h1{
12 | font-weight: 400;
13 | }
14 |
15 | .intro a{
16 | margin-top: 1rem;
17 | display: block;
18 | }
19 |
20 | #connect{
21 | box-shadow: none;
22 | background: white;
23 | border: 1px solid black;
24 | cursor: pointer;
25 | }
26 |
27 | .main-container{
28 | position: relative;
29 | width: 90%;
30 | display: block;
31 | margin: 0 auto;
32 | padding-top: 2rem;
33 | }
34 |
35 | .container{
36 | width: 25%;
37 | min-height: 15rem;
38 | right: 0;
39 | display: inline-block;
40 | vertical-align: top;
41 | border: 1px solid grey;
42 | }
43 |
44 | .pose-image{
45 | display: block;
46 | margin: 0 auto;
47 | width: 60%;
48 | }
49 |
50 | canvas{
51 | width: 100% !important;
52 | height: 100% !important;
53 | }
54 |
55 | .myo-data{
56 | display: inline-block;
57 | width: 45%;
58 | border: 1px solid black;
59 | height: 60%;
60 | margin-right: 2rem;
61 | }
62 |
63 | .myo-data ul li{
64 | font-size: 14px;
65 | list-style: none;
66 | left: 0;
67 | margin-left: 0;
68 | margin-bottom: 0.5rem;
69 | }
70 |
71 | .myo-data ul{
72 | padding-left: 1rem;
73 | }
74 |
--------------------------------------------------------------------------------
/images/child-back-gray.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/curtpw/web-bluetooth-neural-network/5a3b68bc347a7c8d5505724e55afd6d50024edef/images/child-back-gray.png
--------------------------------------------------------------------------------
/images/child-face-gray.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/curtpw/web-bluetooth-neural-network/5a3b68bc347a7c8d5505724e55afd6d50024edef/images/child-face-gray.png
--------------------------------------------------------------------------------
/images/child-left-gray.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/curtpw/web-bluetooth-neural-network/5a3b68bc347a7c8d5505724e55afd6d50024edef/images/child-left-gray.png
--------------------------------------------------------------------------------
/images/child-profile-gray.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/curtpw/web-bluetooth-neural-network/5a3b68bc347a7c8d5505724e55afd6d50024edef/images/child-profile-gray.png
--------------------------------------------------------------------------------
/images/child-right-gray.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/curtpw/web-bluetooth-neural-network/5a3b68bc347a7c8d5505724e55afd6d50024edef/images/child-right-gray.png
--------------------------------------------------------------------------------
/images/clear.cache.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/curtpw/web-bluetooth-neural-network/5a3b68bc347a7c8d5505724e55afd6d50024edef/images/clear.cache.gif
--------------------------------------------------------------------------------
/images/corner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/curtpw/web-bluetooth-neural-network/5a3b68bc347a7c8d5505724e55afd6d50024edef/images/corner.png
--------------------------------------------------------------------------------
/images/crosshair_ball.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/curtpw/web-bluetooth-neural-network/5a3b68bc347a7c8d5505724e55afd6d50024edef/images/crosshair_ball.png
--------------------------------------------------------------------------------
/images/crosshair_ball2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/curtpw/web-bluetooth-neural-network/5a3b68bc347a7c8d5505724e55afd6d50024edef/images/crosshair_ball2.png
--------------------------------------------------------------------------------
/images/crosshair_ball3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/curtpw/web-bluetooth-neural-network/5a3b68bc347a7c8d5505724e55afd6d50024edef/images/crosshair_ball3.png
--------------------------------------------------------------------------------
/images/crosshair_mine.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/curtpw/web-bluetooth-neural-network/5a3b68bc347a7c8d5505724e55afd6d50024edef/images/crosshair_mine.png
--------------------------------------------------------------------------------
/images/crosshair_mine2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/curtpw/web-bluetooth-neural-network/5a3b68bc347a7c8d5505724e55afd6d50024edef/images/crosshair_mine2.png
--------------------------------------------------------------------------------
/images/crosshair_star.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/curtpw/web-bluetooth-neural-network/5a3b68bc347a7c8d5505724e55afd6d50024edef/images/crosshair_star.png
--------------------------------------------------------------------------------
/images/crosshair_thick.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/curtpw/web-bluetooth-neural-network/5a3b68bc347a7c8d5505724e55afd6d50024edef/images/crosshair_thick.png
--------------------------------------------------------------------------------
/images/crosshair_thin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/curtpw/web-bluetooth-neural-network/5a3b68bc347a7c8d5505724e55afd6d50024edef/images/crosshair_thin.png
--------------------------------------------------------------------------------
/images/dpad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/curtpw/web-bluetooth-neural-network/5a3b68bc347a7c8d5505724e55afd6d50024edef/images/dpad.png
--------------------------------------------------------------------------------
/images/green-circle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/curtpw/web-bluetooth-neural-network/5a3b68bc347a7c8d5505724e55afd6d50024edef/images/green-circle.png
--------------------------------------------------------------------------------
/images/grid.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/curtpw/web-bluetooth-neural-network/5a3b68bc347a7c8d5505724e55afd6d50024edef/images/grid.png
--------------------------------------------------------------------------------
/images/hand-gray-left.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/curtpw/web-bluetooth-neural-network/5a3b68bc347a7c8d5505724e55afd6d50024edef/images/hand-gray-left.png
--------------------------------------------------------------------------------
/images/hand-gray-right.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/curtpw/web-bluetooth-neural-network/5a3b68bc347a7c8d5505724e55afd6d50024edef/images/hand-gray-right.png
--------------------------------------------------------------------------------
/images/hand-green-left.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/curtpw/web-bluetooth-neural-network/5a3b68bc347a7c8d5505724e55afd6d50024edef/images/hand-green-left.png
--------------------------------------------------------------------------------
/images/hand-green-right.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/curtpw/web-bluetooth-neural-network/5a3b68bc347a7c8d5505724e55afd6d50024edef/images/hand-green-right.png
--------------------------------------------------------------------------------
/images/hand-left-button.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/curtpw/web-bluetooth-neural-network/5a3b68bc347a7c8d5505724e55afd6d50024edef/images/hand-left-button.png
--------------------------------------------------------------------------------
/images/hand-left-yellow-button.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/curtpw/web-bluetooth-neural-network/5a3b68bc347a7c8d5505724e55afd6d50024edef/images/hand-left-yellow-button.png
--------------------------------------------------------------------------------
/images/hand-right-button.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/curtpw/web-bluetooth-neural-network/5a3b68bc347a7c8d5505724e55afd6d50024edef/images/hand-right-button.png
--------------------------------------------------------------------------------
/images/hand-right-yellow-button.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/curtpw/web-bluetooth-neural-network/5a3b68bc347a7c8d5505724e55afd6d50024edef/images/hand-right-yellow-button.png
--------------------------------------------------------------------------------
/images/hand-rotate-button.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/curtpw/web-bluetooth-neural-network/5a3b68bc347a7c8d5505724e55afd6d50024edef/images/hand-rotate-button.png
--------------------------------------------------------------------------------
/images/hand-yellow-left.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/curtpw/web-bluetooth-neural-network/5a3b68bc347a7c8d5505724e55afd6d50024edef/images/hand-yellow-left.png
--------------------------------------------------------------------------------
/images/hand-yellow-right.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/curtpw/web-bluetooth-neural-network/5a3b68bc347a7c8d5505724e55afd6d50024edef/images/hand-yellow-right.png
--------------------------------------------------------------------------------
/images/hborder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/curtpw/web-bluetooth-neural-network/5a3b68bc347a7c8d5505724e55afd6d50024edef/images/hborder.png
--------------------------------------------------------------------------------
/images/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/curtpw/web-bluetooth-neural-network/5a3b68bc347a7c8d5505724e55afd6d50024edef/images/icon.png
--------------------------------------------------------------------------------
/images/left-arrow-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/curtpw/web-bluetooth-neural-network/5a3b68bc347a7c8d5505724e55afd6d50024edef/images/left-arrow-dark.png
--------------------------------------------------------------------------------
/images/left-arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/curtpw/web-bluetooth-neural-network/5a3b68bc347a7c8d5505724e55afd6d50024edef/images/left-arrow.png
--------------------------------------------------------------------------------
/images/pause_button.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/curtpw/web-bluetooth-neural-network/5a3b68bc347a7c8d5505724e55afd6d50024edef/images/pause_button.png
--------------------------------------------------------------------------------
/images/pause_button_gray.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/curtpw/web-bluetooth-neural-network/5a3b68bc347a7c8d5505724e55afd6d50024edef/images/pause_button_gray.png
--------------------------------------------------------------------------------
/images/record_button.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/curtpw/web-bluetooth-neural-network/5a3b68bc347a7c8d5505724e55afd6d50024edef/images/record_button.png
--------------------------------------------------------------------------------
/images/record_button_gray.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/curtpw/web-bluetooth-neural-network/5a3b68bc347a7c8d5505724e55afd6d50024edef/images/record_button_gray.png
--------------------------------------------------------------------------------
/images/right-arrow-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/curtpw/web-bluetooth-neural-network/5a3b68bc347a7c8d5505724e55afd6d50024edef/images/right-arrow-dark.png
--------------------------------------------------------------------------------
/images/right-arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/curtpw/web-bluetooth-neural-network/5a3b68bc347a7c8d5505724e55afd6d50024edef/images/right-arrow.png
--------------------------------------------------------------------------------
/images/trigger_meter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/curtpw/web-bluetooth-neural-network/5a3b68bc347a7c8d5505724e55afd6d50024edef/images/trigger_meter.png
--------------------------------------------------------------------------------
/images/trigger_meter_fill.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/curtpw/web-bluetooth-neural-network/5a3b68bc347a7c8d5505724e55afd6d50024edef/images/trigger_meter_fill.png
--------------------------------------------------------------------------------
/images/vborder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/curtpw/web-bluetooth-neural-network/5a3b68bc347a7c8d5505724e55afd6d50024edef/images/vborder.png
--------------------------------------------------------------------------------
/images/yellow-circle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/curtpw/web-bluetooth-neural-network/5a3b68bc347a7c8d5505724e55afd6d50024edef/images/yellow-circle.png
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | Activity Tracker Neural Network Gesture Recognition Tutorial
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
29 |
30 |
31 |
32 |
33 |
492 |
493 |
494 |
495 |
496 |
497 |
498 |
499 |
500 |
501 |
502 |
503 |
504 |
505 |
HR Photosensor:
506 |
Pitch:
507 |
Roll:
508 |
Accelerometer X:
509 |
Accelerometer Y:
510 |
Accelerometer Z:
511 |
512 |
513 |
514 |
515 |
516 |
517 |
518 |
519 |
520 |
521 |
522 |
NN1 TRUE: 0
523 |
NN1 FALSE: 0
524 |
NN2 TRUE: 0
525 |
NN2 FALSE: 0
526 |
Neural Network 1 SCORE: na
527 |
Neural Network 2 SCORE: na
528 |
529 |
530 |
531 |
532 |
535 |
536 |
537 |
538 |
539 |
# Samples
540 |
541 |
0
542 |
543 |
544 |
545 |
546 |
547 |
548 |
549 |
550 |
551 |
552 |
553 |
554 |
555 |
556 |
557 |
558 |
559 |
560 |
561 |
562 |
563 |
564 |
581 |
582 |
583 |
584 |
585 |
586 |
587 |
588 |
661 |
662 |
--------------------------------------------------------------------------------
/js/bootstrap.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap v3.2.0 (http://getbootstrap.com)
3 | * Copyright 2011-2014 Twitter, Inc.
4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
5 | */
6 | if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.2.0",d.prototype.close=function(b){function c(){f.detach().trigger("closed.bs.alert").remove()}var d=a(this),e=d.attr("data-target");e||(e=d.attr("href"),e=e&&e.replace(/.*(?=#[^\s]*$)/,""));var f=a(e);b&&b.preventDefault(),f.length||(f=d.hasClass("alert")?d:d.parent()),f.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(f.removeClass("in"),a.support.transition&&f.hasClass("fade")?f.one("bsTransitionEnd",c).emulateTransitionEnd(150):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.2.0",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),d[e](null==f[b]?this.options[b]:f[b]),setTimeout(a.proxy(function(){"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")&&(c.prop("checked")&&this.$element.hasClass("active")?a=!1:b.find(".active").removeClass("active")),a&&c.prop("checked",!this.$element.hasClass("active")).trigger("change")}a&&this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),c.preventDefault()})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b).on("keydown.bs.carousel",a.proxy(this.keydown,this)),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=this.sliding=this.interval=this.$active=this.$items=null,"hover"==this.options.pause&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.2.0",c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0},c.prototype.keydown=function(a){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.to=function(b){var c=this,d=this.getItemIndex(this.$active=this.$element.find(".item.active"));return b>this.$items.length-1||0>b?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){c.to(b)}):d==b?this.pause().cycle():this.slide(b>d?"next":"prev",a(this.$items[b]))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},c.prototype.slide=function(b,c){var d=this.$element.find(".item.active"),e=c||d[b](),f=this.interval,g="next"==b?"left":"right",h="next"==b?"first":"last",i=this;if(!e.length){if(!this.options.wrap)return;e=this.$element.find(".item")[h]()}if(e.hasClass("active"))return this.sliding=!1;var j=e[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:g});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,f&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(e)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:g});return a.support.transition&&this.$element.hasClass("slide")?(e.addClass(b),e[0].offsetWidth,d.addClass(g),e.addClass(g),d.one("bsTransitionEnd",function(){e.removeClass([b,g].join(" ")).addClass("active"),d.removeClass(["active",g].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(1e3*d.css("transition-duration").slice(0,-1))):(d.removeClass("active"),e.addClass("active"),this.sliding=!1,this.$element.trigger(m)),f&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this},a(document).on("click.bs.carousel.data-api","[data-slide], [data-slide-to]",function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}}),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.collapse"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b);!e&&f.toggle&&"show"==b&&(b=!b),e||d.data("bs.collapse",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.transitioning=null,this.options.parent&&(this.$parent=a(this.options.parent)),this.options.toggle&&this.toggle()};c.VERSION="3.2.0",c.DEFAULTS={toggle:!0},c.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},c.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var c=a.Event("show.bs.collapse");if(this.$element.trigger(c),!c.isDefaultPrevented()){var d=this.$parent&&this.$parent.find("> .panel > .in");if(d&&d.length){var e=d.data("bs.collapse");if(e&&e.transitioning)return;b.call(d,"hide"),e||d.data("bs.collapse",null)}var f=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[f](0),this.transitioning=1;var g=function(){this.$element.removeClass("collapsing").addClass("collapse in")[f](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return g.call(this);var h=a.camelCase(["scroll",f].join("-"));this.$element.one("bsTransitionEnd",a.proxy(g,this)).emulateTransitionEnd(350)[f](this.$element[0][h])}}},c.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse").removeClass("in"),this.transitioning=1;var d=function(){this.transitioning=0,this.$element.trigger("hidden.bs.collapse").removeClass("collapsing").addClass("collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(d,this)).emulateTransitionEnd(350):d.call(this)}}},c.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()};var d=a.fn.collapse;a.fn.collapse=b,a.fn.collapse.Constructor=c,a.fn.collapse.noConflict=function(){return a.fn.collapse=d,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(c){var d,e=a(this),f=e.attr("data-target")||c.preventDefault()||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""),g=a(f),h=g.data("bs.collapse"),i=h?"toggle":e.data(),j=e.attr("data-parent"),k=j&&a(j);h&&h.transitioning||(k&&k.find('[data-toggle="collapse"][data-parent="'+j+'"]').not(e).addClass("collapsed"),e[g.hasClass("in")?"addClass":"removeClass"]("collapsed")),b.call(g,i)})}(jQuery),+function(a){"use strict";function b(b){b&&3===b.which||(a(e).remove(),a(f).each(function(){var d=c(a(this)),e={relatedTarget:this};d.hasClass("open")&&(d.trigger(b=a.Event("hide.bs.dropdown",e)),b.isDefaultPrevented()||d.removeClass("open").trigger("hidden.bs.dropdown",e))}))}function c(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.2.0",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=c(e),g=f.hasClass("open");if(b(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a('').insertAfter(a(this)).on("click",b);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;e.trigger("focus"),f.toggleClass("open").trigger("shown.bs.dropdown",h)}return!1}},g.prototype.keydown=function(b){if(/(38|40|27)/.test(b.keyCode)){var d=a(this);if(b.preventDefault(),b.stopPropagation(),!d.is(".disabled, :disabled")){var e=c(d),g=e.hasClass("open");if(!g||g&&27==b.keyCode)return 27==b.which&&e.find(f).trigger("focus"),d.trigger("click");var h=" li:not(.divider):visible a",i=e.find('[role="menu"]'+h+', [role="listbox"]'+h);if(i.length){var j=i.index(i.filter(":focus"));38==b.keyCode&&j>0&&j--,40==b.keyCode&&j').appendTo(this.$body),this.$element.on("click.dismiss.bs.modal",a.proxy(function(a){a.target===a.currentTarget&&("static"==this.options.backdrop?this.$element[0].focus.call(this.$element[0]):this.hide.call(this))},this)),e&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),!b)return;e?this.$backdrop.one("bsTransitionEnd",b).emulateTransitionEnd(150):b()}else if(!this.isShown&&this.$backdrop){this.$backdrop.removeClass("in");var f=function(){c.removeBackdrop(),b&&b()};a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one("bsTransitionEnd",f).emulateTransitionEnd(150):f()}else b&&b()},c.prototype.checkScrollbar=function(){document.body.clientWidth>=window.innerWidth||(this.scrollbarWidth=this.scrollbarWidth||this.measureScrollbar())},c.prototype.setScrollbar=function(){var a=parseInt(this.$body.css("padding-right")||0,10);this.scrollbarWidth&&this.$body.css("padding-right",a+this.scrollbarWidth)},c.prototype.resetScrollbar=function(){this.$body.css("padding-right","")},c.prototype.measureScrollbar=function(){var a=document.createElement("div");a.className="modal-scrollbar-measure",this.$body.append(a);var b=a.offsetWidth-a.clientWidth;return this.$body[0].removeChild(a),b};var d=a.fn.modal;a.fn.modal=b,a.fn.modal.Constructor=c,a.fn.modal.noConflict=function(){return a.fn.modal=d,this},a(document).on("click.bs.modal.data-api",'[data-toggle="modal"]',function(c){var d=a(this),e=d.attr("href"),f=a(d.attr("data-target")||e&&e.replace(/.*(?=#[^\s]+$)/,"")),g=f.data("bs.modal")?"toggle":a.extend({remote:!/#/.test(e)&&e},f.data(),d.data());d.is("a")&&c.preventDefault(),f.one("show.bs.modal",function(a){a.isDefaultPrevented()||f.one("hidden.bs.modal",function(){d.is(":visible")&&d.trigger("focus")})}),b.call(f,g,this)})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tooltip"),f="object"==typeof b&&b;(e||"destroy"!=b)&&(e||d.data("bs.tooltip",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.type=this.options=this.enabled=this.timeout=this.hoverState=this.$element=null,this.init("tooltip",a,b)};c.VERSION="3.2.0",c.DEFAULTS={animation:!0,placement:"top",selector:!1,template:'',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(this.options.viewport.selector||this.options.viewport);for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show()},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide()},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var c=a.contains(document.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!c)return;var d=this,e=this.tip(),f=this.getUID(this.type);this.setContent(),e.attr("id",f),this.$element.attr("aria-describedby",f),this.options.animation&&e.addClass("fade");var g="function"==typeof this.options.placement?this.options.placement.call(this,e[0],this.$element[0]):this.options.placement,h=/\s?auto?\s?/i,i=h.test(g);i&&(g=g.replace(h,"")||"top"),e.detach().css({top:0,left:0,display:"block"}).addClass(g).data("bs."+this.type,this),this.options.container?e.appendTo(this.options.container):e.insertAfter(this.$element);var j=this.getPosition(),k=e[0].offsetWidth,l=e[0].offsetHeight;if(i){var m=g,n=this.$element.parent(),o=this.getPosition(n);g="bottom"==g&&j.top+j.height+l-o.scroll>o.height?"top":"top"==g&&j.top-o.scroll-l<0?"bottom":"right"==g&&j.right+k>o.width?"left":"left"==g&&j.left-kg.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;jg.width&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){return this.$tip=this.$tip||a(this.options.template)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.validate=function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){clearTimeout(this.timeout),this.hide().$element.off("."+this.type).removeData("bs."+this.type)};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;(e||"destroy"!=b)&&(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.2.0",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:''}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").empty()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")},c.prototype.tip=function(){return this.$tip||(this.$tip=a(this.options.template)),this.$tip};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){var e=a.proxy(this.process,this);this.$body=a("body"),this.$scrollElement=a(a(c).is("body")?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",e),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.2.0",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b="offset",c=0;a.isWindow(this.$scrollElement[0])||(b="position",c=this.$scrollElement.scrollTop()),this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight();var d=this;this.$body.find(this.selector).map(function(){var d=a(this),e=d.data("target")||d.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[b]().top+c,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){d.offsets.push(this[0]),d.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b<=e[0])return g!=(a=f[0])&&this.activate(a);for(a=e.length;a--;)g!=f[a]&&b>=e[a]&&(!e[a+1]||b<=e[a+1])&&this.activate(f[a])},b.prototype.activate=function(b){this.activeTarget=b,a(this.selector).parentsUntil(this.options.target,".active").removeClass("active");var c=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',d=a(c).parents("li").addClass("active");d.parent(".dropdown-menu").length&&(d=d.closest("li.dropdown").addClass("active")),d.trigger("activate.bs.scrollspy")};var d=a.fn.scrollspy;a.fn.scrollspy=c,a.fn.scrollspy.Constructor=b,a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=d,this},a(window).on("load.bs.scrollspy.data-api",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);c.call(b,b.data())})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tab");e||d.data("bs.tab",e=new c(this)),"string"==typeof b&&e[b]()})}var c=function(b){this.element=a(b)};c.VERSION="3.2.0",c.prototype.show=function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.data("target");if(d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),!b.parent("li").hasClass("active")){var e=c.find(".active:last a")[0],f=a.Event("show.bs.tab",{relatedTarget:e});if(b.trigger(f),!f.isDefaultPrevented()){var g=a(d);this.activate(b.closest("li"),c),this.activate(g,g.parent(),function(){b.trigger({type:"shown.bs.tab",relatedTarget:e})})}}},c.prototype.activate=function(b,c,d){function e(){f.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),b.addClass("active"),g?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu")&&b.closest("li.dropdown").addClass("active"),d&&d()}var f=c.find("> .active"),g=d&&a.support.transition&&f.hasClass("fade");g?f.one("bsTransitionEnd",e).emulateTransitionEnd(150):e(),f.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this},a(document).on("click.bs.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(c){c.preventDefault(),b.call(a(this),"show")})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=this.unpin=this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.2.0",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=a(document).height(),d=this.$target.scrollTop(),e=this.$element.offset(),f=this.options.offset,g=f.top,h=f.bottom;"object"!=typeof f&&(h=g=f),"function"==typeof g&&(g=f.top(this.$element)),"function"==typeof h&&(h=f.bottom(this.$element));var i=null!=this.unpin&&d+this.unpin<=e.top?!1:null!=h&&e.top+this.$element.height()>=b-h?"bottom":null!=g&&g>=d?"top":!1;if(this.affixed!==i){null!=this.unpin&&this.$element.css("top","");var j="affix"+(i?"-"+i:""),k=a.Event(j+".bs.affix");this.$element.trigger(k),k.isDefaultPrevented()||(this.affixed=i,this.unpin="bottom"==i?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(j).trigger(a.Event(j.replace("affix","affixed"))),"bottom"==i&&this.$element.offset({top:b-this.$element.height()-h}))}}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},d.offsetBottom&&(d.offset.bottom=d.offsetBottom),d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery);
--------------------------------------------------------------------------------
/js/main.js:
--------------------------------------------------------------------------------
1 | /*
2 | x=r sin(φ)cos(θ)
3 | y=r sin(φ)sin(θ)
4 | z=r cos(φ)
5 | */
6 | /* DATA SAMPLE TEMPLATE
7 | {
8 | Thermo1 Object Temp,
9 | Thermo2 Object Temp,
10 | Thermo3 Object Temp,
11 | Thermo4 Object Temp,
12 | Distance,
13 | Pitch,
14 | Roll,
15 | Acc X,
16 | Acc Y,
17 | Acc Z,
18 | Thermo Ave. Device Temp,
19 | Time Stamp,
20 | Hand,
21 | Target,
22 | on/off Target Observed
23 | }*/
24 |
25 |
26 | //sensor data object
27 | var state = {};
28 |
29 | // Web Bluetooth connection -->
30 |
31 | $( document ).ready(function() {
32 | button = document.getElementById("connect");
33 | message = document.getElementById("message");
34 | });
35 |
36 | //connection flag
37 | var bluetoothDataFlag = false;
38 |
39 | if ( 'bluetooth' in navigator === false ) {
40 | button.style.display = 'none';
41 | message.innerHTML = 'This browser doesn\'t support the Web Bluetooth API :(';
42 | }
43 |
44 | const services = {
45 | controlService: {
46 | name: 'control service',
47 | uuid: '0000a000-0000-1000-8000-00805f9b34fb'
48 | }
49 | }
50 |
51 | const characteristics = {
52 | commandReadCharacteristic: {
53 | name: 'command read characteristic',
54 | uuid: '0000a001-0000-1000-8000-00805f9b34fb'
55 | },
56 | commandWriteCharacteristic: {
57 | name: 'command write characteristic',
58 | uuid: '0000a002-0000-1000-8000-00805f9b34fb'
59 | },
60 | deviceDataCharacteristic: {
61 | name: 'imu data characteristic',
62 | uuid: '0000a003-0000-1000-8000-00805f9b34fb'
63 | }
64 | }
65 |
66 | var _this;
67 | var state = {};
68 | var previousPose;
69 |
70 | var sendCommandFlag = false; //global to keep track of when command is sent back to device
71 | //let commandValue = new Uint8Array([0x01,0x03,0x02,0x03,0x01]); //command to send back to device
72 | let commandValue = new Uint8Array([0x99]); //command to send back to device
73 |
74 | class ControllerWebBluetooth {
75 | constructor(name) {
76 | _this = this;
77 | this.name = name;
78 | this.services = services;
79 | this.characteristics = characteristics;
80 | this.standardServer;
81 | }
82 |
83 | connect() {
84 | return navigator.bluetooth.requestDevice({
85 | filters: [{
86 | name: this.name
87 | },
88 | {
89 | services: [services.controlService.uuid]
90 | }
91 | ]
92 | })
93 | .then(device => {
94 | console.log('Device discovered', device.name);
95 | return device.gatt.connect();
96 | })
97 | .then(server => {
98 | console.log('server device: ' + Object.keys(server.device));
99 |
100 | this.getServices([services.controlService, ], [characteristics.commandReadCharacteristic, characteristics.commandWriteCharacteristic, characteristics.deviceDataCharacteristic], server);
101 | })
102 | .catch(error => {
103 | console.log('error', error)
104 | })
105 | }
106 |
107 | getServices(requestedServices, requestedCharacteristics, server) {
108 | this.standardServer = server;
109 |
110 | requestedServices.filter((service) => {
111 | if (service.uuid == services.controlService.uuid) {
112 | _this.getControlService(requestedServices, requestedCharacteristics, this.standardServer);
113 | }
114 | })
115 | }
116 |
117 | getControlService(requestedServices, requestedCharacteristics, server) {
118 | let controlService = requestedServices.filter((service) => {
119 | return service.uuid == services.controlService.uuid
120 | });
121 | let commandReadChar = requestedCharacteristics.filter((char) => {
122 | return char.uuid == characteristics.commandReadCharacteristic.uuid
123 | });
124 | let commandWriteChar = requestedCharacteristics.filter((char) => {
125 | return char.uuid == characteristics.commandWriteCharacteristic.uuid
126 | });
127 |
128 | // Before having access to IMU, EMG and Pose data, we need to indicate to the Myo that we want to receive this data.
129 | return server.getPrimaryService(controlService[0].uuid)
130 | .then(service => {
131 | console.log('getting service: ', controlService[0].name);
132 | return service.getCharacteristic(commandWriteChar[0].uuid);
133 | })
134 | .then(characteristic => {
135 | console.log('getting characteristic: ', commandWriteChar[0].name);
136 | // return new Buffer([0x01,3,emg_mode,imu_mode,classifier_mode]);
137 | // The values passed in the buffer indicate that we want to receive all data without restriction;
138 | // let commandValue = new Uint8Array([0x01,0x03,0x02,0x03,0x01]);
139 | //this could be config info to be sent to the wearable device
140 | let commandValue = new Uint8Array([0x99]);
141 | // characteristic.writeValue(commandValue); //disable initial write to device
142 | })
143 | .then(_ => {
144 |
145 | let deviceDataChar = requestedCharacteristics.filter((char) => {
146 | return char.uuid == characteristics.deviceDataCharacteristic.uuid
147 | });
148 |
149 | console.log('getting service: ', controlService[0].name);
150 | _this.getdeviceData(controlService[0], deviceDataChar[0], server);
151 |
152 | })
153 | .catch(error => {
154 | console.log('error: ', error);
155 | })
156 | }
157 |
158 | sendControlService(requestedServices, requestedCharacteristics, server) {
159 | let controlService = requestedServices.filter((service) => {
160 | return service.uuid == services.controlService.uuid
161 | });
162 | let commandReadChar = requestedCharacteristics.filter((char) => {
163 | return char.uuid == characteristics.commandReadCharacteristic.uuid
164 | });
165 | let commandWriteChar = requestedCharacteristics.filter((char) => {
166 | return char.uuid == characteristics.commandWriteCharacteristic.uuid
167 | });
168 |
169 | return server.getPrimaryService(controlService[0].uuid)
170 | .then(service => {
171 | console.log('getting service: ', controlService[0].name);
172 | return service.getCharacteristic(commandWriteChar[0].uuid);
173 | })
174 | .then(characteristic => {
175 | console.log('getting write command to device characteristic: ', commandWriteChar[0].name);
176 | // return new Buffer([0x01,3,emg_mode,imu_mode,classifier_mode]);
177 | // The values passed in the buffer indicate that we want to receive all data without restriction;
178 | let commandValue = new Uint8Array([0x99]);
179 | getConfig();
180 | commandValue[0] = targetCommand;
181 |
182 | console.log("CONFIG target:" + activeTarget + " command:" + commandValue[0]);
183 | characteristic.writeValue(commandValue);
184 | })
185 | .then(_ => {
186 |
187 | // let deviceDataChar = requestedCharacteristics.filter((char) => {return char.uuid == characteristics.deviceDataCharacteristic.uuid});
188 | console.log("COMMAND SENT TO DEVICE");
189 | sendCommandFlag = false;
190 | // console.log('getting service: ', controlService[0].name);
191 | // _this.getdeviceData(controlService[0], deviceDataChar[0], server);
192 |
193 | })
194 | .catch(error => {
195 | sendCommandFlag = false;
196 | console.log("COMMAND SEND ERROR");
197 | console.log('error: ', error);
198 | })
199 | }
200 |
201 |
202 | handleDeviceDataChanged(event) {
203 | //byteLength of deviceData DataView object is 20.
204 | // deviceData return {{orientation: {w: *, x: *, y: *, z: *}, accelerometer: Array, gyroscope: Array}}
205 |
206 | let deviceData = event.target.value;
207 |
208 | //decompress the very crude compression on device side to fit values into BLE data packet
209 | let accelerometerX = (event.target.value.getUint8(0) / 100) - 1;
210 | let accelerometerY = (event.target.value.getUint8(1) / 100) - 1;
211 | let accelerometerZ = (event.target.value.getUint8(2) / 100) - 1;
212 | let accelerometerRoll = (event.target.value.getUint8(3) * 1.41);
213 | let accelerometerPitch = (event.target.value.getUint8(4) * 1.41);
214 | let devicePhotosensor = (event.target.value.getUint8(5) * 4);
215 | let deviceTouchsensor = (event.target.value.getUint8(6) * 4);
216 |
217 | console.log(accelerometerRoll + " " + accelerometerPitch);
218 |
219 |
220 | /* var data = {
221 | pitch: accelerometerPitch,
222 | roll: accelerometerRoll,
223 | x: accelerometerX,
224 | y: accelerometerY,
225 | z: accelerometerZ,
226 | photosensor: devicePhotosensor,
227 | touch: deviceTouchsensor
228 | } */
229 |
230 | state = {
231 | pitch: accelerometerPitch,
232 | roll: accelerometerRoll,
233 | x: accelerometerX,
234 | y: accelerometerY,
235 | z: accelerometerZ,
236 | photosensor: devicePhotosensor,
237 | touch: deviceTouchsensor
238 |
239 | }
240 |
241 | //move this out of state change
242 | if (sendCommandFlag) {
243 | //this.standardServer = server;
244 | for (var i = 0; i < 3; i++) {
245 | // sendControlService();
246 | _this.sendControlService([services.controlService, ], [characteristics.commandReadCharacteristic, characteristics.commandWriteCharacteristic, characteristics.deviceDataCharacteristic], _this.standardServer);
247 | }
248 | sendCommandFlag = false;
249 | }
250 |
251 | _this.onStateChangeCallback(state);
252 | }
253 |
254 | onStateChangeCallback() {}
255 |
256 | getdeviceData(service, characteristic, server) {
257 | return server.getPrimaryService(service.uuid)
258 | .then(newService => {
259 | console.log('getting characteristic: ', characteristic.name);
260 | return newService.getCharacteristic(characteristic.uuid)
261 | })
262 | .then(char => {
263 | char.startNotifications().then(res => {
264 | char.addEventListener('characteristicvaluechanged', _this.handleDeviceDataChanged);
265 | })
266 | })
267 | }
268 |
269 | onStateChange(callback) {
270 | _this.onStateChangeCallback = callback;
271 | }
272 | }
273 |
274 | /*******************************************************************************************************************
275 | *********************************************** INITIALIZE *********************************************************
276 | ********************************************************************************************************************/
277 |
278 | //sensor array sample data
279 | var sensorDataArray = new Array(12).fill(0);
280 |
281 | //sensor array sample data FOR CUSTOM TRAINING
282 | var NN1TrueDataArray = new Array;
283 | var NN1FalseDataArray = new Array;
284 | var NN2TrueDataArray = new Array;
285 | var NN2FalseDataArray = new Array;
286 |
287 | var NN1Architecture = 'none';
288 | var NN2Architecture = 'none';
289 |
290 | var NN1NumInputs = 3;
291 | var NN2NumInputs = 3;
292 |
293 | //master session data array of arrays
294 | var sensorDataSession = [];
295 |
296 | //which samples in the session data array are part of a particular sample set
297 | var sessionSampleSetIndex = [];
298 |
299 | var getSamplesFlag = 0;
300 | var getSamplesTypeFlag = 0; //0=none 1=NN1T 2=NN1F 3=NN2T 4=NN2F
301 |
302 | //do we have a trained NN to apply to live sensor data?
303 | var haveNNFlag1 = false;
304 | var trainNNFlag1 = false;
305 | var activeNNFlag1 = false;
306 |
307 | var haveNNFlag2 = false;
308 | var trainNNFlag2 = false;
309 | var activeNNFlag2 = false;
310 |
311 | var loadNNFlag = false;
312 |
313 | //NN scores
314 | var scoreArray = new Array(1).fill(0);
315 |
316 | var initialised = false;
317 | var timeout = null;
318 |
319 | $(document).ready(function() {
320 |
321 | /*******************************************************************************************************************
322 | *********************************************** WEB BLUETOOTH ******************************************************
323 | ********************************************************************************************************************/
324 |
325 | //Web Bluetooth connection button and ongoing device data update function
326 | button.onclick = function(e) {
327 | var sensorController = new ControllerWebBluetooth("Tingle");
328 | sensorController.connect();
329 |
330 | //ON SENSOR DATA UPDATE
331 | sensorController.onStateChange(function(state) {
332 | bluetoothDataFlag = true;
333 | });
334 |
335 | //check for new data every X milliseconds - this is to decouple execution from Web Bluetooth actions
336 | setInterval(function() {
337 | // bluetoothDataFlag = getBluetoothDataFlag();
338 |
339 | if (bluetoothDataFlag == true) {
340 |
341 | timeStamp = new Date().getTime();
342 |
343 | //load data into global array
344 | sensorDataArray = new Array(12).fill(0);
345 |
346 | sensorDataArray[0] = state.x.toFixed(2);
347 | sensorDataArray[1] = state.y.toFixed(2);
348 | sensorDataArray[2] = state.z.toFixed(2);
349 | sensorDataArray[3] = state.pitch.toFixed(1);
350 | sensorDataArray[4] = state.roll.toFixed(1);
351 |
352 | sensorDataArray[5] = state.photosensor.toFixed(1);
353 | sensorDataArray[6] = state.touch.toFixed(1);
354 | sensorDataArray[7] = 0;
355 | sensorDataArray[8] = 0;
356 | sensorDataArray[9] = 0;
357 | sensorDataArray[10] = 0;
358 | sensorDataArray[11] = timeStamp;
359 |
360 |
361 | //update time series chart with normalized values
362 | var rawAccXChart = ((sensorDataArray[0] + 2) / 4);
363 | var rawAccYChart = ((sensorDataArray[1] + 2) / 4);
364 | var rawAccZChart = ((sensorDataArray[2] + 2) / 4);
365 |
366 | var rawPitchChart = (sensorDataArray[3] / 361);
367 | var rawRollChart = (sensorDataArray[4] / 361);
368 |
369 | var rawPhotoChart = (sensorDataArray[5] / 1025); //TEMPORARY
370 |
371 |
372 | //sensor values in bottom 2/3 of chart , 1/10 height each
373 | rawAccXChart = (rawAccXChart / 6) + 7 * 0.1;
374 | rawAccYChart = (rawAccYChart / 6) + 6.5 * 0.1;
375 | rawAccZChart = (rawAccZChart / 6) + 6 * 0.1;
376 |
377 | rawPhotoChart = (rawPhotoChart / 10) + 5 * 0.1;
378 |
379 | rawPitchChart = (rawPitchChart / 3) + 3 * 0.1;
380 | rawRollChart = (rawRollChart / 3) + 2 * 0.1;
381 |
382 |
383 | lineAccX.append(timeStamp, rawAccXChart);
384 | lineAccY.append(timeStamp, rawAccYChart);
385 | lineAccZ.append(timeStamp, rawAccZChart);
386 | linePitch.append(timeStamp, rawPitchChart);
387 | lineRoll.append(timeStamp, rawRollChart);
388 | linePhoto.append(timeStamp, rawPhotoChart);
389 |
390 |
391 | //if data sample collection has been flagged
392 | // getSensorData();
393 | if (getSamplesFlag > 0) {
394 | collectData();
395 | } else if (trainNNFlag1 || trainNNFlag2) {
396 | //don't do anything
397 | } else {
398 | if (haveNNFlag1 && activeNNFlag1) { //we have a NN and we want to apply to current sensor data
399 | getNNScore(1);
400 | }
401 | if (haveNNFlag2 && activeNNFlag2) { //we have a NN and we want to apply to current sensor data
402 | getNNScore(2);
403 | }
404 | }
405 |
406 | displayData();
407 |
408 | bluetoothDataFlag = false;
409 | }
410 |
411 | }, 200); // throttle 100 = 10Hz limit
412 | }
413 |
414 |
415 | /*******************************************************************************************************************
416 | **************************************** STREAMING SENSOR DATA CHART ***********************************************
417 | *******************************************************************************************************************/
418 |
419 | //add smoothie.js time series streaming data chart
420 | var chartHeight = 350;
421 | var chartWidth = $(window).width();
422 |
423 | $("#streaming-data-chart").html('');
424 |
425 | var streamingChart = new SmoothieChart({/* grid: { strokeStyle:'rgb(125, 0, 0)', fillStyle:'rgb(60, 0, 0)', lineWidth: 1, millisPerLine: 250, verticalSections: 6, }, labels: { fillStyle:'rgb(60, 0, 0)' } */ });
426 |
427 | streamingChart.streamTo(document.getElementById("chart-canvas"), 350 /*delay*/ );
428 |
429 | var lineAccX = new TimeSeries();
430 | var lineAccY = new TimeSeries();
431 | var lineAccZ = new TimeSeries();
432 | var linePitch = new TimeSeries();
433 | var lineRoll = new TimeSeries();
434 | var linePhoto = new TimeSeries();
435 | var lineNN1 = new TimeSeries();
436 | var lineNN2 = new TimeSeries();
437 |
438 | streamingChart.addTimeSeries(lineAccX, {strokeStyle: 'rgb(185, 156, 107)', lineWidth: 3 });
439 | streamingChart.addTimeSeries(lineAccY, {strokeStyle: 'rgb(143, 59, 27)', lineWidth: 3 });
440 | streamingChart.addTimeSeries(lineAccZ, {strokeStyle: 'rgb(213, 117, 0)', lineWidth: 3 });
441 | streamingChart.addTimeSeries(linePitch, {strokeStyle: 'rgb(128, 128, 128)', lineWidth: 4 });
442 | streamingChart.addTimeSeries(linePhoto, {strokeStyle: 'rgb(206, 66, 244)', lineWidth: 3 });
443 | streamingChart.addTimeSeries(lineRoll, {strokeStyle: 'rgb(240, 240, 240)', lineWidth: 4 });
444 | streamingChart.addTimeSeries(lineNN1, {strokeStyle: 'rgb(72, 244, 68)', lineWidth: 4 });
445 | streamingChart.addTimeSeries(lineNN2, {strokeStyle: 'rgb(244, 66, 66)', lineWidth: 4 });
446 |
447 | //min/max streaming chart button
448 | $('#circleDrop').click(function() {
449 |
450 | $('.card-middle').slideToggle();
451 | $('.close').toggleClass('closeRotate');
452 |
453 | var chartHeight = $(window).height() / 1.2;
454 | var chartWidth = $(window).width();
455 |
456 | if ($("#chart-size-button").hasClass('closeRotate')) {
457 | $("#streaming-data-chart").html('');
458 | } else {
459 | $("#streaming-data-chart").html('');
460 | }
461 |
462 | //hide controls
463 | $("#basic-interface-container, #hand-head-ui-container, #nn-slide-controls, .console, #interface-controls, #dump-print, #record-controls").toggleClass("hide-for-chart");
464 | //redraw chart
465 | streamingChart.streamTo(document.getElementById("chart-canvas"), 350 /*delay*/ );
466 | });
467 |
468 | //numerical data display
469 | function displayData() {
470 | var accelerometerElement1 = document.getElementsByClassName('accelerometer-x-data')[0];
471 | var accelerometerElement2 = document.getElementsByClassName('accelerometer-y-data')[0];
472 | var accelerometerElement3 = document.getElementsByClassName('accelerometer-z-data')[0];
473 | var accelerometerPitchDiv = document.getElementsByClassName('accelerometer-pitch-data')[0];
474 | var accelerometerRollDiv = document.getElementsByClassName('accelerometer-roll-data')[0];
475 | var photosensorRollDiv = document.getElementsByClassName('photosensor-data')[0];
476 |
477 | accelerometerElement1.innerHTML = sensorDataArray[0];
478 | accelerometerElement2.innerHTML = sensorDataArray[1];
479 | accelerometerElement3.innerHTML = sensorDataArray[2];
480 | accelerometerPitchDiv.innerHTML = sensorDataArray[3];
481 | accelerometerRollDiv.innerHTML = sensorDataArray[4];
482 | photosensorRollDiv.innerHTML = sensorDataArray[5];
483 | }
484 |
485 | function getSensorData() {
486 | if (state.accelerometer) {
487 | sensorDataArray[0] = state.x.toFixed(2);
488 | sensorDataArray[1] = state.y.toFixed(2);
489 | sensorDataArray[2] = state.z.toFixed(2);
490 | sensorDataArray[3] = state.pitch.toFixed(2);
491 | sensorDataArray[4] = state.roll.toFixed(2);
492 | sensorDataArray[5] = state.photosensor.toFixed(2);
493 | }
494 | }
495 |
496 | function collectData() {
497 | var collectedDataArray = new Array(12).fill(0); //12 device
498 | collectedDataArray = sensorDataArray;
499 |
500 | console.log("web bluetooth sensor data:");
501 | console.dir(collectedDataArray);
502 |
503 | //add sample to set
504 | sensorDataSession.push(collectedDataArray);
505 |
506 | if (getSamplesTypeFlag == 1) {
507 | NN1TrueDataArray.push(collectedDataArray);
508 | $('.message-nn1-true').html(NN1TrueDataArray.length);
509 | } else if (getSamplesTypeFlag == 2) {
510 | NN1FalseDataArray.push(collectedDataArray);
511 | $('.message-nn1-false').html(NN1FalseDataArray.length);
512 | } else if (getSamplesTypeFlag == 3) {
513 | NN2TrueDataArray.push(collectedDataArray);
514 | $('.message-nn2-true').html(NN2TrueDataArray.length);
515 | } else if (getSamplesTypeFlag == 4) {
516 | NN2FalseDataArray.push(collectedDataArray);
517 | $('.message-nn2-false').html(NN2FalseDataArray.length);
518 | }
519 |
520 | console.log("Set Index: ");
521 | console.dir(sessionSampleSetIndex);
522 |
523 | //countdown for data collection
524 | getSamplesFlag = getSamplesFlag - 1;
525 | }
526 |
527 |
528 | /*******************************************************************************************************************
529 | *********************************************** NEURAL NETWORKS ****************************************************
530 | ********************************************************************************************************************/
531 | /**
532 | * Attach synaptic neural net components to app object
533 | */
534 | var nnRate = $("#rate-input").val();
535 | var nnIterations = $("#iterations-input").val();
536 | var nnError = $("#error-input").val();
537 |
538 | // ************** NEURAL NET #1
539 | var Neuron = synaptic.Neuron;
540 | var Layer = synaptic.Layer;
541 | var Network = synaptic.Network;
542 | var Trainer = synaptic.Trainer;
543 | var Architect = synaptic.Architect;
544 | var neuralNet = new Architect.LSTM(3, 3, 3, 1);
545 | var trainer = new Trainer(neuralNet);
546 | var trainingData;
547 |
548 | // ************* NEURAL NET #2
549 | var Neuron2 = synaptic.Neuron;
550 | var Layer2 = synaptic.Layer;
551 | var Network2 = synaptic.Network;
552 | var Trainer2 = synaptic.Trainer;
553 | var Architect2 = synaptic.Architect;
554 | var neuralNet2 = new Architect2.LSTM(3, 3, 3, 1);
555 | var trainer2 = new Trainer2(neuralNet2);
556 | var trainingData2;
557 |
558 |
559 | function getNNScore(selectNN) {
560 | var feedArray = new Array(1).fill(0);
561 | var scoreArray = new Array(1).fill(0);
562 | var timeStamp = new Date().getTime();
563 | var displayScore;
564 |
565 | if ((selectNN == 1 && NN1NumInputs == 2) || (selectNN == 2 && NN2NumInputs == 2)) {
566 | feedArray[0] = sensorDataArray[3] / 360;
567 | feedArray[1] = sensorDataArray[4] / 360;
568 | }
569 |
570 | if ((selectNN == 1 && NN1NumInputs == 3) || (selectNN == 2 && NN2NumInputs == 3)) {
571 | feedArray[0] = sensorDataArray[3] / 360;
572 | feedArray[1] = sensorDataArray[4] / 360;
573 | feedArray[2] = (sensorDataArray[5] + 2) / 4;
574 | }
575 |
576 | // use trained NN or loaded NN
577 | if (haveNNFlag1 && activeNNFlag1 && selectNN == 1) {
578 | scoreArray = neuralNet.activate(feedArray);
579 | } else if (loadNNFlag && selectNN == 1) {
580 | scoreArray = neuralNetwork1(feedArray);
581 | }
582 |
583 | if (haveNNFlag2 && activeNNFlag2 && selectNN == 2) {
584 | scoreArray = neuralNet2.activate(feedArray);
585 | } else if (loadNNFlag && selectNN == 2) {
586 | scoreArray = neuralNetwork2(feedArray);
587 | }
588 |
589 | displayScore = scoreArray[0].toFixed(4) * 100;
590 | displayScore = displayScore.toFixed(2);
591 |
592 | if (selectNN == 1) {
593 | console.log("NN1 FEED ARRAY: " + feedArray);
594 | console.log("NN1 SCORE ARRAY: " + scoreArray);
595 | $(".message-nn1-score").html(displayScore + '%');
596 | var rawLineNN1Chart = scoreArray[0].toFixed(4);
597 | rawLineNN1Chart = (rawLineNN1Chart / 3) + 0.8;
598 | lineNN1.append(timeStamp, rawLineNN1Chart);
599 |
600 | } else if (selectNN == 2) {
601 | console.log("NN2 FEED ARRAY: " + feedArray);
602 | console.log("NN2 SCORE ARRAY: " + scoreArray);
603 | $(".message-nn2-score").html(displayScore + '%');
604 | var rawLineNN2Chart = scoreArray[0].toFixed(4);
605 | rawLineNN2Chart = (rawLineNN2Chart / 3) + 0.8;
606 | lineNN2.append(timeStamp, rawLineNN2Chart);
607 | }
608 | }
609 |
610 |
611 |
612 | /**************************** TRAIN NN ******************************/
613 | function trainNN(selectNN) {
614 | //'2:1', '2:5:1', '2:5:5:1', '3:1', '3:5:1', '3:5:5:1', '5:5:1', '5:7:7:1'
615 | // var processedDataSession = sensorDataSession;
616 | var processedDataSession = new Array;
617 | var falseDataArray = new Array;
618 | var trueDataArray = new Array;
619 | var combinedTrueFalse = new Array(13).fill(0);
620 | trainingData = new Array;
621 |
622 | var rawNNArchitecture = $(".range-slider__value.nn-architecture").html();
623 | var numInputs = parseInt(rawNNArchitecture.charAt(0));
624 |
625 | nnRate = $("#rate-input").val();
626 | nnIterations = $("#iterations-input").val();
627 | nnError = $("#error-input").val();
628 |
629 | if (selectNN == 1) {
630 | trueDataArray = NN1TrueDataArray;
631 | falseDataArray = NN1FalseDataArray;
632 | } else if (selectNN == 2) {
633 | trueDataArray = NN2TrueDataArray;
634 | falseDataArray = NN2FalseDataArray;
635 | }
636 |
637 | //combine true and false data
638 | for (var j = 0; j < trueDataArray.length; j++) {
639 | combinedTrueFalse = trueDataArray[j];
640 | combinedTrueFalse[12] = 1; //true
641 | processedDataSession.push(combinedTrueFalse);
642 | }
643 | for (var k = 0; k < falseDataArray.length; k++) {
644 | combinedTrueFalse = falseDataArray[k];
645 | combinedTrueFalse[12] = 0; //false
646 | processedDataSession.push(combinedTrueFalse);
647 | }
648 |
649 |
650 |
651 | var getArchitect;
652 | if (rawNNArchitecture == '2:1') {
653 | getArchitect = new Architect.LSTM(2, 1);
654 | } else if (rawNNArchitecture == '2:5:5:1') {
655 | getArchitect = new Architect.LSTM(2, 5, 5, 1);
656 | } else if (rawNNArchitecture == '3:1') {
657 | getArchitect = new Architect.LSTM(3, 1);
658 | } else if (rawNNArchitecture == '3:3:1') {
659 | getArchitect = new Architect.LSTM(3, 3, 1);
660 | } else if (rawNNArchitecture == '3:3:3:1') {
661 | getArchitect = new Architect.LSTM(3, 3, 3, 1);
662 | } else if (rawNNArchitecture == '3:5:5:1') {
663 | getArchitect = new Architect.LSTM(3, 5, 5, 1);
664 | }
665 |
666 | if (selectNN == 1) {
667 | neuralNet = getArchitect;
668 | NN1Architecture = rawNNArchitecture;
669 | NN1NumInputs = numInputs;
670 | trainer = new Trainer(neuralNet);
671 | } else {
672 | neuralNet2 = getArchitect;
673 | NN2Architecture = rawNNArchitecture;
674 | NN2NumInputs = numInputs;
675 | trainer2 = new Trainer2(neuralNet2);
676 | }
677 |
678 | // console.log("raw NN architecture: " + rawNNArchitecture);
679 |
680 | // console.log("SIZE OF UNPROCESSED SESSION DATA: " + processedDataSession.length);
681 |
682 | for (var i = 0; i < processedDataSession.length; i++) {
683 |
684 | var currentSample = processedDataSession[i];
685 | var outputArray = new Array(1).fill(0);
686 | var inputArray = new Array(2).fill(0);
687 |
688 | outputArray[0] = currentSample[12]; //true or false
689 |
690 | if (numInputs == 3) {
691 | inputArray[0] = currentSample[3] / 360;
692 | inputArray[1] = currentSample[4] / 360;
693 | inputArray[2] = (currentSample[2] + 2) / 4;
694 |
695 | } else if (numInputs == 2) {
696 | inputArray[0] = currentSample[3] / 360;
697 | inputArray[1] = currentSample[4] / 360;
698 | }
699 |
700 | trainingData.push({
701 | input: inputArray,
702 | output: outputArray
703 | });
704 |
705 | console.log(currentSample + " TRAINING INPUT: " + inputArray + " --> NN# " + selectNN);
706 | console.log(currentSample + " TRAINING OUTPUT: " + outputArray + " --> NN# " + selectNN);
707 | }
708 |
709 |
710 | if (selectNN == 1) {
711 | console.log("TRAINING ON selectNN1 --> interations:" + nnIterations + " error:" + nnError + " rate:" + nnRate + " arch:" + rawNNArchitecture + " inputs:" + numInputs);
712 |
713 | trainer.train(trainingData, {
714 | rate: nnRate,
715 | // iterations: 15000,
716 | iterations: nnIterations,
717 | error: nnError,
718 | shuffle: true,
719 | // log: 1000,
720 | log: 5,
721 | cost: Trainer.cost.CROSS_ENTROPY
722 | });
723 |
724 | //we have a trained NN to use
725 | haveNNFlag1 = true;
726 | trainNNFlag1 = false;
727 | $('#activate-btn').addClass("haveNN");
728 | $('#export-btn').addClass("haveNN");
729 |
730 | } else if (selectNN == 2) {
731 | console.log("TRAINING ON selectNN2");
732 |
733 | trainer2.train(trainingData, {
734 | rate: nnRate,
735 | // iterations: 15000,
736 | iterations: nnIterations,
737 | error: nnError,
738 | shuffle: true,
739 | // log: 1000,
740 | log: 5,
741 | cost: Trainer2.cost.CROSS_ENTROPY
742 | });
743 |
744 | //we have a trained NN to use
745 | haveNNFlag2 = true;
746 | trainNNFlag2 = false;
747 | $('#activate2-btn').addClass("haveNN");
748 | $('#export2-btn').addClass("haveNN");
749 | }
750 | }
751 |
752 |
753 | /*******************************************************************************************************************
754 | *********************************************** SLIDER UI ******************************************************
755 | ********************************************************************************************************************/
756 | var rangeSlider = function(){
757 | var slider = $('.range-slider'),
758 | range = $('.range-slider__range'),
759 | value = $('.range-slider__value');
760 |
761 | slider.each(function(){
762 |
763 | value.each(function(){
764 | var value = $(this).prev().attr('value');
765 | $(this).html(value);
766 | });
767 |
768 | if( $(this).hasClass('nn-architecture') ){ $('.range-slider__value.nn-architecture').html('3:3:3:1'); }
769 |
770 | range.on('input', function(){
771 | var labels = ['2:1', '2:5:5:1', '3:1', '3:3:1', '3:3:3:1', '3:5:5:1'];
772 | $(this).next(value).html(this.value);
773 |
774 | if( $(this).hasClass('nn-architecture') ){ $(this).next(value).html( labels[this.value] ); }
775 |
776 | });
777 | });
778 | }
779 |
780 | rangeSlider();
781 |
782 | //RANGE SLIDER EVENT HANDLER
783 | $( ".range-slider" ).each(function() {
784 |
785 | if($(this).hasClass("nn-architecture")){
786 | // Add labels to slider whose values
787 | // are specified by min, max and whose
788 | // step is set to 1
789 |
790 | // Get the options for this slider
791 | //var opt = $(this).data().uiSlider.options;
792 | // Get the number of possible values
793 | var $input = $(this).find("input");
794 | var min = parseInt($input.attr("min"));
795 | var max = parseInt($input.attr("max"));
796 | var step = parseInt($input.attr("step"));
797 | var increment = parseInt($input.attr("increment"));
798 | var vals = max - min; //opt.max - opt.min;
799 | //if(min < 0){ vals = max + min; }
800 | var labels = ['2:1', '2:5:5:1', '3:1', '3:3:1', '3:3:3:1', '3:5:5:1'];
801 |
802 | // Space out values
803 | for (var i = 0; (i * increment) <= vals; i++) {
804 | var s = min + (i * increment);
805 | var el = $('').css('left',( 4 + Math.abs((s-min)/vals) *($input.width() -24)+'px'));
806 | // var el = $('').css('left',( 3 + ((s-min)/vals) *($input.width() -24)+'px'));
807 | if(s == 0){ el = $('').css('left',( 21 + Math.abs((s-min)/vals) *($input.width() -24)+'px')); }
808 | if(s == vals){ el = $('').css('left',( -20 + Math.abs((s-min)/vals) *($input.width() -24)+'px')); }
809 | $(this).append(el);
810 | }
811 | }
812 | });
813 |
814 |
815 | /*******************************************************************************************************************
816 | ******************************************* NEURAL NETWORK BUTTONS *************************************************
817 | ********************************************************************************************************************/
818 | $('#train-btn').click(function() {
819 | console.log("train button 1");
820 | trainNNFlag1 = true;
821 | trainNN(1);
822 | });
823 |
824 | $('#activate-btn').click(function() {
825 | console.log("activate button");
826 | activeNNFlag1 = true;
827 | $('#activate-btn').toggleClass("activatedNN");
828 |
829 | //if loaded NN, turn off
830 | if (loadNNFlag) {
831 | loadNNFlag = false;
832 | $('#load-nn-btn').toggleClass("activatedNN");
833 | }
834 | });
835 |
836 | $('#train2-btn').click(function() {
837 | console.log("train button 2");
838 | trainNNFlag2 = true;
839 | trainNN(2);
840 | });
841 |
842 | $('#activate2-btn').click(function() {
843 | console.log("activate button");
844 | activeNNFlag2 = true;
845 | $('#activate2-btn').toggleClass("activatedNN");
846 |
847 | //if leaded NN, turn off
848 | if (loadNNFlag) {
849 | loadNNFlag = false;
850 | $('#load-nn-btn').toggleClass("activatedNN");
851 | }
852 | });
853 |
854 |
855 | // ************* LOAD TWO EXPORTED NEURAL NET ACTIVATION FUNCTIONS AND WEIGHTS
856 | $('#load-nn-btn').click(function() {
857 | console.log("load exported NN button");
858 | loadNNFlag = true;
859 | $('#load-nn-btn').toggleClass("activatedNN");
860 | });
861 | /*******************************************************************************************************************
862 | ********************************** COLLECT, PRINT, LOAD BUTTON ACTIONS *********************************************
863 | ********************************************************************************************************************/
864 |
865 | /*************** COLLECT SAMPLE - SONSOR AND MODEL DATA - STORE IN GSHEET AND ADD TO NN TRAINING OBJECT *****************/
866 | $('#collect-true-1').click(function() {
867 | //how many samples for this set?
868 | getSamplesFlag = $('input.sample-size').val();
869 | getSamplesTypeFlag = 1;
870 | console.log("Collect btn NN1T #samples flag: " + getSamplesFlag);
871 | });
872 |
873 | $('#collect-false-1').click(function() {
874 | //how many samples for this set?
875 | //this flag is applied in the bluetooth data notification function
876 | getSamplesFlag = $('input.sample-size').val();
877 | getSamplesTypeFlag = 2;
878 | console.log("Collect btn NN1F #samples flag: " + getSamplesFlag);
879 | });
880 |
881 | $('#collect-true-2').click(function() {
882 | //how many samples for this set?
883 | getSamplesFlag = $('input.sample-size').val();
884 | //this flag is applied in the bluetooth data notification function
885 | getSamplesTypeFlag = 3;
886 | console.log("Collect btn NN2T #samples flag: " + getSamplesFlag);
887 | });
888 |
889 | $('#collect-false-2').click(function() {
890 | //how many samples for this set?
891 | getSamplesFlag = $('input.sample-size').val();
892 | //this flag is applied in the bluetooth data notification function
893 | getSamplesTypeFlag = 4;
894 | console.log("Collect btn NN2F #samples flag: " + getSamplesFlag);
895 | });
896 |
897 | $('#clear-1').click(function() {
898 | NN1TrueDataArray = new Array;
899 | NN1FalseDataArray = new Array;
900 | sensorDataArray = new Array(18).fill(0);
901 | sensorDataSession = new Array;
902 | $('.message-nn1-true').html('');
903 | $('.message-nn1-false').html('');
904 | $("#dump-print").html("");
905 | console.log("Clear NN1 Data");
906 | });
907 |
908 | $('#clear-2').click(function() {
909 | NN2TrueDataArray = new Array;
910 | NN2FalseDataArray = new Array;
911 | sensorDataArray = new Array(18).fill(0);
912 | sensorDataSession = new Array;
913 | $('.message-nn2-true').html('');
914 | $('.message-nn2-false').html('');
915 | $("#dump-print").html("");
916 | console.log("Clear NN2 Data");
917 | });
918 |
919 | $('#export-btn').click(function() {
920 | console.log("export1 NN button");
921 | //clear everything but key values from stored NN
922 | neuralNet.clear();
923 |
924 | //export optimized weights and activation function
925 | var standalone = neuralNet.standalone();
926 |
927 | //convert to string for parsing
928 | standalone = standalone.toString();
929 |
930 | console.log(standalone);
931 | $("#dump-print").html(standalone);
932 | $("#dump-print").addClass("active-print");
933 | });
934 |
935 | $('#export2-btn').click(function() {
936 | console.log("export2 NN button");
937 | //clear everything but key values from stored NN
938 | neuralNet2.clear();
939 |
940 | //export optimized weights and activation function
941 | var standalone = neuralNet2.standalone();
942 |
943 | //convert to string for parsing
944 | standalone = standalone.toString();
945 |
946 | console.log(standalone);
947 | $("#dump-print").html(standalone);
948 | $("#dump-print").addClass("active-print");
949 | });
950 |
951 | }); // end on document load
952 | //}
--------------------------------------------------------------------------------
/js/threejs/Detector.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author alteredq / http://alteredqualia.com/
3 | * @author mr.doob / http://mrdoob.com/
4 | */
5 |
6 | var Detector = {
7 |
8 | canvas: !! window.CanvasRenderingContext2D,
9 | webgl: ( function () {
10 |
11 | try {
12 |
13 | var canvas = document.createElement( 'canvas' ); return !! ( window.WebGLRenderingContext && ( canvas.getContext( 'webgl' ) || canvas.getContext( 'experimental-webgl' ) ) );
14 |
15 | } catch ( e ) {
16 |
17 | return false;
18 |
19 | }
20 |
21 | } )(),
22 | workers: !! window.Worker,
23 | fileapi: window.File && window.FileReader && window.FileList && window.Blob,
24 |
25 | getWebGLErrorMessage: function () {
26 |
27 | var element = document.createElement( 'div' );
28 | element.id = 'webgl-error-message';
29 | element.style.fontFamily = 'monospace';
30 | element.style.fontSize = '13px';
31 | element.style.fontWeight = 'normal';
32 | element.style.textAlign = 'center';
33 | element.style.background = '#fff';
34 | element.style.color = '#000';
35 | element.style.padding = '1.5em';
36 | element.style.width = '400px';
37 | element.style.margin = '5em auto 0';
38 |
39 | if ( ! this.webgl ) {
40 |
41 | element.innerHTML = window.WebGLRenderingContext ? [
42 | 'Your graphics card does not seem to support WebGL.
',
43 | 'Find out how to get it here.'
44 | ].join( '\n' ) : [
45 | 'Your browser does not seem to support WebGL.
',
46 | 'Find out how to get it here.'
47 | ].join( '\n' );
48 |
49 | }
50 |
51 | return element;
52 |
53 | },
54 |
55 | addGetWebGLMessage: function ( parameters ) {
56 |
57 | var parent, id, element;
58 |
59 | parameters = parameters || {};
60 |
61 | parent = parameters.parent !== undefined ? parameters.parent : document.body;
62 | id = parameters.id !== undefined ? parameters.id : 'oldie';
63 |
64 | element = Detector.getWebGLErrorMessage();
65 | element.id = id;
66 |
67 | parent.appendChild( element );
68 |
69 | }
70 |
71 | };
72 |
73 | // browserify support
74 | if ( typeof module === 'object' ) {
75 |
76 | module.exports = Detector;
77 |
78 | }
79 |
--------------------------------------------------------------------------------
/js/threejs/controls/OrbitControls.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author qiao / https://github.com/qiao
3 | * @author mrdoob / http://mrdoob.com
4 | * @author alteredq / http://alteredqualia.com/
5 | * @author WestLangley / http://github.com/WestLangley
6 | * @author erich666 / http://erichaines.com
7 | */
8 |
9 | // This set of controls performs orbiting, dollying (zooming), and panning.
10 | // Unlike TrackballControls, it maintains the "up" direction object.up (+Y by default).
11 | //
12 | // Orbit - left mouse / touch: one finger move
13 | // Zoom - middle mouse, or mousewheel / touch: two finger spread or squish
14 | // Pan - right mouse, or arrow keys / touch: three finter swipe
15 |
16 | THREE.OrbitControls = function ( object, domElement ) {
17 |
18 | this.object = object;
19 |
20 | this.domElement = ( domElement !== undefined ) ? domElement : document;
21 |
22 | // Set to false to disable this control
23 | this.enabled = true;
24 |
25 | // "target" sets the location of focus, where the object orbits around
26 | this.target = new THREE.Vector3();
27 |
28 | // How far you can dolly in and out ( PerspectiveCamera only )
29 | this.minDistance = 0;
30 | this.maxDistance = Infinity;
31 |
32 | // How far you can zoom in and out ( OrthographicCamera only )
33 | this.minZoom = 0;
34 | this.maxZoom = Infinity;
35 |
36 | // How far you can orbit vertically, upper and lower limits.
37 | // Range is 0 to Math.PI radians.
38 | this.minPolarAngle = 0; // radians
39 | this.maxPolarAngle = Math.PI; // radians
40 |
41 | // How far you can orbit horizontally, upper and lower limits.
42 | // If set, must be a sub-interval of the interval [ - Math.PI, Math.PI ].
43 | this.minAzimuthAngle = - Infinity; // radians
44 | this.maxAzimuthAngle = Infinity; // radians
45 |
46 | // Set to true to enable damping (inertia)
47 | // If damping is enabled, you must call controls.update() in your animation loop
48 | this.enableDamping = false;
49 | this.dampingFactor = 0.25;
50 |
51 | // This option actually enables dollying in and out; left as "zoom" for backwards compatibility.
52 | // Set to false to disable zooming
53 | this.enableZoom = true;
54 | this.zoomSpeed = 1.0;
55 |
56 | // Set to false to disable rotating
57 | this.enableRotate = true;
58 | this.rotateSpeed = 1.0;
59 |
60 | // Set to false to disable panning
61 | this.enablePan = true;
62 | this.keyPanSpeed = 7.0; // pixels moved per arrow key push
63 |
64 | // Set to true to automatically rotate around the target
65 | // If auto-rotate is enabled, you must call controls.update() in your animation loop
66 | this.autoRotate = false;
67 | this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60
68 |
69 | // Set to false to disable use of the keys
70 | this.enableKeys = true;
71 |
72 | // The four arrow keys
73 | this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 };
74 |
75 | // Mouse buttons
76 | this.mouseButtons = { ORBIT: THREE.MOUSE.LEFT, ZOOM: THREE.MOUSE.MIDDLE, PAN: THREE.MOUSE.RIGHT };
77 |
78 | // for reset
79 | this.target0 = this.target.clone();
80 | this.position0 = this.object.position.clone();
81 | this.zoom0 = this.object.zoom;
82 |
83 | //
84 | // public methods
85 | //
86 |
87 | this.getPolarAngle = function () {
88 |
89 | return phi;
90 |
91 | };
92 |
93 | this.getAzimuthalAngle = function () {
94 |
95 | return theta;
96 |
97 | };
98 |
99 | this.reset = function () {
100 |
101 | scope.target.copy( scope.target0 );
102 | scope.object.position.copy( scope.position0 );
103 | scope.object.zoom = scope.zoom0;
104 |
105 | scope.object.updateProjectionMatrix();
106 | scope.dispatchEvent( changeEvent );
107 |
108 | scope.update();
109 |
110 | state = STATE.NONE;
111 |
112 | };
113 |
114 | // this method is exposed, but perhaps it would be better if we can make it private...
115 | this.update = function() {
116 |
117 | var offset = new THREE.Vector3();
118 |
119 | // so camera.up is the orbit axis
120 | var quat = new THREE.Quaternion().setFromUnitVectors( object.up, new THREE.Vector3( 0, 1, 0 ) );
121 | var quatInverse = quat.clone().inverse();
122 |
123 | var lastPosition = new THREE.Vector3();
124 | var lastQuaternion = new THREE.Quaternion();
125 |
126 | return function () {
127 |
128 | var position = scope.object.position;
129 |
130 | offset.copy( position ).sub( scope.target );
131 |
132 | // rotate offset to "y-axis-is-up" space
133 | offset.applyQuaternion( quat );
134 |
135 | // angle from z-axis around y-axis
136 |
137 | theta = Math.atan2( offset.x, offset.z );
138 |
139 | // angle from y-axis
140 |
141 | phi = Math.atan2( Math.sqrt( offset.x * offset.x + offset.z * offset.z ), offset.y );
142 |
143 | if ( scope.autoRotate && state === STATE.NONE ) {
144 |
145 | rotateLeft( getAutoRotationAngle() );
146 |
147 | }
148 |
149 | theta += thetaDelta;
150 | phi += phiDelta;
151 |
152 | // restrict theta to be between desired limits
153 | theta = Math.max( scope.minAzimuthAngle, Math.min( scope.maxAzimuthAngle, theta ) );
154 |
155 | // restrict phi to be between desired limits
156 | phi = Math.max( scope.minPolarAngle, Math.min( scope.maxPolarAngle, phi ) );
157 |
158 | // restrict phi to be betwee EPS and PI-EPS
159 | phi = Math.max( EPS, Math.min( Math.PI - EPS, phi ) );
160 |
161 | var radius = offset.length() * scale;
162 |
163 | // restrict radius to be between desired limits
164 | radius = Math.max( scope.minDistance, Math.min( scope.maxDistance, radius ) );
165 |
166 | // move target to panned location
167 | scope.target.add( panOffset );
168 |
169 | offset.x = radius * Math.sin( phi ) * Math.sin( theta );
170 | offset.y = radius * Math.cos( phi );
171 | offset.z = radius * Math.sin( phi ) * Math.cos( theta );
172 |
173 | // rotate offset back to "camera-up-vector-is-up" space
174 | offset.applyQuaternion( quatInverse );
175 |
176 | position.copy( scope.target ).add( offset );
177 |
178 | scope.object.lookAt( scope.target );
179 |
180 | if ( scope.enableDamping === true ) {
181 |
182 | thetaDelta *= ( 1 - scope.dampingFactor );
183 | phiDelta *= ( 1 - scope.dampingFactor );
184 |
185 | } else {
186 |
187 | thetaDelta = 0;
188 | phiDelta = 0;
189 |
190 | }
191 |
192 | scale = 1;
193 | panOffset.set( 0, 0, 0 );
194 |
195 | // update condition is:
196 | // min(camera displacement, camera rotation in radians)^2 > EPS
197 | // using small-angle approximation cos(x/2) = 1 - x^2 / 8
198 |
199 | if ( zoomChanged ||
200 | lastPosition.distanceToSquared( scope.object.position ) > EPS ||
201 | 8 * ( 1 - lastQuaternion.dot( scope.object.quaternion ) ) > EPS ) {
202 |
203 | scope.dispatchEvent( changeEvent );
204 |
205 | lastPosition.copy( scope.object.position );
206 | lastQuaternion.copy( scope.object.quaternion );
207 | zoomChanged = false;
208 |
209 | return true;
210 |
211 | }
212 |
213 | return false;
214 |
215 | };
216 |
217 | }();
218 |
219 | this.dispose = function() {
220 |
221 | scope.domElement.removeEventListener( 'contextmenu', onContextMenu, false );
222 | scope.domElement.removeEventListener( 'mousedown', onMouseDown, false );
223 | scope.domElement.removeEventListener( 'mousewheel', onMouseWheel, false );
224 | scope.domElement.removeEventListener( 'MozMousePixelScroll', onMouseWheel, false ); // firefox
225 |
226 | scope.domElement.removeEventListener( 'touchstart', onTouchStart, false );
227 | scope.domElement.removeEventListener( 'touchend', onTouchEnd, false );
228 | scope.domElement.removeEventListener( 'touchmove', onTouchMove, false );
229 |
230 | document.removeEventListener( 'mousemove', onMouseMove, false );
231 | document.removeEventListener( 'mouseup', onMouseUp, false );
232 | document.removeEventListener( 'mouseout', onMouseUp, false );
233 |
234 | window.removeEventListener( 'keydown', onKeyDown, false );
235 |
236 | //scope.dispatchEvent( { type: 'dispose' } ); // should this be added here?
237 |
238 | };
239 |
240 | //
241 | // internals
242 | //
243 |
244 | var scope = this;
245 |
246 | var changeEvent = { type: 'change' };
247 | var startEvent = { type: 'start' };
248 | var endEvent = { type: 'end' };
249 |
250 | var STATE = { NONE : - 1, ROTATE : 0, DOLLY : 1, PAN : 2, TOUCH_ROTATE : 3, TOUCH_DOLLY : 4, TOUCH_PAN : 5 };
251 |
252 | var state = STATE.NONE;
253 |
254 | var EPS = 0.000001;
255 |
256 | // current position in spherical coordinates
257 | var theta;
258 | var phi;
259 |
260 | var phiDelta = 0;
261 | var thetaDelta = 0;
262 | var scale = 1;
263 | var panOffset = new THREE.Vector3();
264 | var zoomChanged = false;
265 |
266 | var rotateStart = new THREE.Vector2();
267 | var rotateEnd = new THREE.Vector2();
268 | var rotateDelta = new THREE.Vector2();
269 |
270 | var panStart = new THREE.Vector2();
271 | var panEnd = new THREE.Vector2();
272 | var panDelta = new THREE.Vector2();
273 |
274 | var dollyStart = new THREE.Vector2();
275 | var dollyEnd = new THREE.Vector2();
276 | var dollyDelta = new THREE.Vector2();
277 |
278 | function getAutoRotationAngle() {
279 |
280 | return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
281 |
282 | }
283 |
284 | function getZoomScale() {
285 |
286 | return Math.pow( 0.95, scope.zoomSpeed );
287 |
288 | }
289 |
290 | function rotateLeft( angle ) {
291 |
292 | thetaDelta -= angle;
293 |
294 | }
295 |
296 | function rotateUp( angle ) {
297 |
298 | phiDelta -= angle;
299 |
300 | }
301 |
302 | var panLeft = function() {
303 |
304 | var v = new THREE.Vector3();
305 |
306 | return function panLeft( distance, objectMatrix ) {
307 |
308 | var te = objectMatrix.elements;
309 |
310 | // get X column of objectMatrix
311 | v.set( te[ 0 ], te[ 1 ], te[ 2 ] );
312 |
313 | v.multiplyScalar( - distance );
314 |
315 | panOffset.add( v );
316 |
317 | };
318 |
319 | }();
320 |
321 | var panUp = function() {
322 |
323 | var v = new THREE.Vector3();
324 |
325 | return function panUp( distance, objectMatrix ) {
326 |
327 | var te = objectMatrix.elements;
328 |
329 | // get Y column of objectMatrix
330 | v.set( te[ 4 ], te[ 5 ], te[ 6 ] );
331 |
332 | v.multiplyScalar( distance );
333 |
334 | panOffset.add( v );
335 |
336 | };
337 |
338 | }();
339 |
340 | // deltaX and deltaY are in pixels; right and down are positive
341 | var pan = function() {
342 |
343 | var offset = new THREE.Vector3();
344 |
345 | return function( deltaX, deltaY ) {
346 |
347 | var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
348 |
349 | if ( scope.object instanceof THREE.PerspectiveCamera ) {
350 |
351 | // perspective
352 | var position = scope.object.position;
353 | offset.copy( position ).sub( scope.target );
354 | var targetDistance = offset.length();
355 |
356 | // half of the fov is center to top of screen
357 | targetDistance *= Math.tan( ( scope.object.fov / 2 ) * Math.PI / 180.0 );
358 |
359 | // we actually don't use screenWidth, since perspective camera is fixed to screen height
360 | panLeft( 2 * deltaX * targetDistance / element.clientHeight, scope.object.matrix );
361 | panUp( 2 * deltaY * targetDistance / element.clientHeight, scope.object.matrix );
362 |
363 | } else if ( scope.object instanceof THREE.OrthographicCamera ) {
364 |
365 | // orthographic
366 | panLeft( deltaX * ( scope.object.right - scope.object.left ) / element.clientWidth, scope.object.matrix );
367 | panUp( deltaY * ( scope.object.top - scope.object.bottom ) / element.clientHeight, scope.object.matrix );
368 |
369 | } else {
370 |
371 | // camera neither orthographic nor perspective
372 | console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' );
373 | scope.enablePan = false;
374 |
375 | }
376 |
377 | };
378 |
379 | }();
380 |
381 | function dollyIn( dollyScale ) {
382 |
383 | if ( scope.object instanceof THREE.PerspectiveCamera ) {
384 |
385 | scale /= dollyScale;
386 |
387 | } else if ( scope.object instanceof THREE.OrthographicCamera ) {
388 |
389 | scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom * dollyScale ) );
390 | scope.object.updateProjectionMatrix();
391 | zoomChanged = true;
392 |
393 | } else {
394 |
395 | console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' );
396 | scope.enableZoom = false;
397 |
398 | }
399 |
400 | }
401 |
402 | function dollyOut( dollyScale ) {
403 |
404 | if ( scope.object instanceof THREE.PerspectiveCamera ) {
405 |
406 | scale *= dollyScale;
407 |
408 | } else if ( scope.object instanceof THREE.OrthographicCamera ) {
409 |
410 | scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom / dollyScale ) );
411 | scope.object.updateProjectionMatrix();
412 | zoomChanged = true;
413 |
414 | } else {
415 |
416 | console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' );
417 | scope.enableZoom = false;
418 |
419 | }
420 |
421 | }
422 |
423 | //
424 | // event callbacks - update the object state
425 | //
426 |
427 | function handleMouseDownRotate( event ) {
428 |
429 | //console.log( 'handleMouseDownRotate' );
430 |
431 | rotateStart.set( event.clientX, event.clientY );
432 |
433 | }
434 |
435 | function handleMouseDownDolly( event ) {
436 |
437 | //console.log( 'handleMouseDownDolly' );
438 |
439 | dollyStart.set( event.clientX, event.clientY );
440 |
441 | }
442 |
443 | function handleMouseDownPan( event ) {
444 |
445 | //console.log( 'handleMouseDownPan' );
446 |
447 | panStart.set( event.clientX, event.clientY );
448 |
449 | }
450 |
451 | function handleMouseMoveRotate( event ) {
452 |
453 | //console.log( 'handleMouseMoveRotate' );
454 |
455 | rotateEnd.set( event.clientX, event.clientY );
456 | rotateDelta.subVectors( rotateEnd, rotateStart );
457 |
458 | var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
459 |
460 | // rotating across whole screen goes 360 degrees around
461 | rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed );
462 |
463 | // rotating up and down along whole screen attempts to go 360, but limited to 180
464 | rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed );
465 |
466 | rotateStart.copy( rotateEnd );
467 |
468 | scope.update();
469 |
470 | }
471 |
472 | function handleMouseMoveDolly( event ) {
473 |
474 | //console.log( 'handleMouseMoveDolly' );
475 |
476 | dollyEnd.set( event.clientX, event.clientY );
477 |
478 | dollyDelta.subVectors( dollyEnd, dollyStart );
479 |
480 | if ( dollyDelta.y > 0 ) {
481 |
482 | dollyIn( getZoomScale() );
483 |
484 | } else if ( dollyDelta.y < 0 ) {
485 |
486 | dollyOut( getZoomScale() );
487 |
488 | }
489 |
490 | dollyStart.copy( dollyEnd );
491 |
492 | scope.update();
493 |
494 | }
495 |
496 | function handleMouseMovePan( event ) {
497 |
498 | //console.log( 'handleMouseMovePan' );
499 |
500 | panEnd.set( event.clientX, event.clientY );
501 |
502 | panDelta.subVectors( panEnd, panStart );
503 |
504 | pan( panDelta.x, panDelta.y );
505 |
506 | panStart.copy( panEnd );
507 |
508 | scope.update();
509 |
510 | }
511 |
512 | function handleMouseUp( event ) {
513 |
514 | //console.log( 'handleMouseUp' );
515 |
516 | }
517 |
518 | function handleMouseWheel( event ) {
519 |
520 | //console.log( 'handleMouseWheel' );
521 |
522 | var delta = 0;
523 |
524 | if ( event.wheelDelta !== undefined ) {
525 |
526 | // WebKit / Opera / Explorer 9
527 |
528 | delta = event.wheelDelta;
529 |
530 | } else if ( event.detail !== undefined ) {
531 |
532 | // Firefox
533 |
534 | delta = - event.detail;
535 |
536 | }
537 |
538 | if ( delta > 0 ) {
539 |
540 | dollyOut( getZoomScale() );
541 |
542 | } else if ( delta < 0 ) {
543 |
544 | dollyIn( getZoomScale() );
545 |
546 | }
547 |
548 | scope.update();
549 |
550 | }
551 |
552 | function handleKeyDown( event ) {
553 |
554 | //console.log( 'handleKeyDown' );
555 |
556 | switch ( event.keyCode ) {
557 |
558 | case scope.keys.UP:
559 | pan( 0, scope.keyPanSpeed );
560 | scope.update();
561 | break;
562 |
563 | case scope.keys.BOTTOM:
564 | pan( 0, - scope.keyPanSpeed );
565 | scope.update();
566 | break;
567 |
568 | case scope.keys.LEFT:
569 | pan( scope.keyPanSpeed, 0 );
570 | scope.update();
571 | break;
572 |
573 | case scope.keys.RIGHT:
574 | pan( - scope.keyPanSpeed, 0 );
575 | scope.update();
576 | break;
577 |
578 | }
579 |
580 | }
581 |
582 | function handleTouchStartRotate( event ) {
583 |
584 | //console.log( 'handleTouchStartRotate' );
585 |
586 | rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
587 |
588 | }
589 |
590 | function handleTouchStartDolly( event ) {
591 |
592 | //console.log( 'handleTouchStartDolly' );
593 |
594 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
595 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
596 |
597 | var distance = Math.sqrt( dx * dx + dy * dy );
598 |
599 | dollyStart.set( 0, distance );
600 |
601 | }
602 |
603 | function handleTouchStartPan( event ) {
604 |
605 | //console.log( 'handleTouchStartPan' );
606 |
607 | panStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
608 |
609 | }
610 |
611 | function handleTouchMoveRotate( event ) {
612 |
613 | //console.log( 'handleTouchMoveRotate' );
614 |
615 | rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
616 | rotateDelta.subVectors( rotateEnd, rotateStart );
617 |
618 | var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
619 |
620 | // rotating across whole screen goes 360 degrees around
621 | rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed );
622 |
623 | // rotating up and down along whole screen attempts to go 360, but limited to 180
624 | rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed );
625 |
626 | rotateStart.copy( rotateEnd );
627 |
628 | scope.update();
629 |
630 | }
631 |
632 | function handleTouchMoveDolly( event ) {
633 |
634 | //console.log( 'handleTouchMoveDolly' );
635 |
636 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
637 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
638 |
639 | var distance = Math.sqrt( dx * dx + dy * dy );
640 |
641 | dollyEnd.set( 0, distance );
642 |
643 | dollyDelta.subVectors( dollyEnd, dollyStart );
644 |
645 | if ( dollyDelta.y > 0 ) {
646 |
647 | dollyOut( getZoomScale() );
648 |
649 | } else if ( dollyDelta.y < 0 ) {
650 |
651 | dollyIn( getZoomScale() );
652 |
653 | }
654 |
655 | dollyStart.copy( dollyEnd );
656 |
657 | scope.update();
658 |
659 | }
660 |
661 | function handleTouchMovePan( event ) {
662 |
663 | //console.log( 'handleTouchMovePan' );
664 |
665 | panEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
666 |
667 | panDelta.subVectors( panEnd, panStart );
668 |
669 | pan( panDelta.x, panDelta.y );
670 |
671 | panStart.copy( panEnd );
672 |
673 | scope.update();
674 |
675 | }
676 |
677 | function handleTouchEnd( event ) {
678 |
679 | //console.log( 'handleTouchEnd' );
680 |
681 | }
682 |
683 | //
684 | // event handlers - FSM: listen for events and reset state
685 | //
686 |
687 | function onMouseDown( event ) {
688 |
689 | if ( scope.enabled === false ) return;
690 |
691 | event.preventDefault();
692 |
693 | if ( event.button === scope.mouseButtons.ORBIT ) {
694 |
695 | if ( scope.enableRotate === false ) return;
696 |
697 | handleMouseDownRotate( event );
698 |
699 | state = STATE.ROTATE;
700 |
701 | } else if ( event.button === scope.mouseButtons.ZOOM ) {
702 |
703 | if ( scope.enableZoom === false ) return;
704 |
705 | handleMouseDownDolly( event );
706 |
707 | state = STATE.DOLLY;
708 |
709 | } else if ( event.button === scope.mouseButtons.PAN ) {
710 |
711 | if ( scope.enablePan === false ) return;
712 |
713 | handleMouseDownPan( event );
714 |
715 | state = STATE.PAN;
716 |
717 | }
718 |
719 | if ( state !== STATE.NONE ) {
720 |
721 | document.addEventListener( 'mousemove', onMouseMove, false );
722 | document.addEventListener( 'mouseup', onMouseUp, false );
723 | document.addEventListener( 'mouseout', onMouseUp, false );
724 |
725 | scope.dispatchEvent( startEvent );
726 |
727 | }
728 |
729 | }
730 |
731 | function onMouseMove( event ) {
732 |
733 | if ( scope.enabled === false ) return;
734 |
735 | event.preventDefault();
736 |
737 | if ( state === STATE.ROTATE ) {
738 |
739 | if ( scope.enableRotate === false ) return;
740 |
741 | handleMouseMoveRotate( event );
742 |
743 | } else if ( state === STATE.DOLLY ) {
744 |
745 | if ( scope.enableZoom === false ) return;
746 |
747 | handleMouseMoveDolly( event );
748 |
749 | } else if ( state === STATE.PAN ) {
750 |
751 | if ( scope.enablePan === false ) return;
752 |
753 | handleMouseMovePan( event );
754 |
755 | }
756 |
757 | }
758 |
759 | function onMouseUp( event ) {
760 |
761 | if ( scope.enabled === false ) return;
762 |
763 | handleMouseUp( event );
764 |
765 | document.removeEventListener( 'mousemove', onMouseMove, false );
766 | document.removeEventListener( 'mouseup', onMouseUp, false );
767 | document.removeEventListener( 'mouseout', onMouseUp, false );
768 |
769 | scope.dispatchEvent( endEvent );
770 |
771 | state = STATE.NONE;
772 |
773 | }
774 |
775 | function onMouseWheel( event ) {
776 |
777 | if ( scope.enabled === false || scope.enableZoom === false || state !== STATE.NONE ) return;
778 |
779 | event.preventDefault();
780 | event.stopPropagation();
781 |
782 | handleMouseWheel( event );
783 |
784 | scope.dispatchEvent( startEvent ); // not sure why these are here...
785 | scope.dispatchEvent( endEvent );
786 |
787 | }
788 |
789 | function onKeyDown( event ) {
790 |
791 | if ( scope.enabled === false || scope.enableKeys === false || scope.enablePan === false ) return;
792 |
793 | handleKeyDown( event );
794 |
795 | }
796 |
797 | function onTouchStart( event ) {
798 |
799 | if ( scope.enabled === false ) return;
800 |
801 | switch ( event.touches.length ) {
802 |
803 | case 1: // one-fingered touch: rotate
804 |
805 | if ( scope.enableRotate === false ) return;
806 |
807 | handleTouchStartRotate( event );
808 |
809 | state = STATE.TOUCH_ROTATE;
810 |
811 | break;
812 |
813 | case 2: // two-fingered touch: dolly
814 |
815 | if ( scope.enableZoom === false ) return;
816 |
817 | handleTouchStartDolly( event );
818 |
819 | state = STATE.TOUCH_DOLLY;
820 |
821 | break;
822 |
823 | case 3: // three-fingered touch: pan
824 |
825 | if ( scope.enablePan === false ) return;
826 |
827 | handleTouchStartPan( event );
828 |
829 | state = STATE.TOUCH_PAN;
830 |
831 | break;
832 |
833 | default:
834 |
835 | state = STATE.NONE;
836 |
837 | }
838 |
839 | if ( state !== STATE.NONE ) {
840 |
841 | scope.dispatchEvent( startEvent );
842 |
843 | }
844 |
845 | }
846 |
847 | function onTouchMove( event ) {
848 |
849 | if ( scope.enabled === false ) return;
850 |
851 | event.preventDefault();
852 | event.stopPropagation();
853 |
854 | switch ( event.touches.length ) {
855 |
856 | case 1: // one-fingered touch: rotate
857 |
858 | if ( scope.enableRotate === false ) return;
859 | if ( state !== STATE.TOUCH_ROTATE ) return; // is this needed?...
860 |
861 | handleTouchMoveRotate( event );
862 |
863 | break;
864 |
865 | case 2: // two-fingered touch: dolly
866 |
867 | if ( scope.enableZoom === false ) return;
868 | if ( state !== STATE.TOUCH_DOLLY ) return; // is this needed?...
869 |
870 | handleTouchMoveDolly( event );
871 |
872 | break;
873 |
874 | case 3: // three-fingered touch: pan
875 |
876 | if ( scope.enablePan === false ) return;
877 | if ( state !== STATE.TOUCH_PAN ) return; // is this needed?...
878 |
879 | handleTouchMovePan( event );
880 |
881 | break;
882 |
883 | default:
884 |
885 | state = STATE.NONE;
886 |
887 | }
888 |
889 | }
890 |
891 | function onTouchEnd( event ) {
892 |
893 | if ( scope.enabled === false ) return;
894 |
895 | handleTouchEnd( event );
896 |
897 | scope.dispatchEvent( endEvent );
898 |
899 | state = STATE.NONE;
900 |
901 | }
902 |
903 | function onContextMenu( event ) {
904 |
905 | event.preventDefault();
906 |
907 | }
908 |
909 | //
910 |
911 | scope.domElement.addEventListener( 'contextmenu', onContextMenu, false );
912 |
913 | scope.domElement.addEventListener( 'mousedown', onMouseDown, false );
914 | scope.domElement.addEventListener( 'mousewheel', onMouseWheel, false );
915 | scope.domElement.addEventListener( 'MozMousePixelScroll', onMouseWheel, false ); // firefox
916 |
917 | scope.domElement.addEventListener( 'touchstart', onTouchStart, false );
918 | scope.domElement.addEventListener( 'touchend', onTouchEnd, false );
919 | scope.domElement.addEventListener( 'touchmove', onTouchMove, false );
920 |
921 | window.addEventListener( 'keydown', onKeyDown, false );
922 |
923 | // force an update at start
924 |
925 | this.update();
926 |
927 | };
928 |
929 | THREE.OrbitControls.prototype = Object.create( THREE.EventDispatcher.prototype );
930 | THREE.OrbitControls.prototype.constructor = THREE.OrbitControls;
931 |
932 | Object.defineProperties( THREE.OrbitControls.prototype, {
933 |
934 | center: {
935 |
936 | get: function () {
937 |
938 | console.warn( 'THREE.OrbitControls: .center has been renamed to .target' );
939 | return this.target;
940 |
941 | }
942 |
943 | },
944 |
945 | // backward compatibility
946 |
947 | noZoom: {
948 |
949 | get: function () {
950 |
951 | console.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' );
952 | return ! this.enableZoom;
953 |
954 | },
955 |
956 | set: function ( value ) {
957 |
958 | console.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' );
959 | this.enableZoom = ! value;
960 |
961 | }
962 |
963 | },
964 |
965 | noRotate: {
966 |
967 | get: function () {
968 |
969 | console.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' );
970 | return ! this.enableRotate;
971 |
972 | },
973 |
974 | set: function ( value ) {
975 |
976 | console.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' );
977 | this.enableRotate = ! value;
978 |
979 | }
980 |
981 | },
982 |
983 | noPan: {
984 |
985 | get: function () {
986 |
987 | console.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' );
988 | return ! this.enablePan;
989 |
990 | },
991 |
992 | set: function ( value ) {
993 |
994 | console.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' );
995 | this.enablePan = ! value;
996 |
997 | }
998 |
999 | },
1000 |
1001 | noKeys: {
1002 |
1003 | get: function () {
1004 |
1005 | console.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' );
1006 | return ! this.enableKeys;
1007 |
1008 | },
1009 |
1010 | set: function ( value ) {
1011 |
1012 | console.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' );
1013 | this.enableKeys = ! value;
1014 |
1015 | }
1016 |
1017 | },
1018 |
1019 | staticMoving : {
1020 |
1021 | get: function () {
1022 |
1023 | console.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' );
1024 | return ! this.constraint.enableDamping;
1025 |
1026 | },
1027 |
1028 | set: function ( value ) {
1029 |
1030 | console.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' );
1031 | this.constraint.enableDamping = ! value;
1032 |
1033 | }
1034 |
1035 | },
1036 |
1037 | dynamicDampingFactor : {
1038 |
1039 | get: function () {
1040 |
1041 | console.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' );
1042 | return this.constraint.dampingFactor;
1043 |
1044 | },
1045 |
1046 | set: function ( value ) {
1047 |
1048 | console.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' );
1049 | this.constraint.dampingFactor = value;
1050 |
1051 | }
1052 |
1053 | }
1054 |
1055 | } );
1056 |
--------------------------------------------------------------------------------
/js/threejs/libs/stats.min.js:
--------------------------------------------------------------------------------
1 | // stats.js - http://github.com/mrdoob/stats.js
2 | var Stats=function(){function f(a,e,b){a=document.createElement(a);a.id=e;a.style.cssText=b;return a}function l(a,e,b){var c=f("div",a,"padding:0 0 3px 3px;text-align:left;background:"+b),d=f("div",a+"Text","font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px;color:"+e);d.innerHTML=a.toUpperCase();c.appendChild(d);a=f("div",a+"Graph","width:74px;height:30px;background:"+e);c.appendChild(a);for(e=0;74>e;e++)a.appendChild(f("span","","width:1px;height:30px;float:left;opacity:0.9;background:"+
3 | b));return c}function m(a){for(var b=c.children,d=0;dr+1E3&&(d=Math.round(1E3*
5 | t/(a-r)),u=Math.min(u,d),v=Math.max(v,d),A.textContent=d+" FPS ("+u+"-"+v+")",p(B,d/100),r=a,t=0,void 0!==h)){var b=performance.memory.usedJSHeapSize,c=performance.memory.jsHeapSizeLimit;h=Math.round(9.54E-7*b);y=Math.min(y,h);z=Math.max(z,h);E.textContent=h+" MB ("+y+"-"+z+")";p(F,b/c)}return a},update:function(){k=this.end()}}};"object"===typeof module&&(module.exports=Stats);
6 |
--------------------------------------------------------------------------------
/js/threejs/loaders/OBJLoader.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author mrdoob / http://mrdoob.com/
3 | */
4 |
5 | THREE.OBJLoader = function ( manager ) {
6 |
7 | this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
8 |
9 | this.materials = null;
10 |
11 | };
12 |
13 | THREE.OBJLoader.prototype = {
14 |
15 | constructor: THREE.OBJLoader,
16 |
17 | load: function ( url, onLoad, onProgress, onError ) {
18 |
19 | var scope = this;
20 |
21 | var loader = new THREE.XHRLoader( scope.manager );
22 | loader.setPath( this.path );
23 | loader.load( url, function ( text ) {
24 |
25 | onLoad( scope.parse( text ) );
26 |
27 | }, onProgress, onError );
28 |
29 | },
30 |
31 | setPath: function ( value ) {
32 |
33 | this.path = value;
34 |
35 | },
36 |
37 | setMaterials: function ( materials ) {
38 |
39 | this.materials = materials;
40 |
41 | },
42 |
43 | parse: function ( text ) {
44 |
45 | console.time( 'OBJLoader' );
46 |
47 | var objects = [];
48 | var object;
49 | var foundObjects = false;
50 | var vertices = [];
51 | var normals = [];
52 | var uvs = [];
53 |
54 | function addObject(name) {
55 |
56 | var geometry = {
57 | vertices: [],
58 | normals: [],
59 | uvs: []
60 | };
61 |
62 | var material = {
63 | name: '',
64 | smooth: true
65 | };
66 |
67 | object = {
68 | name: name,
69 | geometry: geometry,
70 | material: material
71 | };
72 |
73 | objects.push( object );
74 |
75 | }
76 |
77 | function parseVertexIndex( value ) {
78 |
79 | var index = parseInt( value );
80 |
81 | return ( index >= 0 ? index - 1 : index + vertices.length / 3 ) * 3;
82 |
83 | }
84 |
85 | function parseNormalIndex( value ) {
86 |
87 | var index = parseInt( value );
88 |
89 | return ( index >= 0 ? index - 1 : index + normals.length / 3 ) * 3;
90 |
91 | }
92 |
93 | function parseUVIndex( value ) {
94 |
95 | var index = parseInt( value );
96 |
97 | return ( index >= 0 ? index - 1 : index + uvs.length / 2 ) * 2;
98 |
99 | }
100 |
101 | function addVertex( a, b, c ) {
102 |
103 | object.geometry.vertices.push(
104 | vertices[ a ], vertices[ a + 1 ], vertices[ a + 2 ],
105 | vertices[ b ], vertices[ b + 1 ], vertices[ b + 2 ],
106 | vertices[ c ], vertices[ c + 1 ], vertices[ c + 2 ]
107 | );
108 |
109 | }
110 |
111 | function addNormal( a, b, c ) {
112 |
113 | object.geometry.normals.push(
114 | normals[ a ], normals[ a + 1 ], normals[ a + 2 ],
115 | normals[ b ], normals[ b + 1 ], normals[ b + 2 ],
116 | normals[ c ], normals[ c + 1 ], normals[ c + 2 ]
117 | );
118 |
119 | }
120 |
121 | function addUV( a, b, c ) {
122 |
123 | object.geometry.uvs.push(
124 | uvs[ a ], uvs[ a + 1 ],
125 | uvs[ b ], uvs[ b + 1 ],
126 | uvs[ c ], uvs[ c + 1 ]
127 | );
128 |
129 | }
130 |
131 | function addFace( a, b, c, d, ua, ub, uc, ud, na, nb, nc, nd ) {
132 |
133 | var ia = parseVertexIndex( a );
134 | var ib = parseVertexIndex( b );
135 | var ic = parseVertexIndex( c );
136 | var id;
137 |
138 | if ( d === undefined ) {
139 |
140 | addVertex( ia, ib, ic );
141 |
142 | } else {
143 |
144 | id = parseVertexIndex( d );
145 |
146 | addVertex( ia, ib, id );
147 | addVertex( ib, ic, id );
148 |
149 | }
150 |
151 | if ( ua !== undefined ) {
152 |
153 | ia = parseUVIndex( ua );
154 | ib = parseUVIndex( ub );
155 | ic = parseUVIndex( uc );
156 |
157 | if ( d === undefined ) {
158 |
159 | addUV( ia, ib, ic );
160 |
161 | } else {
162 |
163 | id = parseUVIndex( ud );
164 |
165 | addUV( ia, ib, id );
166 | addUV( ib, ic, id );
167 |
168 | }
169 |
170 | }
171 |
172 | if ( na !== undefined ) {
173 |
174 | ia = parseNormalIndex( na );
175 | ib = parseNormalIndex( nb );
176 | ic = parseNormalIndex( nc );
177 |
178 | if ( d === undefined ) {
179 |
180 | addNormal( ia, ib, ic );
181 |
182 | } else {
183 |
184 | id = parseNormalIndex( nd );
185 |
186 | addNormal( ia, ib, id );
187 | addNormal( ib, ic, id );
188 |
189 | }
190 |
191 | }
192 |
193 | }
194 |
195 | addObject("");
196 |
197 | // v float float float
198 | var vertex_pattern = /^v\s+([\d|\.|\+|\-|e|E]+)\s+([\d|\.|\+|\-|e|E]+)\s+([\d|\.|\+|\-|e|E]+)/;
199 |
200 | // vn float float float
201 | var normal_pattern = /^vn\s+([\d|\.|\+|\-|e|E]+)\s+([\d|\.|\+|\-|e|E]+)\s+([\d|\.|\+|\-|e|E]+)/;
202 |
203 | // vt float float
204 | var uv_pattern = /^vt\s+([\d|\.|\+|\-|e|E]+)\s+([\d|\.|\+|\-|e|E]+)/;
205 |
206 | // f vertex vertex vertex ...
207 | var face_pattern1 = /^f\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)(?:\s+(-?\d+))?/;
208 |
209 | // f vertex/uv vertex/uv vertex/uv ...
210 | var face_pattern2 = /^f\s+((-?\d+)\/(-?\d+))\s+((-?\d+)\/(-?\d+))\s+((-?\d+)\/(-?\d+))(?:\s+((-?\d+)\/(-?\d+)))?/;
211 |
212 | // f vertex/uv/normal vertex/uv/normal vertex/uv/normal ...
213 | var face_pattern3 = /^f\s+((-?\d+)\/(-?\d+)\/(-?\d+))\s+((-?\d+)\/(-?\d+)\/(-?\d+))\s+((-?\d+)\/(-?\d+)\/(-?\d+))(?:\s+((-?\d+)\/(-?\d+)\/(-?\d+)))?/;
214 |
215 | // f vertex//normal vertex//normal vertex//normal ...
216 | var face_pattern4 = /^f\s+((-?\d+)\/\/(-?\d+))\s+((-?\d+)\/\/(-?\d+))\s+((-?\d+)\/\/(-?\d+))(?:\s+((-?\d+)\/\/(-?\d+)))?/;
217 |
218 | var object_pattern = /^[og]\s+(.+)/;
219 |
220 | var smoothing_pattern = /^s\s+([01]|on|off)/;
221 |
222 | //
223 |
224 | var lines = text.split( '\n' );
225 |
226 | for ( var i = 0; i < lines.length; i ++ ) {
227 |
228 | var line = lines[ i ];
229 | line = line.trim();
230 |
231 | var result;
232 |
233 | if ( line.length === 0 || line.charAt( 0 ) === '#' ) {
234 |
235 | continue;
236 |
237 | } else if ( ( result = vertex_pattern.exec( line ) ) !== null ) {
238 |
239 | // ["v 1.0 2.0 3.0", "1.0", "2.0", "3.0"]
240 |
241 | vertices.push(
242 | parseFloat( result[ 1 ] ),
243 | parseFloat( result[ 2 ] ),
244 | parseFloat( result[ 3 ] )
245 | );
246 |
247 | } else if ( ( result = normal_pattern.exec( line ) ) !== null ) {
248 |
249 | // ["vn 1.0 2.0 3.0", "1.0", "2.0", "3.0"]
250 |
251 | normals.push(
252 | parseFloat( result[ 1 ] ),
253 | parseFloat( result[ 2 ] ),
254 | parseFloat( result[ 3 ] )
255 | );
256 |
257 | } else if ( ( result = uv_pattern.exec( line ) ) !== null ) {
258 |
259 | // ["vt 0.1 0.2", "0.1", "0.2"]
260 |
261 | uvs.push(
262 | parseFloat( result[ 1 ] ),
263 | parseFloat( result[ 2 ] )
264 | );
265 |
266 | } else if ( ( result = face_pattern1.exec( line ) ) !== null ) {
267 |
268 | // ["f 1 2 3", "1", "2", "3", undefined]
269 |
270 | addFace(
271 | result[ 1 ], result[ 2 ], result[ 3 ], result[ 4 ]
272 | );
273 |
274 | } else if ( ( result = face_pattern2.exec( line ) ) !== null ) {
275 |
276 | // ["f 1/1 2/2 3/3", " 1/1", "1", "1", " 2/2", "2", "2", " 3/3", "3", "3", undefined, undefined, undefined]
277 |
278 | addFace(
279 | result[ 2 ], result[ 5 ], result[ 8 ], result[ 11 ],
280 | result[ 3 ], result[ 6 ], result[ 9 ], result[ 12 ]
281 | );
282 |
283 | } else if ( ( result = face_pattern3.exec( line ) ) !== null ) {
284 |
285 | // ["f 1/1/1 2/2/2 3/3/3", " 1/1/1", "1", "1", "1", " 2/2/2", "2", "2", "2", " 3/3/3", "3", "3", "3", undefined, undefined, undefined, undefined]
286 |
287 | addFace(
288 | result[ 2 ], result[ 6 ], result[ 10 ], result[ 14 ],
289 | result[ 3 ], result[ 7 ], result[ 11 ], result[ 15 ],
290 | result[ 4 ], result[ 8 ], result[ 12 ], result[ 16 ]
291 | );
292 |
293 | } else if ( ( result = face_pattern4.exec( line ) ) !== null ) {
294 |
295 | // ["f 1//1 2//2 3//3", " 1//1", "1", "1", " 2//2", "2", "2", " 3//3", "3", "3", undefined, undefined, undefined]
296 |
297 | addFace(
298 | result[ 2 ], result[ 5 ], result[ 8 ], result[ 11 ],
299 | undefined, undefined, undefined, undefined,
300 | result[ 3 ], result[ 6 ], result[ 9 ], result[ 12 ]
301 | );
302 |
303 | } else if ( ( result = object_pattern.exec( line ) ) !== null ) {
304 |
305 | // o object_name
306 | // or
307 | // g group_name
308 |
309 | var name = result[1].trim();
310 |
311 | if ( foundObjects === false ) {
312 |
313 | foundObjects = true;
314 | object.name = name;
315 |
316 | } else {
317 |
318 | addObject(name);
319 |
320 | }
321 |
322 | } else if ( /^usemtl /.test( line ) ) {
323 |
324 | // material
325 |
326 | object.material.name = line.substring( 7 ).trim();
327 |
328 | } else if ( /^mtllib /.test( line ) ) {
329 |
330 | // mtl file
331 |
332 | } else if ( ( result = smoothing_pattern.exec( line ) ) !== null ) {
333 |
334 | // smooth shading
335 |
336 | object.material.smooth = result[ 1 ] === "1" || result[ 1 ] === "on";
337 |
338 | } else {
339 |
340 | // console.log( "THREE.OBJLoader: Unhandled line " + line );
341 |
342 | }
343 |
344 | }
345 |
346 | var container = new THREE.Group();
347 |
348 | for ( var i = 0, l = objects.length; i < l; i ++ ) {
349 |
350 | object = objects[ i ];
351 | var geometry = object.geometry;
352 |
353 | var buffergeometry = new THREE.BufferGeometry();
354 |
355 | buffergeometry.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array( geometry.vertices ), 3 ) );
356 |
357 | if ( geometry.normals.length > 0 ) {
358 |
359 | buffergeometry.addAttribute( 'normal', new THREE.BufferAttribute( new Float32Array( geometry.normals ), 3 ) );
360 |
361 | } else {
362 |
363 | buffergeometry.computeVertexNormals();
364 |
365 | }
366 |
367 | if ( geometry.uvs.length > 0 ) {
368 |
369 | buffergeometry.addAttribute( 'uv', new THREE.BufferAttribute( new Float32Array( geometry.uvs ), 2 ) );
370 |
371 | }
372 |
373 | var material;
374 |
375 | if ( this.materials !== null ) {
376 |
377 | material = this.materials.create( object.material.name );
378 |
379 | }
380 |
381 | if ( !material ) {
382 |
383 | material = new THREE.MeshPhongMaterial();
384 | material.name = object.material.name;
385 |
386 | }
387 |
388 | material.shading = object.material.smooth ? THREE.SmoothShading : THREE.FlatShading;
389 |
390 | var mesh = new THREE.Mesh( buffergeometry, material );
391 | mesh.name = object.name;
392 |
393 | container.add( mesh );
394 |
395 | }
396 |
397 | console.timeEnd( 'OBJLoader' );
398 |
399 | return container;
400 |
401 | }
402 |
403 | };
404 |
--------------------------------------------------------------------------------
/js/util.js:
--------------------------------------------------------------------------------
1 |
2 | var Util = Util || {};
3 |
4 | Util.setupThumbnails = function(tableID, picsArray, basePath, tag) {
5 |
6 | var thumbsTable = $("#" + tableID);
7 |
8 | var picsArray = picsArray;
9 | var basePath = basePath;
10 |
11 | var picCount = picsArray.length;
12 | var rowCount = Math.ceil(picCount / 2);
13 |
14 | var oddCount = false;
15 | if (rowCount * 2 != picCount) oddCount = true;
16 |
17 | for (var i = 0; i < rowCount; i++) {
18 |
19 | var newRow, leftCell, leftImgLink, leftImg,
20 | rightCell, rightImgLing, rightImg;
21 |
22 | newRow = $("
");
23 | thumbsTable.append(newRow);
24 |
25 | var leftPic = basePath + "/thumbnails/" + picsArray[i * 2];
26 | var rightPic = basePath + "/thumbnails/" + picsArray[i * 2 + 1];
27 |
28 | var leftPicFull = basePath + "/" + picsArray[i * 2];
29 | var rightPicFull = basePath + "/" + picsArray[i * 2 + 1];
30 |
31 | leftCell = $(" | ");
32 | leftImgLink = $("");
33 | leftImg = $("
");
34 |
35 | newRow.append( leftCell );
36 | leftCell.append( leftImgLink );
37 | leftImgLink.append( leftImg );
38 |
39 | if (i == rowCount - 1 && oddCount) {
40 |
41 | rightCell = $(" | ");
42 | newRow.append( rightCell );
43 |
44 | } else {
45 |
46 | rightCell = $(" | ");
47 | rightImgLink = $("");
48 | rightImg = $("
");
49 |
50 | newRow.append( rightCell );
51 | rightCell.append( rightImgLink );
52 | rightImgLink.append( rightImg );
53 |
54 | }
55 |
56 | thumbsTable.append($(" |
"));
57 | }
58 |
59 | }
--------------------------------------------------------------------------------