# Copyright 2012 United States Government, as represented by the Secretary of Defense, Under # Secretary of Defense (Personnel & Readiness). # # 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. ## The component representation of a control behavior ## ## @name control.vwf ## @namespace --- properties: controlValue: set: | if("animationTime" in this && this.positions) { for(var i=0; i this.positions[i].controlValue && value < this.positions[i+1].controlValue) { var animationRatio = (this.positions[i+1].animationTime - this.positions[i].animationTime) / (this.positions[i+1].controlValue - this.positions[i].controlValue); this.animationTime = value * animationRatio; } } } if(value !== this.controlValue) { this.controlValue = value; this.controlValueUpdated(); } value: 0 controlScale: 1 controlDirection: set: | switch(value) { case 1: case -1: this.direction = value; break; } value: 1 controlPlaying: false controlMomentary: false linkedControls: [] initialTransform: controlDisabled: false animationRate: 1 methods: mouseInit: animateControlToPosition: parameters: - position controlTick: processLinkedControls: events: controlValueUpdated: pointerDown: pointerMove: pointerUp: scripts: - | this.initialize = function() { // Locate child nodes that extend or implement "http://vwf.example.com/control/position.vwf" // to identify themselves as control key positions. this.positions = this.find( "./element(*,'http://vwf.example.com/control/position.vwf')" ); // Fill in missing `controlValue` properties, distributing evenly between the left and right // positions that define `controlValue`. // 1: [ - ] => [ 0 ] // 1: [ 0, - ] => [ 0, 1 ] // 1: [ -, 1 ] => [ 0, 1 ] // 1: [ 0, -, - ] => [ 0, 1/2, 1 ] // 1: [ -, -, 1 ] => [ 0, 1/2, 1 ] // 1: [ 0, - , -, 1 ] => [ 0, 1/3 , 2/3, 1 ] var leftValue, leftIndex; var rightValue, rightIndex = -Infinity; if ( this.positions.length > 0 ) { this.positions.sort(function(a, b) { return a.sequence - b.sequence; }); if ( this.positions[0].controlValue === null ) { this.positions[0].controlValue = 0; } if ( this.positions[this.positions.length-1].controlValue === null ) { this.positions[this.positions.length-1].controlValue = 1; } this.positions.forEach( function( position, index ) { if ( position.controlValue !== null ) { leftValue = position.controlValue; leftIndex = index; } else { if ( index > rightIndex ) { for ( rightIndex = index + 1; rightIndex < this.positions.length; rightIndex++ ) { if ( ( rightValue = /* assignment! */ this.positions[rightIndex].controlValue ) !== null ) { break; } } } position.controlValue = leftValue + ( rightValue - leftValue ) * ( index - leftIndex ) / ( rightIndex - leftIndex ); } }, this ); } } //@ sourceURL=http://vwf.example.com/control.vwf/scripts~initialize // Sets up the mouse pointer information used for dragging. this.mouseInit = function() { this.input = { "pointerInfo": undefined, "pickInfo": undefined, "previous": { "pointerInfo": undefined, "pickInfo": undefined, }, update: function( pointerInfo, pickInfo ){ if(!this.previous.pointerInfo) { this.previous.pointerInfo = this.pointerInfo; this.previous.pickInfo = this.pickInfo; } this.pointerInfo = pointerInfo; this.pickInfo = pickInfo; }, clear: function(){ this.previous.pointerInfo = undefined; this.previous.pickInfo = undefined; this.pointerInfo = undefined; this.pickInfo = undefined; }, change: function() { var ret = [ 0, 0 ] if ( this.pointerInfo && this.previous.pointerInfo ) { ret[0] = this.pointerInfo.position[0] - this.previous.pointerInfo.position[0]; ret[1] = this.pointerInfo.position[1] - this.previous.pointerInfo.position[1]; } return ret; } }; } this.pointerDown = function( pointerInfo, pickInfo ) { if(!this.controlDisabled) { if ( !this.input ) this.mouseInit(); this.input.clear(); this.input.pointerInfo = pointerInfo; this.input.pickInfo = pickInfo; this.positions = this.find( "./element(*,'http://vwf.example.com/control/position.vwf')" ); this.positions.sort(function(a, b) { return a.sequence - b.sequence; }); if(this.controlMomentary) { this.animateControlToPosition(this.positions[this.positions.length-1]); } } } this.pointerUp = function( pointerInfo, pickInfo ) { if(!this.controlDisabled) { if(this.controlMomentary) { this.animateControlToPosition(this.positions[0]); } else { for(var i=0; i= 0 && (i + this.controlDirection) < this.positions.length)) { this.controlDirection = this.controlDirection * -1; } this.animateControlToPosition(this.positions[i + this.controlDirection]); } else if(i+1 < this.positions.length && this.controlValue > this.positions[i].controlValue && this.controlValue < this.positions[i+1].controlValue) { if(this.controlDirection == 1) { this.animateControlToPosition(this.positions[i + 1]); } else { this.animateControlToPosition(this.positions[i]); } } } else { if(i+1 < this.positions.length && this.controlValue > this.positions[i].controlValue && this.controlValue < this.positions[i+1].controlValue) { var nearPosition, farPosition; if(Math.abs((this.positions[i].controlValue - this.controlValue)) < Math.abs((this.positions[i+1].controlValue - this.controlValue))) { nearPosition = this.positions[i]; farPosition = this.positions[i+1]; } else { nearPosition = this.positions[i+1]; farPosition = this.positions[i]; } switch(nearPosition.controlType) { case 1: this.animateControlToPosition(nearPosition); break; case -1: if(farPosition.controlType != -1) { this.animateControlToPosition(farPosition); } } break; } } } } this.processLinkedControls(); this.input.clear(); } } this.pointerMove = function( pointerInfo, pickInfo ) { if( !this.controlDisabled && !this.controlMomentary ) { if ( this.positions.length ) { var minValue = this.positions[ 0 ].controlValue; var maxValue = this.positions[ this.positions.length - 1 ].controlValue; this.input.update( pointerInfo, pickInfo ); var diff = this.input.change(); if(Math.abs(diff[0]) >= Math.abs(diff[1])) { var changeBy = diff[0] * this.controlScale; if(diff[0] > 0 && this.controlValue < maxValue) { this.controlDirection = 1; if((this.controlValue + changeBy) < maxValue) { this.controlValue = this.controlValue + changeBy; } } else if(diff[0] < 0 && this.controlValue > minValue) { this.controlDirection = -1; if((this.controlValue + changeBy) > minValue) { this.controlValue = this.controlValue + changeBy; } } } else { var changeBy = diff[1] * this.controlScale; if(diff[1] > 0 && this.controlValue < maxValue) { this.controlDirection = 1; if((this.controlValue + changeBy) < maxValue) { this.controlValue = this.controlValue + changeBy; } } else if(diff[1] < 0 && this.controlValue > minValue) { this.controlDirection = -1; if((this.controlValue + changeBy) > minValue) { this.controlValue = this.controlValue + changeBy; } } } this.processLinkedControls(); this.input.previous.pointerInfo = pointerInfo; this.input.previous.pickInfo = pickInfo; } } } this.animateControlToPosition = function(position) { this.controlPlaying = true; this.controlDirection = this.controlValue < position.controlValue ? 1 : -1; this.controlTick(position); } this.controlTick = function (nextPosition) { if ( this.controlPlaying ) { if ( Math.abs(this.animationTime - nextPosition.animationTime) < goog.vec.EPSILON ) { this.controlValue = nextPosition.controlValue; if(nextPosition.controlType == -1) { for(var i=0; i= 0 && this.positions[i-1].controlType != -1) { this.controlDirection = -1; nextPosition = this.positions[i-1]; } else if(i+1 < this.positions.length && this.positions[i+1].controlType != -1) { this.controlDirection = 1; nextPosition = this.positions[i+1]; } break; } } } else { this.controlPlaying = false; } } this.processLinkedControls(); // Schedule the next tick if still playing. if ( this.controlPlaying ) { if ( Math.abs(nextPosition.animationTime - this.animationTime) > 1/60 ) { this.animationTime = this.animationTime + (1/60 * this.controlDirection * this.animationRate); this.in( 1/60 ).controlTick(nextPosition); // next interval } else { this.animationTime = nextPosition.animationTime; this.at( Math.abs(nextPosition.animationTime - this.animationTime) ).controlTick(nextPosition); // exactly at end } } } } this.processLinkedControls = function() { for(var i=0; i 0) { linkedControl[0].controlDirection = this.controlDirection; linkedControl[0].controlValue = this.controlValue; linkedControl[0].animationTime = this.animationTime; } } }