imgMerge.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536
  1. /**
  2. * Loren
  3. *
  4. * imgMerge 1.0.2
  5. *
  6. * Released on: August 1, 2018
  7. */
  8. (function() {
  9. function imgMergeClass(options){
  10. // data默认值
  11. /*
  12. * {
  13. * val:'xxxx.png', // 文字或图片 必填
  14. * x:0, // x坐标 非必填
  15. * y:0, // y坐标 非必填
  16. * color:'#000', // 字体颜色 非必填
  17. * fontSize:"12px", // 字体大小 非必填
  18. * fontFamily:"Arial", // 字体 非必填
  19. * fontAlign:"left", // 字体对齐 非必填
  20. * zIndex:"", // 层级 非必填
  21. * scale:1, // 缩放 非必填
  22. * rotation:0, // 旋转 非必填
  23. * }
  24. */
  25. this.fontFamily = '"Arial", "Verdana", "sans-serif"';
  26. // 默认参数
  27. this.options = {
  28. canvasEl:null,
  29. cWidth:750,
  30. cHeight:1206,
  31. data:[],
  32. moveIndex:null,
  33. parentBoxEl:'',
  34. bgColor:"#ffffff"
  35. };
  36. // 图片判断正则
  37. this.imgReg = /.png|.jpg/i;
  38. // base64 正则
  39. this.base64Reg = /^data:image\/(jpeg|png|gif);base64,/;
  40. // 第一次加载完成的数量
  41. this.loadEndIndex = 0;
  42. for ( var i in options ) {
  43. this.options[i] = options[i];
  44. }
  45. if(this.options.canvasEl){
  46. this.canvas = this.options.canvasEl;
  47. }else{
  48. this.canvas = document.createElement('canvas');
  49. }
  50. if(this.options.parentBoxEl != ''){
  51. this.viewAdaptation();
  52. }else{
  53. this.canvas.width = this.options.cWidth;
  54. this.canvas.height = this.options.cHeight;
  55. }
  56. this.stage = new createjs.Stage(this.canvas);
  57. this.container = new createjs.Container();
  58. // 添加背景色
  59. this.addBgColor();
  60. // 默认参数合并
  61. for ( var i in options ) {
  62. this.options[i] = options[i];
  63. }
  64. this.dataInit();
  65. }
  66. // 添加背景色
  67. imgMergeClass.prototype.addBgColor = function(){
  68. var graphics = new createjs.Graphics().beginFill(this.options.bgColor).drawRect(0, 0, this.options.cWidth, this.options.cHeight);
  69. var shape = new createjs.Shape(graphics);
  70. this.stage.addChild(shape,this.container);
  71. }
  72. // 元素初始化
  73. imgMergeClass.prototype.dataInit = function(){
  74. var dataLength = this.options.data.length;
  75. if(this.options.moveIndex != null){
  76. var id = this.getIdData(this.options.moveIndex);
  77. if(id != -1){
  78. this.options.moveIndex = id;
  79. }else if(!this.options.data[this.options.moveIndex]){
  80. this.options.moveIndex = null;
  81. }
  82. }
  83. for(var d = 0;d<dataLength;d++){
  84. var data = this.options.data[d];
  85. (function(k){
  86. // 判断是不是图片
  87. this.dataCheck(data,k,dataLength);
  88. }.bind(this)(d))
  89. }
  90. this.update();
  91. }
  92. // 添不添加移动事件
  93. imgMergeClass.prototype.isAddImgEvent = function(val){
  94. if(this.options.moveIndex != null){
  95. var imgData = this.options.data[this.options.moveIndex].val;
  96. this.hammerData = {
  97. oldScale: 1,
  98. oldLateY: 0,
  99. oldLateX: 0,
  100. oldAngel: 0,
  101. oldAngel2:0,
  102. lastAngel:0,
  103. lastScale:imgData.scaleY-1,
  104. isScale:false,
  105. beginScale: 0,
  106. IsIn:true,
  107. };
  108. this.addMoveImgEvent();
  109. }
  110. };
  111. imgMergeClass.prototype.removeMove = function(){
  112. this.fileImg = false;
  113. }
  114. // 增加图片事件
  115. imgMergeClass.prototype.addMoveImgEvent = function(){
  116. var _this = this;
  117. this.fileImg = this.options.data[this.options.moveIndex].val;
  118. this.hammer = new Hammer(this.canvas);
  119. this.hammer.on("pinchmove", function (e) {
  120. if(!this.fileImg)return false;
  121. var scale;
  122. scale = this.hammerData.lastScale + this.hammerData.oldScale * e.scale
  123. if(scale >= 0.05){
  124. _this.fileImg.scaleX = scale;
  125. _this.fileImg.scaleY = scale;
  126. }
  127. }.bind(this));
  128. this.hammer.on("pinchend", function (e) {
  129. if(!this.fileImg)return false;
  130. this.hammerData.lastScale = _this.fileImg.scaleY-1;
  131. this.hammerData.beginScale = -1;
  132. this.hammerData.isFirst = false;
  133. }.bind(this))
  134. this.hammer.on("pan", function (e) {
  135. if(!this.fileImg)return false;
  136. var y = _this.fileImg.y + (e.deltaY - this.hammerData.oldLateY)*2;
  137. var x = _this.fileImg.x + (e.deltaX - this.hammerData.oldLateX)*2;
  138. this.hammerData.oldLateX = e.deltaX;
  139. this.hammerData.oldLateY = e.deltaY;
  140. _this.fileImg.x = x;
  141. _this.fileImg.y = y;
  142. }.bind(this));
  143. this.hammer.on("panend", function (e) {
  144. if(!this.fileImg)return false;
  145. this.hammerData.oldLateX = 0;
  146. this.hammerData.oldLateY = 0;
  147. }.bind(this));
  148. this.hammer.on("rotatestart", function (e) {
  149. if(!this.fileImg)return false;
  150. this.hammerData.oldAngel = e.rotation;
  151. }.bind(this))
  152. this.hammer.on("rotatemove", function (e) {
  153. if(!this.fileImg)return false;
  154. var oldAngel = e.rotation - this.hammerData.oldAngel;
  155. this.hammerData.oldAngel = e.rotation;
  156. _this.fileImg.rotation += oldAngel;
  157. }.bind(this));
  158. this.hammer.on("rotateend", function (e) {
  159. if(!this.fileImg)return false;
  160. }.bind(this));
  161. this.hammer.add(new Hammer.Pan({ threshold: 0, pointers: 0 }));
  162. this.hammer.add(new Hammer.Rotate({ threshold: 0 })).recognizeWith(this.hammer.get('pan'));
  163. this.hammer.add(new Hammer.Pinch({ threshold: 0 })).recognizeWith([this.hammer.get('pan'), this.hammer.get('rotate')]);
  164. createjs.Ticker.framerate = 30;
  165. createjs.Ticker.addEventListener("tick", this.stage);
  166. }
  167. // 元素校验
  168. imgMergeClass.prototype.dataCheck = function(obj,index,length){
  169. // 如果没有index 就是单独新增
  170. // 判断是不是图片
  171. if(this.imgReg.test(obj.val) || this.base64Reg.test(obj.val)){
  172. var imgX = obj.x || 0;
  173. var imgY = obj.y || 0;
  174. var imgScale = obj.scale || 1;
  175. var imgRotation = obj.rotation || 0;
  176. var imgN = new Image();
  177. imgN.src = obj.val;
  178. if(typeof index === "number"){
  179. imgN.index = index;
  180. }else{
  181. imgN.index = this.options.data.length-1;
  182. }
  183. imgN.data = obj;
  184. imgN.onload = function(){
  185. var img = new createjs.Bitmap(imgN);
  186. img.x = imgX;
  187. img.y = imgY;
  188. img.scaleX = imgScale;
  189. img.scaleY = imgScale;
  190. img.rotation = imgRotation;
  191. var shapeValIndex = imgN.index;
  192. this.options.data[shapeValIndex].val = img;
  193. if(typeof index === "number"){
  194. this.imgDataInit(img);
  195. if(this.options.moveIndex == shapeValIndex){
  196. this.isAddImgEvent(imgN.data.moveIndex);
  197. }
  198. ++this.loadEndIndex;
  199. }else{
  200. // 判断需不需要更新需要移动的元素
  201. if(this.options.moveIndex){
  202. this.fileImg = this.options.data[this.options.moveIndex].val;
  203. var fileImgW = this.fileImg.getBounds().width/2;
  204. var fileImgH = this.fileImg.getBounds().height/2;
  205. if(this.fileImg.regX != fileImgW && this.fileImg.regY != fileImgH){
  206. this.imgDataInit(this.fileImg);
  207. }
  208. }
  209. }
  210. // 判断图片是否铺满剧中
  211. if(imgN.data.align == 'center'){
  212. if(imgN.width > imgN.height){
  213. var scale = this.options.cWidth/imgN.width;
  214. }else{
  215. var scale = this.options.cHeight/imgN.height;
  216. }
  217. if(imgN.width > this.options.cWidth || imgN.height > this.options.cHeight){
  218. img.scaleX = scale;
  219. img.scaleY = scale;
  220. img.x -= (imgN.width - imgN.width*scale)/2;
  221. img.y -= (imgN.height - imgN.height*scale)/2;
  222. img.x += this.options.cWidth/2 - imgN.width*scale/2;
  223. img.y += this.options.cHeight/2 - imgN.height*scale/2;
  224. }else{
  225. img.x += this.options.cWidth/2 - imgN.width*img.scaleX/2;
  226. img.y += this.options.cHeight/2 - imgN.height*img.scaleX/2;
  227. }
  228. }
  229. // 执行图片加载完成的回调
  230. if(typeof imgN.data.callback == 'function'){
  231. imgN.data.callback(img,imgN.width,imgN.height);
  232. }
  233. this.container.addChild(img);
  234. this.stage.update();
  235. this.dataSort();
  236. if(this.loadEndIndex >= length){
  237. this.loadingEnd();
  238. }
  239. }.bind(this);
  240. imgN.onerror = function(){
  241. alert("图片地址错误");
  242. }
  243. }else{
  244. // 文字默认参数
  245. var defaultObj = {
  246. x:0,
  247. y:0,
  248. color:'#000',
  249. fontSize:"12px",
  250. fontFamily:this.fontFamily,
  251. fontAlign:"left",
  252. val:'',
  253. scale:1,
  254. rotation:0,
  255. callback:null
  256. }
  257. for ( var i in defaultObj) {
  258. defaultObj[i] = obj[i];
  259. }
  260. obj = defaultObj;
  261. var textN = new createjs.Text(obj.val, obj.fontSize+" "+obj.fontFamily, obj.color);
  262. textN.setTransform(obj.x,obj.y,obj.scale,obj.scale,obj.rotation);
  263. textN.textAlign = obj.fontAlign;
  264. this.container.addChild(textN);
  265. if(typeof index === "number"){
  266. this.options.data[index].val = textN;
  267. if(this.options.moveIndex == index){
  268. this.isAddImgEvent(obj.moveIndex);
  269. }
  270. ++this.loadEndIndex;
  271. }else{
  272. this.options.data[this.options.data.length-1].val = textN;
  273. this.dataSort();
  274. }
  275. if(typeof obj.callback == 'function'){
  276. obj.callback();
  277. }
  278. }
  279. };
  280. imgMergeClass.prototype.imgDataInit = function (file){
  281. var fileImgW = file.getBounds().width/2;
  282. var fileImgH = file.getBounds().height/2;
  283. var regX = fileImgW - file.regX;
  284. var regY = fileImgH - file.regY;
  285. file.regX = regX;
  286. file.regY = regY;
  287. var fileImgX = file.scaleX*regX;
  288. var fileImgY = file.scaleX*regY;
  289. file.x += fileImgX;
  290. file.y += fileImgY;
  291. return file;
  292. }
  293. // 全部元素加载完成
  294. imgMergeClass.prototype.loadingEnd = function (){
  295. this.dataSort();
  296. this.update();
  297. if(typeof this.options.firstAllLoadEnd == 'function'){
  298. this.options.firstAllLoadEnd();
  299. }
  300. }
  301. // 添加元素到画布
  302. imgMergeClass.prototype.addData = function(data){
  303. var arr = [];
  304. if(typeof data === 'object' && data.val){
  305. arr.push(data);
  306. data = arr;
  307. }
  308. if(data instanceof Array){
  309. for(var i = 0,dataLength = data.length;i<dataLength;i++){
  310. this.options.data.push(data[i]);
  311. (function(k){
  312. // 判断是不是图片
  313. this.dataCheck(data[k]);
  314. }.bind(this)(i))
  315. }
  316. }
  317. }
  318. // 删除元素
  319. imgMergeClass.prototype.removeData = function(val){
  320. val = val || 'delactAll';
  321. var index = -1,idArr = [];
  322. if(val == 'delactAll'){
  323. idArr = [];
  324. this.container.removeAllChildren();
  325. this.options.data = [];
  326. this.update();
  327. }else if(val instanceof Array){
  328. idArr = val;
  329. }else{
  330. idArr.push(val);
  331. }
  332. for(var i = 0,idLength = idArr.length;i<idLength;i++){
  333. var idIndex = this.getIdData(idArr[i]);
  334. if(idIndex != -1){
  335. var index = idIndex;
  336. }else if(typeof idArr[i] === 'number'){
  337. var index = val;
  338. }
  339. if(index != -1 || this.options.data[index]){
  340. this.container.removeChild(this.options.data[index].val);
  341. this.options.data.splice(index,1);
  342. this.update();
  343. }
  344. index = -1;
  345. }
  346. }
  347. // 获取id的元素
  348. imgMergeClass.prototype.getIdData = function(id){
  349. for(var i = 0;i<this.options.data.length;i++){
  350. if(this.options.data[i].id == id){
  351. return i;
  352. }
  353. }
  354. return -1;
  355. }
  356. // 改变移动的图片
  357. imgMergeClass.prototype.changeMoveImg = function(val){
  358. var index = -1;
  359. if(this.getIdData(val) != -1){
  360. var index = this.getIdData(val);
  361. }else if(typeof val === 'number' && this.options.data[index].val){
  362. var index = val;
  363. }
  364. if(index != -1){
  365. this.options.moveIndex = index;
  366. this.fileImg = this.options.data[index].val;
  367. this.hammerData = {
  368. oldScale: 1,
  369. oldLateY: 0,
  370. oldLateX: 0,
  371. oldAngel: 0,
  372. oldAngel2:0,
  373. lastAngel:0,
  374. lastScale:this.options.data[index].scale-1 || 0,
  375. isScale:false,
  376. beginScale: 0,
  377. IsIn:true,
  378. };
  379. // 添加元素的时候添加移动事件
  380. if(!this.hammer){
  381. this.addMoveImgEvent();
  382. }
  383. }
  384. }
  385. // 添加套画布上
  386. imgMergeClass.prototype.update = function(){
  387. this.stage.update();
  388. }
  389. // 设置层级
  390. imgMergeClass.prototype.setZIndex = function(data,index){
  391. if(typeof index === "number"){
  392. this.container.setChildIndex(data,index);
  393. }
  394. }
  395. // 排序
  396. imgMergeClass.prototype.dataSort = function(data,index){
  397. var sortArr = [];
  398. for(var i = 0;i<this.options.data.length;i++){
  399. var item = this.options.data[i];
  400. if(typeof item.zIndex !== 'number'){
  401. var index = 0;
  402. }else{
  403. var index = item.zIndex;
  404. }
  405. sortArr.push(index);
  406. }
  407. function sequence(a,b){
  408. return a - b;
  409. }
  410. sortArr.sort(sequence);
  411. for(var i = 0;i<sortArr.length;i++){
  412. if(sortArr[i] != 0){
  413. var index = sortArr.indexOf(this.options.data[i].zIndex);
  414. this.setZIndex(this.options.data[i].val,index);
  415. sortArr[index] = null;
  416. }
  417. }
  418. }
  419. // 获取页面元素位置的数据
  420. imgMergeClass.prototype.getPathData = function(){
  421. var pathData = [];
  422. for(var d = 0;d<this.options.data.length;d++){
  423. var data = this.options.data[d].val;
  424. if(data.text){
  425. var obj = {
  426. text:data.text,
  427. x:data.x,
  428. y:data.y,
  429. color:data.color,
  430. };
  431. }else{
  432. var obj = {
  433. x:data.x,
  434. y:data.y,
  435. scaleX:data.scaleX,
  436. scaleY:data.scaleY,
  437. };
  438. }
  439. pathData.push(obj);
  440. }
  441. return pathData;
  442. };
  443. // 导出
  444. imgMergeClass.prototype.export = function(){
  445. var base64 = this.stage.toDataURL('image/png');
  446. return base64;
  447. };
  448. // 适配
  449. imgMergeClass.prototype.viewAdaptation = function(){
  450. // 判断是不是id
  451. var classIndex = this.options.parentBoxEl.indexOf("#");
  452. var classData = this.options.parentBoxEl.slice(1,this.options.parentBoxEl.length);
  453. if(classIndex != -1){
  454. var parentBox = document.getElementById(classData);
  455. }else{
  456. var parentBox = document.getElementsByClassName(classData);
  457. if(parentBox.length == 0){
  458. parentBox.clientWidth = 0;
  459. }else{
  460. parentBox = parentBox[0];
  461. }
  462. }
  463. var stageWidth = parentBox.clientWidth;
  464. var stageScale = stageWidth/this.options.cWidth;
  465. this.canvas.width = this.options.cWidth;
  466. this.canvas.height = this.options.cHeight;
  467. this.canvas.style.width = this.options.cWidth*stageScale + 'px';
  468. this.canvas.style.height = this.options.cHeight*stageScale + 'px';
  469. }
  470. // 销毁
  471. imgMergeClass.prototype.destroy = function(){
  472. // 判读有没有添加编辑事件
  473. if(this.hammer){
  474. this.hammer.off("pan");
  475. this.hammer.off("pinchmove");
  476. this.hammer.off("pinchend");
  477. this.hammer.off("panend");
  478. this.hammer.off("rotatemove");
  479. this.hammer.off("rotateend");
  480. }
  481. this.stage.removeAllChildren();
  482. createjs.Ticker.removeEventListener("tick", this.stage);
  483. }
  484. if (typeof exports !== 'undefined') exports.imgMerge = imgMergeClass;
  485. else window.imgMerge = imgMergeClass;
  486. }());