laya.device.js 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033
  1. (function(window,document,Laya){
  2. var __un=Laya.un,__uns=Laya.uns,__static=Laya.static,__class=Laya.class,__getset=Laya.getset,__newvec=Laya.__newvec;
  3. var Bitmap=laya.resource.Bitmap,Browser=laya.utils.Browser,Event=laya.events.Event,EventDispatcher=laya.events.EventDispatcher;
  4. var Handler=laya.utils.Handler,LayaGL=laya.layagl.LayaGL,Rectangle=laya.maths.Rectangle,Render=laya.renders.Render;
  5. var Sprite=laya.display.Sprite,Stage=laya.display.Stage,Texture=laya.resource.Texture,Utils=laya.utils.Utils;
  6. var WebGL=laya.webgl.WebGL,WebGLContext=laya.webgl.WebGLContext;
  7. /**
  8. *使用前可用<code>supported</code>查看浏览器支持。
  9. */
  10. //class laya.device.geolocation.Geolocation
  11. var Geolocation=(function(){
  12. function Geolocation(){}
  13. __class(Geolocation,'laya.device.geolocation.Geolocation');
  14. Geolocation.getCurrentPosition=function(onSuccess,onError){
  15. Geolocation.navigator.geolocation.getCurrentPosition(function(pos){
  16. Geolocation.position.setPosition(pos);
  17. onSuccess.runWith(Geolocation.position);
  18. },
  19. function(error){
  20. onError.runWith(error);
  21. },{
  22. enableHighAccuracy :laya.device.geolocation.Geolocation.enableHighAccuracy,
  23. timeout :laya.device.geolocation.Geolocation.timeout,
  24. maximumAge :laya.device.geolocation.Geolocation.maximumAge
  25. });
  26. }
  27. Geolocation.watchPosition=function(onSuccess,onError){
  28. return Geolocation.navigator.geolocation.watchPosition(function(pos){
  29. Geolocation.position.setPosition(pos);
  30. onSuccess.runWith(Geolocation.position);
  31. },
  32. function(error){
  33. onError.runWith(error);
  34. },{
  35. enableHighAccuracy :Geolocation.enableHighAccuracy,
  36. timeout :Geolocation.timeout,
  37. maximumAge :Geolocation.maximumAge
  38. });
  39. }
  40. Geolocation.clearWatch=function(id){
  41. Geolocation.navigator.geolocation.clearWatch(id);
  42. }
  43. Geolocation.PERMISSION_DENIED=1;
  44. Geolocation.POSITION_UNAVAILABLE=2;
  45. Geolocation.TIMEOUT=3;
  46. Geolocation.enableHighAccuracy=false;
  47. Geolocation.maximumAge=0;
  48. __static(Geolocation,
  49. ['navigator',function(){return this.navigator=Browser.window.navigator;},'position',function(){return this.position=new GeolocationInfo();},'supported',function(){return this.supported=!!Geolocation.navigator.geolocation;},'timeout',function(){return this.timeout=1E10;}
  50. ]);
  51. return Geolocation;
  52. })()
  53. /**
  54. *Media用于捕捉摄像头和麦克风。可以捕捉任意之一,或者同时捕捉两者。<code>getCamera</code>前可以使用<code>supported()</code>检查当前浏览器是否支持。
  55. *<b>NOTE:</b>
  56. *<p>目前Media在移动平台只支持Android,不支持IOS。只可在FireFox完整地使用,Chrome测试时无法捕捉视频。</p>
  57. */
  58. //class laya.device.media.Media
  59. var Media=(function(){
  60. function Media(){}
  61. __class(Media,'laya.device.media.Media');
  62. Media.supported=function(){
  63. return !!Browser.window.navigator.getUserMedia;
  64. }
  65. Media.getMedia=function(options,onSuccess,onError){
  66. if (Browser.window.navigator.getUserMedia){
  67. Browser.window.navigator.getUserMedia(options,function(stream){
  68. onSuccess.runWith(Browser.window.URL.createObjectURL(stream));
  69. },function(err){
  70. onError.runWith(err);
  71. });
  72. }
  73. }
  74. Media.__init$=function(){
  75. /*__JS__ */navigator.getUserMedia=navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;;
  76. }
  77. return Media;
  78. })()
  79. /**
  80. *加速度x/y/z的单位均为m/s²。
  81. *在硬件(陀螺仪)不支持的情况下,alpha、beta和gamma值为null。
  82. *
  83. *@author Survivor
  84. */
  85. //class laya.device.motion.AccelerationInfo
  86. var AccelerationInfo=(function(){
  87. function AccelerationInfo(){
  88. /**
  89. *x轴上的加速度值。
  90. */
  91. this.x=NaN;
  92. /**
  93. *y轴上的加速度值。
  94. */
  95. this.y=NaN;
  96. /**
  97. *z轴上的加速度值。
  98. */
  99. this.z=NaN;
  100. }
  101. __class(AccelerationInfo,'laya.device.motion.AccelerationInfo');
  102. return AccelerationInfo;
  103. })()
  104. //class laya.device.geolocation.GeolocationInfo
  105. var GeolocationInfo=(function(){
  106. function GeolocationInfo(){
  107. this.pos=null;
  108. this.coords=null;
  109. }
  110. __class(GeolocationInfo,'laya.device.geolocation.GeolocationInfo');
  111. var __proto=GeolocationInfo.prototype;
  112. __proto.setPosition=function(pos){
  113. this.pos=pos;
  114. this.coords=pos.coords;
  115. }
  116. __getset(0,__proto,'heading',function(){
  117. return this.coords.heading;
  118. });
  119. __getset(0,__proto,'latitude',function(){
  120. return this.coords.latitude;
  121. });
  122. __getset(0,__proto,'altitudeAccuracy',function(){
  123. return this.coords.altitudeAccuracy;
  124. });
  125. __getset(0,__proto,'longitude',function(){
  126. return this.coords.longitude;
  127. });
  128. __getset(0,__proto,'altitude',function(){
  129. return this.coords.altitude;
  130. });
  131. __getset(0,__proto,'accuracy',function(){
  132. return this.coords.accuracy;
  133. });
  134. __getset(0,__proto,'speed',function(){
  135. return this.coords.speed;
  136. });
  137. __getset(0,__proto,'timestamp',function(){
  138. return this.pos.timestamp;
  139. });
  140. return GeolocationInfo;
  141. })()
  142. /**
  143. *保存旋转信息的类。请勿修改本类的属性。
  144. *@author Survivor
  145. */
  146. //class laya.device.motion.RotationInfo
  147. var RotationInfo=(function(){
  148. function RotationInfo(){
  149. /**
  150. *<p>
  151. *指示设备是否可以提供绝对方位数据(指向地球坐标系),或者设备决定的任意坐标系。
  152. *关于坐标系参见<i>https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Orientation_and_motion_data_explained</i>。
  153. *</p>
  154. *需要注意的是,IOS环境下,该值始终为false。即使如此,你依旧可以从<code>alpha</code>中取得正确的值。
  155. */
  156. this.absolute=false;
  157. /**
  158. *Z轴旋转角度,其值范围从0至360。
  159. *若<code>absolute</code>为true或者在IOS中,alpha值是从北方到当前设备方向的角度值。
  160. */
  161. this.alpha=NaN;
  162. /**
  163. *X轴旋转角度,其值范围从-180至180。代表设备从前至后的运动。
  164. */
  165. this.beta=NaN;
  166. /**
  167. *Y轴旋转角度,其值范围从-90至90。代表设备从左至右的运动。
  168. */
  169. this.gamma=NaN;
  170. /**
  171. *罗盘数据的精确度(角度)。仅IOS可用。
  172. */
  173. this.compassAccuracy=NaN;
  174. }
  175. __class(RotationInfo,'laya.device.motion.RotationInfo');
  176. return RotationInfo;
  177. })()
  178. /**
  179. *使用Gyroscope.instance获取唯一的Gyroscope引用,请勿调用构造函数。
  180. *
  181. *<p>
  182. *listen()的回调处理器接受两个参数:
  183. *<code>function onOrientationChange(absolute:Boolean,info:RotationInfo):void</code>
  184. *<ol>
  185. *<li><b>absolute</b>:指示设备是否可以提供绝对方位数据(指向地球坐标系),或者设备决定的任意坐标系。关于坐标系参见<i>https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Orientation_and_motion_data_explained</i>。</li>
  186. *<li><b>info</b>:<code>RotationInfo</code>类型参数,保存设备的旋转值。</li>
  187. *</ol>
  188. *</p>
  189. *
  190. *<p>
  191. *浏览器兼容性参见:<i>http://caniuse.com/#search=deviceorientation</i>
  192. *</p>
  193. */
  194. //class laya.device.motion.Gyroscope extends laya.events.EventDispatcher
  195. var Gyroscope=(function(_super){
  196. function Gyroscope(singleton){
  197. Gyroscope.__super.call(this);
  198. /*__JS__ */this.onDeviceOrientationChange=this.onDeviceOrientationChange.bind(this);
  199. }
  200. __class(Gyroscope,'laya.device.motion.Gyroscope',_super);
  201. var __proto=Gyroscope.prototype;
  202. /**
  203. *监视陀螺仪运动。
  204. *@param observer 回调函数接受一个Boolean类型的<code>absolute</code>和<code>GyroscopeInfo</code>类型参数。
  205. */
  206. __proto.on=function(type,caller,listener,args){
  207. _super.prototype.on.call(this,type,caller,listener,args);
  208. Browser.window.addEventListener('deviceorientation',this.onDeviceOrientationChange);
  209. return this;
  210. }
  211. /**
  212. *取消指定处理器对陀螺仪的监视。
  213. *@param observer
  214. */
  215. __proto.off=function(type,caller,listener,onceOnly){
  216. (onceOnly===void 0)&& (onceOnly=false);
  217. if (!this.hasListener(type))
  218. Browser.window.removeEventListener('deviceorientation',this.onDeviceOrientationChange);
  219. return _super.prototype.off.call(this,type,caller,listener,onceOnly);
  220. }
  221. __proto.onDeviceOrientationChange=function(e){
  222. Gyroscope.info.alpha=e.alpha;
  223. Gyroscope.info.beta=e.beta;
  224. Gyroscope.info.gamma=e.gamma;
  225. if (e.webkitCompassHeading){
  226. Gyroscope.info.alpha=e.webkitCompassHeading *-1;
  227. Gyroscope.info.compassAccuracy=e.webkitCompassAccuracy;
  228. }
  229. this.event(/*laya.events.Event.CHANGE*/"change",[e.absolute,Gyroscope.info]);
  230. }
  231. __getset(1,Gyroscope,'instance',function(){Gyroscope._instance=Gyroscope._instance|| new Gyroscope(0);
  232. return Gyroscope._instance;
  233. },laya.events.EventDispatcher._$SET_instance);
  234. Gyroscope._instance=null;
  235. __static(Gyroscope,
  236. ['info',function(){return this.info=new RotationInfo();}
  237. ]);
  238. return Gyroscope;
  239. })(EventDispatcher)
  240. /**
  241. *Shake只能在支持此操作的设备上有效。
  242. *
  243. *@author Survivor
  244. */
  245. //class laya.device.Shake extends laya.events.EventDispatcher
  246. var Shake=(function(_super){
  247. function Shake(){
  248. this.throushold=0;
  249. this.shakeInterval=0;
  250. this.callback=null;
  251. this.lastX=NaN;
  252. this.lastY=NaN;
  253. this.lastZ=NaN;
  254. this.lastMillSecond=NaN;
  255. Shake.__super.call(this);
  256. }
  257. __class(Shake,'laya.device.Shake',_super);
  258. var __proto=Shake.prototype;
  259. /**
  260. *开始响应设备摇晃。
  261. *@param throushold 响应的瞬时速度阈值,轻度摇晃的值约在5~10间。
  262. *@param timeout 设备摇晃的响应间隔时间。
  263. *@param callback 在设备摇晃触发时调用的处理器。
  264. */
  265. __proto.start=function(throushold,interval){
  266. this.throushold=throushold;
  267. this.shakeInterval=interval;
  268. this.lastX=this.lastY=this.lastZ=NaN;
  269. Accelerator.instance.on(/*laya.events.Event.CHANGE*/"change",this,this.onShake);
  270. }
  271. /**
  272. *停止响应设备摇晃。
  273. */
  274. __proto.stop=function(){
  275. Accelerator.instance.off(/*laya.events.Event.CHANGE*/"change",this,this.onShake);
  276. }
  277. __proto.onShake=function(acceleration,accelerationIncludingGravity,rotationRate,interval){
  278. if(isNaN(this.lastX)){
  279. this.lastX=accelerationIncludingGravity.x;
  280. this.lastY=accelerationIncludingGravity.y;
  281. this.lastZ=accelerationIncludingGravity.z;
  282. this.lastMillSecond=Browser.now();
  283. return;
  284. };
  285. var deltaX=Math.abs(this.lastX-accelerationIncludingGravity.x);
  286. var deltaY=Math.abs(this.lastY-accelerationIncludingGravity.y);
  287. var deltaZ=Math.abs(this.lastZ-accelerationIncludingGravity.z);
  288. if(this.isShaked(deltaX,deltaY,deltaZ)){
  289. var deltaMillSecond=Browser.now()-this.lastMillSecond;
  290. if (deltaMillSecond > this.shakeInterval){
  291. this.event(/*laya.events.Event.CHANGE*/"change");
  292. this.lastMillSecond=Browser.now();
  293. }
  294. }
  295. this.lastX=accelerationIncludingGravity.x;
  296. this.lastY=accelerationIncludingGravity.y;
  297. this.lastZ=accelerationIncludingGravity.z;
  298. }
  299. // 通过任意两个分量判断是否满足摇晃设定。
  300. __proto.isShaked=function(deltaX,deltaY,deltaZ){
  301. return (deltaX > this.throushold && deltaY > this.throushold)||
  302. (deltaX > this.throushold && deltaZ > this.throushold)||
  303. (deltaY > this.throushold && deltaZ > this.throushold)
  304. }
  305. __getset(1,Shake,'instance',function(){Shake._instance=Shake._instance|| new Shake();
  306. return Shake._instance;
  307. },laya.events.EventDispatcher._$SET_instance);
  308. Shake._instance=null;
  309. return Shake;
  310. })(EventDispatcher)
  311. /**
  312. *Accelerator.instance获取唯一的Accelerator引用,请勿调用构造函数。
  313. *
  314. *<p>
  315. *listen()的回调处理器接受四个参数:
  316. *<ol>
  317. *<li><b>acceleration</b>:表示用户给予设备的加速度。</li>
  318. *<li><b>accelerationIncludingGravity</b>:设备受到的总加速度(包含重力)。</li>
  319. *<li><b>rotationRate</b>:设备的自转速率。</li>
  320. *<li><b>interval</b>:加速度获取的时间间隔(毫秒)。</li>
  321. *</ol>
  322. *</p>
  323. *<p>
  324. *<b>NOTE</b><br/>
  325. *如,rotationRate的alpha在apple和moz文档中都是z轴旋转角度,但是实测是x轴旋转角度。为了使各属性表示的值与文档所述相同,实际值与其他属性进行了对调。
  326. *其中:
  327. *<ul>
  328. *<li>alpha使用gamma值。</li>
  329. *<li>beta使用alpha值。</li>
  330. *<li>gamma使用beta。</li>
  331. *</ul>
  332. *目前孰是孰非尚未可知,以此为注。
  333. *</p>
  334. */
  335. //class laya.device.motion.Accelerator extends laya.events.EventDispatcher
  336. var Accelerator=(function(_super){
  337. function Accelerator(singleton){
  338. Accelerator.__super.call(this);
  339. /*__JS__ */this.onDeviceOrientationChange=this.onDeviceOrientationChange.bind(this);
  340. }
  341. __class(Accelerator,'laya.device.motion.Accelerator',_super);
  342. var __proto=Accelerator.prototype;
  343. /**
  344. *侦听加速器运动。
  345. *@param observer 回调函数接受4个参数,见类说明。
  346. */
  347. __proto.on=function(type,caller,listener,args){
  348. _super.prototype.on.call(this,type,caller,listener,args);
  349. Browser.window.addEventListener('devicemotion',this.onDeviceOrientationChange);
  350. return this;
  351. }
  352. /**
  353. *取消侦听加速器。
  354. *@param handle 侦听加速器所用处理器。
  355. */
  356. __proto.off=function(type,caller,listener,onceOnly){
  357. (onceOnly===void 0)&& (onceOnly=false);
  358. if (!this.hasListener(type))
  359. Browser.window.removeEventListener('devicemotion',this.onDeviceOrientationChange)
  360. return _super.prototype.off.call(this,type,caller,listener,onceOnly);
  361. }
  362. __proto.onDeviceOrientationChange=function(e){
  363. var interval=e.interval;
  364. Accelerator.acceleration.x=e.acceleration.x;
  365. Accelerator.acceleration.y=e.acceleration.y;
  366. Accelerator.acceleration.z=e.acceleration.z;
  367. Accelerator.accelerationIncludingGravity.x=e.accelerationIncludingGravity.x;
  368. Accelerator.accelerationIncludingGravity.y=e.accelerationIncludingGravity.y;
  369. Accelerator.accelerationIncludingGravity.z=e.accelerationIncludingGravity.z;
  370. Accelerator.rotationRate.alpha=e.rotationRate.gamma *-1;
  371. Accelerator.rotationRate.beta=e.rotationRate.alpha *-1;
  372. Accelerator.rotationRate.gamma=e.rotationRate.beta;
  373. if (Browser.onAndroid){
  374. if (Accelerator.onChrome){
  375. Accelerator.rotationRate.alpha *=180 / Math.PI;
  376. Accelerator.rotationRate.beta *=180 / Math.PI;
  377. Accelerator.rotationRate.gamma *=180 / Math.PI;
  378. }
  379. Accelerator.acceleration.x *=-1;
  380. Accelerator.accelerationIncludingGravity.x *=-1;
  381. }
  382. else if (Browser.onIOS){
  383. Accelerator.acceleration.y *=-1;
  384. Accelerator.acceleration.z *=-1;
  385. Accelerator.accelerationIncludingGravity.y *=-1;
  386. Accelerator.accelerationIncludingGravity.z *=-1;
  387. interval *=1000;
  388. }
  389. this.event(/*laya.events.Event.CHANGE*/"change",[Accelerator.acceleration,Accelerator.accelerationIncludingGravity,Accelerator.rotationRate,interval]);
  390. }
  391. __getset(1,Accelerator,'instance',function(){Accelerator._instance=Accelerator._instance|| new Accelerator(0)
  392. return Accelerator._instance;
  393. },laya.events.EventDispatcher._$SET_instance);
  394. Accelerator.getTransformedAcceleration=function(acceleration){Accelerator.transformedAcceleration=Accelerator.transformedAcceleration|| new AccelerationInfo();
  395. Accelerator.transformedAcceleration.z=acceleration.z;
  396. if (Browser.window.orientation==90){
  397. Accelerator.transformedAcceleration.x=acceleration.y;
  398. Accelerator.transformedAcceleration.y=-acceleration.x;
  399. }
  400. else if (Browser.window.orientation==-90){
  401. Accelerator.transformedAcceleration.x=-acceleration.y;
  402. Accelerator.transformedAcceleration.y=acceleration.x;
  403. }
  404. else if (!Browser.window.orientation){
  405. Accelerator.transformedAcceleration.x=acceleration.x;
  406. Accelerator.transformedAcceleration.y=acceleration.y;
  407. }
  408. else if (Browser.window.orientation==180){
  409. Accelerator.transformedAcceleration.x=-acceleration.x;
  410. Accelerator.transformedAcceleration.y=-acceleration.y;
  411. };
  412. var tx=NaN;
  413. if (Laya.stage.canvasDegree==-90){
  414. tx=Accelerator.transformedAcceleration.x;
  415. Accelerator.transformedAcceleration.x=-Accelerator.transformedAcceleration.y;
  416. Accelerator.transformedAcceleration.y=tx;
  417. }
  418. else if (Laya.stage.canvasDegree==90){
  419. tx=Accelerator.transformedAcceleration.x;
  420. Accelerator.transformedAcceleration.x=Accelerator.transformedAcceleration.y;
  421. Accelerator.transformedAcceleration.y=-tx;
  422. }
  423. return Accelerator.transformedAcceleration;
  424. }
  425. Accelerator._instance=null;
  426. Accelerator.transformedAcceleration=null;
  427. __static(Accelerator,
  428. ['acceleration',function(){return this.acceleration=new AccelerationInfo();},'accelerationIncludingGravity',function(){return this.accelerationIncludingGravity=new AccelerationInfo();},'rotationRate',function(){return this.rotationRate=new RotationInfo();},'onChrome',function(){return this.onChrome=(Browser.userAgent.indexOf("Chrome")>-1);}
  429. ]);
  430. return Accelerator;
  431. })(EventDispatcher)
  432. /**
  433. *<code>Video</code>将视频显示到Canvas上。<code>Video</code>可能不会在所有浏览器有效。
  434. *<p>关于Video支持的所有事件参见:<i>http://www.w3school.com.cn/tags/html_ref_audio_video_dom.asp</i>。</p>
  435. *<p>
  436. *<b>注意:</b><br/>
  437. *在PC端可以在任何时机调用<code>play()</code>因此,可以在程序开始运行时就使Video开始播放。但是在移动端,只有在用户第一次触碰屏幕后才可以调用play(),所以移动端不可能在程序开始运行时就自动开始播放Video。
  438. *</p>
  439. *
  440. *<p>MDN Video链接: <i>https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video</i></p>
  441. */
  442. //class laya.device.media.Video extends laya.display.Sprite
  443. var Video=(function(_super){
  444. function Video(width,height){
  445. this.htmlVideo=null;
  446. this.videoElement=null;
  447. this.internalTexture=null;
  448. (width===void 0)&& (width=320);
  449. (height===void 0)&& (height=240);
  450. Video.__super.call(this);
  451. this.htmlVideo=new WebGLVideo();
  452. this.videoElement=this.htmlVideo.getVideo();
  453. this.videoElement.layaTarget=this;
  454. this.internalTexture=new Texture(this.htmlVideo);
  455. this.videoElement.addEventListener("abort",Video.onAbort);
  456. this.videoElement.addEventListener("canplay",Video.onCanplay);
  457. this.videoElement.addEventListener("canplaythrough",Video.onCanplaythrough);
  458. this.videoElement.addEventListener("durationchange",Video.onDurationchange);
  459. this.videoElement.addEventListener("emptied",Video.onEmptied);
  460. this.videoElement.addEventListener("error",Video.onError);
  461. this.videoElement.addEventListener("loadeddata",Video.onLoadeddata);
  462. this.videoElement.addEventListener("loadedmetadata",Video.onLoadedmetadata);
  463. this.videoElement.addEventListener("loadstart",Video.onLoadstart);
  464. this.videoElement.addEventListener("pause",Video.onPause);
  465. this.videoElement.addEventListener("play",Video.onPlay);
  466. this.videoElement.addEventListener("playing",Video.onPlaying);
  467. this.videoElement.addEventListener("progress",Video.onProgress);
  468. this.videoElement.addEventListener("ratechange",Video.onRatechange);
  469. this.videoElement.addEventListener("seeked",Video.onSeeked);
  470. this.videoElement.addEventListener("seeking",Video.onSeeking);
  471. this.videoElement.addEventListener("stalled",Video.onStalled);
  472. this.videoElement.addEventListener("suspend",Video.onSuspend);
  473. this.videoElement.addEventListener("timeupdate",Video.onTimeupdate);
  474. this.videoElement.addEventListener("volumechange",Video.onVolumechange);
  475. this.videoElement.addEventListener("waiting",Video.onWaiting);
  476. this.videoElement.addEventListener("ended",this.onPlayComplete['bind'](this));
  477. this.size(width,height);
  478. if (Browser.onMobile){
  479. /*__JS__ */this.onDocumentClick=this.onDocumentClick.bind(this);
  480. Browser.document.addEventListener("touchend",this.onDocumentClick);
  481. }
  482. }
  483. __class(Video,'laya.device.media.Video',_super);
  484. var __proto=Video.prototype;
  485. __proto.onPlayComplete=function(e){
  486. this.event("ended");
  487. if(!Render.isConchApp || !this.videoElement || !this.videoElement.loop)
  488. Laya.timer.clear(this,this.renderCanvas);
  489. }
  490. /**
  491. *设置播放源。
  492. *@param url 播放源路径。
  493. */
  494. __proto.load=function(url){
  495. if (url.indexOf("blob:")==0)
  496. this.videoElement.src=url;
  497. else
  498. this.htmlVideo.setSource(url,laya.device.media.Video.MP4);
  499. }
  500. /**
  501. *开始播放视频。
  502. */
  503. __proto.play=function(){
  504. this.videoElement.play();
  505. Laya.timer.frameLoop(1,this,this.renderCanvas);
  506. }
  507. /**
  508. *暂停视频播放。
  509. */
  510. __proto.pause=function(){
  511. this.videoElement.pause();
  512. Laya.timer.clear(this,this.renderCanvas);
  513. }
  514. /**
  515. *重新加载视频。
  516. */
  517. __proto.reload=function(){
  518. this.videoElement.load();
  519. }
  520. /**
  521. *检测是否支持播放指定格式视频。
  522. *@param type 参数为Video.MP4 / Video.OGG / Video.WEBM之一。
  523. *@return 表示支持的级别。可能的值:
  524. *<ul>
  525. *<li>"probably",Video.SUPPORT_PROBABLY-浏览器最可能支持该音频/视频类型</li>
  526. *<li>"maybe",Video.SUPPORT_MAYBY-浏览器也许支持该音频/视频类型</li>
  527. *<li>"",Video.SUPPORT_NO-(空字符串)浏览器不支持该音频/视频类型</li>
  528. *</ul>
  529. */
  530. __proto.canPlayType=function(type){
  531. var typeString;
  532. switch (type){
  533. case laya.device.media.Video.MP4:
  534. typeString="video/mp4";
  535. break ;
  536. case laya.device.media.Video.OGG:
  537. typeString="video/ogg";
  538. break ;
  539. case laya.device.media.Video.WEBM:
  540. typeString="video/webm";
  541. break ;
  542. }
  543. return this.videoElement.canPlayType(typeString);
  544. }
  545. __proto.renderCanvas=function(){
  546. if (this.readyState===0)
  547. return;
  548. this.htmlVideo['updateTexture']();
  549. this.graphics.clear();
  550. this.graphics.drawTexture(this.internalTexture,0,0,this.width,this.height);
  551. }
  552. __proto.onDocumentClick=function(){
  553. this.videoElement.play();
  554. this.videoElement.pause();
  555. Browser.document.removeEventListener("touchend",this.onDocumentClick);
  556. }
  557. __proto.size=function(width,height){
  558. _super.prototype.size.call(this,width,height)
  559. if (Render.isConchApp){
  560. var transform=Utils.getTransformRelativeToWindow(this,0,0);
  561. this.videoElement.width=width *transform.scaleX;
  562. }
  563. else{
  564. this.videoElement.width=width / Browser.pixelRatio;
  565. }
  566. if (this.paused)this.renderCanvas();
  567. return this;
  568. }
  569. /**
  570. *销毁内部事件绑定。
  571. */
  572. __proto.destroy=function(detroyChildren){
  573. (detroyChildren===void 0)&& (detroyChildren=true);
  574. _super.prototype.destroy.call(this,detroyChildren);
  575. this.videoElement.removeEventListener("abort",Video.onAbort);
  576. this.videoElement.removeEventListener("canplay",Video.onCanplay);
  577. this.videoElement.removeEventListener("canplaythrough",Video.onCanplaythrough);
  578. this.videoElement.removeEventListener("durationchange",Video.onDurationchange);
  579. this.videoElement.removeEventListener("emptied",Video.onEmptied);
  580. this.videoElement.removeEventListener("error",Video.onError);
  581. this.videoElement.removeEventListener("loadeddata",Video.onLoadeddata);
  582. this.videoElement.removeEventListener("loadedmetadata",Video.onLoadedmetadata);
  583. this.videoElement.removeEventListener("loadstart",Video.onLoadstart);
  584. this.videoElement.removeEventListener("pause",Video.onPause);
  585. this.videoElement.removeEventListener("play",Video.onPlay);
  586. this.videoElement.removeEventListener("playing",Video.onPlaying);
  587. this.videoElement.removeEventListener("progress",Video.onProgress);
  588. this.videoElement.removeEventListener("ratechange",Video.onRatechange);
  589. this.videoElement.removeEventListener("seeked",Video.onSeeked);
  590. this.videoElement.removeEventListener("seeking",Video.onSeeking);
  591. this.videoElement.removeEventListener("stalled",Video.onStalled);
  592. this.videoElement.removeEventListener("suspend",Video.onSuspend);
  593. this.videoElement.removeEventListener("timeupdate",Video.onTimeupdate);
  594. this.videoElement.removeEventListener("volumechange",Video.onVolumechange);
  595. this.videoElement.removeEventListener("waiting",Video.onWaiting);
  596. this.videoElement.removeEventListener("ended",this.onPlayComplete);
  597. this.pause();
  598. this.videoElement.layaTarget=null
  599. this.videoElement=null;
  600. this.htmlVideo.destroy();
  601. }
  602. __proto.syncVideoPosition=function(){
  603. var stage=Laya.stage;
  604. var rec;
  605. rec=Utils.getGlobalPosAndScale(this);
  606. var a=stage._canvasTransform.a,d=stage._canvasTransform.d;
  607. var x=rec.x *stage.clientScaleX *a+stage.offset.x;
  608. var y=rec.y *stage.clientScaleY *d+stage.offset.y;
  609. this.videoElement.style.left=x+'px';;
  610. this.videoElement.style.top=y+'px';
  611. this.videoElement.width=this.width / Browser.pixelRatio;
  612. this.videoElement.height=this.height / Browser.pixelRatio;
  613. }
  614. /**
  615. *buffered 属性返回 TimeRanges(JS)对象。TimeRanges 对象表示用户的音视频缓冲范围。缓冲范围指的是已缓冲音视频的时间范围。如果用户在音视频中跳跃播放,会得到多个缓冲范围。
  616. *<p>buffered.length返回缓冲范围个数。如获取第一个缓冲范围则是buffered.start(0)和buffered.end(0)。以秒计。</p>
  617. *@return TimeRanges(JS)对象
  618. */
  619. __getset(0,__proto,'buffered',function(){
  620. return this.videoElement.buffered;
  621. });
  622. /**
  623. *获取视频源尺寸。ready事件触发后可用。
  624. */
  625. __getset(0,__proto,'videoWidth',function(){
  626. return this.videoElement.videoWidth;
  627. });
  628. /**
  629. *获取当前播放源路径。
  630. */
  631. __getset(0,__proto,'currentSrc',function(){
  632. return this.videoElement.currentSrc;
  633. });
  634. /**
  635. *设置和获取当前播放头位置。
  636. */
  637. __getset(0,__proto,'currentTime',function(){
  638. return this.videoElement.currentTime;
  639. },function(value){
  640. this.videoElement.currentTime=value;
  641. this.renderCanvas();
  642. });
  643. /**
  644. *返回音频/视频的播放是否已结束
  645. */
  646. __getset(0,__proto,'ended',function(){
  647. return this.videoElement.ended;
  648. });
  649. /**
  650. *设置和获取当前音量。
  651. */
  652. __getset(0,__proto,'volume',function(){
  653. return this.videoElement.volume;
  654. },function(value){
  655. this.videoElement.volume=value;
  656. });
  657. __getset(0,__proto,'videoHeight',function(){
  658. return this.videoElement.videoHeight;
  659. });
  660. /**
  661. *表示视频元素的就绪状态:
  662. *<ul>
  663. *<li>0=HAVE_NOTHING-没有关于音频/视频是否就绪的信息</li>
  664. *<li>1=HAVE_METADATA-关于音频/视频就绪的元数据</li>
  665. *<li>2=HAVE_CURRENT_DATA-关于当前播放位置的数据是可用的,但没有足够的数据来播放下一帧/毫秒</li>
  666. *<li>3=HAVE_FUTURE_DATA-当前及至少下一帧的数据是可用的</li>
  667. *<li>4=HAVE_ENOUGH_DATA-可用数据足以开始播放</li>
  668. *</ul>
  669. */
  670. __getset(0,__proto,'readyState',function(){
  671. return this.videoElement.readyState;
  672. });
  673. /**
  674. *获取视频长度(秒)。ready事件触发后可用。
  675. */
  676. __getset(0,__proto,'duration',function(){
  677. return this.videoElement.duration;
  678. });
  679. /**
  680. *返回表示音频/视频错误状态的 MediaError(JS)对象。
  681. */
  682. __getset(0,__proto,'error',function(){
  683. return this.videoElement.error;
  684. });
  685. /**
  686. *设置或返回音频/视频是否应在结束时重新播放。
  687. */
  688. __getset(0,__proto,'loop',function(){
  689. return this.videoElement.loop;
  690. },function(value){
  691. this.videoElement.loop=value;
  692. });
  693. /**
  694. *设置视频的x坐标
  695. */
  696. __getset(0,__proto,'x',_super.prototype._$get_x,function(val){
  697. Laya.superSet(Sprite,this,'x',val);
  698. if (Render.isConchApp){
  699. var transform=Utils.getTransformRelativeToWindow(this,0,0);
  700. this.videoElement.style.left=transform.x;
  701. }
  702. });
  703. /**
  704. *设置视频的y坐标
  705. */
  706. __getset(0,__proto,'y',_super.prototype._$get_y,function(val){
  707. Laya.superSet(Sprite,this,'y',val);
  708. if (Render.isConchApp){
  709. var transform=Utils.getTransformRelativeToWindow(this,0,0);
  710. this.videoElement.style.top=transform.y;
  711. }
  712. });
  713. /**
  714. *playbackRate 属性设置或返回音频/视频的当前播放速度。如:
  715. *<ul>
  716. *<li>1.0 正常速度</li>
  717. *<li>0.5 半速(更慢)</li>
  718. *<li>2.0 倍速(更快)</li>
  719. *<li>-1.0 向后,正常速度</li>
  720. *<li>-0.5 向后,半速</li>
  721. *</ul>
  722. *<p>只有 Google Chrome 和 Safari 支持 playbackRate 属性。</p>
  723. */
  724. __getset(0,__proto,'playbackRate',function(){
  725. return this.videoElement.playbackRate;
  726. },function(value){
  727. this.videoElement.playbackRate=value;
  728. });
  729. /**
  730. *获取和设置静音状态。
  731. */
  732. __getset(0,__proto,'muted',function(){
  733. return this.videoElement.muted;
  734. },function(value){
  735. this.videoElement.muted=value;
  736. });
  737. /**
  738. *返回视频是否暂停
  739. */
  740. __getset(0,__proto,'paused',function(){
  741. return this.videoElement.paused;
  742. });
  743. /**
  744. *preload 属性设置或返回是否在页面加载后立即加载视频。可赋值如下:
  745. *<ul>
  746. *<li>auto 指示一旦页面加载,则开始加载视频。</li>
  747. *<li>metadata 指示当页面加载后仅加载音频/视频的元数据。</li>
  748. *<li>none 指示页面加载后不应加载音频/视频。</li>
  749. *</ul>
  750. */
  751. __getset(0,__proto,'preload',function(){
  752. return this.videoElement.preload;
  753. },function(value){
  754. this.videoElement.preload=value;
  755. });
  756. /**
  757. *参见 <i>http://www.w3school.com.cn/tags/av_prop_seekable.asp</i>。
  758. */
  759. __getset(0,__proto,'seekable',function(){
  760. return this.videoElement.seekable;
  761. });
  762. /**
  763. *seeking 属性返回用户目前是否在音频/视频中寻址。
  764. *寻址中(Seeking)指的是用户在音频/视频中移动/跳跃到新的位置。
  765. */
  766. __getset(0,__proto,'seeking',function(){
  767. return this.videoElement.seeking;
  768. });
  769. __getset(0,__proto,'width',_super.prototype._$get_width,function(value){
  770. if (Render.isConchApp){
  771. var transform=Utils.getTransformRelativeToWindow(this,0,0);
  772. this.videoElement.width=value *transform.scaleX;
  773. }
  774. else{
  775. this.videoElement.width=this.width / Browser.pixelRatio;
  776. }
  777. Laya.superSet(Sprite,this,'width',value);
  778. if (this.paused)this.renderCanvas();
  779. });
  780. __getset(0,__proto,'height',_super.prototype._$get_height,function(value){
  781. if (Render.isConchApp){
  782. var transform=Utils.getTransformRelativeToWindow(this,0,0);
  783. this.videoElement.height=value *transform.scaleY;
  784. }
  785. else{
  786. this.videoElement.height=this.height / Browser.pixelRatio;
  787. }
  788. Laya.superSet(Sprite,this,'height',value);
  789. });
  790. Video.onAbort=function(e){e.target.layaTarget.event("abort")}
  791. Video.onCanplay=function(e){e.target.layaTarget.event("canplay")}
  792. Video.onCanplaythrough=function(e){e.target.layaTarget.event("canplaythrough")}
  793. Video.onDurationchange=function(e){e.target.layaTarget.event("durationchange")}
  794. Video.onEmptied=function(e){e.target.layaTarget.event("emptied")}
  795. Video.onError=function(e){e.target.layaTarget.event("error")}
  796. Video.onLoadeddata=function(e){e.target.layaTarget.event("loadeddata")}
  797. Video.onLoadedmetadata=function(e){e.target.layaTarget.event("loadedmetadata")}
  798. Video.onLoadstart=function(e){e.target.layaTarget.event("loadstart")}
  799. Video.onPause=function(e){e.target.layaTarget.event("pause")}
  800. Video.onPlay=function(e){e.target.layaTarget.event("play")}
  801. Video.onPlaying=function(e){e.target.layaTarget.event("playing")}
  802. Video.onProgress=function(e){e.target.layaTarget.event("progress")}
  803. Video.onRatechange=function(e){e.target.layaTarget.event("ratechange")}
  804. Video.onSeeked=function(e){e.target.layaTarget.event("seeked")}
  805. Video.onSeeking=function(e){e.target.layaTarget.event("seeking")}
  806. Video.onStalled=function(e){e.target.layaTarget.event("stalled")}
  807. Video.onSuspend=function(e){e.target.layaTarget.event("suspend")}
  808. Video.onTimeupdate=function(e){e.target.layaTarget.event("timeupdate")}
  809. Video.onVolumechange=function(e){e.target.layaTarget.event("volumechange")}
  810. Video.onWaiting=function(e){e.target.layaTarget.event("waiting")}
  811. Video.MP4=1;
  812. Video.OGG=2;
  813. Video.CAMERA=4;
  814. Video.WEBM=8;
  815. Video.SUPPORT_PROBABLY="probably";
  816. Video.SUPPORT_MAYBY="maybe";
  817. Video.SUPPORT_NO="";
  818. return Video;
  819. })(Sprite)
  820. /**
  821. *@private
  822. */
  823. //class laya.device.media.HtmlVideo extends laya.resource.Bitmap
  824. var HtmlVideo=(function(_super){
  825. function HtmlVideo(){
  826. this.video=null;
  827. this._source=null;
  828. HtmlVideo.__super.call(this);
  829. this._width=1;
  830. this._height=1;
  831. this.createDomElement();
  832. }
  833. __class(HtmlVideo,'laya.device.media.HtmlVideo',_super);
  834. var __proto=HtmlVideo.prototype;
  835. __proto.createDomElement=function(){
  836. var _$this=this;
  837. this._source=this.video=Browser.createElement("video");
  838. var style=this.video.style;
  839. style.position='absolute';
  840. style.top='0px';
  841. style.left='0px';
  842. this.video.addEventListener("loadedmetadata",(function(){
  843. this._w=_$this.video.videoWidth;
  844. this._h=_$this.video.videoHeight;
  845. })['bind'](this));
  846. }
  847. __proto.setSource=function(url,extension){
  848. while(this.video.childElementCount)
  849. this.video.firstChild.remove();
  850. if (extension & Video.MP4)
  851. this.appendSource(url,"video/mp4");
  852. if (extension & Video.OGG)
  853. this.appendSource(url+".ogg","video/ogg");
  854. }
  855. __proto.appendSource=function(source,type){
  856. var sourceElement=Browser.createElement("source");
  857. sourceElement.src=source;
  858. sourceElement.type=type;
  859. this.video.appendChild(sourceElement);
  860. }
  861. __proto.getVideo=function(){
  862. return this.video;
  863. }
  864. __proto._getSource=function(){
  865. return this._source;
  866. }
  867. __proto.destroy=function(){
  868. laya.resource.Resource.prototype.destroy.call(this);
  869. var isConchApp=/*__JS__ */Render.isConchApp;
  870. if (isConchApp){
  871. this.video._destroy();
  872. }
  873. }
  874. HtmlVideo.create=function(){
  875. return new HtmlVideo();
  876. }
  877. return HtmlVideo;
  878. })(Bitmap)
  879. /**
  880. *@private
  881. */
  882. //class laya.device.media.WebGLVideo extends laya.device.media.HtmlVideo
  883. var WebGLVideo=(function(_super){
  884. function WebGLVideo(){
  885. this.gl=null;
  886. this.preTarget=null;
  887. this.preTexture=null;
  888. WebGLVideo.__super.call(this);
  889. if(!Render.isConchApp && Browser.onIPhone)
  890. return;
  891. this.gl=/*__JS__ */Render.isConchApp ? LayaGLContext.instance :WebGL.mainContext;
  892. this._source=this.gl.createTexture();
  893. WebGLContext.bindTexture(this.gl,/*laya.webgl.WebGLContext.TEXTURE_2D*/0x0DE1,this._source);
  894. this.gl.texParameteri(/*laya.webgl.WebGLContext.TEXTURE_2D*/0x0DE1,/*laya.webgl.WebGLContext.TEXTURE_WRAP_S*/0x2802,/*laya.webgl.WebGLContext.CLAMP_TO_EDGE*/0x812F);
  895. this.gl.texParameteri(/*laya.webgl.WebGLContext.TEXTURE_2D*/0x0DE1,/*laya.webgl.WebGLContext.TEXTURE_WRAP_T*/0x2803,/*laya.webgl.WebGLContext.CLAMP_TO_EDGE*/0x812F);
  896. this.gl.texParameteri(/*laya.webgl.WebGLContext.TEXTURE_2D*/0x0DE1,/*laya.webgl.WebGLContext.TEXTURE_MAG_FILTER*/0x2800,/*laya.webgl.WebGLContext.LINEAR*/0x2601);
  897. this.gl.texParameteri(/*laya.webgl.WebGLContext.TEXTURE_2D*/0x0DE1,/*laya.webgl.WebGLContext.TEXTURE_MIN_FILTER*/0x2801,/*laya.webgl.WebGLContext.LINEAR*/0x2601);
  898. WebGLContext.bindTexture(this.gl,/*laya.webgl.WebGLContext.TEXTURE_2D*/0x0DE1,null);
  899. }
  900. __class(WebGLVideo,'laya.device.media.WebGLVideo',_super);
  901. var __proto=WebGLVideo.prototype;
  902. //(preTarget && preTexture)&& (WebGLContext.bindTexture(gl,preTarget,preTexture));
  903. __proto.updateTexture=function(){
  904. if(!Render.isConchApp && Browser.onIPhone)
  905. return;
  906. WebGLContext.bindTexture(this.gl,/*laya.webgl.WebGLContext.TEXTURE_2D*/0x0DE1,this._source);
  907. this.gl.texImage2D(/*laya.webgl.WebGLContext.TEXTURE_2D*/0x0DE1,0,/*laya.webgl.WebGLContext.RGB*/0x1907,/*laya.webgl.WebGLContext.RGB*/0x1907,/*laya.webgl.WebGLContext.UNSIGNED_BYTE*/0x1401,this.video);
  908. WebGLVideo.curBindSource=this._source;
  909. }
  910. __proto.destroy=function(){
  911. if (this._source){
  912. this.gl=/*__JS__ */Render.isConchApp ? LayaGLContext.instance :WebGL.mainContext;
  913. if (WebGLVideo.curBindSource==this._source){
  914. WebGLContext.bindTexture(this.gl,/*laya.webgl.WebGLContext.TEXTURE_2D*/0x0DE1,null);
  915. WebGLVideo.curBindSource=null;
  916. }
  917. this.gl.deleteTexture(this._source);
  918. }
  919. _super.prototype.destroy.call(this);
  920. }
  921. __getset(0,__proto,'_glTexture',function(){
  922. return this._source;
  923. });
  924. WebGLVideo.curBindSource=null;
  925. return WebGLVideo;
  926. })(HtmlVideo)
  927. Laya.__init([Media]);
  928. })(window,document,Laya);