ImageClipper.js 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112
  1. o2.widget = o2.widget || {};
  2. o2.widget.ImageClipper = o2.ImageClipper = new Class({
  3. Implements: [Options, Events],
  4. Extends: o2.widget.Common,
  5. options: {
  6. "style": "default",
  7. "path": o2.session.path+"/widget/$ImageClipper/",
  8. "imageUrl" : "",
  9. "action" : null, //上传服务,可选,如果不设置,使用公共图片服务
  10. "method": "", //使用action 的方法
  11. "parameter": {}, //action 时的url参数
  12. "data": null, //formdata 的data, H5有效
  13. "reference": "", //使用公共图片服务上传时的参数
  14. "referenceType" : "", //使用公共图片服务上传时的参数, 目前支持 processPlatformJob, processPlatformForm, portalPage, cmsDocument, forumDocument
  15. "description" : "",
  16. "aspectRatio" : 1, //生成图片的宽高比, 0 表示不限制
  17. "resultMaxSize" : 800, //生成图片的最大宽或高
  18. "editorSize" : 340, //H5有效,图形容器
  19. "frameMinSize" : 30, //H5有效, 选择框的最小宽度
  20. "previewerSize" : 260, //H5有效, 预览区域大小
  21. "showPreviewer" : true, //H5有效
  22. "fromLocalEnable" : true, //H5有效,本地图片
  23. "fromFileEnable" : true, //H5有效,云文件图片
  24. "resetEnable" : false, //H5有效
  25. "uploadSourceEnable" : true, //H5有效
  26. "downloadSourceEnable": true //H5有效
  27. },
  28. initialize: function(node, options){
  29. this.node = node;
  30. if( isNaN( options.aspectRatio ) )options.aspectRatio = 0;
  31. if( isNaN( options.resultMaxSize ) )options.resultMaxSize = 800;
  32. this.setOptions(options);
  33. this.path = this.options.path || (o2.session.path+"/widget/$ImageClipper/");
  34. this.cssPath = this.path + this.options.style+"/css.wcss";
  35. this._loadCss();
  36. this.fireEvent("init");
  37. },
  38. load: function( imageBase64 ){
  39. this.container = new Element("div.container", { styles : this.css.container}).inject(this.node);
  40. this.container.addEvent("selectstart", function(e){
  41. e.preventDefault();
  42. e.stopPropagation();
  43. });
  44. if( this.checkBroswer() ){
  45. //this._loadWithSWF();
  46. this._loadWithH5( imageBase64 );
  47. }else{
  48. this._loadWithSWF();
  49. }
  50. },
  51. _loadWithSWF : function(){
  52. this.clipper = new o2.widget.FlashImageClipper( this.container, this.options, this );
  53. this.clipper.load()
  54. },
  55. _loadWithH5 : function( imageBase64 ){
  56. this.clipper = new o2.widget.HTML5ImageClipper( this.container, this.options, this );
  57. this.clipper.load( imageBase64 )
  58. },
  59. _openDownloadDialog: function(url, saveName){
  60. /**
  61. * 通用的打开下载对话框方法,没有测试过具体兼容性
  62. * @param url 下载地址,也可以是一个blob对象,必选
  63. * @param saveName 保存文件名,可选
  64. */
  65. if( Browser.name !== 'ie' ){
  66. if(typeof url == 'object' && url instanceof Blob){
  67. url = URL.createObjectURL(url); // 创建blob地址
  68. }
  69. var aLink = document.createElement('a');
  70. aLink.href = url;
  71. aLink.download = saveName || ''; // HTML5新增的属性,指定保存文件名,可以不要后缀,注意,file:///模式下不会生效
  72. var event;
  73. if(window.MouseEvent && typeOf( window.MouseEvent ) == "function" ) event = new MouseEvent('click');
  74. else
  75. {
  76. event = document.createEvent('MouseEvents');
  77. event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
  78. }
  79. aLink.dispatchEvent(event);
  80. }else{
  81. window.navigator.msSaveBlob( url, saveName);
  82. }
  83. },
  84. download: function(){
  85. // var image = this.getBase64Image();
  86. // if( image ){
  87. // this._openDownloadDialog( this.getBase64Image(), this.clipper.fileName || new Date().format("db") );
  88. // }
  89. },
  90. downloadSourceImage: function(){
  91. this.clipper.downloadSourceImage();
  92. },
  93. downloadResizedImage: function(){
  94. this.clipper.downloadResizedImage();
  95. },
  96. uploadImage: function( success, failure ){
  97. this.clipper.uploadImage( success, failure )
  98. },
  99. getFormData : function(){
  100. return this.clipper.getFormData()
  101. },
  102. getResizedImage : function(){
  103. return this.clipper.getResizedImage();
  104. },
  105. getBase64Code : function(){
  106. return this.clipper.getBase64Code();
  107. },
  108. getBase64Image: function(){
  109. return this.clipper.getBase64Image();
  110. },
  111. close : function(){
  112. this.clipper.close();
  113. },
  114. checkBroswer : function(){
  115. if( window.Uint8Array && window.HTMLCanvasElement && window.atob && window.Blob){
  116. this.available = true;
  117. return true;
  118. }else{
  119. this.available = false;
  120. //this.container.set("html", "<p>您的浏览器不支持以下特性:</p><ul><li>canvas</li><li>Blob</li><li>Uint8Array</li><li>FormData</li><li>atob</li></ul>");
  121. return false;
  122. }
  123. }
  124. });
  125. o2.widget.FlashImageClipper = new Class({
  126. Implements: [Options, Events],
  127. options: {
  128. "style": "default",
  129. "path": o2.session.path+"/widget/$ImageClipper/",
  130. "imageUrl" : "",
  131. "action" : null, //可选,如果不设置,使用公共图片服务
  132. "method": "", //使用action 的方法
  133. "parameter": {}, //action 时的url参数
  134. "reference": "", //使用公共图片服务上传时的参数
  135. "referenceType" : "", //使用公共图片服务上传时的参数, 目前支持 processPlatformJob, processPlatformForm, portalPage, cmsDocument, forumDocument
  136. "description" : "",
  137. "aspectRatio" : 1, //生成图片的宽高比, 0 表示不限制
  138. "resultMaxSize" : 800 //生成图片的最大宽或高
  139. },
  140. initialize: function(node, options, parent){
  141. this.container = node;
  142. this.setOptions(options);
  143. this.parent = parent;
  144. if( !this.options.aspectRatio ){
  145. this.options.aspectRatio = 1;
  146. }
  147. //this.path = this.options.path || (o2.session.path+"/widget/$ImageClipper/");
  148. //this.cssPath = this.path + this.options.style+"/css.wcss";
  149. this.Previer_MaxSize = 240;
  150. this.css = this.parent.css;
  151. this.fireEvent("init");
  152. },
  153. load : function(){
  154. window.uploadevent_flash = function( value ){
  155. if( typeOf( value ) == "number" ){
  156. value += '';
  157. switch(value){
  158. case '1':
  159. alert( o2.LP.widget.uploadSuccess );
  160. var time = new Date().getTime();
  161. ok();
  162. break;
  163. case '2':
  164. if( this.isUploading ){
  165. return 0;
  166. }else{
  167. this.isUploading = true;
  168. return 1;
  169. }
  170. //if(confirm('js call upload')){
  171. // return 1;
  172. //}else{
  173. // return 0;
  174. //}
  175. break;
  176. case '-1':
  177. this.isUploading = false;
  178. //alert("您已取消!");
  179. //cancel();
  180. break;
  181. case '-2':
  182. this.isUploading = false;
  183. alert( o2.LP.widget.uploadFail );
  184. window.location.href = "#";
  185. break;
  186. default:
  187. //alert(typeof(status) + ' ' + status);
  188. }
  189. }else{
  190. this.isUploading = false;
  191. var json = JSON.parse( value );
  192. if( json.type == "error" ){
  193. alert( json.message );
  194. }else{
  195. if(this.uploadSuccess)this.uploadSuccess( json.data );
  196. }
  197. }
  198. }.bind(this);
  199. this.getUploadUrl( function(){
  200. this.renderFlash()
  201. }.bind(this));
  202. },
  203. renderFlash : function(){
  204. this.contentNode = new Element("div.contentNode", {
  205. styles : this.css.contentNode,
  206. id : "imageclipper_swf"
  207. }).inject(this.container);
  208. var path = o2.session.path+"/widget/$ImageClipper/";
  209. var imageUrl = this.options.imageUrl || path + "flash_default.png";
  210. if( this.options.aspectRatio > 1 ){
  211. var previewerWidth = this.Previer_MaxSize;
  212. var previewerHeight = this.Previer_MaxSize / this.options.aspectRatio;
  213. }else{
  214. var previewerWidth = this.Previer_MaxSize * this.options.aspectRatio;
  215. var previewerHeight = this.Previer_MaxSize;
  216. }
  217. COMMON.AjaxModule.load( path +"swfobject.js", function () {
  218. swfobject.embedSWF( path+"FaustCplus.swf", this.contentNode, "650", "370", "9.0.0", path+"expressInstall.swf", {
  219. "jsfunc":"uploadevent_flash",
  220. "imgUrl": imageUrl,
  221. "tip" : this.options.description,
  222. "aspectRatio" : this.options.aspectRatio,
  223. "reqContentDisposition" : "", //"" 或者 formData
  224. "imageUploadKey" : "thumb.jpg", //reqContentDisposition 为 formdata 时候有效,文件名称
  225. "imageSrcUploadKey" : "src.jpg", //reqContentDisposition 为 formdata 时候有效,文件名称
  226. "showZoom" : false,
  227. "showSaveBtns" : false,
  228. "showTurn" : false,
  229. "showColorAdjuster" : false,
  230. "pid":"75642723",
  231. "uploadSrc":false,
  232. "showBrow":true,
  233. "showCame":false,
  234. "pSize":"300|300|"+previewerWidth+"|"+previewerHeight, //|80|40|40|20"//,
  235. "uploadUrl": this.uploadUrl //+encodeURI("<计算的值>")+"?shortname=<计算的值>?filepath=<计算的值>?sizes=160|80|40?imgnames=face.jpg|face_medium.jpg|face_small.jpg" //sizes 几张图片的比例
  236. }, {
  237. menu: "false",
  238. scale: "noScale",
  239. allowFullscreen: "true",
  240. allowScriptAccess: "always",
  241. wmode:"transparent",
  242. bgcolor: "#FFFFFF"
  243. }, {
  244. id:"FaustCplus"
  245. }, function( swf ){
  246. this.swf = swf;
  247. }.bind(this));
  248. }.bind(this))
  249. },
  250. getUploadUrl : function( callback ){
  251. if( this.options.action ){
  252. this.action = (typeOf(this.options.action)=="string") ? o2.Actions.get(action).action : this.options.action;
  253. this.action.getActions(function(){
  254. var url = this.action.actions[this.options.method];
  255. url = this.action.address+url.uri;
  256. if(this.options.parameter){
  257. Object.each(this.options.parameter, function(v, k){
  258. url = url.replace("{"+k+"}", v);
  259. });
  260. }
  261. this.uploadUrl = url;
  262. if(callback)callback(url);
  263. }.bind(this));
  264. }else{
  265. //公共图片服务
  266. var addressObj = layout.serviceAddressList["x_file_assemble_control"];
  267. var defaultPort = layout.config.app_protocol==='https' ? "443" : "80";
  268. if (addressObj){
  269. var appPort = addressObj.port || window.location.port;
  270. var address = layout.config.app_protocol+"//"+(addressObj.host || window.location.hostname)+((!appPort || appPort.toString()===defaultPort) ? "" : ":"+appPort)+addressObj.context;
  271. // var address = layout.config.app_protocol+"//"+addressObj.host+(addressObj.port==80 ? "" : ":"+addressObj.port)+addressObj.context;
  272. }else{
  273. var host = layout.desktop.centerServer.host || window.location.hostname;
  274. var port = layout.desktop.centerServer.port || window.location.port;
  275. var address = layout.config.app_protocol+"//"+host+((!port || port.toString()===defaultPort) ? "" : ":"+port)+"/x_file_assemble_control";
  276. }
  277. var url = "/jaxrs/file/upload/referencetype/"+ this.options.referenceType + "/reference/" + this.options.reference + "/scale/" + this.options.resultMaxSize;
  278. this.uploadUrl = address+url;
  279. if(callback)callback(this.uploadUrl);
  280. }
  281. },
  282. uploadImage: function( success, failure ){
  283. this.uploadSuccess = success;
  284. if( this.swf ){
  285. this.swf.ref["jscall_updateAvatar"](); //JsCallAs是flash里addCallback的函数
  286. }
  287. },
  288. getFormData : function(){
  289. return true;
  290. },
  291. getResizedImage : function(){
  292. return true;
  293. },
  294. getBase64Code : function(){
  295. return true;
  296. },
  297. getBase64Image: function(){
  298. return true;
  299. },
  300. close : function(){
  301. }
  302. });
  303. o2.widget.HTML5ImageClipper = new Class({
  304. Implements: [Options, Events],
  305. options: {
  306. "style": "default",
  307. "path": o2.session.path+"/widget/$ImageClipper/",
  308. "imageUrl" : "",
  309. "editorSize" : 340, //图形容器
  310. "aspectRatio" : 1, //生成图片的宽高比, 0 表示不限制
  311. "frameMinSize" : 30, //选择框的最小宽度
  312. "previewerSize" : 260, //预览区域大小
  313. "resultMaxSize" : 800, //生成图片的最大宽或高
  314. "action" : null, //可选,如果不设置,使用公共图片服务
  315. "method": "", //使用action 的方法
  316. "parameter": {}, //action 时的url参数
  317. "data": null, //formdata 的data
  318. "reference": "", //使用公共图片服务上传时的参数
  319. "referenceType" : "", //使用公共图片服务上传时的参数, 目前支持 processPlatformJob, processPlatformForm, portalPage, cmsDocument, forumDocument
  320. "uploadSourceEnable" : true, //是否允许上传原图
  321. "downloadSourceEnable": true,
  322. "showPreviewer" : true,
  323. "fromLocalEnable" : true, //本地图片
  324. "fromFileEnable" : true, //云文件图片
  325. "resetEnable" : false,
  326. "description" : ""
  327. },
  328. initialize: function(node, options, parent){
  329. this.container = node;
  330. this.setOptions(options);
  331. this.parent = parent;
  332. //this.path = this.options.path || (o2.session.path+"/widget/$ImageClipper/");
  333. //this.cssPath = this.path + this.options.style+"/css.wcss";
  334. this.fileName = "untitled.png";
  335. this.fileType = "image/png";
  336. this.fileSize = null;
  337. this.css = this.parent.css;
  338. this.fireEvent("init");
  339. },
  340. load : function( imageBase64 ){
  341. this.lastPoint=null;
  342. this.loadToolBar();
  343. this.contentNode = new Element("div.contentNode", { styles : this.css.contentNode}).inject(this.container);
  344. this.loadEditorNode();
  345. this.loadResultNode();
  346. if( this.options.description ){
  347. this.loadDescriptionNode();
  348. }
  349. if( this.options.imageUrl ){
  350. this.loadImageAsUrl( this.options.imageUrl );
  351. }
  352. if( imageBase64 ){
  353. this.loadImageAsFile( this.base64ToBlob( imageBase64 ) );
  354. }
  355. },
  356. uploadImage: function( success, failure ){
  357. if( this.resizedImage ){
  358. if( this.options.action ){
  359. this.action = (typeOf(this.options.action)=="string") ? o2.Actions.get(this.options.action).action : this.options.action;
  360. this.action.invoke({
  361. "name": this.options.method,
  362. "async": true,
  363. "data": this.getFormData(),
  364. "file": this.resizedImage,
  365. "parameter": this.options.parameter,
  366. "success": function(json){
  367. success(json)
  368. }.bind(this)
  369. });
  370. }else{
  371. //公共图片上传服务
  372. var maxSize = this.options.resultMaxSize;
  373. if( this.uploadSourceInput && this.uploadSourceInput.get("checked") ){
  374. maxSize = 0; //上传原图
  375. }
  376. o2.xDesktop.uploadImageByScale(
  377. this.options.reference,
  378. this.options.referenceType,
  379. maxSize,
  380. this.getFormData(),
  381. this.resizedImage,
  382. success,
  383. failure
  384. );
  385. }
  386. }else{
  387. }
  388. },
  389. downloadSourceImage: function(){
  390. if( this.imageNode && this.imageNode.get("src") ) {
  391. this.parent._openDownloadDialog( this.imageNode.get("src"), this.fileName || new Date().format("db"));
  392. }
  393. },
  394. downloadResizedImage: function(){
  395. if( this.resizedImage ){
  396. this.parent._openDownloadDialog( this.resizedImage, this.fileName || new Date().format("db"));
  397. }
  398. },
  399. getFormData : function(){
  400. var formData = new FormData();
  401. formData.append('file',this.resizedImage, this.fileName );
  402. if( this.options.data ){
  403. Object.each(this.options.data, function(v, k){
  404. formData.append(k, v)
  405. });
  406. }
  407. return formData;
  408. },
  409. getResizedImage : function(){
  410. return this.resizedImage;
  411. },
  412. getBase64Code : function(){
  413. return this.base64Code;
  414. },
  415. getBase64Image: function(){
  416. if( !this.base64Code )return null;
  417. return 'data:'+ this.fileType +';base64,' + this.base64Code;
  418. },
  419. checkBroswer : function(){
  420. if( window.Uint8Array && window.HTMLCanvasElement && window.atob && window.Blob){
  421. this.available = true;
  422. return true;
  423. }else{
  424. this.available = false;
  425. //this.container.set("html", "<p>您的浏览器不支持以下特性:</p><ul><li>canvas</li><li>Blob</li><li>Uint8Array</li><li>FormData</li><li>atob</li></ul>");
  426. return false;
  427. }
  428. },
  429. close : function(){
  430. this.docBody.removeEvent("touchmove",this.bodyMouseMoveFun);
  431. this.docBody.removeEvent("mousemove",this.bodyMouseMoveFun);
  432. this.docBody.removeEvent("touchend",this.bodyMouseEndFun);
  433. this.docBody.removeEvent("mouseup",this.bodyMouseEndFun);
  434. this.container.destroy();
  435. delete this;
  436. },
  437. loadToolBar: function(){
  438. this.uploadToolbar = new Element("div.uploadToolbar", {
  439. "styles" : this.css.uploadToolbar
  440. }).inject(this.container);
  441. //var width = this.options.editorSize;
  442. //this.uploadToolbar.setStyle( "width" , width+ "px");
  443. if( this.options.fromLocalEnable ){
  444. this.uploadLocalImage = new Element("button.uploadActionNode",{
  445. "styles" : this.css.uploadActionNode,
  446. "text" : o2.LP.widget.selectLocalImage
  447. }).inject(this.uploadToolbar);
  448. this.uploadLocalImage.addEvents({
  449. "click": function(){ this.fileNode.click(); }.bind(this)
  450. });
  451. this.fileNode = new Element("input.file", {
  452. "type" : "file",
  453. "accept":"image/*",
  454. "styles" : {"display":"none"}
  455. }).inject(this.container);
  456. this.fileNode.addEvent("change", function(event){
  457. var file=this.fileNode.files[0];
  458. this.fileType = file.type;
  459. this.fileName = file.name;
  460. this.fileSize = file.size;
  461. this.loadImageAsFile( file );
  462. }.bind(this));
  463. }
  464. this._createUploadButtom();
  465. this.uploadCloudFileArea = new Element("span").inject( this.uploadToolbar );
  466. if( this.options.fromFileEnable ){
  467. var url = o2.session.path+"/xDesktop/$Layout/applications.json";
  468. o2.getJSON(url, function(json){
  469. json.each( function(obj){
  470. if( obj.name == "File" || obj.path == "File" ){
  471. this.uploadCloudFile = new Element("button.uploadActionNode",{
  472. "styles" : this.css.uploadActionNode,
  473. "text" : o2.LP.widget.selectCloudImage
  474. }).inject(this.uploadCloudFileArea );
  475. this.uploadCloudFile.addEvents({
  476. "click": function(){ this.selectFileImage(
  477. function( url, id ,attachmentInfo ){
  478. this.fileName = attachmentInfo.name;
  479. this.fileType = ["jpeg","jpg"].contains( attachmentInfo.extension.toLowerCase() ) ? "image/jpeg" : "image/png" ;
  480. this.fileSize = attachmentInfo.length;
  481. this.loadImageAsUrl( url );
  482. }.bind(this)
  483. ); }.bind(this)
  484. });
  485. }
  486. }.bind(this));
  487. }.bind(this));
  488. }
  489. if( this.options.uploadSourceEnable ){
  490. this.uploadSourceInput = new Element( "input", {
  491. type : "checkbox",
  492. events : {
  493. change : function(){
  494. this.clipImage();
  495. }.bind(this)
  496. }
  497. }).inject( this.uploadToolbar );
  498. new Element("span",{
  499. text : o2.LP.widget.uploadOriginalImage
  500. }).inject( this.uploadToolbar );
  501. }
  502. if( this.options.resetEnable ){
  503. this.resetAction = new Element("button.resetAction",{
  504. "styles" : this.css.resetActionNode,
  505. "text" : o2.LP.widget.empty
  506. }).inject(this.uploadToolbar);
  507. this.resetAction.addEvents({
  508. "click": function(){ this.reset(); }.bind(this)
  509. });
  510. }
  511. if( this.options.downloadSourceEnable ){
  512. this.downloadSourceAction = new Element("button.downloadSourceAction",{
  513. "styles" : this.css.resetActionNode,
  514. "text" : o2.LP.widget.download
  515. }).inject(this.uploadToolbar);
  516. this.downloadSourceAction.addEvents({
  517. "click": function(){ this.downloadSourceImage(); }.bind(this)
  518. });
  519. }
  520. },
  521. _createUploadButtom : function(){
  522. },
  523. reset: function(){
  524. this.fileName = "untitled.png";
  525. this.fileType = "image/png";
  526. this.fileSize = null;
  527. this.resizedImage = "";
  528. this.base64Code = "";
  529. this.resetImage();
  530. this.setFrameSize({width:0, height:0});
  531. this.frameOffset.top = 0;
  532. this.frameOffset.left = 0;
  533. this.frameNode.setStyles({
  534. top:0,
  535. left:0
  536. });
  537. this.resultNode.empty();
  538. this.editorContainer.setStyles( this.css.editorContainer );
  539. this.imageNode.setStyle("display","none");
  540. this.innerNode.setStyles({
  541. "width" : 0,
  542. "height" : 0
  543. })
  544. },
  545. selectFileImage : function( callback ){
  546. var _self = this;
  547. o2.xDesktop.requireApp("File", "FileSelector", function(){
  548. _self.selector_cloud = new o2.xApplication.File.FileSelector( document.body ,{
  549. "style" : "default",
  550. "title": o2.LP.widget.selectCloudImage,
  551. "copyToPublic" : false,
  552. //"reference" : _self.options.reference,
  553. //"referenceType" : _self.options.referenceType,
  554. "listStyle": "preview",
  555. "selectType" : "images",
  556. "onPostSelectAttachment" : function( url, id, attachmentInfor ){
  557. if(callback)callback(url, id, attachmentInfor );
  558. }
  559. });
  560. _self.selector_cloud.load();
  561. }, true);
  562. },
  563. loadResultNode: function(){
  564. if( this.options.showPreviewer ){
  565. this.resultContainer = new Element("div", {"styles":this.css.resultContainer}).inject(this.contentNode);
  566. var containerHeight = Math.max( this.options.editorSize ,this.options.previewerSize ) - (parseInt(this.resultContainer.getStyle("padding-left"))*2);
  567. this.resultContainer.setStyles( {
  568. "width": this.options.previewerSize+"px",
  569. "height": containerHeight +"px"
  570. } );
  571. this.resultTitleNode = new Element("div", {
  572. "styles":this.css.resultTitleNode,
  573. "text" : o2.LP.widget.preview
  574. }
  575. ).inject(this.resultContainer);
  576. var titleHeight = this.resultTitleNode.getSize().y;
  577. var nodeHeight = this.options.aspectRatio ? ( this.options.previewerSize / this.options.aspectRatio) : this.options.previewerSize ;
  578. this.resultNode = new Element("div.resultNode", {
  579. "styles":this.css.resultNode
  580. }).inject(this.resultContainer);
  581. this.resultNode.setStyles( {
  582. "padding-top": (containerHeight-titleHeight-nodeHeight)/2 - 10 +"px"
  583. } );
  584. }else{
  585. this.resultNode = new Element("div", {
  586. styles : {display : "none"}
  587. }).inject(this.contentNode);
  588. }
  589. },
  590. loadEditorNode: function(){
  591. this.docBody = window.document.body;
  592. this.editorContainer = new Element("div.editorContainer", { styles : this.css.editorContainer}).inject(this.contentNode);
  593. this.editorContainer.setStyles( {
  594. "width": this.options.editorSize+"px",
  595. "height": this.options.editorSize+"px"
  596. } );
  597. this.editorNode = new Element("div.editorNode", { styles : this.css.editorNode}).inject(this.editorContainer);
  598. this.innerNode = new Element("div.innerNode",{ styles : this.css.innerNode } ).inject(this.editorNode);
  599. this.imageNode = new Element("img",{
  600. styles : this.css.imageNode,
  601. crossOrigin :"use-credentials"
  602. }).inject(this.innerNode);
  603. this.imageNode.ondragstart = function(){
  604. return false;
  605. };
  606. this.frameNode = new Element("div.frameNode",{ styles : this.css.frameNode }).inject(this.innerNode);
  607. this.frameOffset={ top:0, left:0 };
  608. this.frameNode.addEvents({
  609. "touchstart" : function(ev){ this.getOffset(ev) }.bind(this),
  610. "mousedown" : function(ev){ this.getOffset(ev) }.bind(this),
  611. "touchmove" : function(ev){
  612. if(!this.lastPoint)return;
  613. var offset= this.getOffset(ev);
  614. if( this.resizeMode ){
  615. this.resizeFrames( offset );
  616. }else{
  617. this.moveFrames( offset );
  618. }
  619. ev.stopPropagation();
  620. }.bind(this),
  621. "mousemove" : function(ev){
  622. if(!this.lastPoint)return;
  623. var offset= this.getOffset(ev);
  624. if( this.resizeMode ){
  625. this.resizeFrames( offset );
  626. }else{
  627. this.moveFrames( offset );
  628. }
  629. ev.stopPropagation();
  630. }.bind(this),
  631. "touchend" : function(ev){
  632. this.lastPoint=null;
  633. if( this.resizeMode ){
  634. this.frameNode.setStyle("cursor", "move" );
  635. this.docBody.setStyle("cursor", "default" );
  636. this.resizeMode = false;
  637. }
  638. this.clipImage();
  639. ev.stopPropagation();
  640. }.bind(this),
  641. "mouseup" : function(ev){
  642. this.lastPoint=null;
  643. if( this.resizeMode ){
  644. this.frameNode.setStyle("cursor", "move" );
  645. this.docBody.setStyle("cursor", "default" );
  646. this.resizeMode = false;
  647. }
  648. this.clipImage();
  649. ev.stopPropagation();
  650. }.bind(this)
  651. });
  652. this.reizeNode = new Element("div.reizeNode",{ styles : this.css.reizeNode }).inject(this.frameNode);
  653. this.reizeNode.addEvents({
  654. "touchstart" : function(ev){
  655. this.frameNode.setStyle("cursor", "nw-resize" );
  656. this.docBody.setStyle("cursor", "nw-resize" );
  657. this.resizeMode = true;
  658. this.getOffset(ev);
  659. ev.stopPropagation();
  660. }.bind(this),
  661. "mousedown" : function(ev){
  662. this.frameNode.setStyle("cursor", "nw-resize" );
  663. this.docBody.setStyle("cursor", "nw-resize" );
  664. this.resizeMode = true;
  665. this.getOffset(ev);
  666. ev.stopPropagation();
  667. }.bind(this),
  668. "touchmove" : function(ev){
  669. if(!this.lastPoint)return;
  670. var offset= this.getOffset(ev);
  671. this.resizeFrames( offset );
  672. ev.stopPropagation();
  673. }.bind(this),
  674. "mousemove" : function(ev){
  675. if(!this.lastPoint)return;
  676. var offset= this.getOffset(ev);
  677. this.resizeFrames( offset );
  678. ev.stopPropagation();
  679. }.bind(this),
  680. "touchend" : function(ev){
  681. this.frameNode.setStyle("cursor", "move" );
  682. this.docBody.setStyle("cursor", "default" );
  683. this.resizeMode = false;
  684. this.lastPoint=null;
  685. this.clipImage();
  686. ev.stopPropagation();
  687. }.bind(this),
  688. "mouseup" : function(ev){
  689. this.frameNode.setStyle("cursor", "move" );
  690. this.docBody.setStyle("cursor", "default" );
  691. this.resizeMode = false;
  692. this.lastPoint=null;
  693. this.clipImage();
  694. ev.stopPropagation();
  695. }.bind(this)
  696. });
  697. this.bodyMouseMoveFun = this.bodyMouseMove.bind(this);
  698. this.docBody.addEvent("touchmove", this.bodyMouseMoveFun);
  699. this.docBody.addEvent("mousemove", this.bodyMouseMoveFun);
  700. this.bodyMouseEndFun = this.bodyMouseEnd.bind(this);
  701. this.docBody.addEvent("touchend", this.bodyMouseEndFun);
  702. this.docBody.addEvent("mouseup", this.bodyMouseEndFun);
  703. },
  704. loadDescriptionNode: function(){
  705. new Element("div",{
  706. "styles": this.css.descriptionNode,
  707. "text": this.options.description
  708. }).inject( this.container )
  709. },
  710. bodyMouseMove: function(ev){
  711. if(!this.lastPoint)return;
  712. if( this.resizeMode ){
  713. var offset= this.getOffset(ev);
  714. this.resizeFrames( offset );
  715. }
  716. },
  717. bodyMouseEnd: function(ev){
  718. this.lastPoint=null;
  719. if( this.resizeMode ){
  720. this.frameNode.setStyle("cursor", "move" );
  721. this.docBody.setStyle("cursor", "default" );
  722. this.resizeMode = false;
  723. this.clipImage();
  724. }
  725. },
  726. clipImage: function(){
  727. this.resultNode.empty();
  728. var nh=this.imageNode.naturalHeight,
  729. nw=this.imageNode.naturalWidth,
  730. max = (this.uploadSourceInput && this.uploadSourceInput.get("checked")) ? 0 : this.options.resultMaxSize,
  731. size,
  732. ratio;
  733. ratio = this.options.aspectRatio ? this.options.aspectRatio : (this.frameOffset.size.width / this.frameOffset.size.height );
  734. if( max == 0 || ( nh<=max && nw<=max )){
  735. size = this.getRatioMaxSize(nw, nh , ratio);
  736. }else{
  737. var min = Math.min(max, nh, nw);
  738. size = this.getRatioMaxSize(min, min, ratio);
  739. }
  740. var canvas = new Element("canvas", size);
  741. var ctx=canvas.getContext('2d'),
  742. scale=nw/this.offset.width,
  743. x=this.frameOffset.left*scale,
  744. y=this.frameOffset.top*scale,
  745. w=this.frameOffset.size.width*scale,
  746. h=this.frameOffset.size.height*scale;
  747. ctx.drawImage(this.imageNode,x,y,w,h,0,0,size.width,size.height);
  748. var src=canvas.toDataURL( this.fileType );
  749. this.canvas=canvas;
  750. canvas.inject(this.resultNode);
  751. src=src.split(',')[1];
  752. if(!src){
  753. this.resizedImage = null;
  754. this.base64Code = "";
  755. return;
  756. }
  757. this.base64Code = src;
  758. src=window.atob(src);
  759. var ia = new Uint8Array(src.length);
  760. for (var i = 0; i < src.length; i++) {
  761. ia[i] = src.charCodeAt(i);
  762. }
  763. this.resizedImage = new Blob([ia], {type: this.fileType });
  764. var fileName = "image_"+new Date().getTime();
  765. if( this.fileType && this.fileType.contains("/") ) {
  766. this.resizedImage.name = fileName + "." + this.fileType.split("/")[1];
  767. }else{
  768. this.resizedImage.name = fileName + ".unknow";
  769. }
  770. var min = Math.min(this.options.previewerSize, nh, nw, this.options.resultMaxSize);
  771. size = this.getRatioMaxSize(min, min, ratio);
  772. canvas.setStyles({
  773. width : size.width + "px",
  774. height : size.height + "px"
  775. });
  776. },
  777. loadImageAsFile: function( file ){
  778. this.resetImage();
  779. this.editorContainer.setStyles( this.css.editorContainer_active );
  780. this.imageNode.setStyle("display","");
  781. this.setFrameSize({width:0, height:0});
  782. this.frameOffset.top = 0;
  783. this.frameOffset.left = 0;
  784. this.frameNode.setStyles({
  785. top:0,
  786. left:0
  787. });
  788. var reader=new FileReader();
  789. reader.onload=function(){
  790. this.imageNode.src=reader.result;
  791. reader = null;
  792. //this.setImageSize();
  793. //this.setFrameSize( this.getDefaultSize() );
  794. //this.clipImage();
  795. this.onImageLoad();
  796. }.bind(this);
  797. reader.readAsDataURL(file);
  798. },
  799. loadImageAsUrl: function( url ){
  800. this.resetImage();
  801. this.editorContainer.setStyles( this.css.editorContainer_active );
  802. this.imageNode.setStyle("display","");
  803. this.setFrameSize({width:0, height:0});
  804. this.frameOffset.top = 0;
  805. this.frameOffset.left = 0;
  806. this.frameNode.setStyles({
  807. top:0,
  808. left:0
  809. });
  810. this.onImageLoadFun = this.onImageLoad.bind(this);
  811. this.imageNode.addEvent( "load",this.onImageLoadFun );
  812. this.imageNode.src = url;
  813. },
  814. onImageLoad: function(){
  815. var nh=this.imageNode.naturalHeight,
  816. nw=this.imageNode.naturalWidth;
  817. if( isNaN(nh) || isNaN(nw) || nh == 0 || nw == 0 ){
  818. setTimeout( function(){
  819. this.onImageLoad();
  820. }.bind(this), 100 );
  821. }else{
  822. this._onImageLoad();
  823. }
  824. },
  825. _onImageLoad: function(){
  826. this.setImageSize();
  827. this.setFrameSize( this.getDefaultSize() );
  828. this.clipImage();
  829. if(this.onImageLoadFun){
  830. this.imageNode.removeEvent("load", this.onImageLoadFun);
  831. this.onImageLoadFun = null;
  832. }
  833. },
  834. resetImage: function(){
  835. this.imageNode.src='';
  836. if( this.canvas )this.canvas.destroy();
  837. },
  838. setImageSize: function(){
  839. var nh=this.imageNode.naturalHeight,
  840. nw=this.imageNode.naturalWidth,
  841. size;
  842. if( nw > nh ){
  843. size = {
  844. width : this.options.editorSize,
  845. height : this.options.editorSize * (nh / nw)
  846. }
  847. }else{
  848. size = {
  849. width : this.options.editorSize * (nw / nh),
  850. height : this.options.editorSize
  851. }
  852. }
  853. //if( isNaN(size.width) || isNaN(size.height) ){
  854. // debugger;
  855. //}
  856. this.offset = size;
  857. this.imageNode.setStyles( size );
  858. },
  859. setFrameSize: function(size){
  860. this.frameOffset.size=size;
  861. return this.frameNode.setStyles({
  862. width:size.width+'px',
  863. height:size.height+'px'
  864. });
  865. },
  866. getDefaultSize: function(){
  867. this.innerNode.setStyles({
  868. "width" : this.offset.width,
  869. "height" : this.offset.height,
  870. "margin-left" : (this.options.editorSize-this.offset.width)/2 +"px",
  871. "margin-top" : (this.options.editorSize-this.offset.height)/2 +"px"
  872. });
  873. if( this.options.aspectRatio ){
  874. return this.getRatioMaxSize(this.offset.width, this.offset.height);
  875. }else{
  876. //var min = Math.min(this.offset.width, this.offset.height);
  877. //return { width : min, height : min };
  878. return {
  879. width : this.offset.width,
  880. height : this.offset.height
  881. };
  882. }
  883. },
  884. getRatioMaxSize: function( width, height , radio ){
  885. if( !radio )radio = this.options.aspectRatio;
  886. var r = width / height;
  887. if( r > radio ){
  888. return {
  889. width : height * radio,
  890. height : height
  891. }
  892. }else{
  893. return {
  894. width : width,
  895. height : width / radio
  896. }
  897. }
  898. },
  899. resizeFrames: function( offset ){
  900. var x=offset.x;
  901. if( x == 0 )return;
  902. var y=offset.y;
  903. if( y == 0 )return;
  904. var top=this.frameOffset.top,
  905. left=this.frameOffset.left,
  906. size=this.frameOffset.size,
  907. width=this.offset.width,
  908. height=this.offset.height,
  909. ratio = this.options.aspectRatio,
  910. w,
  911. h;
  912. if( ratio ){
  913. if( Math.abs(x)/Math.abs(y) > ratio ){
  914. if( x+size.width+left>width ){
  915. return;
  916. }else{
  917. w = x + size.width;
  918. h = w / ratio;
  919. if( h+top > height ){
  920. return;
  921. }
  922. }
  923. }else{
  924. if(y+size.height+top>height){
  925. return;
  926. }else{
  927. h = y+ size.height;
  928. w = h * ratio;
  929. }
  930. if( w+left > width ){
  931. return;
  932. }
  933. }
  934. }else{
  935. if( x+size.width+left>width ){
  936. return;
  937. }else{
  938. w = x + size.width
  939. }
  940. if(y+size.height+top>height){
  941. return;
  942. }else{
  943. h = y+ size.height;
  944. }
  945. }
  946. var minWidth = this.options.frameMinSize;
  947. var minHeight = ratio ? minWidth / ratio : minWidth;
  948. w=w< minWidth ?minWidth:w;
  949. h=h< minHeight ? minHeight:h;
  950. this.frameNode.setStyles({
  951. width:w+'px',
  952. height:h+'px'
  953. });
  954. this.frameOffset.size={
  955. width : w,
  956. height : h
  957. }
  958. },
  959. moveFrames: function(offset){
  960. var x=offset.x,
  961. y=offset.y,
  962. top=this.frameOffset.top,
  963. left=this.frameOffset.left,
  964. size=this.frameOffset.size,
  965. width=this.offset.width,
  966. height=this.offset.height;
  967. if(x+size.width+left>width){
  968. x=width-size.width;
  969. }else{
  970. x=x+left;
  971. }
  972. if(y+size.height+top>height){
  973. y=height-size.height;
  974. }else{
  975. y=y+top;
  976. }
  977. x=x<0?0:x;
  978. y=y<0?0:y;
  979. this.frameNode.setStyles({
  980. top:y+'px',
  981. left:x+'px'
  982. });
  983. this.frameOffset.top=y;
  984. this.frameOffset.left=x;
  985. },
  986. getOffset: function(event){
  987. event=event.event;
  988. var x,y;
  989. if(event.touches){
  990. var touch=event.touches[0];
  991. x=touch.clientX;
  992. y=touch.clientY;
  993. }else{
  994. x=event.clientX;
  995. y=event.clientY;
  996. }
  997. if(!this.lastPoint){
  998. this.lastPoint={
  999. x:x,
  1000. y:y
  1001. };
  1002. }
  1003. var offset={
  1004. x:x-this.lastPoint.x,
  1005. y:y-this.lastPoint.y
  1006. };
  1007. this.lastPoint={
  1008. x:x,
  1009. y:y
  1010. };
  1011. return offset;
  1012. },
  1013. base64ToBlob : function( base64 ){
  1014. if( base64.substr( 0, 10 ) == 'data:image' ){
  1015. var bytes=window.atob(base64.split(',')[1]); //去掉url的头,并转换为byte
  1016. }else{
  1017. var bytes=window.atob(base64)
  1018. }
  1019. //处理异常,将ascii码小于0的转换为大于0
  1020. var ab = new ArrayBuffer(bytes.length);
  1021. var ia = new Uint8Array(ab);
  1022. for (var i = 0; i < bytes.length; i++) {
  1023. ia[i] = bytes.charCodeAt(i);
  1024. }
  1025. return new Blob( [ab] , {type : this.fileType });
  1026. }
  1027. });