PageRenderTime 1251ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/src/com/panozona/player/manager/Manager.as

http://github.com/mstandio/SaladoPlayer
ActionScript | 462 lines | 386 code | 51 blank | 25 comment | 84 complexity | 96d2aae2bf3946c642fd9c780f33f37c MD5 | raw file
Possible License(s): LGPL-3.0
  1. /*
  2. Copyright 2012 Marek Standio.
  3. This file is part of SaladoPlayer.
  4. SaladoPlayer is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published
  6. by the Free Software Foundation, either version 3 of the License,
  7. or (at your option) any later version.
  8. SaladoPlayer is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty
  10. of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. See the GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with SaladoPlayer. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. package com.panozona.player.manager {
  16. import com.panosalado.controller.SimpleTransition;
  17. import com.panosalado.core.PanoSalado;
  18. import com.panosalado.events.AutorotationEvent;
  19. import com.panosalado.events.PanoSaladoEvent;
  20. import com.panosalado.model.AutorotationCameraData;
  21. import com.panosalado.view.Hotspot;
  22. import com.panosalado.view.ManagedChild;
  23. import com.panozona.player.manager.data.actions.ActionData;
  24. import com.panozona.player.manager.data.actions.FunctionData;
  25. import com.panozona.player.manager.data.ManagerData;
  26. import com.panozona.player.manager.data.panoramas.HotspotData;
  27. import com.panozona.player.manager.data.panoramas.HotspotDataSwf;
  28. import com.panozona.player.manager.data.panoramas.PanoramaData;
  29. import com.panozona.player.manager.events.LoadLoadableEvent;
  30. import com.panozona.player.manager.events.PanoramaEvent;
  31. import com.panozona.player.manager.utils.loading.LoadablesLoader;
  32. import com.panozona.player.manager.utils.Trace;
  33. import com.panozona.player.module.utils.ModuleDescription;
  34. import com.panozona.player.SaladoPlayer;
  35. import flash.display.BlendMode;
  36. import flash.display.Sprite;
  37. import flash.events.Event;
  38. import flash.events.MouseEvent;
  39. import flash.events.TimerEvent;
  40. import flash.geom.Matrix3D;
  41. import flash.geom.Vector3D;
  42. import flash.utils.Dictionary;
  43. import flash.utils.Timer;
  44. public class Manager extends PanoSalado{
  45. public const description:ModuleDescription = new ModuleDescription("SaladoPlayer", "1.3.5", "http://openpano.org/links/saladoplayer/");
  46. /**
  47. * Dictionary, where key is hotspotData object
  48. * and value is loaded hotspot (DisplayObject)
  49. */
  50. public var hotspots:Dictionary;
  51. protected var panoramaIsMoving:Boolean;
  52. protected var pendingActionId:String;
  53. protected var panoramaLoadingCanceled:Boolean;
  54. protected var _managerData:ManagerData;
  55. protected var _saladoPlayer:SaladoPlayer; // parent needed to access loaded modules
  56. protected var _currentPanoramaData:PanoramaData;
  57. protected var _previousPanoramaData:PanoramaData;
  58. protected var arrListeners:Array; // hold hotspots mouse event listeners so that they can be removed
  59. public function Manager() {
  60. description.addFunctionDescription("runAction", String);
  61. description.addFunctionDescription("print", String);
  62. description.addFunctionDescription("loadPano", String);
  63. description.addFunctionDescription("waitThen", Number, String);
  64. description.addFunctionDescription("moveToHotspot", String, Number);
  65. description.addFunctionDescription("moveToHotspotThen", String, Number, String);
  66. description.addFunctionDescription("moveToView", Number, Number, Number);
  67. description.addFunctionDescription("moveToViewThen", Number, Number, Number, String);
  68. description.addFunctionDescription("jumpToView", Number, Number, Number);
  69. description.addFunctionDescription("startMoving", Number, Number);
  70. description.addFunctionDescription("stopMoving");
  71. description.addFunctionDescription("advancedMoveToHotspot", String, Number, Number, Function);
  72. description.addFunctionDescription("advancedMoveToHotspotThen", String, Number, Number, Function, String);
  73. description.addFunctionDescription("advancedMoveToView", Number, Number, Number, Number, Function);
  74. description.addFunctionDescription("advancedMoveToViewThen", Number, Number, Number, Number, Function, String);
  75. description.addFunctionDescription("advancedStartMoving", Number, Number, Number, Number, Number);
  76. if (stage) stageReady();
  77. else addEventListener(Event.ADDED_TO_STAGE, stageReady);
  78. }
  79. private function stageReady(e:Event = null):void {
  80. removeEventListener(Event.ADDED_TO_STAGE, stageReady);
  81. _saladoPlayer = SaladoPlayer(this.parent);
  82. _managerData = _saladoPlayer.managerData;
  83. }
  84. public override function initialize(dependencies:Array):void {
  85. super.initialize(dependencies);
  86. for (var i:int = 0; i < dependencies.length; i++ ) {
  87. if (dependencies[i] is SimpleTransition){
  88. dependencies[i].addEventListener( Event.COMPLETE, transitionComplete, false, 0, true);
  89. }else if (dependencies[i] is AutorotationCameraData) {
  90. dependencies[i].addEventListener( AutorotationEvent.AUTOROTATION_CHANGE, onAutorotationChange, false, 0, true);
  91. }
  92. }
  93. addEventListener(Event.COMPLETE, panoramaLoaded, false, 0, true);
  94. }
  95. public function get currentPanoramaData():PanoramaData {
  96. return _currentPanoramaData
  97. }
  98. public function loadFirstPanorama():void {
  99. if (_managerData.allPanoramasData.firstPanorama != null) {
  100. loadPanoramaById(_managerData.allPanoramasData.firstPanorama);
  101. }else {
  102. if (_managerData.panoramasData != null && _managerData.panoramasData.length > 0) {
  103. loadPanoramaById(_managerData.panoramasData[0].id);
  104. }
  105. }
  106. }
  107. public function loadPanoramaById(panoramaId:String):void {
  108. var panoramaData:PanoramaData = _managerData.getPanoramaDataById(panoramaId);
  109. if (panoramaData == null || panoramaData === _currentPanoramaData) return;
  110. if (!panoramaLoadingCanceled && _currentPanoramaData != null && _currentPanoramaData.onLeaveToAttempt[panoramaData.id] != null) {
  111. panoramaLoadingCanceled = true;
  112. runAction(_currentPanoramaData.onLeaveToAttempt[panoramaData.id]);
  113. return;
  114. }
  115. panoramaLoadingCanceled = false;
  116. _previousPanoramaData = _currentPanoramaData;
  117. _currentPanoramaData = panoramaData;
  118. panoramaIsMoving = true;
  119. if(_previousPanoramaData != null){
  120. runAction(_previousPanoramaData.onLeave);
  121. runAction(_previousPanoramaData.onLeaveTo[currentPanoramaData.id]);
  122. }
  123. dispatchEvent(new PanoramaEvent(PanoramaEvent.PANORAMA_STARTED_LOADING));
  124. Trace.instance.printInfo("Loading panorama: " + panoramaData.id);
  125. if (arrListeners != null){
  126. for (var i:int = 0; i < _managedChildren.numChildren; i++ ) {
  127. for(var j:Number = 0; j < arrListeners.length; j++){
  128. if (_managedChildren.getChildAt(i).hasEventListener(arrListeners[j].type)) {
  129. if(arrListeners[j].type != MouseEvent.ROLL_OUT && arrListeners[j].type != MouseEvent.MOUSE_UP){
  130. _managedChildren.getChildAt(i).removeEventListener(arrListeners[j].type, arrListeners[j].listener);
  131. }
  132. }
  133. }
  134. }
  135. }
  136. arrListeners = new Array();
  137. _canvas.blendMode = BlendMode.LAYER;
  138. super.loadPanorama(panoramaData.params.clone());
  139. }
  140. protected function panoramaLoaded(e:Event):void {
  141. dispatchEvent(new PanoramaEvent(PanoramaEvent.PANORAMA_LOADED));
  142. if (_previousPanoramaData != null && isNaN(currentPanoramaData.params.pan)) {
  143. pan += (_previousPanoramaData.direction - currentPanoramaData.direction);
  144. }
  145. loadHotspots(currentPanoramaData);
  146. panoramaIsMoving = false;
  147. runAction(currentPanoramaData.onEnter);
  148. if (_previousPanoramaData != null ){
  149. runAction(currentPanoramaData.onEnterFrom[_previousPanoramaData.id]);
  150. }else {
  151. runAction(_managerData.allPanoramasData.firstOnEnter);
  152. onAutorotationChange();
  153. }
  154. }
  155. protected function loadHotspots(panoramaData:PanoramaData):void {
  156. hotspots = new Dictionary(true);
  157. var hotspotsLoader:LoadablesLoader = new LoadablesLoader();
  158. hotspotsLoader.addEventListener(LoadLoadableEvent.LOST, hotspotLost);
  159. hotspotsLoader.addEventListener(LoadLoadableEvent.LOADED, hotspotLoaded);
  160. hotspotsLoader.addEventListener(LoadLoadableEvent.FINISHED, hotspotsFinished);
  161. hotspotsLoader.load(panoramaData.getHotspotsLoadable());
  162. }
  163. protected function hotspotLost(event:LoadLoadableEvent):void {
  164. _saladoPlayer.traceWindow.printError("Could not load hotspot: " + event.loadable.path);
  165. }
  166. protected function hotspotLoaded(event:LoadLoadableEvent):void {
  167. var hotspot:Sprite;
  168. var hotspotData:HotspotData = (event.loadable as HotspotData);
  169. if (hotspotData is HotspotDataSwf) {
  170. if ("references" in (event.content as Object)) {
  171. try {(event.content as Object).references(_saladoPlayer, (hotspotData as HotspotDataSwf))} catch (e:Error){}
  172. }
  173. }
  174. hotspot = new Hotspot(event.content);
  175. insertHotspot(hotspot as ManagedChild, hotspotData);
  176. }
  177. protected function insertHotspot(managedChild:ManagedChild, hotspotData:HotspotData):void {
  178. managedChild.buttonMode = hotspotData.handCursor;
  179. var tmpFunction:Function;
  180. if (hotspotData.target != null) {
  181. tmpFunction = getTargetHandler(hotspotData.target);
  182. managedChild.addEventListener(MouseEvent.CLICK, tmpFunction);
  183. arrListeners.push({type:MouseEvent.CLICK, listener:tmpFunction});
  184. }
  185. if (hotspotData.mouse.onClick != null) {
  186. tmpFunction = getMouseEventHandler(hotspotData.mouse.onClick);
  187. managedChild.addEventListener(MouseEvent.CLICK, tmpFunction);
  188. arrListeners.push({type:MouseEvent.CLICK, listener:tmpFunction} );
  189. }
  190. if (hotspotData.mouse.onPress != null) {
  191. tmpFunction = getMouseEventHandler(hotspotData.mouse.onPress)
  192. managedChild.addEventListener(MouseEvent.MOUSE_DOWN, tmpFunction);
  193. arrListeners.push({type:MouseEvent.MOUSE_DOWN, listener:tmpFunction});
  194. }
  195. if (hotspotData.mouse.onRelease != null) {
  196. tmpFunction = getMouseEventHandler(hotspotData.mouse.onRelease)
  197. managedChild.addEventListener(MouseEvent.MOUSE_UP, tmpFunction, false, 0, true);
  198. arrListeners.push({type:MouseEvent.MOUSE_UP, listener:tmpFunction});
  199. }
  200. if (hotspotData.mouse.onOver != null) {
  201. tmpFunction = getMouseEventHandler(hotspotData.mouse.onOver)
  202. managedChild.addEventListener(MouseEvent.ROLL_OVER, tmpFunction);
  203. arrListeners.push({type:MouseEvent.ROLL_OVER, listener:tmpFunction});
  204. }
  205. if (hotspotData.mouse.onOut != null) {
  206. tmpFunction = getMouseEventHandler(hotspotData.mouse.onOut)
  207. managedChild.addEventListener(MouseEvent.ROLL_OUT, tmpFunction, false, 0, true);
  208. arrListeners.push({type:MouseEvent.ROLL_OUT, listener:tmpFunction});
  209. }
  210. var matrix3D:Matrix3D = new Matrix3D();
  211. matrix3D.appendScale(hotspotData.transform.scaleX, hotspotData.transform.scaleY, hotspotData.transform.scaleZ);
  212. if(!hotspotData.transform.flat){
  213. matrix3D.appendRotation(hotspotData.location.tilt, Vector3D.X_AXIS);
  214. matrix3D.appendRotation(hotspotData.location.pan, Vector3D.Y_AXIS);
  215. }else {
  216. managedChild.flat = true;
  217. }
  218. var piOver180:Number = Math.PI / 180;
  219. var pr:Number = -1 * (hotspotData.location.pan - 90) * piOver180;
  220. var tr:Number = -1 * hotspotData.location.tilt * piOver180;
  221. var xc:Number = hotspotData.location.distance * Math.cos(pr) * Math.cos(tr);
  222. var yc:Number = hotspotData.location.distance * Math.sin(tr);
  223. var zc:Number = hotspotData.location.distance * Math.sin(pr) * Math.cos(tr);
  224. matrix3D.appendTranslation(xc, yc, zc);
  225. matrix3D.prependRotation(hotspotData.transform.rotationX, Vector3D.X_AXIS);
  226. matrix3D.prependRotation(hotspotData.transform.rotationY, Vector3D.Y_AXIS);
  227. matrix3D.prependRotation(hotspotData.transform.rotationZ, Vector3D.Z_AXIS);
  228. var decomposition:Vector.<Vector3D> = matrix3D.decompose();
  229. managedChild.x = decomposition[0].x;
  230. managedChild.y = decomposition[0].y;
  231. managedChild.z = decomposition[0].z;
  232. managedChild.rotationX = decomposition[1].x;
  233. managedChild.rotationY = decomposition[1].y;
  234. managedChild.rotationZ = decomposition[1].z;
  235. managedChild.scaleX = decomposition[2].x;
  236. managedChild.scaleY = decomposition[2].y;
  237. managedChild.scaleZ = decomposition[2].z;
  238. var precedingHotspotData:HotspotData = null;
  239. for (var addedHotspotData:Object in hotspots) {
  240. if (!isNaN(addedHotspotData.location.distance) && !isNaN(hotspotData.location.distance)
  241. && addedHotspotData.location.distance < hotspotData.location.distance) {
  242. if (precedingHotspotData == null || precedingHotspotData.location.distance < addedHotspotData.location.distance){
  243. precedingHotspotData = addedHotspotData as HotspotData;
  244. }
  245. }
  246. }
  247. hotspots[hotspotData] = managedChild;
  248. if (precedingHotspotData == null) {
  249. addChild(managedChild);
  250. } else {
  251. addChildAt(managedChild, _managedChildren.getChildIndex(hotspots[precedingHotspotData]));
  252. }
  253. updateChildren(this);
  254. }
  255. private function getMouseEventHandler(id:String):Function{
  256. return function(e:MouseEvent):void {
  257. runAction(id);
  258. }
  259. }
  260. private function getTargetHandler(panoramaId:String):Function{
  261. return function(e:MouseEvent):void {
  262. loadPanoramaById(panoramaId);
  263. }
  264. }
  265. protected function hotspotsFinished(event:LoadLoadableEvent):void {
  266. event.target.removeEventListener(LoadLoadableEvent.LOST, hotspotLost);
  267. event.target.removeEventListener(LoadLoadableEvent.LOADED, hotspotLoaded);
  268. event.target.removeEventListener(LoadLoadableEvent.FINISHED, hotspotsFinished);
  269. dispatchEvent(new PanoramaEvent(PanoramaEvent.HOTSPOTS_LOADED));
  270. }
  271. protected function transitionComplete(e:Event):void {
  272. _canvas.blendMode = BlendMode.NORMAL;
  273. if (_previousPanoramaData == null) {
  274. runAction(_managerData.allPanoramasData.firstOnTransitionEnd);
  275. }else {
  276. runAction(currentPanoramaData.onTransitionEndFrom[_previousPanoramaData.id]);
  277. }
  278. runAction(currentPanoramaData.onTransitionEnd);
  279. dispatchEvent(new PanoramaEvent(PanoramaEvent.TRANSITION_ENDED));
  280. }
  281. protected function onAutorotationChange(e:Event = null):void {
  282. if (_managerData.controlData.autorotationCameraData.isAutorotating) {
  283. runAction(_managerData.allPanoramasData.onAutorotationStart);
  284. }else {
  285. runAction(_managerData.allPanoramasData.onAutorotationStop);
  286. }
  287. }
  288. protected function swingComplete(e:PanoSaladoEvent):void {
  289. removeEventListener(PanoSaladoEvent.SWING_TO_CHILD_COMPLETE, swingComplete);
  290. removeEventListener(PanoSaladoEvent.SWING_TO_COMPLETE, swingComplete);
  291. panoramaIsMoving = false;
  292. if (pendingActionId != null) {
  293. runAction(pendingActionId);
  294. }
  295. }
  296. ///////////////////////////////////////////////////////////////////////////////
  297. // Exposed functions
  298. ///////////////////////////////////////////////////////////////////////////////
  299. public function runAction(actionId:String):void {
  300. var actionData:ActionData = _managerData.getActionDataById(actionId);
  301. if (actionData == null) {
  302. if (actionId != null) Trace.instance.printWarning("Action not found: " + actionId);
  303. return;
  304. }
  305. for each(var functionData:FunctionData in actionData.functions) {
  306. try{
  307. if (functionData.owner == description.name) {
  308. if (description.functionsDescription[functionData.name] != undefined){
  309. (this[functionData.name] as Function).apply(this, functionData.args);
  310. }else {
  311. _saladoPlayer.traceWindow.printError("Unknown function: " + functionData.owner + "." + functionData.name);
  312. }
  313. }else{
  314. (_saladoPlayer.getModuleByName(functionData.owner) as Object).execute(functionData);
  315. }
  316. }catch (error:Error) {
  317. _saladoPlayer.traceWindow.printError("Could not execute " + functionData.owner + "." + functionData.name + ": " + error.message);
  318. }
  319. }
  320. }
  321. public function waitThen(time:Number, actionId:String):void {
  322. var timer:Timer = new Timer(time*1000,1);
  323. timer.addEventListener(TimerEvent.TIMER, function():void { runAction(actionId) }, false, 0, true);
  324. timer.start();
  325. }
  326. public function print(value:String):void {
  327. _saladoPlayer.traceWindow.printInfo(value);
  328. }
  329. public function loadPano(panramaId:String):void {
  330. loadPanoramaById(panramaId);
  331. }
  332. public function moveToHotspot(hotspotId:String, fieldOfView:Number):void {
  333. if (panoramaIsMoving) return;
  334. panoramaIsMoving = true;
  335. pendingActionId = null;
  336. addEventListener(PanoSaladoEvent.SWING_TO_CHILD_COMPLETE, swingComplete);
  337. swingToChild(hotspots[currentPanoramaData.hotspotDataById(hotspotId)], fieldOfView);
  338. }
  339. public function moveToHotspotThen(hotspotId:String, fieldOfView:Number, actionId:String):void {
  340. if (panoramaIsMoving) return;
  341. panoramaIsMoving = true;
  342. pendingActionId = actionId;
  343. addEventListener(PanoSaladoEvent.SWING_TO_CHILD_COMPLETE, swingComplete);
  344. swingToChild(hotspots[currentPanoramaData.hotspotDataById(hotspotId)], fieldOfView);
  345. }
  346. public function moveToView(pan:Number, tilt:Number, fieldOfView:Number):void {
  347. if (panoramaIsMoving) return;
  348. panoramaIsMoving = true;
  349. pendingActionId = null;
  350. addEventListener(PanoSaladoEvent.SWING_TO_COMPLETE, swingComplete);
  351. swingTo(pan, tilt, fieldOfView);
  352. }
  353. public function moveToViewThen(pan:Number, tilt:Number, fieldOfView:Number, actionId:String):void {
  354. if (panoramaIsMoving) return;
  355. panoramaIsMoving = true;
  356. pendingActionId = actionId;
  357. addEventListener(PanoSaladoEvent.SWING_TO_COMPLETE, swingComplete);
  358. swingTo(pan, tilt, fieldOfView);
  359. }
  360. public function jumpToView(pan:Number, tilt:Number, fieldOfView:Number):void {
  361. if (panoramaIsMoving) return;
  362. renderAt(pan, tilt, fieldOfView);
  363. }
  364. public function startMoving(panSpeed:Number, tiltSpeed:Number):void {
  365. if (panoramaIsMoving) return;
  366. panoramaIsMoving = true;
  367. startInertialSwing(panSpeed, tiltSpeed);
  368. }
  369. public function stopMoving():void {
  370. panoramaIsMoving = false;
  371. stopInertialSwing();
  372. }
  373. public function advancedMoveToHotspot(hotspotId:String, fieldOfView:Number, speed:Number, tween:Function):void {
  374. if (panoramaIsMoving) return;
  375. panoramaIsMoving = true;
  376. pendingActionId = null;
  377. addEventListener(PanoSaladoEvent.SWING_TO_CHILD_COMPLETE, swingComplete);
  378. swingToChild(hotspots[currentPanoramaData.hotspotDataById(hotspotId)], fieldOfView, speed, tween);
  379. }
  380. public function advancedMoveToHotspotThen(hotspotId:String, fieldOfView:Number, speed:Number, tween:Function, actionId:String):void {
  381. if (panoramaIsMoving) return;
  382. panoramaIsMoving = true;
  383. pendingActionId = actionId;
  384. addEventListener(PanoSaladoEvent.SWING_TO_CHILD_COMPLETE, swingComplete);
  385. swingToChild(hotspots[currentPanoramaData.hotspotDataById(hotspotId)], fieldOfView, speed, tween);
  386. }
  387. public function advancedMoveToView(pan:Number, tilt:Number, fieldOfView:Number, speed:Number, tween:Function):void {
  388. if (panoramaIsMoving) return;
  389. panoramaIsMoving = true;
  390. pendingActionId = null;
  391. addEventListener(PanoSaladoEvent.SWING_TO_COMPLETE, swingComplete);
  392. swingTo(pan, tilt, fieldOfView, speed, tween);
  393. }
  394. public function advancedMoveToViewThen(pan:Number, tilt:Number, fieldOfView:Number, speed:Number, tween:Function, actionId:String):void {
  395. if (panoramaIsMoving) return;
  396. panoramaIsMoving = true;
  397. pendingActionId = actionId;
  398. addEventListener(PanoSaladoEvent.SWING_TO_COMPLETE, swingComplete);
  399. swingTo(pan, tilt, fieldOfView, speed, tween);
  400. }
  401. public function advancedStartMoving(panSpeed:Number, tiltSpeed:Number, sensitivity:Number, friction:Number, threshold:Number):void {
  402. if (panoramaIsMoving) return;
  403. panoramaIsMoving = true;
  404. startInertialSwing(panSpeed, tiltSpeed, sensitivity, friction, threshold);
  405. }
  406. }
  407. }