hilo-flash.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586
  1. ;(function(){
  2. /**
  3. * @class Flash渲染器。将可视对象以flash方式渲染出来。
  4. * @augments Renderer
  5. * @param {Object} properties 创建对象的属性参数。可包含此类所有可写属性。
  6. * @module hilo/flash/FlashRenderer
  7. * @requires hilo/core/Class
  8. * @requires hilo/core/Hilo
  9. * @requires hilo/renderer/Renderer
  10. */
  11. var FlashRenderer = (function(){
  12. var _stageStateList = ["x", "y", "scaleX", "scaleY", "rotation", "visible", "alpha"];
  13. var _stateList = _stageStateList.concat(["pivotX", "pivotY", "width", "height", "depth"]);
  14. var _textStateList = _stateList.concat(["text", "color", "textAlign", "outline", "lineSpacing", "font"]);
  15. var n = 0;
  16. var state = {
  17. View: _stateList,
  18. Stage: _stageStateList,
  19. Graphics: _stateList,
  20. Text: _textStateList
  21. };
  22. function createFid(target){
  23. return target.id + (n++);
  24. }
  25. return Hilo.Class.create(/** @lends FlashRenderer.prototype */{
  26. Extends: Hilo.Renderer,
  27. constructor: function(properties){
  28. FlashRenderer.superclass.constructor.call(this, properties);
  29. this.stage._ADD_TO_FLASH = true;
  30. this.stage.fid = createFid(this.stage);
  31. this.stage.flashType = "Stage";
  32. this.commands = properties.commands || [];
  33. this.commands.push("create", this.stage.fid, "Stage");
  34. this.commands.push("stageAddChild", this.stage.fid);
  35. },
  36. /**
  37. * @private
  38. * @see Renderer#startDraw
  39. */
  40. startDraw: function(target){
  41. if(target == this.stage){
  42. return true;
  43. }
  44. target._lastState = target._lastState || {};
  45. //create
  46. if(!target._ADD_TO_FLASH){
  47. target._ADD_TO_FLASH = true;
  48. target.fid = createFid(target);
  49. if(target._drawTextLine){
  50. target.flashType = "Text";
  51. }
  52. else if(target.beginLinearGradientFill){
  53. target.flashType = "Graphics";
  54. }
  55. else if(target == this.stage){
  56. target.flashType = "Stage";
  57. }
  58. else{
  59. target.flashType = "View";
  60. }
  61. this.commands.push("create", target.fid, target.flashType);
  62. }
  63. return true;
  64. },
  65. /**
  66. * @private
  67. * @see Renderer#draw
  68. */
  69. draw: function(target){
  70. if(target == this.stage){
  71. return;
  72. }
  73. target._lastState = target._lastState || {};
  74. var lastParent = target._lastState.parent;
  75. var parent = target.parent;
  76. if(parent){
  77. if(!lastParent || parent.fid != lastParent.fid){
  78. this.commands.push("addChild", parent.fid, target.fid, target.depth);
  79. }
  80. }
  81. target._lastState.parent = target.parent;
  82. switch(target.flashType){
  83. case "Graphics":
  84. if(target.isDirty && target.flashGraphicsCommands && target.flashGraphicsCommands.length > 0){
  85. this.commands.push("graphicsDraw", target.fid, target.flashGraphicsCommands.join(";"));
  86. target.isDirty = false;
  87. }
  88. break;
  89. case "Text":
  90. break;
  91. }
  92. },
  93. /**
  94. * @private
  95. * @see Renderer#transform
  96. */
  97. transform: function(target){
  98. var stateList = state[target.flashType];
  99. var lastState = target._lastState = target._lastState||{};
  100. if(stateList){
  101. for(var i = 0,l = stateList.length;i < l;i ++){
  102. var prop = stateList[i];
  103. var lastValue = lastState[prop];
  104. var value = target[prop];
  105. lastState[prop] = value;
  106. if(lastValue != value){
  107. this.commands.push("setProp", target.fid, prop, value);
  108. }
  109. }
  110. //画图
  111. if(target.drawable && target.drawable.image){
  112. var image = target.drawable.image;
  113. var rect = target.drawable.rect;
  114. var lastRect = lastState.rect||[];
  115. var lastImage = lastState.image||{};
  116. if(rect && rect.join(",")!= lastRect.join(",")){
  117. this.commands.push("setProp", target.fid, "rect", rect.join(","));
  118. }
  119. if(image && (image.src != lastImage.src)) {
  120. this.commands.push("setImage", target.fid, image.src);
  121. }
  122. lastState.rect = rect;
  123. lastState.image = image;
  124. }
  125. }
  126. },
  127. /**
  128. * @private
  129. * @see Renderer#remove
  130. */
  131. remove: function(target){
  132. var parent = target.parent;
  133. if(parent){
  134. this.commands.push("removeChild", target.parent.fid, target.fid);
  135. if(target._lastState){
  136. target._lastState.parent = null;
  137. }
  138. }
  139. }
  140. });
  141. })();
  142. /**
  143. * @class FlashAdaptor
  144. * @module hilo/flash/FlashAdaptor
  145. * @requires hilo/core/Hilo
  146. * @requires hilo/view/Text
  147. * @requires hilo/view/Graphics
  148. * @requires hilo/media/WebAudio
  149. * @requires hilo/media/WebSound
  150. * @requires hilo/view/Stage
  151. * @requires hilo/flash/FlashRenderer
  152. */
  153. var FlashAdaptor = (function(){
  154. var scripts = document.scripts;
  155. var selfScript = scripts[scripts.length - 1];
  156. var scriptDir = selfScript.src.substring(0, selfScript.src.lastIndexOf('/') + 1);
  157. var defaultSwf = scriptDir + 'hilo.swf';
  158. var defaultOption = {
  159. url: defaultSwf,
  160. id: "hiloFlash",
  161. width: "100%",
  162. height: "100%",
  163. color: "#ffffff",
  164. fps: 60
  165. };
  166. var imageCallBacks = {};
  167. var isFlashReady = false;
  168. var flashCommands = [];
  169. var Adaptor = {
  170. /**
  171. * 初始化flash
  172. * @public
  173. * @method init
  174. * @param {Object} option 参数option定义
  175. * option.url flash网址
  176. * option.fps flash fps, 默认60
  177. * option.forceFlash 强制falsh模式
  178. * option.id flash id,默认 hiloFlash
  179. */
  180. init:function(option){
  181. option = option || {};
  182. var that = this;
  183. if(!Hilo.browser.supportCanvas || option.forceFlash || location.search.indexOf("forceFlash") > -1){
  184. Hilo.isFlash = true;
  185. this._addFlashCallback();
  186. this._flashShim(option);
  187. }
  188. else{
  189. Hilo.View.prototype.release = function(){
  190. this.removeFromParent();
  191. };
  192. }
  193. },
  194. setFps:function(fps){
  195. if(this._fps != fps){
  196. this._fps = fps;
  197. flashCommands.push("setFps", fps);
  198. }
  199. },
  200. _flashShim:function(option){
  201. var that = this;
  202. option = Hilo.copy(defaultOption, option||{});
  203. Array.prototype.indexOf = Array.prototype.indexOf||function(a){
  204. for(var i = 0, l = this.length;i > l;i ++){
  205. if(this[i] === a){
  206. return i;
  207. }
  208. }
  209. return -1;
  210. };
  211. Hilo.Stage.prototype._initRenderer = function(properties){
  212. var canvas = this.canvas;
  213. if(typeof canvas === 'string') canvas = Hilo.getElement(canvas);
  214. var container = properties.container;
  215. if(typeof container === 'string') container = Hilo.getElement(container);
  216. if(!container) container = document.body;
  217. if(canvas && canvas.parentNode){
  218. container = container||canvas.parentNode;
  219. canvas.parentNode.removeChild(canvas);
  220. }
  221. this.canvas = container;
  222. var width = this.width, height = this.height,
  223. viewport = this.updateViewport();
  224. if(!properties.width) width = (viewport && viewport.width) || 320;
  225. if(!properties.height) height = (viewport && viewport.height) || 480;
  226. that._insertSwf(Hilo.copy(option, {
  227. container:container,
  228. width:width * (this.scaleX||1),
  229. height:height * (this.scaleY||1)
  230. }));
  231. var props = {canvas:container, stage:this, commands:flashCommands};
  232. this.renderer = new FlashRenderer(props);
  233. };
  234. Hilo.Stage.prototype.addTo = function(domElement){
  235. var swf = this._swf;
  236. if(swf && swf.parentNode !== domElement){
  237. domElement.appendChild(swf);
  238. }
  239. return this;
  240. };
  241. var enableDOMEvent = Hilo.Stage.prototype.enableDOMEvent;
  242. Hilo.Stage.prototype.enableDOMEvent = function(type, enabled){
  243. var canvas = this.canvas;
  244. if(!canvas.addEventListener){
  245. canvas.addEventListener = function(type, handler){
  246. canvas.attachEvent('on' + type, handler);
  247. };
  248. canvas.removeEventListener = function(type, handler){
  249. canvas.detachEvent('on' + type, handler);
  250. };
  251. }
  252. return enableDOMEvent.call(this, type, enabled);
  253. };
  254. var onDOMEvent = Hilo.Stage.prototype._onDOMEvent;
  255. Hilo.Stage.prototype._onDOMEvent = function(e){
  256. onDOMEvent.call(this, e || fixEvent());
  257. };
  258. Hilo.View.prototype.release = function(){
  259. this.removeFromParent();
  260. if(this.fid){
  261. flashCommands.push("release", this.fid);
  262. }
  263. };
  264. Hilo.Text.prototype.render = function(renderer){
  265. renderer.draw(this);
  266. };
  267. Hilo.Graphics.prototype.render = function(renderer){
  268. renderer.draw(this);
  269. };
  270. var graphicsFuncs = [
  271. "lineStyle", "beginFill", "endFill",
  272. "beginBitmapFill", "beginPath", "closePath", "moveTo", "lineTo", "quadraticCurveTo", "bezierCurveTo",
  273. "drawRect", "drawRoundRectComplex", "drawRoundRect", "drawCircle", "drawEllipse", "cache", "uncache", "clear"
  274. ];
  275. //flashGraphicsCommands command由";"分割 参数由","分割 参数中数组由":"分割
  276. for(var i = 0;i < graphicsFuncs.length;i ++){
  277. var funcName = graphicsFuncs[i];
  278. Hilo.Graphics.prototype[funcName] = function(funcName){
  279. return function(){
  280. var args = Array.prototype.slice.call(arguments);
  281. var arr = [funcName].concat(args).join(",");
  282. this.flashGraphicsCommands = this.flashGraphicsCommands||[];
  283. this.flashGraphicsCommands.push(arr);
  284. this.isDirty = true;
  285. return this;
  286. }
  287. }(funcName);
  288. }
  289. Hilo.Graphics.prototype.beginRadialGradientFill = function(x0, y0, r0, x1, y1, r1, colors, ratios){
  290. var cmd = ["beginRadialGradientFill", x0, y0, r0, x1, y1, r1, colors.join(":"), ratios.join(":")].join(",");
  291. this.flashGraphicsCommands = this.flashGraphicsCommands||[];
  292. this.flashGraphicsCommands.push(cmd);
  293. this.isDirty = true;
  294. return this;
  295. };
  296. Hilo.Graphics.prototype.beginLinearGradientFill = function(x0, y0, x1, y1, colors, ratios){
  297. var cmd = ["beginLinearGradientFill", x0, y0, x1, y1, colors.join(":"), ratios.join(":")].join(",");
  298. this.flashGraphicsCommands = this.flashGraphicsCommands||[];
  299. this.flashGraphicsCommands.push(cmd);
  300. this.isDirty = true;
  301. return this;
  302. };
  303. Hilo.Graphics.prototype.drawSVGPath = function(pathData){
  304. var me = this, addAction = me._addAction,
  305. path = pathData.split(/,| (?=[a-zA-Z])/);
  306. me.beginPath();
  307. for(var i = 0, len = path.length; i < len; i++){
  308. var str = path[i], cmd = str.charAt(0).toUpperCase(), p = str.substring(1).split(/,| /);
  309. if(p[0].length == 0) p.shift();
  310. switch(cmd){
  311. case 'M':
  312. me.moveTo(p[0], p[1]);
  313. break;
  314. case 'L':
  315. me.lineTo(p[0], p[1]);
  316. break;
  317. case 'C':
  318. me.bezierCurveTo(p[0], p[1], p[2], p[3], p[4], p[5]);
  319. break;
  320. case 'Z':
  321. me.closePath();
  322. break;
  323. }
  324. }
  325. return me;
  326. };
  327. Hilo.WebSound.removeAudio = function(source){
  328. var src = typeof source === 'string' ? source : source.src;
  329. var audio = this._audios[src];
  330. if(audio){
  331. audio.stop();
  332. audio.off();
  333. audio.release();
  334. this._audios[src] = null;
  335. delete this._audios[src];
  336. }
  337. };
  338. Hilo.WebAudio.isSupported = true;
  339. Hilo.WebAudio.enabled = true;
  340. Hilo.WebAudio.enable = function(){};
  341. Hilo.WebAudio.prototype._init = function(){
  342. this.fid = Hilo.getUid("audio");
  343. flashCommands.push("audio", "create", this.fid, this.src);
  344. if(this.autoPlay){
  345. this.play();
  346. }
  347. };
  348. Hilo.WebAudio.prototype.load = function(){
  349. flashCommands.push("audio", "load", this.fid);
  350. return this;
  351. };
  352. Hilo.WebAudio.prototype.play = function(){
  353. flashCommands.push("audio", "play", this.fid, this.loop?1:0);
  354. return this;
  355. };
  356. Hilo.WebAudio.prototype.pause = function(){
  357. flashCommands.push("audio", "pause", this.fid);
  358. return this;
  359. };
  360. Hilo.WebAudio.prototype.resume = function(){
  361. flashCommands.push("audio", "resume", this.fid);
  362. return this;
  363. };
  364. Hilo.WebAudio.prototype.stop = function(){
  365. flashCommands.push("audio", "stop", this.fid);
  366. return this;
  367. };
  368. Hilo.WebAudio.prototype.setVolume = function(volume){
  369. flashCommands.push("audio", "setVolume", this.fid, volume);
  370. return this;
  371. };
  372. Hilo.WebAudio.prototype.setMute = function(muted){
  373. flashCommands.push("audio", "setMute", this.fid, muted?1:0);
  374. return this;
  375. };
  376. Hilo.WebAudio.prototype.release = function(){
  377. flashCommands.push("audio", "release", this.fid);
  378. return this;
  379. };
  380. },
  381. _insertSwf:function(option){
  382. var that = this;
  383. var swf;
  384. var src = option.url;
  385. var id = option.id;
  386. var color = option.color||null;
  387. var fps = option.fps;
  388. var container = option.container;
  389. var width = option.width;
  390. var height = option.height;
  391. this.setFps(fps);
  392. if(window.attachEvent){
  393. var hasHTML = container.innerHTML;
  394. container.innerHTML =
  395. '<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"' +
  396. ' codebase="' + location.protocol + '//fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0">' +
  397. '<param name="allowScriptAccess" value="always">' +
  398. '<param name="flashvars" value="id=' + id + '">' +
  399. '<param name="wmode" value="transparent">' +
  400. '<param name="bgcolor" value="' + color + '">' +
  401. '</object>' + hasHTML;
  402. var swf = container.getElementsByTagName("object")[0];
  403. swf["movie"] = src;
  404. }
  405. else{
  406. swf = document.createElement("embed");
  407. swf.setAttribute("src",src);
  408. swf.setAttribute("type","application/x-shockwave-flash");
  409. swf.setAttribute("allowScriptAccess","always");
  410. swf.setAttribute("allowFullScreen","true");
  411. swf.setAttribute("bgcolor",color);
  412. swf.setAttribute("pluginspage","http://www.adobe.com/go/getflashplayer_cn");
  413. swf.setAttribute("wmode", "transparent");
  414. swf.setAttribute("FlashVars", "debug=0");
  415. container.appendChild(swf);
  416. }
  417. swf.name = id;
  418. swf.width = width;
  419. swf.height = height;
  420. swf.id = id;
  421. this._swf = swf;
  422. setInterval(function(){
  423. that.tick();
  424. }, 1000/fps)
  425. return swf;
  426. },
  427. tick:function(){
  428. if(isFlashReady && flashCommands.length > 0){
  429. this._swf.CallFunction(
  430. '<invoke name="executeCommand" returntype="javascript"><arguments><string>'
  431. + flashCommands.join("√") + '</string></arguments></invoke>'
  432. );
  433. // console.log("executeCommand", flashCommands.join(","));
  434. flashCommands.length = 0;
  435. }
  436. },
  437. _addFlashCallback:function(){
  438. /*
  439. * 加载flash图片
  440. * @method loadFlashImage
  441. */
  442. Hilo.loadFlashImage = function(src, successHandler, errorHandler){
  443. imageCallBacks[src] = imageCallBacks[src]||[];
  444. imageCallBacks[src].push([successHandler, errorHandler||successHandler]);
  445. flashCommands.push("loadImage", src);
  446. };
  447. /*
  448. *flash 可以调接口时回调函数
  449. */
  450. Hilo.unlock = function(){
  451. isFlashReady = true;
  452. };
  453. /*
  454. * falsh图片加载完回调函数
  455. * @argument src:图片地址
  456. * @argument errorCode: 0:图片加载成功, 1:图片加载失败
  457. * @argument width:图片宽
  458. * argument height:图片高
  459. */
  460. Hilo.imageCallBack = function(src, errorCode, width, height){
  461. // console.log("imageCallBack", src, errorCode);
  462. var arr = imageCallBacks[src];
  463. if(arr && arr.length > 0){
  464. for(var i = 0, l = arr.length;i < l;i ++){
  465. arr[i][errorCode]({
  466. target:{
  467. src:src,
  468. width:width,
  469. height:height,
  470. isFlash:true
  471. },
  472. errorCode:errorCode
  473. });
  474. }
  475. arr.length = 0;
  476. }
  477. }
  478. }
  479. };
  480. function fixEvent(){
  481. var event = window.event;
  482. var e = {
  483. rawEvent:event,
  484. type:event.type,
  485. target:event.srcElememt,
  486. preventDefault:function(){
  487. event.returnValue = false;
  488. },
  489. stopPropagation:function(){
  490. event.cancelBubble = true;
  491. }
  492. };
  493. if(event.type.indexOf("mouse") != -1){
  494. e.clientX = event.clientX;
  495. e.clientY = event.clientY;
  496. if(event.type == "mouseover")
  497. e.relatedTarget = event.fromElement;
  498. else if(event.type == "mouseout")
  499. e.relatedTarget = event.toElement;
  500. }
  501. else if(event.type.indexOf("key") != -1){
  502. e.charCode = e.keyCode = event.keyCode;
  503. }
  504. return e;
  505. }
  506. if(selfScript.getAttribute('data-auto') === 'true') Adaptor.init();
  507. return Hilo.FlashAdaptor = Adaptor;
  508. })();
  509. })();