VRButtonViewModel.js 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. import defaultValue from "../../Core/defaultValue.js";
  2. import defined from "../../Core/defined.js";
  3. import destroyObject from "../../Core/destroyObject.js";
  4. import DeveloperError from "../../Core/DeveloperError.js";
  5. import EventHelper from "../../Core/EventHelper.js";
  6. import Fullscreen from "../../Core/Fullscreen.js";
  7. import OrthographicFrustum from "../../Core/OrthographicFrustum.js";
  8. import knockout from "../../ThirdParty/knockout.js";
  9. import NoSleep from "../../ThirdParty/nosleep.js";
  10. import createCommand from "../createCommand.js";
  11. import getElement from "../getElement.js";
  12. function lockScreen(orientation) {
  13. let locked = false;
  14. const screen = window.screen;
  15. if (defined(screen)) {
  16. if (defined(screen.lockOrientation)) {
  17. locked = screen.lockOrientation(orientation);
  18. } else if (defined(screen.mozLockOrientation)) {
  19. locked = screen.mozLockOrientation(orientation);
  20. } else if (defined(screen.msLockOrientation)) {
  21. locked = screen.msLockOrientation(orientation);
  22. } else if (defined(screen.orientation && screen.orientation.lock)) {
  23. locked = screen.orientation.lock(orientation);
  24. }
  25. }
  26. return locked;
  27. }
  28. function unlockScreen() {
  29. const screen = window.screen;
  30. if (defined(screen)) {
  31. if (defined(screen.unlockOrientation)) {
  32. screen.unlockOrientation();
  33. } else if (defined(screen.mozUnlockOrientation)) {
  34. screen.mozUnlockOrientation();
  35. } else if (defined(screen.msUnlockOrientation)) {
  36. screen.msUnlockOrientation();
  37. } else if (defined(screen.orientation && screen.orientation.unlock)) {
  38. screen.orientation.unlock();
  39. }
  40. }
  41. }
  42. function toggleVR(viewModel, scene, isVRMode, isOrthographic) {
  43. if (isOrthographic()) {
  44. return;
  45. }
  46. if (isVRMode()) {
  47. scene.useWebVR = false;
  48. if (viewModel._locked) {
  49. unlockScreen();
  50. viewModel._locked = false;
  51. }
  52. viewModel._noSleep.disable();
  53. Fullscreen.exitFullscreen();
  54. isVRMode(false);
  55. } else {
  56. if (!Fullscreen.fullscreen) {
  57. Fullscreen.requestFullscreen(viewModel._vrElement);
  58. }
  59. viewModel._noSleep.enable();
  60. if (!viewModel._locked) {
  61. viewModel._locked = lockScreen("landscape");
  62. }
  63. scene.useWebVR = true;
  64. isVRMode(true);
  65. }
  66. }
  67. /**
  68. * The view model for {@link VRButton}.
  69. * @alias VRButtonViewModel
  70. * @constructor
  71. *
  72. * @param {Scene} scene The scene.
  73. * @param {Element|String} [vrElement=document.body] The element or id to be placed into VR mode.
  74. */
  75. function VRButtonViewModel(scene, vrElement) {
  76. //>>includeStart('debug', pragmas.debug);
  77. if (!defined(scene)) {
  78. throw new DeveloperError("scene is required.");
  79. }
  80. //>>includeEnd('debug');
  81. const that = this;
  82. const isEnabled = knockout.observable(Fullscreen.enabled);
  83. const isVRMode = knockout.observable(false);
  84. /**
  85. * Gets whether or not VR mode is active.
  86. *
  87. * @type {Boolean}
  88. */
  89. this.isVRMode = undefined;
  90. knockout.defineProperty(this, "isVRMode", {
  91. get: function () {
  92. return isVRMode();
  93. },
  94. });
  95. /**
  96. * Gets or sets whether or not VR functionality should be enabled.
  97. *
  98. * @type {Boolean}
  99. * @see Fullscreen.enabled
  100. */
  101. this.isVREnabled = undefined;
  102. knockout.defineProperty(this, "isVREnabled", {
  103. get: function () {
  104. return isEnabled();
  105. },
  106. set: function (value) {
  107. isEnabled(value && Fullscreen.enabled);
  108. },
  109. });
  110. /**
  111. * Gets the tooltip. This property is observable.
  112. *
  113. * @type {String}
  114. */
  115. this.tooltip = undefined;
  116. knockout.defineProperty(this, "tooltip", function () {
  117. if (!isEnabled()) {
  118. return "VR mode is unavailable";
  119. }
  120. return isVRMode() ? "Exit VR mode" : "Enter VR mode";
  121. });
  122. const isOrthographic = knockout.observable(false);
  123. this._isOrthographic = undefined;
  124. knockout.defineProperty(this, "_isOrthographic", {
  125. get: function () {
  126. return isOrthographic();
  127. },
  128. });
  129. this._eventHelper = new EventHelper();
  130. this._eventHelper.add(scene.preRender, function () {
  131. isOrthographic(scene.camera.frustum instanceof OrthographicFrustum);
  132. });
  133. this._locked = false;
  134. this._noSleep = new NoSleep();
  135. this._command = createCommand(function () {
  136. toggleVR(that, scene, isVRMode, isOrthographic);
  137. }, knockout.getObservable(this, "isVREnabled"));
  138. this._vrElement = defaultValue(getElement(vrElement), document.body);
  139. this._callback = function () {
  140. if (!Fullscreen.fullscreen && isVRMode()) {
  141. scene.useWebVR = false;
  142. if (that._locked) {
  143. unlockScreen();
  144. that._locked = false;
  145. }
  146. that._noSleep.disable();
  147. isVRMode(false);
  148. }
  149. };
  150. document.addEventListener(Fullscreen.changeEventName, this._callback);
  151. }
  152. Object.defineProperties(VRButtonViewModel.prototype, {
  153. /**
  154. * Gets or sets the HTML element to place into VR mode when the
  155. * corresponding button is pressed.
  156. * @memberof VRButtonViewModel.prototype
  157. *
  158. * @type {Element}
  159. */
  160. vrElement: {
  161. //TODO:@exception {DeveloperError} value must be a valid HTML Element.
  162. get: function () {
  163. return this._vrElement;
  164. },
  165. set: function (value) {
  166. //>>includeStart('debug', pragmas.debug);
  167. if (!(value instanceof Element)) {
  168. throw new DeveloperError("value must be a valid Element.");
  169. }
  170. //>>includeEnd('debug');
  171. this._vrElement = value;
  172. },
  173. },
  174. /**
  175. * Gets the Command to toggle VR mode.
  176. * @memberof VRButtonViewModel.prototype
  177. *
  178. * @type {Command}
  179. */
  180. command: {
  181. get: function () {
  182. return this._command;
  183. },
  184. },
  185. });
  186. /**
  187. * @returns {Boolean} true if the object has been destroyed, false otherwise.
  188. */
  189. VRButtonViewModel.prototype.isDestroyed = function () {
  190. return false;
  191. };
  192. /**
  193. * Destroys the view model. Should be called to
  194. * properly clean up the view model when it is no longer needed.
  195. */
  196. VRButtonViewModel.prototype.destroy = function () {
  197. this._eventHelper.removeAll();
  198. document.removeEventListener(Fullscreen.changeEventName, this._callback);
  199. destroyObject(this);
  200. };
  201. export default VRButtonViewModel;