control.vwf.yaml 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. # Copyright 2012 United States Government, as represented by the Secretary of Defense, Under
  2. # Secretary of Defense (Personnel & Readiness).
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
  5. # in compliance with the License. You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software distributed under the License
  10. # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
  11. # or implied. See the License for the specific language governing permissions and limitations under
  12. # the License.
  13. ## The component representation of a control behavior
  14. ##
  15. ## @name control.vwf
  16. ## @namespace
  17. ---
  18. properties:
  19. controlValue:
  20. set: |
  21. if("animationTime" in this && this.positions) {
  22. for(var i=0; i<this.positions.length; i++) {
  23. if(value == this.positions[i].controlValue) {
  24. this.animationTime = this.positions[i].animationTime;
  25. }
  26. else if(i+1 < this.positions.length && value > this.positions[i].controlValue && value < this.positions[i+1].controlValue) {
  27. var animationRatio = (this.positions[i+1].animationTime - this.positions[i].animationTime) / (this.positions[i+1].controlValue - this.positions[i].controlValue);
  28. this.animationTime = value * animationRatio;
  29. }
  30. }
  31. }
  32. if(value !== this.controlValue) {
  33. this.controlValue = value;
  34. this.controlValueUpdated();
  35. }
  36. value: 0
  37. controlScale: 1
  38. controlDirection:
  39. set: |
  40. switch(value) {
  41. case 1:
  42. case -1:
  43. this.direction = value;
  44. break;
  45. }
  46. value: 1
  47. controlPlaying: false
  48. controlMomentary: false
  49. linkedControls: []
  50. initialTransform:
  51. controlDisabled: false
  52. animationRate: 1
  53. methods:
  54. mouseInit:
  55. animateControlToPosition:
  56. parameters:
  57. - position
  58. controlTick:
  59. processLinkedControls:
  60. events:
  61. controlValueUpdated:
  62. pointerDown:
  63. pointerMove:
  64. pointerUp:
  65. scripts:
  66. - |
  67. this.initialize = function() {
  68. // Locate child nodes that extend or implement "http://vwf.example.com/control/position.vwf"
  69. // to identify themselves as control key positions.
  70. this.positions = this.find( "./element(*,'http://vwf.example.com/control/position.vwf')" );
  71. // Fill in missing `controlValue` properties, distributing evenly between the left and right
  72. // positions that define `controlValue`.
  73. // 1: [ - ] => [ 0 ]
  74. // 1: [ 0, - ] => [ 0, 1 ]
  75. // 1: [ -, 1 ] => [ 0, 1 ]
  76. // 1: [ 0, -, - ] => [ 0, 1/2, 1 ]
  77. // 1: [ -, -, 1 ] => [ 0, 1/2, 1 ]
  78. // 1: [ 0, - , -, 1 ] => [ 0, 1/3 , 2/3, 1 ]
  79. var leftValue, leftIndex;
  80. var rightValue, rightIndex = -Infinity;
  81. if ( this.positions.length > 0 ) {
  82. this.positions.sort(function(a, b) {
  83. return a.sequence - b.sequence;
  84. });
  85. if ( this.positions[0].controlValue === null ) {
  86. this.positions[0].controlValue = 0;
  87. }
  88. if ( this.positions[this.positions.length-1].controlValue === null ) {
  89. this.positions[this.positions.length-1].controlValue = 1;
  90. }
  91. this.positions.forEach( function( position, index ) {
  92. if ( position.controlValue !== null ) {
  93. leftValue = position.controlValue;
  94. leftIndex = index;
  95. } else {
  96. if ( index > rightIndex ) {
  97. for ( rightIndex = index + 1; rightIndex < this.positions.length; rightIndex++ ) {
  98. if ( ( rightValue = /* assignment! */ this.positions[rightIndex].controlValue ) !== null ) {
  99. break;
  100. }
  101. }
  102. }
  103. position.controlValue = leftValue + ( rightValue - leftValue ) *
  104. ( index - leftIndex ) / ( rightIndex - leftIndex );
  105. }
  106. }, this );
  107. }
  108. } //@ sourceURL=http://vwf.example.com/control.vwf/scripts~initialize
  109. // Sets up the mouse pointer information used for dragging.
  110. this.mouseInit = function() {
  111. this.input = {
  112. "pointerInfo": undefined,
  113. "pickInfo": undefined,
  114. "previous": {
  115. "pointerInfo": undefined,
  116. "pickInfo": undefined,
  117. },
  118. update: function( pointerInfo, pickInfo ){
  119. if(!this.previous.pointerInfo) {
  120. this.previous.pointerInfo = this.pointerInfo;
  121. this.previous.pickInfo = this.pickInfo;
  122. }
  123. this.pointerInfo = pointerInfo;
  124. this.pickInfo = pickInfo;
  125. },
  126. clear: function(){
  127. this.previous.pointerInfo = undefined;
  128. this.previous.pickInfo = undefined;
  129. this.pointerInfo = undefined;
  130. this.pickInfo = undefined;
  131. },
  132. change: function() {
  133. var ret = [ 0, 0 ]
  134. if ( this.pointerInfo && this.previous.pointerInfo ) {
  135. ret[0] = this.pointerInfo.position[0] - this.previous.pointerInfo.position[0];
  136. ret[1] = this.pointerInfo.position[1] - this.previous.pointerInfo.position[1];
  137. }
  138. return ret;
  139. }
  140. };
  141. }
  142. this.pointerDown = function( pointerInfo, pickInfo ) {
  143. if(!this.controlDisabled) {
  144. if ( !this.input ) this.mouseInit();
  145. this.input.clear();
  146. this.input.pointerInfo = pointerInfo;
  147. this.input.pickInfo = pickInfo;
  148. this.positions = this.find( "./element(*,'http://vwf.example.com/control/position.vwf')" );
  149. this.positions.sort(function(a, b) {
  150. return a.sequence - b.sequence;
  151. });
  152. if(this.controlMomentary) {
  153. this.animateControlToPosition(this.positions[this.positions.length-1]);
  154. }
  155. }
  156. }
  157. this.pointerUp = function( pointerInfo, pickInfo ) {
  158. if(!this.controlDisabled) {
  159. if(this.controlMomentary) {
  160. this.animateControlToPosition(this.positions[0]);
  161. }
  162. else {
  163. for(var i=0; i<this.positions.length; i++) {
  164. if(this.input.previous.pointerInfo == undefined) {
  165. if(this.controlValue == this.positions[i].controlValue) {
  166. if(!((i + this.controlDirection) >= 0 && (i + this.controlDirection) < this.positions.length)) {
  167. this.controlDirection = this.controlDirection * -1;
  168. }
  169. this.animateControlToPosition(this.positions[i + this.controlDirection]);
  170. }
  171. else if(i+1 < this.positions.length && this.controlValue > this.positions[i].controlValue && this.controlValue < this.positions[i+1].controlValue) {
  172. if(this.controlDirection == 1) {
  173. this.animateControlToPosition(this.positions[i + 1]);
  174. }
  175. else {
  176. this.animateControlToPosition(this.positions[i]);
  177. }
  178. }
  179. }
  180. else {
  181. if(i+1 < this.positions.length && this.controlValue > this.positions[i].controlValue && this.controlValue < this.positions[i+1].controlValue) {
  182. var nearPosition, farPosition;
  183. if(Math.abs((this.positions[i].controlValue - this.controlValue)) < Math.abs((this.positions[i+1].controlValue - this.controlValue))) {
  184. nearPosition = this.positions[i];
  185. farPosition = this.positions[i+1];
  186. }
  187. else {
  188. nearPosition = this.positions[i+1];
  189. farPosition = this.positions[i];
  190. }
  191. switch(nearPosition.controlType) {
  192. case 1:
  193. this.animateControlToPosition(nearPosition);
  194. break;
  195. case -1:
  196. if(farPosition.controlType != -1) {
  197. this.animateControlToPosition(farPosition);
  198. }
  199. }
  200. break;
  201. }
  202. }
  203. }
  204. }
  205. this.processLinkedControls();
  206. this.input.clear();
  207. }
  208. }
  209. this.pointerMove = function( pointerInfo, pickInfo ) {
  210. if( !this.controlDisabled && !this.controlMomentary ) {
  211. if ( this.positions.length ) {
  212. var minValue = this.positions[ 0 ].controlValue;
  213. var maxValue = this.positions[ this.positions.length - 1 ].controlValue;
  214. this.input.update( pointerInfo, pickInfo );
  215. var diff = this.input.change();
  216. if(Math.abs(diff[0]) >= Math.abs(diff[1])) {
  217. var changeBy = diff[0] * this.controlScale;
  218. if(diff[0] > 0 && this.controlValue < maxValue) {
  219. this.controlDirection = 1;
  220. if((this.controlValue + changeBy) < maxValue) {
  221. this.controlValue = this.controlValue + changeBy;
  222. }
  223. }
  224. else if(diff[0] < 0 && this.controlValue > minValue) {
  225. this.controlDirection = -1;
  226. if((this.controlValue + changeBy) > minValue) {
  227. this.controlValue = this.controlValue + changeBy;
  228. }
  229. }
  230. }
  231. else {
  232. var changeBy = diff[1] * this.controlScale;
  233. if(diff[1] > 0 && this.controlValue < maxValue) {
  234. this.controlDirection = 1;
  235. if((this.controlValue + changeBy) < maxValue) {
  236. this.controlValue = this.controlValue + changeBy;
  237. }
  238. }
  239. else if(diff[1] < 0 && this.controlValue > minValue) {
  240. this.controlDirection = -1;
  241. if((this.controlValue + changeBy) > minValue) {
  242. this.controlValue = this.controlValue + changeBy;
  243. }
  244. }
  245. }
  246. this.processLinkedControls();
  247. this.input.previous.pointerInfo = pointerInfo;
  248. this.input.previous.pickInfo = pickInfo;
  249. }
  250. }
  251. }
  252. this.animateControlToPosition = function(position) {
  253. this.controlPlaying = true;
  254. this.controlDirection = this.controlValue < position.controlValue ? 1 : -1;
  255. this.controlTick(position);
  256. }
  257. this.controlTick = function (nextPosition) {
  258. if ( this.controlPlaying ) {
  259. if ( Math.abs(this.animationTime - nextPosition.animationTime) < goog.vec.EPSILON ) {
  260. this.controlValue = nextPosition.controlValue;
  261. if(nextPosition.controlType == -1) {
  262. for(var i=0; i<this.positions.length; i++) {
  263. if(this.positions[i].controlValue == nextPosition.controlValue) {
  264. if(i-1 >= 0 && this.positions[i-1].controlType != -1) {
  265. this.controlDirection = -1;
  266. nextPosition = this.positions[i-1];
  267. }
  268. else if(i+1 < this.positions.length && this.positions[i+1].controlType != -1) {
  269. this.controlDirection = 1;
  270. nextPosition = this.positions[i+1];
  271. }
  272. break;
  273. }
  274. }
  275. }
  276. else {
  277. this.controlPlaying = false;
  278. }
  279. }
  280. this.processLinkedControls();
  281. // Schedule the next tick if still playing.
  282. if ( this.controlPlaying ) {
  283. if ( Math.abs(nextPosition.animationTime - this.animationTime) > 1/60 ) {
  284. this.animationTime = this.animationTime + (1/60 * this.controlDirection * this.animationRate);
  285. this.in( 1/60 ).controlTick(nextPosition); // next interval
  286. } else {
  287. this.animationTime = nextPosition.animationTime;
  288. this.at( Math.abs(nextPosition.animationTime - this.animationTime) ).controlTick(nextPosition); // exactly at end
  289. }
  290. }
  291. }
  292. }
  293. this.processLinkedControls = function() {
  294. for(var i=0; i<this.linkedControls.length; i++) {
  295. var linkedControl = this.find("//" + this.linkedControls[i]);
  296. if(linkedControl.length > 0) {
  297. linkedControl[0].controlDirection = this.controlDirection;
  298. linkedControl[0].controlValue = this.controlValue;
  299. linkedControl[0].animationTime = this.animationTime;
  300. }
  301. }
  302. }