/home/lindsay/xeolabs/xeogl-next/xeogl/src/canvas/spinner.js
API Docs for:

File: /home/lindsay/xeolabs/xeogl-next/xeogl/src/canvas/spinner.js

  1. /**
  2. A Progress displays a progress animation at the center of its {{#crossLink "Canvas"}}{{/crossLink}} while things are loading or otherwise busy.
  3.  
  4. ## Overview
  5.  
  6. * Spinners are normally shown by {{#crossLink "Model"}}Models{{/crossLink}} while they are loading, however they may also
  7. be shown by any application code that wants to indicate busyness.
  8. * By default, they are also shown by components that load assets, such as {{#crossLink "Texture"}}{{/crossLink}}. You
  9. can disable that by flipping the Spinner's {{#crossLink "Spinner/textures:property"}}{{/crossLink}} property.
  10. * A Spinner component has a {{#crossLink "Spinner/processes:property"}}{{/crossLink}} count that indicates how many
  11. active processes it currently represents. As a process starts, a process would increment {{#crossLink "Spinner/processes:property"}}{{/crossLink}}, then as it
  12. completes (or fails), would decrement it again.
  13. * A Spinner is only visible while {{#crossLink "Spinner/processes:property"}}{{/crossLink}} is greater than zero.
  14.  
  15. ## Examples
  16.  
  17. * [Loading glTF model with spinner](../../examples/#importing_gltf_GearboxAssy)
  18.  
  19. ## Usage
  20.  
  21. ````javascript
  22. var spinner = myScene.canvas.spinner;
  23.  
  24. // Increment count of busy processes represented by the spinner;
  25. // assuming the count was zero, this now shows the spinner
  26. spinner.processes++;
  27.  
  28. // Increment the count again, by some other process;
  29. // spinner already visible, now requires two decrements
  30. // before it becomes invisible again
  31. spinner.processes++;
  32.  
  33. // Decrement the count; count still greater
  34. // than zero, so spinner remains visible
  35. spinner.process--;
  36.  
  37. // Decrement the count; count now zero,
  38. // so spinner becomes invisible
  39. spinner.process--;
  40. ````
  41.  
  42. By default, a Spinner shows while resources are loading for components like
  43. {{#crossLink "Texture"}}{{/crossLink}}. We can disable that like this:
  44.  
  45. ````javascript
  46. // Don't show while resources are loading for Textures etc.
  47. spinner.textures = false;
  48. ````
  49.  
  50. @class Spinner
  51. @module xeogl
  52. @submodule canvas
  53. @extends Component
  54. */
  55.  
  56. import {Component} from '../component.js';
  57.  
  58. const type = "xeogl.Spinner";
  59.  
  60. let spinnerCSSInjected = false; // Ensures lazy-injected CSS only injected once
  61.  
  62. const spinnerCSS = ".sk-fading-circle {\
  63. background: transparent;\
  64. margin: 20px auto;\
  65. width: 50px;\
  66. height:50px;\
  67. position: relative;\
  68. }\
  69. .sk-fading-circle .sk-circle {\
  70. width: 120%;\
  71. height: 120%;\
  72. position: absolute;\
  73. left: 0;\
  74. top: 0;\
  75. }\
  76. .sk-fading-circle .sk-circle:before {\
  77. content: '';\
  78. display: block;\
  79. margin: 0 auto;\
  80. width: 15%;\
  81. height: 15%;\
  82. background-color: #ff8800;\
  83. border-radius: 100%;\
  84. -webkit-animation: sk-circleFadeDelay 1.2s infinite ease-in-out both;\
  85. animation: sk-circleFadeDelay 1.2s infinite ease-in-out both;\
  86. }\
  87. .sk-fading-circle .sk-circle2 {\
  88. -webkit-transform: rotate(30deg);\
  89. -ms-transform: rotate(30deg);\
  90. transform: rotate(30deg);\
  91. }\
  92. .sk-fading-circle .sk-circle3 {\
  93. -webkit-transform: rotate(60deg);\
  94. -ms-transform: rotate(60deg);\
  95. transform: rotate(60deg);\
  96. }\
  97. .sk-fading-circle .sk-circle4 {\
  98. -webkit-transform: rotate(90deg);\
  99. -ms-transform: rotate(90deg);\
  100. transform: rotate(90deg);\
  101. }\
  102. .sk-fading-circle .sk-circle5 {\
  103. -webkit-transform: rotate(120deg);\
  104. -ms-transform: rotate(120deg);\
  105. transform: rotate(120deg);\
  106. }\
  107. .sk-fading-circle .sk-circle6 {\
  108. -webkit-transform: rotate(150deg);\
  109. -ms-transform: rotate(150deg);\
  110. transform: rotate(150deg);\
  111. }\
  112. .sk-fading-circle .sk-circle7 {\
  113. -webkit-transform: rotate(180deg);\
  114. -ms-transform: rotate(180deg);\
  115. transform: rotate(180deg);\
  116. }\
  117. .sk-fading-circle .sk-circle8 {\
  118. -webkit-transform: rotate(210deg);\
  119. -ms-transform: rotate(210deg);\
  120. transform: rotate(210deg);\
  121. }\
  122. .sk-fading-circle .sk-circle9 {\
  123. -webkit-transform: rotate(240deg);\
  124. -ms-transform: rotate(240deg);\
  125. transform: rotate(240deg);\
  126. }\
  127. .sk-fading-circle .sk-circle10 {\
  128. -webkit-transform: rotate(270deg);\
  129. -ms-transform: rotate(270deg);\
  130. transform: rotate(270deg);\
  131. }\
  132. .sk-fading-circle .sk-circle11 {\
  133. -webkit-transform: rotate(300deg);\
  134. -ms-transform: rotate(300deg);\
  135. transform: rotate(300deg);\
  136. }\
  137. .sk-fading-circle .sk-circle12 {\
  138. -webkit-transform: rotate(330deg);\
  139. -ms-transform: rotate(330deg);\
  140. transform: rotate(330deg);\
  141. }\
  142. .sk-fading-circle .sk-circle2:before {\
  143. -webkit-animation-delay: -1.1s;\
  144. animation-delay: -1.1s;\
  145. }\
  146. .sk-fading-circle .sk-circle3:before {\
  147. -webkit-animation-delay: -1s;\
  148. animation-delay: -1s;\
  149. }\
  150. .sk-fading-circle .sk-circle4:before {\
  151. -webkit-animation-delay: -0.9s;\
  152. animation-delay: -0.9s;\
  153. }\
  154. .sk-fading-circle .sk-circle5:before {\
  155. -webkit-animation-delay: -0.8s;\
  156. animation-delay: -0.8s;\
  157. }\
  158. .sk-fading-circle .sk-circle6:before {\
  159. -webkit-animation-delay: -0.7s;\
  160. animation-delay: -0.7s;\
  161. }\
  162. .sk-fading-circle .sk-circle7:before {\
  163. -webkit-animation-delay: -0.6s;\
  164. animation-delay: -0.6s;\
  165. }\
  166. .sk-fading-circle .sk-circle8:before {\
  167. -webkit-animation-delay: -0.5s;\
  168. animation-delay: -0.5s;\
  169. }\
  170. .sk-fading-circle .sk-circle9:before {\
  171. -webkit-animation-delay: -0.4s;\
  172. animation-delay: -0.4s;\
  173. }\
  174. .sk-fading-circle .sk-circle10:before {\
  175. -webkit-animation-delay: -0.3s;\
  176. animation-delay: -0.3s;\
  177. }\
  178. .sk-fading-circle .sk-circle11:before {\
  179. -webkit-animation-delay: -0.2s;\
  180. animation-delay: -0.2s;\
  181. }\
  182. .sk-fading-circle .sk-circle12:before {\
  183. -webkit-animation-delay: -0.1s;\
  184. animation-delay: -0.1s;\
  185. }\
  186. @-webkit-keyframes sk-circleFadeDelay {\
  187. 0%, 39%, 100% { opacity: 0; }\
  188. 40% { opacity: 1; }\
  189. }\
  190. @keyframes sk-circleFadeDelay {\
  191. 0%, 39%, 100% { opacity: 0; }\
  192. 40% { opacity: 1; }\
  193. }";
  194.  
  195. class Spinner extends Component {
  196.  
  197. /**
  198. JavaScript class name for this Component.
  199.  
  200. For example: "xeogl.AmbientLight", "xeogl.MetallicMaterial" etc.
  201.  
  202. @property type
  203. @type String
  204. @final
  205. */
  206. get type() {
  207. return type;
  208. }
  209.  
  210. init(cfg) {
  211. super.init(cfg);
  212. this._canvas = cfg.canvas;
  213. this._injectSpinnerCSS();
  214. const div = document.createElement('div');
  215. const style = div.style;
  216. style["z-index"] = "9000";
  217. style.position = "absolute";
  218. div.innerHTML = '<div class="sk-fading-circle">\
  219. <div class="sk-circle1 sk-circle"></div>\
  220. <div class="sk-circle2 sk-circle"></div>\
  221. <div class="sk-circle3 sk-circle"></div>\
  222. <div class="sk-circle4 sk-circle"></div>\
  223. <div class="sk-circle5 sk-circle"></div>\
  224. <div class="sk-circle6 sk-circle"></div>\
  225. <div class="sk-circle7 sk-circle"></div>\
  226. <div class="sk-circle8 sk-circle"></div>\
  227. <div class="sk-circle9 sk-circle"></div>\
  228. <div class="sk-circle10 sk-circle"></div>\
  229. <div class="sk-circle11 sk-circle"></div>\
  230. <div class="sk-circle12 sk-circle"></div>\
  231. </div>';
  232. this._canvas.parentElement.appendChild(div);
  233. this._element = div;
  234. this._adjustPosition();
  235. this.processes = 0;
  236. }
  237.  
  238. /**
  239. The number of processes this Spinner represents.
  240.  
  241. The Spinner is visible while this property is greater than zero.
  242.  
  243. Increment this property whenever you commence some process during which you want
  244. the Spinner to be visible, then decrement it again when the process is complete.
  245.  
  246. Clamps to zero if you attempt to set to to a negative value.
  247.  
  248. Fires a {{#crossLink "Spinner/processes:event"}}{{/crossLink}} event on change.
  249.  
  250. @property processes
  251. @default 0
  252. @type Number
  253. */
  254. set processes(value) {
  255. value = value || 0;
  256. if (this._processes === value) {
  257. return;
  258. }
  259. if (value < 0) {
  260. return;
  261. }
  262. const prevValue = this._processes;
  263. this._processes = value;
  264. this._element.style["visibility"] = (this._processes > 0) ? "visible" : "hidden";
  265. /**
  266. Fired whenever this Spinner's {{#crossLink "Spinner/visible:property"}}{{/crossLink}} property changes.
  267.  
  268. @event processes
  269. @param value The property's new value
  270. */
  271. this.fire("processes", this._processes);
  272. if (this._processes === 0 && this._processes !== prevValue) {
  273. /**
  274. Fired whenever this Spinner's {{#crossLink "Spinner/visible:property"}}{{/crossLink}} property becomes zero.
  275.  
  276. @event zeroProcesses
  277. */
  278. this.fire("zeroProcesses", this._processes);
  279. }
  280. }
  281.  
  282. get processes() {
  283. return this._processes;
  284. }
  285.  
  286. _adjustPosition() { // (Re)positions spinner DIV over the center of the canvas
  287. if (!this._canvas || !this._element) {
  288. return;
  289. }
  290. const canvas = this._canvas;
  291. const spinner = this._element;
  292. const spinnerStyle = spinner.style;
  293. spinnerStyle["left"] = (canvas.offsetLeft + (canvas.clientWidth * 0.5) - (spinner.clientWidth * 0.5)) + "px";
  294. spinnerStyle["top"] = (canvas.offsetTop + (canvas.clientHeight * 0.5) - (spinner.clientHeight * 0.5)) + "px";
  295. }
  296.  
  297. _injectSpinnerCSS() {
  298. if (spinnerCSSInjected) {
  299. return;
  300. }
  301. const node = document.createElement('style');
  302. node.innerHTML = spinnerCSS;
  303. document.body.appendChild(node);
  304. spinnerCSSInjected = true;
  305. }
  306. }
  307.  
  308. export{Spinner};
  309.