ImageClipper.js 29 KB

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