Compare commits
	
		
			35 Commits
		
	
	
		
			remove-con
			...
			open933-fr
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 4087b9cdde | ||
|   | 43a804eef4 | ||
|   | b3a4f52fe2 | ||
|   | 671e3016d4 | ||
|   | 379828315f | ||
|   | 8c5538ec4d | ||
|   | 8b694ef337 | ||
|   | e193e3dfba | ||
|   | 8214c8e895 | ||
|   | 33b2225d10 | ||
|   | 14463d39a8 | ||
|   | fcfda50e73 | ||
|   | 06af84c161 | ||
|   | 5238aa2731 | ||
|   | fd29473664 | ||
|   | 97f3fd516b | ||
|   | 088416905d | ||
|   | 2056d87453 | ||
|   | 64ce8a2b2a | ||
|   | 585da38a16 | ||
|   | bf0e85a94c | ||
|   | 84b7a9dc2f | ||
|   | 11caa8396a | ||
|   | 0017b77439 | ||
|   | 7b7b21d748 | ||
|   | 788483ec13 | ||
|   | 7b19f91ce6 | ||
|   | 5cc81ba12a | ||
|   | 0a0bc55f5f | ||
|   | 4e7b69c4df | ||
|   | cf83040c4b | ||
|   | 32f7bc86af | ||
|   | e230b92946 | ||
|   | 58ed500ecf | ||
|   | bca5eb0fdb | 
| @@ -18,6 +18,8 @@ | ||||
|     "node-uuid": "^1.4.7", | ||||
|     "comma-separated-values": "^3.6.4", | ||||
|     "FileSaver.js": "^0.0.2", | ||||
|     "zepto": "^1.1.6" | ||||
|     "zepto": "^1.1.6", | ||||
|     "eventemitter3": "^1.2.0", | ||||
|     "d3": "~4.1.0" | ||||
|   } | ||||
| } | ||||
|   | ||||
							
								
								
									
										11
									
								
								main.js
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								main.js
									
									
									
									
									
								
							| @@ -28,13 +28,15 @@ requirejs.config({ | ||||
|         "angular-route": "bower_components/angular-route/angular-route.min", | ||||
|         "csv": "bower_components/comma-separated-values/csv.min", | ||||
|         "es6-promise": "bower_components/es6-promise/promise.min", | ||||
|         "EventEmitter": "bower_components/eventemitter3/index", | ||||
|         "moment": "bower_components/moment/moment", | ||||
|         "moment-duration-format": "bower_components/moment-duration-format/lib/moment-duration-format", | ||||
|         "saveAs": "bower_components/FileSaver.js/FileSaver.min", | ||||
|         "screenfull": "bower_components/screenfull/dist/screenfull.min", | ||||
|         "text": "bower_components/text/text", | ||||
|         "uuid": "bower_components/node-uuid/uuid", | ||||
|         "zepto": "bower_components/zepto/zepto.min" | ||||
|         "zepto": "bower_components/zepto/zepto.min", | ||||
|         "d3": "bower_components/d3/d3.min" | ||||
|     }, | ||||
|     "shim": { | ||||
|         "angular": { | ||||
| @@ -43,6 +45,9 @@ requirejs.config({ | ||||
|         "angular-route": { | ||||
|             "deps": ["angular"] | ||||
|         }, | ||||
|         "EventEmitter": { | ||||
|             "exports": "EventEmitter" | ||||
|         }, | ||||
|         "moment-duration-format": { | ||||
|             "deps": ["moment"] | ||||
|         }, | ||||
| @@ -51,6 +56,9 @@ requirejs.config({ | ||||
|         }, | ||||
|         "zepto": { | ||||
|             "exports": "Zepto" | ||||
|         }, | ||||
|         "d3": { | ||||
|             "exports": "d3" | ||||
|         } | ||||
|     } | ||||
| }); | ||||
| @@ -82,6 +90,7 @@ define([ | ||||
|     './platform/features/pages/bundle', | ||||
|     './platform/features/plot/bundle', | ||||
|     './platform/features/timeline/bundle', | ||||
|     './platform/features/conductor-v2/bundle', | ||||
|     './platform/features/table/bundle', | ||||
|     './platform/forms/bundle', | ||||
|     './platform/identity/bundle', | ||||
|   | ||||
| @@ -43,7 +43,7 @@ | ||||
|             </mct-representation> | ||||
|         </div> | ||||
|     </div> | ||||
|     <div class="holder l-flex-col flex-elem grows l-object-wrapper"> | ||||
|     <div class="holder l-flex-col flex-elem grows l-object-wrapper l-controls-visible l-time-controller-visible"> | ||||
|         <div class="holder l-flex-col flex-elem grows l-object-wrapper-inner"> | ||||
|             <!-- Toolbar and Save/Cancel buttons --> | ||||
|             <div class="l-edit-controls flex-elem l-flex-row flex-align-end"> | ||||
| @@ -59,4 +59,9 @@ | ||||
|             </mct-representation> | ||||
|         </div> | ||||
|     </div> | ||||
|     <!-- put time conductor in here? --> | ||||
|     <mct-representation mct-object="domainObject" | ||||
|                         key="'time-conductor'" | ||||
|                         class="abs holder flex-elem flex-fixed l-flex-row l-time-conductor-holder"> | ||||
|     </mct-representation> | ||||
| </div> | ||||
|   | ||||
| @@ -36,14 +36,14 @@ | ||||
|  | ||||
|         </ul> | ||||
|     </div> | ||||
|     <div class="pane right menu-item-description"> | ||||
|         <div class="desc-area ui-symbol icon type-icon"> | ||||
|     <div class="pane right menu-item-description l-flex-col"> | ||||
|         <div class="desc-area flex-elem holder ui-symbol icon type-icon"> | ||||
|             {{representation.activeMetadata.glyph}} | ||||
|         </div> | ||||
|         <div class="desc-area title"> | ||||
|         <div class="desc-area flex-elem holder title"> | ||||
|             {{representation.activeMetadata.name}} | ||||
|         </div> | ||||
|         <div class="desc-area description"> | ||||
|         <div class="desc-area flex-elem holder description"> | ||||
|             {{representation.activeMetadata.description}} | ||||
|         </div> | ||||
|     </div> | ||||
|   | ||||
| @@ -23,10 +23,12 @@ | ||||
| define([ | ||||
|     "./src/FormatProvider", | ||||
|     "./src/UTCTimeFormat", | ||||
|     "./src/DurationFormat", | ||||
|     'legacyRegistry' | ||||
| ], function ( | ||||
|     FormatProvider, | ||||
|     UTCTimeFormat, | ||||
|     DurationFormat, | ||||
|     legacyRegistry | ||||
| ) { | ||||
|  | ||||
| @@ -48,6 +50,10 @@ define([ | ||||
|                 { | ||||
|                     "key": "utc", | ||||
|                     "implementation": UTCTimeFormat | ||||
|                 }, | ||||
|                 { | ||||
|                     "key": "duration", | ||||
|                     "implementation": DurationFormat | ||||
|                 } | ||||
|             ], | ||||
|             "constants": [ | ||||
|   | ||||
							
								
								
									
										60
									
								
								platform/commonUI/formats/src/DurationFormat.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								platform/commonUI/formats/src/DurationFormat.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | ||||
| /***************************************************************************** | ||||
|  * Open MCT Web, Copyright (c) 2014-2015, United States Government | ||||
|  * as represented by the Administrator of the National Aeronautics and Space | ||||
|  * Administration. All rights reserved. | ||||
|  * | ||||
|  * Open MCT Web is licensed under the Apache License, Version 2.0 (the | ||||
|  * "License"); you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0. | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
|  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
|  * License for the specific language governing permissions and limitations | ||||
|  * under the License. | ||||
|  * | ||||
|  * Open MCT Web includes source code licensed under additional open source | ||||
|  * licenses. See the Open Source Licenses file (LICENSES.md) included with | ||||
|  * this source code distribution or the Licensing information page available | ||||
|  * at runtime from the About dialog for additional information. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| define([ | ||||
|     'moment' | ||||
| ], function ( | ||||
|     moment | ||||
| ) { | ||||
|  | ||||
|     var DATE_FORMAT = "HH:mm:ss", | ||||
|         DATE_FORMATS = [ | ||||
|             DATE_FORMAT | ||||
|         ]; | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * Formatter for UTC timestamps. Interprets numeric values as | ||||
|      * milliseconds since the start of 1970. Displays only the utc time. Can | ||||
|      * be used, with care, for specifying time intervals. | ||||
|      * | ||||
|      * @implements {Format} | ||||
|      * @constructor | ||||
|      * @memberof platform/commonUI/formats | ||||
|      */ | ||||
|     function DurationFormat() { | ||||
|     } | ||||
|  | ||||
|     DurationFormat.prototype.format = function (value) { | ||||
|         return moment.utc(value).format(DATE_FORMAT); | ||||
|     }; | ||||
|  | ||||
|     DurationFormat.prototype.parse = function (text) { | ||||
|         return moment.duration(text).asMilliseconds(); | ||||
|     }; | ||||
|  | ||||
|     DurationFormat.prototype.validate = function (text) { | ||||
|         return moment.utc(text, DATE_FORMATS).isValid(); | ||||
|     }; | ||||
|  | ||||
|     return DurationFormat; | ||||
| }); | ||||
							
								
								
									
										91
									
								
								platform/commonUI/general/res/sass/_animations.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								platform/commonUI/general/res/sass/_animations.scss
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,91 @@ | ||||
| @include keyframes(rotation) { | ||||
|     100% { @include transform(rotate(360deg)); } | ||||
| } | ||||
|  | ||||
| @include keyframes(rotation-centered) { | ||||
|     0%   { @include transform(translate(-50%, -50%) rotate(0deg)); } | ||||
|     100% { @include transform(translate(-50%, -50%) rotate(360deg)); } | ||||
| } | ||||
|  | ||||
| @include keyframes(clock-hands) { | ||||
|     0% { @include transform(translate(-50%, -50%) rotate(0deg)); } | ||||
|     100% { @include transform(translate(-50%, -50%) rotate(360deg));  } | ||||
| } | ||||
|  | ||||
| @include keyframes(clock-hands-sticky) { | ||||
|     0% { | ||||
|         @include transform(translate(-50%, -50%) rotate(0deg)); | ||||
|     } | ||||
|     7% { | ||||
|         @include transform(translate(-50%, -50%) rotate(0deg)); | ||||
|     } | ||||
|     8% { | ||||
|         @include transform(translate(-50%, -50%) rotate(30deg)); | ||||
|     } | ||||
|     15% { | ||||
|         @include transform(translate(-50%, -50%) rotate(30deg)); | ||||
|     } | ||||
|     16% { | ||||
|         @include transform(translate(-50%, -50%) rotate(60deg)); | ||||
|     } | ||||
|     24% { | ||||
|         @include transform(translate(-50%, -50%) rotate(60deg)); | ||||
|     } | ||||
|     25% { | ||||
|         @include transform(translate(-50%, -50%) rotate(90deg)); | ||||
|     } | ||||
|     32% { | ||||
|         @include transform(translate(-50%, -50%) rotate(90deg)); | ||||
|     } | ||||
|     33% { | ||||
|         @include transform(translate(-50%, -50%) rotate(120deg)); | ||||
|     } | ||||
|     40% { | ||||
|         @include transform(translate(-50%, -50%) rotate(120deg)); | ||||
|     } | ||||
|     41% { | ||||
|         @include transform(translate(-50%, -50%) rotate(150deg)); | ||||
|     } | ||||
|     49% { | ||||
|         @include transform(translate(-50%, -50%) rotate(150deg)); | ||||
|     } | ||||
|     50% { | ||||
|         @include transform(translate(-50%, -50%) rotate(180deg)); | ||||
|     } | ||||
|     57% { | ||||
|         @include transform(translate(-50%, -50%) rotate(180deg)); | ||||
|     } | ||||
|     58% { | ||||
|         @include transform(translate(-50%, -50%) rotate(210deg)); | ||||
|     } | ||||
|     65% { | ||||
|         @include transform(translate(-50%, -50%) rotate(210deg)); | ||||
|     } | ||||
|     66% { | ||||
|         @include transform(translate(-50%, -50%) rotate(240deg)); | ||||
|     } | ||||
|     74% { | ||||
|         @include transform(translate(-50%, -50%) rotate(240deg)); | ||||
|     } | ||||
|     75% { | ||||
|         @include transform(translate(-50%, -50%) rotate(270deg)); | ||||
|     } | ||||
|     82% { | ||||
|         @include transform(translate(-50%, -50%) rotate(270deg)); | ||||
|     } | ||||
|     83% { | ||||
|         @include transform(translate(-50%, -50%) rotate(300deg)); | ||||
|     } | ||||
|     90% { | ||||
|         @include transform(translate(-50%, -50%) rotate(300deg)); | ||||
|     } | ||||
|     91% { | ||||
|         @include transform(translate(-50%, -50%) rotate(330deg)); | ||||
|     } | ||||
|     99% { | ||||
|         @include transform(translate(-50%, -50%) rotate(330deg)); | ||||
|     } | ||||
|     100% { | ||||
|         @include transform(translate(-50%, -50%) rotate(360deg)); | ||||
|     } | ||||
| } | ||||
| @@ -108,6 +108,9 @@ | ||||
|         &.grows { | ||||
|             @include flex(1 1 auto); | ||||
|         } | ||||
|         &.contents-align-right { | ||||
|             text-align: right; | ||||
|         } | ||||
|     } | ||||
|     .flex-container { | ||||
|         // Apply to wrapping elements, mct-includes, etc. | ||||
| @@ -121,17 +124,18 @@ | ||||
| .l-flex-row { | ||||
|     @include flex-direction(row); | ||||
|     &.flex-elem { @include flex(1 1 auto); } | ||||
|     .flex-elem { | ||||
|     > .flex-elem { | ||||
|         height: inherit; | ||||
|         line-height: inherit; | ||||
|         min-width: 0; | ||||
|         &.holder:not(:last-child) { margin-right: $interiorMargin; } | ||||
|     } | ||||
|     .flex-container { @include flex-direction(row); } | ||||
| } | ||||
|  | ||||
| .l-flex-col { | ||||
|     @include flex-direction(column); | ||||
|     .flex-elem { | ||||
|     > .flex-elem { | ||||
|         min-height: 0; | ||||
|         &.holder:not(:last-child) { margin-bottom: $interiorMarginLg; } | ||||
|     } | ||||
|   | ||||
| @@ -48,7 +48,7 @@ $uePaneMiniTabW: 10px; | ||||
| $uePaneMiniTabCollapsedW: 11px; | ||||
| $ueEditLeftPaneW: 75%; | ||||
| $treeSearchInputBarH: 25px; | ||||
| $ueTimeControlH: (33px, 18px, 20px); | ||||
| $ueTimeControlH: (25px, 6px, 20px); | ||||
| /*************** Panes */ | ||||
| $ueBrowseLeftPaneTreeMinW: 150px; | ||||
| $ueBrowseLeftPaneTreeMaxW: 35%; | ||||
| @@ -108,6 +108,7 @@ $bubbleMaxW: 300px; | ||||
| $reqSymbolW: 15px; | ||||
| $reqSymbolM: $interiorMargin * 2; | ||||
| $reqSymbolFontSize: 0.7em; | ||||
| $inputTextP: 3px 5px; | ||||
| /*************** Wait Spinner Defaults */ | ||||
| $waitSpinnerD: 32px; | ||||
| $waitSpinnerTreeD: 20px; | ||||
|   | ||||
| @@ -66,7 +66,7 @@ input, textarea { | ||||
| input[type="text"], | ||||
| input[type="search"] { | ||||
| 	vertical-align: baseline; | ||||
| 	padding: 3px 5px; | ||||
| 	padding: $inputTextP; | ||||
| } | ||||
|  | ||||
| h1, h2, h3 { | ||||
|   | ||||
| @@ -66,8 +66,7 @@ | ||||
| } | ||||
|  | ||||
| .menu .type-icon, | ||||
| .tree-item .type-icon, | ||||
| .super-menu.menu .type-icon { | ||||
| .tree-item .type-icon { | ||||
| 	position: absolute; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -21,6 +21,7 @@ | ||||
|  *****************************************************************************/ | ||||
| @import "effects"; | ||||
| @import "global"; | ||||
| @import "animations"; | ||||
| @import "archetypes"; | ||||
| @import "about"; | ||||
| @import "text"; | ||||
| @@ -40,7 +41,7 @@ | ||||
| @import "controls/lists"; | ||||
| @import "controls/menus"; | ||||
| @import "controls/messages"; | ||||
| @import "controls/time-controller"; | ||||
| @import "controls/time-conductor"; | ||||
| @import "mobile/controls/menus"; | ||||
|  | ||||
| /********************************* FORMS */ | ||||
|   | ||||
| @@ -185,21 +185,15 @@ | ||||
| } | ||||
|  | ||||
| @mixin sliderTrack($bg: $scrollbarTrackColorBg) { | ||||
|     //$b: 1px solid lighten($bg, 30%); | ||||
|     border-radius: 2px; | ||||
|     box-sizing: border-box; | ||||
|     @include boxIncised(0.7); | ||||
|     background-color: $bg; | ||||
|     //border-bottom: $b; | ||||
|     //border-right: $b; | ||||
| } | ||||
|  | ||||
| @mixin controlGrippy($b, $direction: horizontal, $w: 1px, $style: dotted) { | ||||
|     //&:before { | ||||
|     //@include trans-prop-nice("border-color", 25ms); | ||||
|     content: ''; | ||||
|     display: block; | ||||
|     //height: auto; | ||||
|     pointer-events: none; | ||||
|     position: absolute; | ||||
|     z-index: 2; | ||||
| @@ -305,7 +299,6 @@ | ||||
| 	border-radius: $controlCr; | ||||
| 	box-sizing: border-box; | ||||
| 	color: $fg; | ||||
| 	display: inline-block; | ||||
| } | ||||
|  | ||||
| @mixin btnBase($bg: $colorBodyBg, $bgHovColor: none, $fg: $colorBodyFg, $ic: $colorBtnIcon) { | ||||
|   | ||||
| @@ -33,6 +33,7 @@ $pad: $interiorMargin * $baseRatio; | ||||
|  | ||||
| .s-btn { | ||||
|     box-sizing: border-box; | ||||
|     display: inline-block; | ||||
|     padding: 0 $pad; | ||||
|     font-size: 0.7rem; | ||||
|     vertical-align: top; | ||||
|   | ||||
| @@ -420,6 +420,63 @@ input[type="search"] { | ||||
|     } | ||||
| } | ||||
|  | ||||
| @mixin sliderKnob() { | ||||
|     $h: 16px; | ||||
|     cursor: pointer; | ||||
|     width: floor($h/1.75); | ||||
|     height: $h; | ||||
|     margin-top: 1 + floor($h/2) * -1; | ||||
|     @include btnSubtle(pullForward($colorBtnBg, 10%)); | ||||
|     //border-radius: 50% !important; | ||||
| } | ||||
|  | ||||
| @mixin sliderKnobRound() { | ||||
|     $h: 12px; | ||||
|     cursor: pointer; | ||||
|     width: $h; | ||||
|     height: $h; | ||||
|     margin-top: 1 + floor($h/2) * -1; | ||||
|     @include btnSubtle(pullForward($colorBtnBg, 10%)); | ||||
|     border-radius: 50% !important; | ||||
| } | ||||
|  | ||||
| input[type="range"] { | ||||
|     // HTML5 range inputs | ||||
|  | ||||
|     -webkit-appearance: none; /* Hides the slider so that custom slider can be made */ | ||||
|     background: transparent; /* Otherwise white in Chrome */ | ||||
|     &:focus { | ||||
|         outline: none; /* Removes the blue border. */ | ||||
|     } | ||||
|  | ||||
|     // Thumb | ||||
|     &::-webkit-slider-thumb { | ||||
|         -webkit-appearance: none; | ||||
|         @include sliderKnobRound(); | ||||
|     } | ||||
|     &::-moz-range-thumb { | ||||
|         border: none; | ||||
|         @include sliderKnobRound(); | ||||
|     } | ||||
|     &::-ms-thumb { | ||||
|         border: none; | ||||
|         @include sliderKnobRound(); | ||||
|     } | ||||
|  | ||||
|     // Track | ||||
|     &::-webkit-slider-runnable-track { | ||||
|         width: 100%; | ||||
|         height: 3px; | ||||
|         @include sliderTrack(); | ||||
|     } | ||||
|  | ||||
|     &::-moz-range-track { | ||||
|         width: 100%; | ||||
|         height: 3px; | ||||
|         @include sliderTrack(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| /******************************************************** DATETIME PICKER */ | ||||
| .l-datetime-picker { | ||||
|     $r1H: 15px; | ||||
|   | ||||
| @@ -167,7 +167,7 @@ | ||||
| 	} | ||||
| 	.pane { | ||||
| 		box-sizing: border-box; | ||||
| 		&.left { | ||||
| 		&.menu-items { | ||||
| 			border-right: 1px solid pullForward($colorMenuBg, 10%); | ||||
| 			left: 0; | ||||
| 			padding-right: $interiorMargin; | ||||
| @@ -183,38 +183,53 @@ | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		&.right { | ||||
| 		&.menu-item-description { | ||||
| 			left: auto; | ||||
| 			right: 0; | ||||
| 			padding: $interiorMargin * 5; | ||||
| 			width: $prw; | ||||
|             .desc-area { | ||||
|                 &.icon { | ||||
|                     color: $colorCreateMenuLgIcon; | ||||
|                     font-size: 8em; | ||||
|                     margin-bottom: $interiorMargin * 3; | ||||
|                     position: relative; | ||||
|                     text-align: center; | ||||
|                 } | ||||
|                 &.title { | ||||
|                     color: $colorCreateMenuText; | ||||
|                     font-size: 1.2em; | ||||
|                     margin-bottom: $interiorMargin * 2; | ||||
|                 } | ||||
|                 &.description { | ||||
|                     color: pushBack($colorCreateMenuText, 20%); | ||||
|                     font-size: 0.8em; | ||||
|                     line-height: 1.5em; | ||||
|                 } | ||||
|             } | ||||
| 		} | ||||
| 	} | ||||
| 	.menu-item-description { | ||||
| 		.desc-area { | ||||
| 			&.icon { | ||||
| 				$h: 150px; | ||||
| 				color: $colorCreateMenuLgIcon; | ||||
| 				position: relative; | ||||
| 				font-size: 8em; | ||||
| 				left: 0; | ||||
| 				height: $h; | ||||
| 				line-height: $h; | ||||
| 				margin-bottom: $interiorMargin * 5; | ||||
| 				text-align: center; | ||||
| 			} | ||||
| 			&.title { | ||||
| 				color: $colorCreateMenuText; | ||||
| 				font-size: 1.2em; | ||||
| 				margin-bottom: 0.5em; | ||||
| 			} | ||||
| 			&.description { | ||||
| 				color: $colorCreateMenuText; | ||||
| 				font-size: 0.8em; | ||||
| 				line-height: 1.5em; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
|     &.mini { | ||||
|         width: 400px; | ||||
|         height: 300px; | ||||
|         .pane { | ||||
|             &.menu-items { | ||||
|                 font-size: 0.8em; | ||||
|             } | ||||
|             &.menu-item-description { | ||||
|                 padding: $interiorMargin * 3; | ||||
|                 .desc-area { | ||||
|                     &.icon { | ||||
|                         font-size: 4em; | ||||
|                     } | ||||
|                     &.title { | ||||
|                         font-size: 1em; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| .context-menu { | ||||
| 	font-size: 0.80rem; | ||||
| @@ -251,3 +266,7 @@ | ||||
| 	right: 0; | ||||
| 	width: auto; | ||||
| } | ||||
|  | ||||
| .menus-up .menu { | ||||
|     bottom: $btnStdH; top: auto; | ||||
| } | ||||
|   | ||||
							
								
								
									
										376
									
								
								platform/commonUI/general/res/sass/controls/_time-conductor.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										376
									
								
								platform/commonUI/general/res/sass/controls/_time-conductor.scss
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,376 @@ | ||||
| @mixin toiLineHovEffects() { | ||||
|     &:before, | ||||
|     &:after { | ||||
|         background-color: $timeControllerToiLineColorHov; | ||||
|     } | ||||
| } | ||||
|  | ||||
| .l-time-conductor-holder { | ||||
|     $minW: 500px; | ||||
|     border-top: 1px solid $colorInteriorBorder; | ||||
|     min-width: $minW; | ||||
|     padding-top: $interiorMargin; | ||||
| } | ||||
|  | ||||
| .time-conductor-icon { | ||||
|     $c: $colorObjHdrIc; | ||||
|     $d: 20px; | ||||
|     background: $c; | ||||
|     border-radius: 4px; | ||||
|     height: $d !important; | ||||
|     width: $d; | ||||
|     position: relative; | ||||
|      | ||||
|     // Icon shape: brackets | ||||
|     &:before, | ||||
|     &:after { | ||||
|         content: ''; | ||||
|         background: $colorBodyBg; | ||||
|         position: absolute; | ||||
|     } | ||||
|     &:before { | ||||
|         $in: 7px; | ||||
|         left: $in; | ||||
|         top: 0; | ||||
|         right: $in; | ||||
|         bottom: 0; | ||||
|  | ||||
|     } | ||||
|     &:after { | ||||
|         $in: 4px; | ||||
|         left: $in; | ||||
|         top: $in; | ||||
|         right: $in; | ||||
|         bottom: $in; | ||||
|     } | ||||
|  | ||||
|     // Clock hands | ||||
|     div[class*="hand"] { | ||||
|         $handW: 2px; | ||||
|         $handH: 8px; | ||||
|         @include transform(translate(-50%, -50%)); | ||||
|         @include animation-iteration-count(infinite); | ||||
|         @include animation-timing-function(linear); | ||||
|         position: absolute; | ||||
|         height: $handW; | ||||
|         width: $handW; | ||||
|         left: 50%; | ||||
|         top: 50%; | ||||
|         z-index: 2; | ||||
|         &:before { | ||||
|             background-color: $c; | ||||
|             content: ''; | ||||
|             display: block; | ||||
|             position: absolute; | ||||
|             width: 100%; | ||||
|             bottom: -1px; | ||||
|         } | ||||
|         &.hand-little { | ||||
|             z-index: 2; | ||||
|             @include animation-duration(12s); | ||||
|             &:before { | ||||
|                 //background: red; | ||||
|                 height: ceil($handH * 0.7); | ||||
|             } | ||||
|         } | ||||
|         &.hand-big { | ||||
|             z-index: 1; | ||||
|             @include animation-duration(1s); | ||||
|             &:before { | ||||
|                 height: $handH; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| .l-time-conductor { | ||||
|     $knobHOffset: 0px; | ||||
|     $rangeValPad: $interiorMargin; | ||||
|     $rangeValOffset: $sliderKnobW + $interiorMargin; | ||||
|     $r1H: nth($ueTimeControlH, 1); | ||||
|     $r2H: nth($ueTimeControlH, 2); | ||||
|     $r3H: nth($ueTimeControlH, 3); | ||||
|  | ||||
|     // Glyphs Todo: replace with refactored CSS approach when that is merged into master | ||||
|     $glyphIconFixed: '\e604'; | ||||
|     $glyphIconRealtime: '\43'; | ||||
|     $glyphIconLatest: '\44'; | ||||
|  | ||||
|     position: relative; | ||||
|  | ||||
|     > .l-row-elem { | ||||
|         // First order row elements | ||||
|         box-sizing: border-box; | ||||
|         width: 100%; | ||||
|         position: relative; | ||||
|     } | ||||
|  | ||||
|     .mode-selector .s-menu-btn, | ||||
|     .time-delta { | ||||
|         &:before { | ||||
|             @extend .ui-symbol; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     .time-delta { | ||||
|         &:before { | ||||
|             color: $colorTimeCondKeyBg; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     .l-time-conductor-inputs-holder, | ||||
|     .l-time-conductor-ticks, | ||||
|     .l-time-conductor-zoom-w { | ||||
|         font-size: 0.8rem; | ||||
|     } | ||||
|  | ||||
|     .l-time-conductor-inputs-holder { | ||||
|         $trInputW: 180px; | ||||
|         $hmInputW: 60px; | ||||
|         $ticksBlockerFadeW: 50px; | ||||
|         $iconCalendarW: 16px; | ||||
|         $wBgColor: $colorBodyBg; | ||||
|  | ||||
|         height: $r1H; | ||||
|         z-index: 1; | ||||
|         .l-time-range-w { | ||||
|             // Wraps a datetime text input field | ||||
|             height: 100%; | ||||
|             position: absolute; | ||||
|             &.start-w { | ||||
|                 @include background-image(linear-gradient(270deg, transparent, $wBgColor $ticksBlockerFadeW)); | ||||
|                 padding-right: $ticksBlockerFadeW; | ||||
|             } | ||||
|             &.end-w { | ||||
|                 @include background-image(linear-gradient(90deg, transparent, $wBgColor $ticksBlockerFadeW)); | ||||
|                 padding-left: $ticksBlockerFadeW; | ||||
|                 right: 0; | ||||
|                 text-align: right; | ||||
|             } | ||||
|             input[type="text"] { | ||||
|                 @include trans-prop-nice(padding, 250ms); | ||||
|             } | ||||
|             .time-range-input input { | ||||
|                 width: $trInputW; | ||||
|             } | ||||
|             .hrs-min-input input { | ||||
|                 width: $hmInputW; | ||||
|             } | ||||
|             .icon-calendar { | ||||
|                 margin-top: 4px; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     .l-time-conductor-ticks { | ||||
|         $c: $colorTick; | ||||
|         height: $r1H; | ||||
|         mct-conductor-axis { | ||||
|             display: block; | ||||
|             position: relative; | ||||
|             width: 100%; | ||||
|         } | ||||
|         .l-axis-holder { | ||||
|             height: $r1H; | ||||
|             position: relative; | ||||
|             width: 100%; | ||||
|             svg { | ||||
|                 text-rendering: geometricPrecision; | ||||
|                 width: 100%; | ||||
|                 height: 100%; | ||||
|                 > g { | ||||
|                     font-size: 0.9em; | ||||
|                 } | ||||
|                 path { | ||||
|                     // Line beneath ticks | ||||
|                     display: none; | ||||
|                 } | ||||
|                 line { | ||||
|                     // Tick marks | ||||
|                     stroke: $c; | ||||
|                 } | ||||
|                 text { | ||||
|                     // Tick labels | ||||
|                     fill: $c; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     .l-data-visualization { | ||||
|         background: $colorTimeCondDataVisBg; | ||||
|         height: $r2H; | ||||
|     } | ||||
|  | ||||
|     .l-time-conductor-controls { | ||||
|         align-items: center; | ||||
|         margin-top: $interiorMargin; | ||||
|         .l-time-conductor-zoom-w { | ||||
|             @include justify-content(flex-end); | ||||
|             .time-conductor-zoom { | ||||
|                 height: $r3H; | ||||
|                 min-width: 100px; | ||||
|                 width: 20%; | ||||
|             } | ||||
|             .time-conductor-zoom-current-range { | ||||
|                 color: $colorTick; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|     } | ||||
|     // Fixed | ||||
|     &.fixed-mode { | ||||
|         .time-conductor-icon div[class*="hand"] { | ||||
|             &.hand-little { | ||||
|                 @include transform(rotate(120deg)); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // Realtime, latest modes | ||||
|     &.realtime-mode, | ||||
|     &.latest-mode { | ||||
|         .time-conductor-icon { | ||||
|             background: $colorTimeCondKeyBg; | ||||
|             div[class*="hand"] { | ||||
|                 @include animation-name(clock-hands); | ||||
|                 &:before { | ||||
|                     background: $colorTimeCondKeyBg; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         .l-time-conductor-inputs-holder { | ||||
|             .l-time-range-input-w { | ||||
|                 input[type="text"]:not(.error) { | ||||
|                     background: transparent; | ||||
|                     box-shadow: none; | ||||
|                     border-radius: 0; | ||||
|                     padding-left: 0; | ||||
|                     padding-right: 0; | ||||
|                     &:hover, | ||||
|                     &:focus { | ||||
|                         @include nice-input(); | ||||
|                         padding: $inputTextP; | ||||
|                     } | ||||
|                 } | ||||
|                 &.start-date { | ||||
|                     pointer-events: none; | ||||
|                 } | ||||
|                 .icon-calendar { | ||||
|                     display: none; | ||||
|                 } | ||||
|                 &.end-date { | ||||
|                     display: none; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         &.realtime-mode .time-conductor-icon div[class*="hand"] { @include animation-name(clock-hands); } | ||||
|         &.latest-mode .time-conductor-icon div[class*="hand"] { | ||||
|             @include animation-name(clock-hands-sticky); | ||||
|             &.hand-big { @include animation-duration(5s); } | ||||
|             &.hand-little { @include animation-duration(60s); } | ||||
|         } | ||||
|  | ||||
|         .l-data-visualization { | ||||
|             background: $colorTimeCondDataVisRtBg !important | ||||
|         } | ||||
|         .mode-selector .s-menu-btn { | ||||
|             @include btnSubtle($colorTimeCondKeyBg, pullForward($colorTimeCondKeyBg, $ltGamma), $colorTimeCondKeyFg); | ||||
|         } | ||||
|     } | ||||
|     &.fixed-mode { | ||||
|         $i: $glyphIconFixed; | ||||
|         .mode-selector .s-menu-btn:before { | ||||
|             content: $i; | ||||
|         } | ||||
|     } | ||||
|     &.realtime-mode { | ||||
|         $i: $glyphIconRealtime; | ||||
|         .time-delta:before { | ||||
|             content: $i; | ||||
|         } | ||||
|         .mode-selector .s-menu-btn:before { | ||||
|             content: $i; | ||||
|         } | ||||
|     } | ||||
|     &.latest-mode { | ||||
|         $i: $glyphIconLatest; | ||||
|         .time-delta:before { | ||||
|             content: $i; | ||||
|         } | ||||
|         .mode-selector .s-menu-btn:before { | ||||
|             content: $i; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| .s-time-range-val { | ||||
|     border-radius: $controlCr; | ||||
|     background-color: $colorInputBg; | ||||
|     padding: 1px 1px 0 $interiorMargin; | ||||
| } | ||||
|  | ||||
| /******************************************************************** MOBILE */ | ||||
|  | ||||
| @include phoneandtablet { | ||||
|     .l-time-conductor { | ||||
|         min-width: 0; | ||||
|         .l-time-range-slider-holder, | ||||
|         .l-time-conductor-ticks { | ||||
|             display: none; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @include phone { | ||||
|     .l-time-conductor { | ||||
|         .l-time-conductor-inputs-holder { | ||||
|             &.l-flex-row, | ||||
|             .l-flex-row { | ||||
|                 @include align-items(flex-start); | ||||
|             } | ||||
|             .l-time-range-inputs-elem { | ||||
|                 &.type-icon { | ||||
|                     margin-top: 3px; | ||||
|                 } | ||||
|             } | ||||
|             .l-time-conductor-inputs-holder { | ||||
|                 @include flex-direction(column); | ||||
|                 .l-time-range-input-w:not(:first-child) { | ||||
|                     &:not(:first-child) { | ||||
|                         margin-top: $interiorMargin; | ||||
|                     } | ||||
|                     margin-right: 0; | ||||
|                 } | ||||
|                 .l-time-range-inputs-elem { | ||||
|                     &.lbl { | ||||
|                         display: none; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @include phonePortrait { | ||||
|     .l-time-conductor { | ||||
|         .l-time-conductor-inputs-holder { | ||||
|             .l-time-conductor-inputs-holder { | ||||
|                 @include flex(1 1 auto); | ||||
|                 padding-top: 25px; // Make room for the ever lovin' Time Domain Selector | ||||
|                 .flex-elem { | ||||
|                     @include flex(1 1 auto); | ||||
|                     width: 100%; | ||||
|                 } | ||||
|                 input[type="text"] { | ||||
|                     width: 100%; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     .l-time-domain-selector { | ||||
|         right: auto; | ||||
|         left: 20px; | ||||
|     } | ||||
| } | ||||
| @@ -1,266 +0,0 @@ | ||||
| @mixin toiLineHovEffects() { | ||||
| 	&:before, | ||||
| 	&:after { | ||||
| 		background-color: $timeControllerToiLineColorHov; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| .l-time-controller { | ||||
| 	$minW: 500px; | ||||
| 	$knobHOffset: 0px; | ||||
| 	$knobM: ($sliderKnobW + $knobHOffset) * -1; | ||||
| 	$rangeValPad: $interiorMargin; | ||||
| 	$rangeValOffset: $sliderKnobW + $interiorMargin; | ||||
| 	$timeRangeSliderLROffset: 150px + ($sliderKnobW * 2); | ||||
| 	$r1H: nth($ueTimeControlH,1); // Not currently used | ||||
| 	$r2H: nth($ueTimeControlH,2); | ||||
| 	$r3H: nth($ueTimeControlH,3); | ||||
|  | ||||
|     min-width: $minW; | ||||
|     font-size: 0.8rem; | ||||
|  | ||||
| 	.l-time-range-inputs-holder, | ||||
| 	.l-time-range-slider-holder, | ||||
| 	.l-time-range-ticks-holder | ||||
| 	{ | ||||
| 		box-sizing: border-box; | ||||
|         position: relative; | ||||
|         &:not(:first-child) { | ||||
|             margin-top: $interiorMargin; | ||||
|         } | ||||
| 	} | ||||
| 	.l-time-range-slider, | ||||
| 	.l-time-range-ticks { | ||||
| 		@include absPosDefault(0, visible); | ||||
| 		left: $timeRangeSliderLROffset; right: $timeRangeSliderLROffset; | ||||
| 	} | ||||
|  | ||||
| 	.l-time-range-inputs-holder { | ||||
| 		border-top: 1px solid $colorInteriorBorder; | ||||
|         padding-top: $interiorMargin; | ||||
|         &.l-flex-row, | ||||
|         .l-flex-row { | ||||
|             @include align-items(center); | ||||
|             .flex-elem { | ||||
|                 height: auto; | ||||
|                 line-height: normal; | ||||
|             } | ||||
|         } | ||||
| 		.type-icon { | ||||
| 			font-size: 120%; | ||||
| 			vertical-align: middle; | ||||
| 		} | ||||
| 		.l-time-range-input-w, | ||||
| 		.l-time-range-inputs-elem { | ||||
| 			margin-right: $interiorMargin; | ||||
| 			.lbl { | ||||
| 				color: $colorPlotLabelFg; | ||||
| 			} | ||||
| 			.ui-symbol.icon { | ||||
| 				font-size: 11px; | ||||
| 			} | ||||
| 		} | ||||
|         .l-time-range-input-w { | ||||
|             // Wraps a datetime text input field | ||||
|             position: relative; | ||||
|             input[type="text"] { | ||||
|                 width: 200px; | ||||
|                 &.picker-icon { | ||||
|                     padding-right: 20px; | ||||
|                 } | ||||
|             } | ||||
|             .icon-calendar { | ||||
|                 position: absolute; | ||||
|                 right: 5px; | ||||
|                 top: 5px; | ||||
|             } | ||||
|         } | ||||
| 	} | ||||
|  | ||||
| 	.l-time-range-slider-holder { | ||||
| 		height: $r2H; | ||||
| 		.range-holder { | ||||
| 			box-shadow: none; | ||||
| 			background: none; | ||||
| 			border: none; | ||||
| 			.range { | ||||
| 				.toi-line { | ||||
| 					$myC: $timeControllerToiLineColor; | ||||
| 					$myW: 8px; | ||||
| 					@include transform(translateX(50%)); | ||||
| 					position: absolute; | ||||
| 					top: 0; right: 0; bottom: 0px; left: auto; | ||||
| 					width: $myW; | ||||
| 					height: auto; | ||||
| 					z-index: 2; | ||||
| 					&:before { | ||||
| 						// Vert line | ||||
|                         background-color: $myC; | ||||
|                         position: absolute; | ||||
|                         content: ""; | ||||
| 						top: 0; right: auto; bottom: -10px; left: floor($myW/2) - 1; | ||||
| 						width: 1px; | ||||
| 					} | ||||
| 				} | ||||
| 				&:hover .toi-line { | ||||
| 					@include toiLineHovEffects; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		&:not(:active) { | ||||
| 			.knob, | ||||
| 			.range { | ||||
| 				@include transition-property(left, right); | ||||
| 				@include transition-duration(500ms); | ||||
| 				@include transition-timing-function(ease-in-out); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	.l-time-range-ticks-holder { | ||||
| 		height: $r3H; | ||||
| 		.l-time-range-ticks { | ||||
| 			border-top: 1px solid $colorTick; | ||||
| 			.tick { | ||||
| 				background-color: $colorTick; | ||||
| 				border:none; | ||||
| 				height: 5px; | ||||
| 				width: 1px; | ||||
| 				margin-left: -1px; | ||||
| 				position: absolute; | ||||
| 				&:first-child { | ||||
| 					margin-left: 0; | ||||
| 				} | ||||
| 				.l-time-range-tick-label { | ||||
| 					@include webkitProp(transform, translateX(-50%)); | ||||
| 					color: $colorPlotLabelFg; | ||||
| 					display: inline-block; | ||||
| 					font-size: 0.7rem; | ||||
| 					position: absolute; | ||||
| 					top: 5px; | ||||
| 					white-space: nowrap; | ||||
| 					z-index: 2; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	.knob { | ||||
| 		z-index: 2; | ||||
|         &:before { | ||||
|             $mTB: 2px; | ||||
|             $grippyW: 3px; | ||||
|             $mLR: ($sliderKnobW - $grippyW)/2; | ||||
|             @include bgStripes($c: pullForward($sliderColorKnob, 20%), $a: 1, $bgsize: 4px, $angle: 0deg); | ||||
|             content: ''; | ||||
|             display: block; | ||||
|             position: absolute; | ||||
|             top: $mTB; right: $mLR; bottom: $mTB; left: $mLR; | ||||
|         } | ||||
| 		.range-value { | ||||
| 			@include trans-prop-nice-fade(.25s); | ||||
|             font-size: 0.7rem; | ||||
| 			position: absolute; | ||||
| 			height: $r2H; | ||||
| 			line-height: $r2H; | ||||
|             white-space: nowrap; | ||||
|             z-index: 1; | ||||
| 		} | ||||
| 		&:hover { | ||||
|             .range-value { | ||||
|                 color: $sliderColorKnobHov; | ||||
|             } | ||||
| 		} | ||||
| 		&.knob-l { | ||||
| 			margin-left: $knobM; | ||||
| 			.range-value { | ||||
| 				text-align: right; | ||||
| 				right: $rangeValOffset; | ||||
| 			} | ||||
| 		} | ||||
| 		&.knob-r { | ||||
| 			margin-right: $knobM; | ||||
| 			.range-value { | ||||
| 				left: $rangeValOffset; | ||||
| 			} | ||||
| 			&:hover + .range-holder .range .toi-line { | ||||
| 				@include toiLineHovEffects; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	.l-time-domain-selector { | ||||
| 		position: absolute; | ||||
| 		right: 0px; | ||||
| 		top: $interiorMargin; | ||||
| 	} | ||||
|  | ||||
| } | ||||
|  | ||||
| .s-time-range-val { | ||||
| 	border-radius: $controlCr; | ||||
| 	background-color: $colorInputBg; | ||||
| 	padding: 1px 1px 0 $interiorMargin; | ||||
| } | ||||
|  | ||||
| /******************************************************************** MOBILE */ | ||||
|  | ||||
| @include phoneandtablet { | ||||
|     .l-time-controller { | ||||
|         min-width: 0; | ||||
|         .l-time-range-slider-holder, | ||||
|         .l-time-range-ticks-holder { | ||||
|             display: none; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @include phone { | ||||
|     .l-time-controller { | ||||
|         .l-time-range-inputs-holder { | ||||
|             &.l-flex-row, | ||||
|             .l-flex-row { | ||||
|                 @include align-items(flex-start); | ||||
|             } | ||||
|             .l-time-range-inputs-elem { | ||||
|                 &.type-icon { | ||||
|                     margin-top: 3px; | ||||
|                 } | ||||
|             } | ||||
|             .t-inputs-w { | ||||
|                 @include flex-direction(column); | ||||
|                 .l-time-range-input-w:not(:first-child) { | ||||
|                     &:not(:first-child) { | ||||
|                         margin-top: $interiorMargin; | ||||
|                     } | ||||
|                     margin-right: 0; | ||||
|                 } | ||||
|                 .l-time-range-inputs-elem { | ||||
|                     &.lbl { display: none; } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @include phonePortrait { | ||||
|     .l-time-controller { | ||||
|         .l-time-range-inputs-holder { | ||||
|             .t-inputs-w { | ||||
|                 @include flex(1 1 auto); | ||||
|                 padding-top: 25px; // Make room for the ever lovin' Time Domain Selector | ||||
|                 .flex-elem { | ||||
|                     @include flex(1 1 auto); | ||||
|                     width: 100%; | ||||
|                 } | ||||
|                 input[type="text"] { | ||||
|                     width: 100%; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     .l-time-domain-selector { | ||||
|         right: auto; | ||||
|         left: 20px; | ||||
|     } | ||||
| } | ||||
| @@ -19,15 +19,6 @@ | ||||
|  * this source code distribution or the Licensing information page available | ||||
|  * at runtime from the About dialog for additional information. | ||||
|  *****************************************************************************/ | ||||
| @include keyframes(rotation) { | ||||
|     100% { @include transform(rotate(360deg)); } | ||||
| } | ||||
|  | ||||
| @include keyframes(rotation-centered) { | ||||
|     0%   { @include transform(translate(-50%, -50%) rotate(0deg)); } | ||||
|     100% { @include transform(translate(-50%, -50%) rotate(360deg)); } | ||||
| } | ||||
|  | ||||
| @mixin  spinner($b: 5px, $c: $colorKey) { | ||||
|     @include transform-origin(center); | ||||
|     @include animation-name(rotation-centered); | ||||
|   | ||||
| @@ -129,6 +129,8 @@ | ||||
|     } | ||||
|  | ||||
|     .primary-pane { | ||||
|         // Clip element that have min-widths | ||||
|         overflow: hidden; | ||||
|         // Need to lift up this pane to ensure that 'collapsed' panes don't block user interactions | ||||
|         z-index: 4; | ||||
|     } | ||||
|   | ||||
| @@ -23,6 +23,7 @@ | ||||
|     <input type="text" | ||||
|            ng-model="textValue" | ||||
|            ng-blur="restoreTextValue(); ngBlur()" | ||||
|            ng-mouseup="ngMouseup()" | ||||
|            ng-class="{ | ||||
|                         error: textInvalid || | ||||
|                             (structure.validate && | ||||
|   | ||||
| @@ -20,10 +20,10 @@ | ||||
|  at runtime from the About dialog for additional information. | ||||
| --> | ||||
| <div ng-controller="TimeRangeController as trCtrl" class="l-flex-col"> | ||||
|     <form class="l-time-range-inputs-holder l-flex-row flex-elem" | ||||
|     <form class="l-time-conductor-inputs-holder l-flex-row flex-elem" | ||||
|           ng-submit="trCtrl.updateBoundsFromForm()"> | ||||
|         <span class="l-time-range-inputs-elem ui-symbol type-icon flex-elem">C</span> | ||||
|         <span class="l-time-range-inputs-elem t-inputs-w l-flex-row flex-elem"> | ||||
|         <span class="l-time-range-inputs-elem l-flex-row flex-elem"> | ||||
|             <span class="l-time-range-input-w flex-elem"> | ||||
|                 <mct-control key="'datetime-field'" | ||||
|                              structure="{ | ||||
| @@ -86,7 +86,7 @@ | ||||
|         </div> | ||||
|     </div> | ||||
|  | ||||
|     <div class="l-time-range-ticks-holder flex-elem"> | ||||
|     <div class="l-time-conductor-ticks flex-elem"> | ||||
|         <div class="l-time-range-ticks"> | ||||
|             <div | ||||
|                 ng-repeat="tick in ticks track by $index" | ||||
|   | ||||
| @@ -52,7 +52,7 @@ $colorGridLines: rgba(#fff, 0.05); | ||||
| $colorInvokeMenu: #fff; | ||||
| $colorObjHdrTxt: $colorBodyFg; | ||||
| $colorObjHdrIc: pullForward($colorObjHdrTxt, 20%); | ||||
| $colorTick: rgba(white, 0.2); | ||||
| $colorTick: pullForward($colorBodyBg, 20%); | ||||
|  | ||||
| // Menu colors | ||||
| $colorMenuBg: pullForward($colorBodyBg, 23%); | ||||
| @@ -207,4 +207,10 @@ $colorAboutLink: #84b3ff; | ||||
|  | ||||
| // Loading | ||||
| $colorLoadingFg: $colorAlt1; | ||||
| $colorLoadingBg: rgba($colorBodyFg, 0.2); | ||||
| $colorLoadingBg: rgba($colorBodyFg, 0.2); | ||||
|  | ||||
| // Time Conductor | ||||
| $colorTimeCondKeyBg: #4e70dc; | ||||
| $colorTimeCondKeyFg: #fff; | ||||
| $colorTimeCondDataVisBg: pullForward($colorBodyBg, 10%); | ||||
| $colorTimeCondDataVisRtBg: pushBack($colorTimeCondKeyBg, 10%); | ||||
| @@ -52,7 +52,7 @@ $colorGridLines: rgba(#000, 0.05); | ||||
| $colorInvokeMenu: #fff; | ||||
| $colorObjHdrTxt: $colorBodyFg; | ||||
| $colorObjHdrIc: pushBack($colorObjHdrTxt, 30%); | ||||
| $colorTick: rgba(black, 0.2); | ||||
| $colorTick: pullForward($colorBodyBg, 30%); | ||||
|  | ||||
| // Menu colors | ||||
| $colorMenuBg: pushBack($colorBodyBg, 10%); | ||||
| @@ -185,6 +185,7 @@ $scrollbarThumbColorOverlayHov: $scrollbarThumbColorHov; | ||||
| // Splitter | ||||
| $splitterD: 16px; // splitterD and $splitterHandleD should both be odd, or even | ||||
| $splitterHandleD: 2px; | ||||
| $splitterDSm: 16px; // Smaller splitter, used inside elements like a Timeline view | ||||
| $colorSplitterBg: pullForward($colorBodyBg, 10%); | ||||
| $splitterShdw: none; | ||||
| $splitterEndCr: none; | ||||
| @@ -207,3 +208,9 @@ $colorAboutLink: #84b3ff; | ||||
| // Loading | ||||
| $colorLoadingFg: $colorAlt1; | ||||
| $colorLoadingBg: rgba($colorLoadingFg, 0.1); | ||||
|  | ||||
| // Time Conductor | ||||
| $colorTimeCondKeyBg: #6178dc; | ||||
| $colorTimeCondKeyFg: #fff; | ||||
| $colorTimeCondDataVisBg: pullForward($colorBodyBg, 10%); | ||||
| $colorTimeCondDataVisRtBg: pushBack($colorTimeCondKeyBg, 30%); | ||||
|   | ||||
							
								
								
									
										85
									
								
								platform/features/conductor-v2/bundle.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								platform/features/conductor-v2/bundle.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,85 @@ | ||||
| /***************************************************************************** | ||||
|  * Open MCT Web, Copyright (c) 2014-2015, United States Government | ||||
|  * as represented by the Administrator of the National Aeronautics and Space | ||||
|  * Administration. All rights reserved. | ||||
|  * | ||||
|  * Open MCT Web is licensed under the Apache License, Version 2.0 (the | ||||
|  * "License"); you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0. | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
|  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
|  * License for the specific language governing permissions and limitations | ||||
|  * under the License. | ||||
|  * | ||||
|  * Open MCT Web includes source code licensed under additional open source | ||||
|  * licenses. See the Open Source Licenses file (LICENSES.md) included with | ||||
|  * this source code distribution or the Licensing information page available | ||||
|  * at runtime from the About dialog for additional information. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| define([ | ||||
|     "./src/TimeConductor", | ||||
|     "./src/TimeConductorController", | ||||
|     "./src/MCTConductorAxis", | ||||
|     "text!./res/templates/time-conductor.html", | ||||
|     "text!./res/templates/mode-selector/mode-selector.html", | ||||
|     "text!./res/templates/mode-selector/mode-menu.html", | ||||
|     'legacyRegistry' | ||||
| ], function ( | ||||
|     TimeConductor, | ||||
|     TimeConductorController, | ||||
|     MCTConductorAxis, | ||||
|     timeConductorTemplate, | ||||
|     modeSelectorTemplate, | ||||
|     modeMenuTemplate, | ||||
|     legacyRegistry | ||||
| ) { | ||||
|  | ||||
|     legacyRegistry.register("platform/features/conductor-v2", { | ||||
|         "extensions": { | ||||
|             "services": [ | ||||
|                 { | ||||
|                     "key": "timeConductor", | ||||
|                     "implementation": TimeConductor | ||||
|                 } | ||||
|             ], | ||||
|             "controllers": [ | ||||
|                 { | ||||
|                     "key": "TimeConductorController", | ||||
|                     "implementation": TimeConductorController, | ||||
|                     "depends": [ | ||||
|                         "$scope", | ||||
|                         "$timeout", | ||||
|                         "timeConductor" | ||||
|                     ] | ||||
|                 } | ||||
|             ], | ||||
|             "directives": [ | ||||
|                 { | ||||
|                     "key": "mctConductorAxis", | ||||
|                     "implementation": MCTConductorAxis, | ||||
|                     "depends": [ | ||||
|                         "timeConductor" | ||||
|                     ] | ||||
|                 } | ||||
|             ], | ||||
|             "representations": [ | ||||
|                 { | ||||
|                     "key": "time-conductor", | ||||
|                     "template": timeConductorTemplate | ||||
|                 }, | ||||
|                 { | ||||
|                     "key": "mode-selector", | ||||
|                     "template": modeSelectorTemplate | ||||
|                 }, | ||||
|                 { | ||||
|                     "key": "mode-menu", | ||||
|                     "template": modeMenuTemplate | ||||
|                 } | ||||
|             ] | ||||
|         } | ||||
|     }); | ||||
| }); | ||||
| @@ -0,0 +1,49 @@ | ||||
| <!-- | ||||
|  Open MCT Web, Copyright (c) 2014-2015, United States Government | ||||
|  as represented by the Administrator of the National Aeronautics and Space | ||||
|  Administration. All rights reserved. | ||||
|  | ||||
|  Open MCT Web is licensed under the Apache License, Version 2.0 (the | ||||
|  "License"); you may not use this file except in compliance with the License. | ||||
|  You may obtain a copy of the License at | ||||
|  http://www.apache.org/licenses/LICENSE-2.0. | ||||
|  | ||||
|  Unless required by applicable law or agreed to in writing, software | ||||
|  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
|  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
|  License for the specific language governing permissions and limitations | ||||
|  under the License. | ||||
|  | ||||
|  Open MCT Web includes source code licensed under additional open source | ||||
|  licenses. See the Open Source Licenses file (LICENSES.md) included with | ||||
|  this source code distribution or the Licensing information page available | ||||
|  at runtime from the About dialog for additional information. | ||||
| --> | ||||
| <div class="contents"> | ||||
|     <div class="pane left menu-items"> | ||||
|         <ul> | ||||
|             <li ng-repeat="(selected, option) in ngModel.options" | ||||
|                 ng-click="ngModel.selected=selected"> | ||||
|                 <a | ||||
|                    ng-mouseover="representation.activeMetadata = option" | ||||
|                    ng-mouseleave="representation.activeMetadata = undefined"> | ||||
|                     <span class="ui-symbol icon type-icon"> | ||||
|                         {{option.glyph}} | ||||
|                     </span> | ||||
|                     {{option.name}} | ||||
|                 </a> | ||||
|             </li> | ||||
|         </ul> | ||||
|     </div> | ||||
|     <div class="pane right menu-item-description"> | ||||
|         <div class="desc-area ui-symbol icon type-icon"> | ||||
|             {{representation.activeMetadata.glyph}} | ||||
|         </div> | ||||
|         <div class="desc-area title"> | ||||
|             {{representation.activeMetadata.name}} | ||||
|         </div> | ||||
|         <div class="desc-area description"> | ||||
|             {{representation.activeMetadata.description}} | ||||
|         </div> | ||||
|     </div> | ||||
| </div> | ||||
| @@ -0,0 +1,34 @@ | ||||
| <!-- | ||||
|  Open MCT Web, Copyright (c) 2014-2015, United States Government | ||||
|  as represented by the Administrator of the National Aeronautics and Space | ||||
|  Administration. All rights reserved. | ||||
|  | ||||
|  Open MCT Web is licensed under the Apache License, Version 2.0 (the | ||||
|  "License"); you may not use this file except in compliance with the License. | ||||
|  You may obtain a copy of the License at | ||||
|  http://www.apache.org/licenses/LICENSE-2.0. | ||||
|  | ||||
|  Unless required by applicable law or agreed to in writing, software | ||||
|  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
|  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
|  License for the specific language governing permissions and limitations | ||||
|  under the License. | ||||
|  | ||||
|  Open MCT Web includes source code licensed under additional open source | ||||
|  licenses. See the Open Source Licenses file (LICENSES.md) included with | ||||
|  this source code distribution or the Licensing information page available | ||||
|  at runtime from the About dialog for additional information. | ||||
| --> | ||||
| <span ng-controller="ClickAwayController as modeController"> | ||||
|     <div class="s-menu-btn" | ||||
|          ng-click="modeController.toggle()"> | ||||
| 		<span class="title-label">{{ngModel.options[ngModel.selected].label}}</span> | ||||
|     </div> | ||||
|     <div class="menu super-menu mini mode-selector-menu" | ||||
|          ng-show="modeController.isActive()"> | ||||
|         <mct-representation mct-object="domainObject" | ||||
|                             key="'mode-menu'" | ||||
|                             ng-model="ngModel"> | ||||
|         </mct-representation> | ||||
|     </div> | ||||
| </span> | ||||
							
								
								
									
										115
									
								
								platform/features/conductor-v2/res/templates/time-conductor.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								platform/features/conductor-v2/res/templates/time-conductor.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,115 @@ | ||||
| <!-- Parent holder for time conductor. follow-mode | fixed-mode --> | ||||
| <div ng-controller="TimeConductorController as tcController" | ||||
|      class="holder grows flex-elem l-flex-row l-time-conductor {{modeModel.selected}}-mode"> | ||||
|  | ||||
|     <div class="flex-elem holder time-conductor-icon"> | ||||
|         <div class="hand-little"></div> | ||||
|         <div class="hand-big"></div> | ||||
|     </div> | ||||
|  | ||||
|     <div class="flex-elem holder grows l-flex-col l-time-conductor-inner"> | ||||
|         <!-- Holds inputs and ticks --> | ||||
|         <div class="l-time-conductor-ticks l-row-elem l-flex-row flex-elem no-margin"> | ||||
|             <form class="abs l-time-conductor-inputs-holder" | ||||
|                   ng-submit="tcController.updateBoundsFromForm(formModel)"> | ||||
|                 <span class="l-time-range-w start-w"> | ||||
|                     <span class="l-time-range-input-w start-date"> | ||||
|                         <mct-control key="'datetime-field'" | ||||
|                                      structure="{ | ||||
|                                          format: 'utc', | ||||
|                                          validate: tcController.validateStart | ||||
|                                      }" | ||||
|                                      ng-model="formModel" | ||||
|                                      ng-mouseup="tcController.changing['start'] = true" | ||||
|                                      ng-blur="tcController.changing['start'] = false; tcController.updateBoundsFromForm(formModel)" | ||||
|                                      field="'start'" | ||||
|                                      class="time-range-input"> | ||||
|                         </mct-control> | ||||
|                     </span> | ||||
|                     <span class="l-time-range-input-w time-delta start-delta" | ||||
|                           ng-class="{'hide':(modeModel.selected === 'fixed')}"> | ||||
|                         - | ||||
|                         <mct-control key="'datetime-field'" | ||||
|                                      structure="{ | ||||
|                                         format: 'duration', | ||||
|                                         validate: tcController.validateStartDelta | ||||
|                                      }" | ||||
|                                      ng-model="formModel" | ||||
|                                      ng-mouseup="tcController.changing['startDelta'] = true" | ||||
|                                      ng-blur="tcController.changing['startDelta'] = false; tcController.updateDeltasFromForm(formModel)" | ||||
|                                      field="'startDelta'" | ||||
|                                      class="hrs-min-input"> | ||||
|                         </mct-control> | ||||
|                     </span> | ||||
|                 </span> | ||||
|  | ||||
|  | ||||
|                 <span class="l-time-range-w end-w"> | ||||
|                     <span class="l-time-range-input-w time-delta end-delta" | ||||
|                           ng-class="{'hide':(modeModel.selected === 'fixed')}"> | ||||
|                         + | ||||
|                         <mct-control key="'datetime-field'" | ||||
|                                      structure="{ | ||||
|                                         format: 'duration', | ||||
|                                         validate: tcController.validateEndDelta | ||||
|                                      }" | ||||
|                                      ng-model="formModel" | ||||
|                                      ng-mouseup="tcController.changing['endDelta'] = true" | ||||
|                                      ng-blur="tcController.changing['endDelta'] = false; tcController.updateDeltasFromForm(formModel)" | ||||
|                                      field="'endDelta'" | ||||
|                                      class="hrs-min-input"> | ||||
|                         </mct-control> | ||||
|                     </span> | ||||
|                     <span class="l-time-range-input-w end-date" | ||||
|                           ng-controller="ToggleController as t2"> | ||||
|                         <mct-control key="'datetime-field'" | ||||
|                                      structure="{ | ||||
|                                          format: 'utc', | ||||
|                                          validate: tcController.validateEnd | ||||
|                                      }" | ||||
|                                      ng-model="formModel" | ||||
|                                      ng-mouseup="tcController.changing['end'] = true" | ||||
|                                      ng-blur="tcController.changing['end'] = false; tcController.updateBoundsFromForm(formModel)" | ||||
|                                      field="'end'" | ||||
|                                      class="time-range-input"> | ||||
|                         </mct-control> | ||||
|                     </span> | ||||
|                 </span> | ||||
|  | ||||
|                 <input type="submit" class="hidden"> | ||||
|             </form> | ||||
|             <mct-conductor-axis></mct-conductor-axis> | ||||
|         </div> | ||||
|  | ||||
|         <!-- Holds data availability, time of interest --> | ||||
|         <div class="l-data-visualization l-row-elem l-flex-row flex-elem"></div> | ||||
|  | ||||
|         <!-- Holds time system and session selectors, and zoom control --> | ||||
|         <div class="l-time-conductor-controls l-row-elem l-flex-row flex-elem"> | ||||
|             <mct-representation | ||||
|                 key="'mode-selector'" | ||||
|                 mct-object="domainObject" | ||||
|                 ng-model="modeModel" | ||||
|                 class="holder flex-elem menus-up mode-selector"> | ||||
|             </mct-representation> | ||||
|             <mct-control | ||||
|                 key="'menu-button'" | ||||
|                 class="holder flex-elem menus-up time-system" | ||||
|                 ng-model="conductorModel.timeSystem" | ||||
|                 structure="{ | ||||
|                         text: 'UTC', | ||||
|                         options: [ | ||||
|                             {name: 'UTC', key:'utc', glyph:'\u0043'}, | ||||
|                             {name: 'SCET', key:'scet', glyph:'\u0043'}, | ||||
|                             {name: 'SCLK', key:'sclk', glyph:'\u0043'} | ||||
|                     ]}"> | ||||
|             </mct-control> | ||||
|             <!-- Zoom control --> | ||||
|             <div class="l-time-conductor-zoom-w grows flex-elem l-flex-row"> | ||||
|                 <span class="time-conductor-zoom-current-range flex-elem flex-fixed holder">Mars Minutes</span> | ||||
|                 <input class="time-conductor-zoom flex-elem" type="range" /> | ||||
|             </div> | ||||
|         </div> | ||||
|  | ||||
|     </div> | ||||
| </div> | ||||
							
								
								
									
										100
									
								
								platform/features/conductor-v2/src/MctConductorAxis.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								platform/features/conductor-v2/src/MctConductorAxis.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,100 @@ | ||||
| /***************************************************************************** | ||||
|  * Open MCT Web, Copyright (c) 2014-2015, United States Government | ||||
|  * as represented by the Administrator of the National Aeronautics and Space | ||||
|  * Administration. All rights reserved. | ||||
|  * | ||||
|  * Open MCT Web is licensed under the Apache License, Version 2.0 (the | ||||
|  * "License"); you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0. | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
|  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
|  * License for the specific language governing permissions and limitations | ||||
|  * under the License. | ||||
|  * | ||||
|  * Open MCT Web includes source code licensed under additional open source | ||||
|  * licenses. See the Open Source Licenses file (LICENSES.md) included with | ||||
|  * this source code distribution or the Licensing information page available | ||||
|  * at runtime from the About dialog for additional information. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| define( | ||||
|     [ | ||||
|         "zepto", | ||||
|         "d3" | ||||
|     ], | ||||
|     function ($, d3) { | ||||
|  | ||||
|         /** | ||||
|          * The mct-control will dynamically include the control | ||||
|          * for a form element based on a symbolic key. Individual | ||||
|          * controls are defined under the extension category | ||||
|          * `controls`; this allows plug-ins to introduce new form | ||||
|          * control types while still making use of the form | ||||
|          * generator to ensure an overall consistent form style. | ||||
|          * @constructor | ||||
|          * @memberof platform/forms | ||||
|          */ | ||||
|         function MCTConductorAxis(conductor) { | ||||
|  | ||||
|             function link(scope, element, attrs, ngModelController) { | ||||
|                 var target = element[0].firstChild, | ||||
|                     height = target.offsetHeight, | ||||
|                     padding = 1; | ||||
|  | ||||
|                 var vis = d3.select(target) | ||||
|                             .append('svg:svg') | ||||
|                             .attr('width', '100%') | ||||
|                             .attr('height', height); | ||||
|                 var xScale = d3.scaleUtc(); | ||||
|                 var xAxis = d3.axisTop(); | ||||
|                 // draw x axis with labels and move to the bottom of the chart area | ||||
|                 var axisElement = vis.append("g") | ||||
|                     .attr("transform", "translate(0," + (height - padding) + ")"); | ||||
|  | ||||
|                 function setScale(start, end) { | ||||
|                     var width = target.offsetWidth; | ||||
|                     xScale.domain([new Date(start), new Date(end)]) | ||||
|                         .range([padding, width - padding * 2]); | ||||
|                     xAxis.scale(xScale); | ||||
|                     axisElement.call(xAxis); | ||||
|                 } | ||||
|  | ||||
|                 scope.resize = function () { | ||||
|                     setScale(conductor.bounds().start, conductor.bounds().end); | ||||
|                 }; | ||||
|  | ||||
|                 conductor.on('bounds', function (bounds) { | ||||
|                     setScale(bounds.start, bounds.end); | ||||
|                 }); | ||||
|  | ||||
|                 //Set initial scale. | ||||
|                 setScale(conductor.bounds().start, conductor.bounds().end); | ||||
|             } | ||||
|  | ||||
|             return { | ||||
|                 // Only show at the element level | ||||
|                 restrict: "E", | ||||
|  | ||||
|                 template: "<div class=\"l-axis-holder\" mct-resize=\"resize()\"></div>", | ||||
|  | ||||
|                 // ngOptions is terminal, so we need to be higher priority | ||||
|                 priority: 1000, | ||||
|  | ||||
|                 // Link function | ||||
|                 link: link, | ||||
|  | ||||
|                 // Pass through Angular's normal input field attributes | ||||
|                 scope: { | ||||
|                     // Used to choose which form control to use | ||||
|                     start: "=", | ||||
|                     end: "=" | ||||
|                 } | ||||
|             }; | ||||
|         } | ||||
|  | ||||
|         return MCTConductorAxis; | ||||
|     } | ||||
| ); | ||||
							
								
								
									
										183
									
								
								platform/features/conductor-v2/src/TimeConductor.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										183
									
								
								platform/features/conductor-v2/src/TimeConductor.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,183 @@ | ||||
| /***************************************************************************** | ||||
|  * Open MCT Web, Copyright (c) 2014-2015, United States Government | ||||
|  * as represented by the Administrator of the National Aeronautics and Space | ||||
|  * Administration. All rights reserved. | ||||
|  * | ||||
|  * Open MCT Web is licensed under the Apache License, Version 2.0 (the | ||||
|  * "License"); you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0. | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
|  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
|  * License for the specific language governing permissions and limitations | ||||
|  * under the License. | ||||
|  * | ||||
|  * Open MCT Web includes source code licensed under additional open source | ||||
|  * licenses. See the Open Source Licenses file (LICENSES.md) included with | ||||
|  * this source code distribution or the Licensing information page available | ||||
|  * at runtime from the About dialog for additional information. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| define(['EventEmitter'], function (EventEmitter) { | ||||
|  | ||||
|     /** | ||||
|      * The public API for setting and querying time conductor state. The | ||||
|      * time conductor is the means by which the temporal bounds of a view | ||||
|      * are controlled. Time-sensitive views will typically respond to | ||||
|      * changes to bounds or other properties of the time conductor and | ||||
|      * update the data displayed based on the time conductor state. | ||||
|      * | ||||
|      * The TimeConductor extends the EventEmitter class. A number of events are | ||||
|      * fired when properties of the time conductor change, which are | ||||
|      * documented below. | ||||
|      * @constructor | ||||
|      */ | ||||
|     function TimeConductor() { | ||||
|         EventEmitter.call(this); | ||||
|  | ||||
|         //The Time System | ||||
|         this.system = undefined; | ||||
|         //The Time Of Interest | ||||
|         this.toi = undefined; | ||||
|  | ||||
|         this.boundsVal = { | ||||
|             start: undefined, | ||||
|             end: undefined | ||||
|         }; | ||||
|  | ||||
|         //Default to fixed mode | ||||
|         this.followMode = false; | ||||
|     } | ||||
|  | ||||
|     TimeConductor.prototype = Object.create(EventEmitter.prototype); | ||||
|  | ||||
|     /** | ||||
|      * Validate the given bounds. This can be used for pre-validation of | ||||
|      * bounds, for example by views validating user inputs. | ||||
|      * @param bounds The start and end time of the conductor. | ||||
|      * @returns {string | true} A validation error, or true if valid | ||||
|      */ | ||||
|     TimeConductor.prototype.validateBounds = function (bounds) { | ||||
|         if ((bounds.start === undefined) || | ||||
|             (bounds.end === undefined) || | ||||
|             isNaN(bounds.start) || | ||||
|             isNaN(bounds.end) | ||||
|         ) { | ||||
|             return "Start and end must be specified as integer values"; | ||||
|         } else if (bounds.start > bounds.end) { | ||||
|             return "Specified start date exceeds end bound"; | ||||
|         } | ||||
|         return true; | ||||
|     }; | ||||
|  | ||||
|     function throwOnError(validationResult) { | ||||
|         if (validationResult !== true) { | ||||
|             throw new Error(validationResult); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Get or set the follow mode of the time conductor. In follow mode the | ||||
|      * time conductor ticks, regularly updating the bounds from a timing | ||||
|      * source appropriate to the selected time system and mode of the time | ||||
|      * conductor. | ||||
|      * @fires TimeConductor#follow | ||||
|      * @param {boolean} followMode | ||||
|      * @returns {boolean} | ||||
|      */ | ||||
|     TimeConductor.prototype.follow = function (followMode) { | ||||
|         if (arguments.length > 0) { | ||||
|             this.followMode = followMode; | ||||
|             /** | ||||
|              * @event TimeConductor#follow The TimeConductor has toggled | ||||
|              * into or out of follow mode. | ||||
|              * @property {boolean} followMode true if follow mode is | ||||
|              * enabled, otherwise false. | ||||
|              */ | ||||
|             this.emit('follow', this.followMode); | ||||
|         } | ||||
|         return this.followMode; | ||||
|     }; | ||||
|  | ||||
|     /** | ||||
|      * @typedef {Object} TimeConductorBounds | ||||
|      * @property {number} start The start time displayed by the time conductor in ms since epoch. Epoch determined by current time system | ||||
|      * @property {number} end The end time displayed by the time conductor in ms since epoch. | ||||
|      */ | ||||
|     /** | ||||
|      * Get or set the start and end time of the time conductor. Basic validation | ||||
|      * of bounds is performed. | ||||
|      * | ||||
|      * @param {TimeConductorBounds} newBounds | ||||
|      * @throws {Error} Validation error | ||||
|      * @fires TimeConductor#bounds | ||||
|      * @returns {TimeConductorBounds} | ||||
|      */ | ||||
|     TimeConductor.prototype.bounds = function (newBounds) { | ||||
|         if (arguments.length > 0) { | ||||
|             throwOnError(this.validateBounds(newBounds)); | ||||
|             this.boundsVal = newBounds; | ||||
|             /** | ||||
|              * @event TimeConductor#bounds The start time, end time, or | ||||
|              * both have been updated | ||||
|              * @property {TimeConductorBounds} bounds | ||||
|              */ | ||||
|             this.emit('bounds', this.boundsVal); | ||||
|         } | ||||
|         return this.boundsVal; | ||||
|     }; | ||||
|  | ||||
|     /** | ||||
|      * Get or set the time system of the TimeConductor. Time systems determine | ||||
|      * units, epoch, and other aspects of time representation. When changing | ||||
|      * the time system in use, new valid bounds must also be provided. | ||||
|      * @param {TimeSystem} newTimeSystem | ||||
|      * @param {TimeConductorBounds} bounds | ||||
|      * @fires TimeConductor#timeSystem | ||||
|      * @returns {TimeSystem} The currently applied time system | ||||
|      */ | ||||
|     TimeConductor.prototype.timeSystem = function (newTimeSystem, bounds) { | ||||
|         if (arguments.length >= 2) { | ||||
|             this.system = newTimeSystem; | ||||
|             /** | ||||
|              * @event TimeConductor#timeSystem The time system used by the time | ||||
|              * conductor has changed. A change in Time System will always be | ||||
|              * followed by a bounds event specifying new query bounds | ||||
|              * @property {TimeSystem} The value of the currently applied | ||||
|              * Time System | ||||
|              * */ | ||||
|             this.emit('timeSystem', this.system); | ||||
|             // Do something with bounds here. Try and convert between | ||||
|             // time systems? Or just set defaults when time system changes? | ||||
|             // eg. | ||||
|             this.bounds(bounds); | ||||
|         } else if (arguments.length === 1) { | ||||
|             throw new Error('Must set bounds when changing time system'); | ||||
|         } | ||||
|         return this.system; | ||||
|     }; | ||||
|  | ||||
|     /** | ||||
|      * Get or set the Time of Interest. The Time of Interest is the temporal | ||||
|      * focus of the current view. It can be manipulated by the user from the | ||||
|      * time conductor or from other views. | ||||
|      * @fires TimeConductor#timeOfInterest | ||||
|      * @param newTOI | ||||
|      * @returns {number} the current time of interest | ||||
|      */ | ||||
|     TimeConductor.prototype.timeOfInterest = function (newTOI) { | ||||
|         if (arguments.length > 0) { | ||||
|             this.toi = newTOI; | ||||
|             /** | ||||
|              * @event TimeConductor#timeOfInterest The Time of Interest has moved. | ||||
|              * @property {number} Current time of interest | ||||
|              */ | ||||
|             this.emit('timeOfInterest', this.toi); | ||||
|         } | ||||
|         return this.toi; | ||||
|     }; | ||||
|  | ||||
|     return TimeConductor; | ||||
| }); | ||||
							
								
								
									
										205
									
								
								platform/features/conductor-v2/src/TimeConductorController.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										205
									
								
								platform/features/conductor-v2/src/TimeConductorController.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,205 @@ | ||||
| /***************************************************************************** | ||||
|  * Open MCT Web, Copyright (c) 2014-2015, United States Government | ||||
|  * as represented by the Administrator of the National Aeronautics and Space | ||||
|  * Administration. All rights reserved. | ||||
|  * | ||||
|  * Open MCT Web is licensed under the Apache License, Version 2.0 (the | ||||
|  * "License"); you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0. | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
|  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
|  * License for the specific language governing permissions and limitations | ||||
|  * under the License. | ||||
|  * | ||||
|  * Open MCT Web includes source code licensed under additional open source | ||||
|  * licenses. See the Open Source Licenses file (LICENSES.md) included with | ||||
|  * this source code distribution or the Licensing information page available | ||||
|  * at runtime from the About dialog for additional information. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| define( | ||||
|     [], | ||||
|     function () { | ||||
|  | ||||
|         var FIFTEEN_MINUTES = 15 * 60 * 1000; | ||||
|  | ||||
|         function TimeConductorController($scope, $timeout, conductor) { | ||||
|             var self = this; | ||||
|  | ||||
|             this.$scope = $scope; | ||||
|             this.$timeout = $timeout; | ||||
|             this.conductor = conductor; | ||||
|             this.startDelta = FIFTEEN_MINUTES; | ||||
|             this.endDelta = 0; | ||||
|  | ||||
|             this.changing = { | ||||
|                 'start': false, | ||||
|                 'end': false | ||||
|             }; | ||||
|  | ||||
|             $scope.formModel = { | ||||
|                 startDelta: this.startDelta, | ||||
|                 endDelta: this.endDelta | ||||
|             }; | ||||
|  | ||||
|             conductor.on('bounds', function (bounds) { | ||||
|                 if (!self.changing['start']) { | ||||
|                     $scope.formModel.start = bounds.start; | ||||
|                 } | ||||
|                 if (!self.changing['end']) { | ||||
|                     $scope.formModel.end = bounds.end; | ||||
|                 } | ||||
|             }); | ||||
|  | ||||
|             conductor.on('follow', function (follow){ | ||||
|                 $scope.followMode = follow; | ||||
|             }); | ||||
|  | ||||
|             Object.keys(TimeConductorController.prototype).filter(function (key) { | ||||
|                 return typeof TimeConductorController.prototype[key] === 'function'; | ||||
|             }).forEach(function (key) { | ||||
|                 self[key] = self[key].bind(self); | ||||
|             }); | ||||
|  | ||||
|             $scope.$watch('modeModel.selected', this.switchMode); | ||||
|  | ||||
|             $scope.modeModel = { | ||||
|                 selected: 'fixed', | ||||
|                 options: { | ||||
|                     'fixed': { | ||||
|                         glyph: '\ue604', | ||||
|                         label: 'Fixed', | ||||
|                         name: 'Fixed Timespan Mode', | ||||
|                         description: 'Query and explore data that falls between two fixed datetimes.' | ||||
|                     }, | ||||
|                     'realtime': { | ||||
|                         glyph: '\u0043', | ||||
|                         label: 'Real-time', | ||||
|                         name: 'Real-time Mode', | ||||
|                         description: 'Monitor real-time streaming data as it comes in. The Time Conductor and displays will automatically advance themselves based on a UTC clock.' | ||||
|                     }, | ||||
|                     'latest': { | ||||
|                         glyph: '\u0044', | ||||
|                         label: 'LAD', | ||||
|                         name: 'LAD Mode', | ||||
|                         description: 'Latest Available Data mode monitors real-time streaming data as it comes in. The Time Conductor and displays will only advance when data becomes available.' | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             $scope.$on('$destroy', function() { | ||||
|                 if (self.mode) { | ||||
|                     self.mode(); | ||||
|                 } | ||||
|             }); | ||||
|  | ||||
|             self.initialize(); | ||||
|         } | ||||
|  | ||||
|         TimeConductorController.prototype.initialize = function () { | ||||
|             var now = Math.ceil(Date.now() / 1000) * 1000; | ||||
|             //Set the time conductor to some default | ||||
|             this.conductor.bounds({start: now - FIFTEEN_MINUTES, end: now}); | ||||
|  | ||||
|             this.$scope.modeModel.selected = 'fixed'; | ||||
|             this.conductor.follow(false); | ||||
|         }; | ||||
|  | ||||
|         TimeConductorController.prototype.validateStart = function (start) { | ||||
|             var bounds = this.conductor.bounds(); | ||||
|             return this.conductor.validateBounds({start: start, end: bounds.end}) === true; | ||||
|         }; | ||||
|  | ||||
|         TimeConductorController.prototype.validateEnd = function (end) { | ||||
|             var bounds = this.conductor.bounds(); | ||||
|             return this.conductor.validateBounds({start: bounds.start, end: end}) === true; | ||||
|         }; | ||||
|  | ||||
|         TimeConductorController.prototype.updateBoundsFromForm = function (formModel) { | ||||
|             var newBounds = {start: formModel.start, end: formModel.end}; | ||||
|  | ||||
|             if (this.conductor.validateBounds(newBounds) === true) { | ||||
|                 this.conductor.bounds(newBounds); | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         TimeConductorController.prototype.validateStartDelta = function (startDelta) { | ||||
|             return startDelta > 0; | ||||
|         }; | ||||
|  | ||||
|         TimeConductorController.prototype.validateEndDelta = function (endDelta) { | ||||
|             return endDelta >= 0; | ||||
|         }; | ||||
|  | ||||
|         TimeConductorController.prototype.validateDeltas = function (formModel) { | ||||
|             // Validate that start Delta is some non-zero value, and that end | ||||
|             // delta is zero or positive (ie. 'now' or some time in the future). | ||||
|             return this.validateStartDelta(formModel.startDelta) && this.validateEndDelta(formModel.endDelta); | ||||
|         }; | ||||
|  | ||||
|         TimeConductorController.prototype.updateDeltasFromForm = function (formModel) { | ||||
|  | ||||
|             if (this.validateDeltas(formModel)) { | ||||
|                 //Calculate the previous 'true' end value (without delta) | ||||
|                 var oldEnd = this.conductor.bounds().end - this.endDelta || 0; | ||||
|  | ||||
|                 this.startDelta = formModel.startDelta; | ||||
|                 this.endDelta = formModel.endDelta; | ||||
|  | ||||
|                 var newBounds = { | ||||
|                     start: oldEnd - this.startDelta, | ||||
|                     end: oldEnd + this.endDelta | ||||
|                 }; | ||||
|  | ||||
|                 this.conductor.bounds(newBounds); | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         TimeConductorController.prototype.switchMode = function (newMode) { | ||||
|             if (this.mode) { | ||||
|                 this.mode(); | ||||
|             } | ||||
|             this.mode = TimeConductorController.modes[newMode].call(this); | ||||
|         }; | ||||
|  | ||||
|         TimeConductorController.modes = { | ||||
|             'fixed': function () { | ||||
|                 this.conductor.follow(false); | ||||
|             }, | ||||
|             'realtime': function () { | ||||
|                 var tickInterval = 1000; | ||||
|                 var conductor = this.conductor; | ||||
|                 var $timeout = this.$timeout; | ||||
|                 var self = this; | ||||
|  | ||||
|                 conductor.follow(true); | ||||
|                 setBoundsToNow(self.startDelta, self.endDelta); | ||||
|  | ||||
|                 var timeoutPromise = $timeout(tick, tickInterval); | ||||
|  | ||||
|                 function setBoundsToNow(startDelta, endDelta) { | ||||
|                     var now = Math.ceil(Date.now() / 1000) * 1000; | ||||
|                     conductor.bounds({start: now - startDelta, end: now + endDelta}); | ||||
|                 } | ||||
|  | ||||
|                 function tick() { | ||||
|                     setBoundsToNow(self.startDelta, self.endDelta); | ||||
|                     timeoutPromise = $timeout(tick, tickInterval) | ||||
|                 } | ||||
|  | ||||
|                 return function destroy() { | ||||
|                     $timeout.cancel(timeoutPromise); | ||||
|                 } | ||||
|             }, | ||||
|             'latest': function () { | ||||
|                 //Don't know what to do here yet... | ||||
|                 this.conductor.follow(true); | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         return TimeConductorController; | ||||
|     } | ||||
| ); | ||||
							
								
								
									
										110
									
								
								platform/features/conductor-v2/src/TimeConductorSpec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								platform/features/conductor-v2/src/TimeConductorSpec.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,110 @@ | ||||
| /***************************************************************************** | ||||
|  * Open MCT Web, Copyright (c) 2014-2015, United States Government | ||||
|  * as represented by the Administrator of the National Aeronautics and Space | ||||
|  * Administration. All rights reserved. | ||||
|  * | ||||
|  * Open MCT Web is licensed under the Apache License, Version 2.0 (the | ||||
|  * "License"); you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0. | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
|  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
|  * License for the specific language governing permissions and limitations | ||||
|  * under the License. | ||||
|  * | ||||
|  * Open MCT Web includes source code licensed under additional open source | ||||
|  * licenses. See the Open Source Licenses file (LICENSES.md) included with | ||||
|  * this source code distribution or the Licensing information page available | ||||
|  * at runtime from the About dialog for additional information. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| define(['./TimeConductor'], function (TimeConductor) { | ||||
|     describe("The Time Conductor", function () { | ||||
|         var tc, | ||||
|             timeSystem, | ||||
|             bounds, | ||||
|             eventListener, | ||||
|             toi, | ||||
|             follow; | ||||
|  | ||||
|         beforeEach(function () { | ||||
|             tc = new TimeConductor(); | ||||
|             timeSystem = {}; | ||||
|             bounds = {start: 0, end: 0}; | ||||
|             eventListener = jasmine.createSpy("eventListener"); | ||||
|             toi = 111; | ||||
|             follow = true; | ||||
|         }); | ||||
|  | ||||
|         it("Supports setting and querying of time of interest and and follow mode", function () { | ||||
|             expect(tc.timeOfInterest()).not.toBe(toi); | ||||
|             tc.timeOfInterest(toi); | ||||
|             expect(tc.timeOfInterest()).toBe(toi); | ||||
|  | ||||
|             expect(tc.follow()).not.toBe(follow); | ||||
|             tc.follow(follow); | ||||
|             expect(tc.follow()).toBe(follow); | ||||
|         }); | ||||
|  | ||||
|         it("Allows setting of valid bounds", function () { | ||||
|             bounds = {start: 0, end: 1}; | ||||
|             expect(tc.bounds()).not.toBe(bounds); | ||||
|             expect(tc.bounds.bind(tc, bounds)).not.toThrow(); | ||||
|             expect(tc.bounds()).toBe(bounds); | ||||
|         }); | ||||
|  | ||||
|         it("Disallows setting of invalid bounds", function () { | ||||
|             bounds = {start: 1, end: 0}; | ||||
|             expect(tc.bounds()).not.toBe(bounds); | ||||
|             expect(tc.bounds.bind(tc, bounds)).toThrow(); | ||||
|             expect(tc.bounds()).not.toBe(bounds); | ||||
|  | ||||
|             bounds = {start: 1}; | ||||
|             expect(tc.bounds()).not.toBe(bounds); | ||||
|             expect(tc.bounds.bind(tc, bounds)).toThrow(); | ||||
|             expect(tc.bounds()).not.toBe(bounds); | ||||
|         }); | ||||
|  | ||||
|         it("Allows setting of time system with bounds", function () { | ||||
|             expect(tc.timeSystem()).not.toBe(timeSystem); | ||||
|             expect(tc.timeSystem.bind(tc, timeSystem, bounds)).not.toThrow(); | ||||
|             expect(tc.timeSystem()).toBe(timeSystem); | ||||
|         }); | ||||
|  | ||||
|         it("Disallows setting of time system without bounds", function () { | ||||
|             expect(tc.timeSystem()).not.toBe(timeSystem); | ||||
|             expect(tc.timeSystem.bind(tc, timeSystem)).toThrow(); | ||||
|             expect(tc.timeSystem()).not.toBe(timeSystem); | ||||
|         }); | ||||
|  | ||||
|         it("Emits an event when time system changes", function () { | ||||
|             expect(eventListener).not.toHaveBeenCalled(); | ||||
|             tc.on("timeSystem", eventListener); | ||||
|             tc.timeSystem(timeSystem, bounds); | ||||
|             expect(eventListener).toHaveBeenCalledWith(timeSystem); | ||||
|         }); | ||||
|  | ||||
|         it("Emits an event when time of interest changes", function () { | ||||
|             expect(eventListener).not.toHaveBeenCalled(); | ||||
|             tc.on("timeOfInterest", eventListener); | ||||
|             tc.timeOfInterest(toi); | ||||
|             expect(eventListener).toHaveBeenCalledWith(toi); | ||||
|         }); | ||||
|  | ||||
|         it("Emits an event when bounds change", function () { | ||||
|             expect(eventListener).not.toHaveBeenCalled(); | ||||
|             tc.on("bounds", eventListener); | ||||
|             tc.bounds(bounds); | ||||
|             expect(eventListener).toHaveBeenCalledWith(bounds); | ||||
|         }); | ||||
|  | ||||
|         it("Emits an event when follow mode changes", function () { | ||||
|             expect(eventListener).not.toHaveBeenCalled(); | ||||
|             tc.on("follow", eventListener); | ||||
|             tc.follow(follow); | ||||
|             expect(eventListener).toHaveBeenCalledWith(follow); | ||||
|         }); | ||||
|     }); | ||||
| }); | ||||
| @@ -71,6 +71,9 @@ define( | ||||
|                     // Allow controls to trigger blur-like events | ||||
|                     ngBlur: "&", | ||||
|  | ||||
|                     // Allow controls to trigger blur-like events | ||||
|                     ngMouseup: "&", | ||||
|  | ||||
|                     // The state of the form value itself | ||||
|                     ngModel: "=", | ||||
|  | ||||
|   | ||||
| @@ -48,13 +48,14 @@ requirejs.config({ | ||||
|         "angular-route": "bower_components/angular-route/angular-route.min", | ||||
|         "csv": "bower_components/comma-separated-values/csv.min", | ||||
|         "es6-promise": "bower_components/es6-promise/promise.min", | ||||
|         "EventEmitter": "bower_components/eventemitter3/index", | ||||
|         "moment": "bower_components/moment/moment", | ||||
|         "moment-duration-format": "bower_components/moment-duration-format/lib/moment-duration-format", | ||||
|         "saveAs": "bower_components/FileSaver.js/FileSaver.min", | ||||
|         "screenfull": "bower_components/screenfull/dist/screenfull.min", | ||||
|         "text": "bower_components/text/text", | ||||
|         "uuid": "bower_components/node-uuid/uuid", | ||||
|         "zepto": "bower_components/zepto/zepto.min" | ||||
|         "zepto": "bower_components/zepto/zepto.min", | ||||
|     }, | ||||
|  | ||||
|     "shim": { | ||||
| @@ -64,6 +65,9 @@ requirejs.config({ | ||||
|         "angular-route": { | ||||
|             "deps": [ "angular" ] | ||||
|         }, | ||||
|         "EventEmitter": { | ||||
|             "exports": "EventEmitter" | ||||
|         }, | ||||
|         "moment-duration-format": { | ||||
|             "deps": [ "moment" ] | ||||
|         }, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user