ding-image-editor 3.15.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (374) hide show
  1. package/README.md +193 -0
  2. package/dist/svg/icon-a.svg +376 -0
  3. package/dist/svg/icon-b.svg +369 -0
  4. package/dist/svg/icon-c.svg +369 -0
  5. package/dist/svg/icon-d.svg +369 -0
  6. package/dist/tui-image-editor.css +6 -0
  7. package/dist/tui-image-editor.js +62329 -0
  8. package/dist/tui-image-editor.min.css +5 -0
  9. package/dist/tui-image-editor.min.js +15 -0
  10. package/index.d.ts +334 -0
  11. package/package.json +52 -0
  12. package/src/css/buttons.styl +102 -0
  13. package/src/css/checkbox.styl +86 -0
  14. package/src/css/colorpicker.styl +98 -0
  15. package/src/css/gridtable.styl +45 -0
  16. package/src/css/icon.styl +44 -0
  17. package/src/css/index.styl +17 -0
  18. package/src/css/main.styl +163 -0
  19. package/src/css/position.styl +309 -0
  20. package/src/css/range.styl +91 -0
  21. package/src/css/submenu.styl +168 -0
  22. package/src/index.js +29 -0
  23. package/src/js/action.js +686 -0
  24. package/src/js/command/addIcon.js +42 -0
  25. package/src/js/command/addImageObject.js +34 -0
  26. package/src/js/command/addObject.js +43 -0
  27. package/src/js/command/addShape.js +51 -0
  28. package/src/js/command/addText.js +73 -0
  29. package/src/js/command/applyFilter.js +95 -0
  30. package/src/js/command/changeIconColor.js +48 -0
  31. package/src/js/command/changeSelection.js +31 -0
  32. package/src/js/command/changeShape.js +84 -0
  33. package/src/js/command/changeText.js +44 -0
  34. package/src/js/command/changeTextStyle.js +80 -0
  35. package/src/js/command/clearObjects.js +33 -0
  36. package/src/js/command/flip.js +36 -0
  37. package/src/js/command/loadImage.js +58 -0
  38. package/src/js/command/removeFilter.js +38 -0
  39. package/src/js/command/removeObject.js +37 -0
  40. package/src/js/command/resize.js +41 -0
  41. package/src/js/command/resizeCanvasDimension.js +40 -0
  42. package/src/js/command/rotate.js +64 -0
  43. package/src/js/command/setObjectPosition.js +50 -0
  44. package/src/js/command/setObjectProperties.js +55 -0
  45. package/src/js/component/cropper.js +407 -0
  46. package/src/js/component/filter.js +229 -0
  47. package/src/js/component/flip.js +146 -0
  48. package/src/js/component/freeDrawing.js +144 -0
  49. package/src/js/component/icon.js +246 -0
  50. package/src/js/component/imageLoader.js +84 -0
  51. package/src/js/component/line.js +205 -0
  52. package/src/js/component/resize.js +103 -0
  53. package/src/js/component/rotation.js +91 -0
  54. package/src/js/component/shape.js +601 -0
  55. package/src/js/component/text.js +572 -0
  56. package/src/js/component/zoom.js +708 -0
  57. package/src/js/consts.js +404 -0
  58. package/src/js/drawingMode/cropper.js +35 -0
  59. package/src/js/drawingMode/freeDrawing.js +36 -0
  60. package/src/js/drawingMode/icon.js +35 -0
  61. package/src/js/drawingMode/lineDrawing.js +36 -0
  62. package/src/js/drawingMode/resize.js +35 -0
  63. package/src/js/drawingMode/shape.js +35 -0
  64. package/src/js/drawingMode/text.js +35 -0
  65. package/src/js/drawingMode/zoom.js +37 -0
  66. package/src/js/extension/arrowLine.js +172 -0
  67. package/src/js/extension/blur.js +29 -0
  68. package/src/js/extension/colorFilter.js +104 -0
  69. package/src/js/extension/cropzone.js +568 -0
  70. package/src/js/extension/emboss.js +29 -0
  71. package/src/js/extension/mask.js +90 -0
  72. package/src/js/extension/sharpen.js +29 -0
  73. package/src/js/factory/command.js +36 -0
  74. package/src/js/factory/errorMessage.js +27 -0
  75. package/src/js/graphics.js +1539 -0
  76. package/src/js/helper/imagetracer.js +1396 -0
  77. package/src/js/helper/selectionModifyHelper.js +86 -0
  78. package/src/js/helper/shapeFilterFillHelper.js +564 -0
  79. package/src/js/helper/shapeResizeHelper.js +237 -0
  80. package/src/js/imageEditor.js +1795 -0
  81. package/src/js/interface/command.js +131 -0
  82. package/src/js/interface/component.js +127 -0
  83. package/src/js/interface/drawingMode.js +47 -0
  84. package/src/js/invoker.js +292 -0
  85. package/src/js/polyfill.js +498 -0
  86. package/src/js/ui/crop.js +139 -0
  87. package/src/js/ui/draw.js +187 -0
  88. package/src/js/ui/filter.js +510 -0
  89. package/src/js/ui/flip.js +87 -0
  90. package/src/js/ui/history.js +171 -0
  91. package/src/js/ui/icon.js +191 -0
  92. package/src/js/ui/locale/locale.js +19 -0
  93. package/src/js/ui/mask.js +96 -0
  94. package/src/js/ui/panelMenu.js +130 -0
  95. package/src/js/ui/resize.js +241 -0
  96. package/src/js/ui/rotate.js +123 -0
  97. package/src/js/ui/shape.js +265 -0
  98. package/src/js/ui/submenuBase.js +122 -0
  99. package/src/js/ui/template/controls.js +21 -0
  100. package/src/js/ui/template/mainContainer.js +38 -0
  101. package/src/js/ui/template/style.js +146 -0
  102. package/src/js/ui/template/submenu/crop.js +73 -0
  103. package/src/js/ui/template/submenu/draw.js +42 -0
  104. package/src/js/ui/template/submenu/filter.js +157 -0
  105. package/src/js/ui/template/submenu/flip.js +41 -0
  106. package/src/js/ui/template/submenu/history.js +22 -0
  107. package/src/js/ui/template/submenu/icon.js +108 -0
  108. package/src/js/ui/template/submenu/mask.js +30 -0
  109. package/src/js/ui/template/submenu/resize.js +54 -0
  110. package/src/js/ui/template/submenu/rotate.js +32 -0
  111. package/src/js/ui/template/submenu/shape.js +45 -0
  112. package/src/js/ui/template/submenu/text.js +67 -0
  113. package/src/js/ui/template/submenu/zoom.js +41 -0
  114. package/src/js/ui/text.js +279 -0
  115. package/src/js/ui/theme/standard.js +220 -0
  116. package/src/js/ui/theme/theme.js +249 -0
  117. package/src/js/ui/tools/colorpicker.js +250 -0
  118. package/src/js/ui/tools/range.js +390 -0
  119. package/src/js/ui.js +858 -0
  120. package/src/js/util.js +551 -0
  121. package/src/svg/default.svg +335 -0
  122. package/src/svg/icon-a/ic-apply.svg +6 -0
  123. package/src/svg/icon-a/ic-cancel.svg +6 -0
  124. package/src/svg/icon-a/ic-color-transparent-w.svg +12 -0
  125. package/src/svg/icon-a/ic-crop.svg +7 -0
  126. package/src/svg/icon-a/ic-delete-all.svg +6 -0
  127. package/src/svg/icon-a/ic-delete.svg +6 -0
  128. package/src/svg/icon-a/ic-draw-free.svg +5 -0
  129. package/src/svg/icon-a/ic-draw-line.svg +5 -0
  130. package/src/svg/icon-a/ic-draw.svg +6 -0
  131. package/src/svg/icon-a/ic-filter.svg +7 -0
  132. package/src/svg/icon-a/ic-flip-reset.svg +7 -0
  133. package/src/svg/icon-a/ic-flip-x.svg +6 -0
  134. package/src/svg/icon-a/ic-flip-y.svg +6 -0
  135. package/src/svg/icon-a/ic-flip.svg +6 -0
  136. package/src/svg/icon-a/ic-history-check.svg +5 -0
  137. package/src/svg/icon-a/ic-history-crop.svg +7 -0
  138. package/src/svg/icon-a/ic-history-delete.svg +9 -0
  139. package/src/svg/icon-a/ic-history-draw.svg +7 -0
  140. package/src/svg/icon-a/ic-history-filter.svg +8 -0
  141. package/src/svg/icon-a/ic-history-flip.svg +6 -0
  142. package/src/svg/icon-a/ic-history-group.svg +9 -0
  143. package/src/svg/icon-a/ic-history-icon.svg +6 -0
  144. package/src/svg/icon-a/ic-history-load.svg +7 -0
  145. package/src/svg/icon-a/ic-history-mask.svg +9 -0
  146. package/src/svg/icon-a/ic-history-resize.svg +12 -0
  147. package/src/svg/icon-a/ic-history-rotate.svg +16 -0
  148. package/src/svg/icon-a/ic-history-shape.svg +7 -0
  149. package/src/svg/icon-a/ic-history-text.svg +8 -0
  150. package/src/svg/icon-a/ic-history.svg +6 -0
  151. package/src/svg/icon-a/ic-icon-arrow-2.svg +5 -0
  152. package/src/svg/icon-a/ic-icon-arrow-3.svg +5 -0
  153. package/src/svg/icon-a/ic-icon-arrow.svg +5 -0
  154. package/src/svg/icon-a/ic-icon-bubble.svg +5 -0
  155. package/src/svg/icon-a/ic-icon-heart.svg +5 -0
  156. package/src/svg/icon-a/ic-icon-load.svg +8 -0
  157. package/src/svg/icon-a/ic-icon-location.svg +8 -0
  158. package/src/svg/icon-a/ic-icon-polygon.svg +5 -0
  159. package/src/svg/icon-a/ic-icon-star-2.svg +5 -0
  160. package/src/svg/icon-a/ic-icon-star.svg +5 -0
  161. package/src/svg/icon-a/ic-icon.svg +5 -0
  162. package/src/svg/icon-a/ic-mask-load.svg +8 -0
  163. package/src/svg/icon-a/ic-mask.svg +6 -0
  164. package/src/svg/icon-a/ic-redo.svg +7 -0
  165. package/src/svg/icon-a/ic-reset.svg +7 -0
  166. package/src/svg/icon-a/ic-resize.svg +13 -0
  167. package/src/svg/icon-a/ic-rotate-clockwise.svg +7 -0
  168. package/src/svg/icon-a/ic-rotate-counterclockwise.svg +7 -0
  169. package/src/svg/icon-a/ic-rotate.svg +7 -0
  170. package/src/svg/icon-a/ic-shape-circle.svg +5 -0
  171. package/src/svg/icon-a/ic-shape-rectangle.svg +5 -0
  172. package/src/svg/icon-a/ic-shape-triangle.svg +5 -0
  173. package/src/svg/icon-a/ic-shape.svg +6 -0
  174. package/src/svg/icon-a/ic-text-align-center.svg +6 -0
  175. package/src/svg/icon-a/ic-text-align-left.svg +6 -0
  176. package/src/svg/icon-a/ic-text-align-right.svg +6 -0
  177. package/src/svg/icon-a/ic-text-bold.svg +7 -0
  178. package/src/svg/icon-a/ic-text-italic.svg +6 -0
  179. package/src/svg/icon-a/ic-text-underline.svg +7 -0
  180. package/src/svg/icon-a/ic-text.svg +7 -0
  181. package/src/svg/icon-a/ic-undo.svg +7 -0
  182. package/src/svg/icon-a/ic-zoom-hand.svg +8 -0
  183. package/src/svg/icon-a/ic-zoom-zoom-in.svg +10 -0
  184. package/src/svg/icon-a/ic-zoom-zoom-out.svg +9 -0
  185. package/src/svg/icon-a/img-bi.svg +5 -0
  186. package/src/svg/icon-b/ic-apply.svg +6 -0
  187. package/src/svg/icon-b/ic-cancel.svg +6 -0
  188. package/src/svg/icon-b/ic-crop.svg +7 -0
  189. package/src/svg/icon-b/ic-delete-all.svg +6 -0
  190. package/src/svg/icon-b/ic-delete.svg +6 -0
  191. package/src/svg/icon-b/ic-draw-free.svg +5 -0
  192. package/src/svg/icon-b/ic-draw-line.svg +5 -0
  193. package/src/svg/icon-b/ic-draw.svg +6 -0
  194. package/src/svg/icon-b/ic-filter.svg +7 -0
  195. package/src/svg/icon-b/ic-flip-reset.svg +7 -0
  196. package/src/svg/icon-b/ic-flip-x.svg +6 -0
  197. package/src/svg/icon-b/ic-flip-y.svg +6 -0
  198. package/src/svg/icon-b/ic-flip.svg +6 -0
  199. package/src/svg/icon-b/ic-history-check.svg +5 -0
  200. package/src/svg/icon-b/ic-history-crop.svg +7 -0
  201. package/src/svg/icon-b/ic-history-delete.svg +9 -0
  202. package/src/svg/icon-b/ic-history-draw.svg +7 -0
  203. package/src/svg/icon-b/ic-history-filter.svg +8 -0
  204. package/src/svg/icon-b/ic-history-flip.svg +6 -0
  205. package/src/svg/icon-b/ic-history-group.svg +9 -0
  206. package/src/svg/icon-b/ic-history-icon.svg +6 -0
  207. package/src/svg/icon-b/ic-history-load.svg +7 -0
  208. package/src/svg/icon-b/ic-history-mask.svg +9 -0
  209. package/src/svg/icon-b/ic-history-resize.svg +12 -0
  210. package/src/svg/icon-b/ic-history-rotate.svg +16 -0
  211. package/src/svg/icon-b/ic-history-shape.svg +7 -0
  212. package/src/svg/icon-b/ic-history-text.svg +8 -0
  213. package/src/svg/icon-b/ic-history.svg +6 -0
  214. package/src/svg/icon-b/ic-icon-arrow-2.svg +5 -0
  215. package/src/svg/icon-b/ic-icon-arrow-3.svg +5 -0
  216. package/src/svg/icon-b/ic-icon-arrow.svg +5 -0
  217. package/src/svg/icon-b/ic-icon-bubble.svg +5 -0
  218. package/src/svg/icon-b/ic-icon-heart.svg +5 -0
  219. package/src/svg/icon-b/ic-icon-load.svg +8 -0
  220. package/src/svg/icon-b/ic-icon-location.svg +8 -0
  221. package/src/svg/icon-b/ic-icon-polygon.svg +5 -0
  222. package/src/svg/icon-b/ic-icon-star-2.svg +5 -0
  223. package/src/svg/icon-b/ic-icon-star.svg +5 -0
  224. package/src/svg/icon-b/ic-icon.svg +5 -0
  225. package/src/svg/icon-b/ic-mask-load.svg +8 -0
  226. package/src/svg/icon-b/ic-mask.svg +6 -0
  227. package/src/svg/icon-b/ic-redo.svg +7 -0
  228. package/src/svg/icon-b/ic-reset.svg +7 -0
  229. package/src/svg/icon-b/ic-resize.svg +13 -0
  230. package/src/svg/icon-b/ic-rotate-clockwise.svg +7 -0
  231. package/src/svg/icon-b/ic-rotate-counterclockwise.svg +7 -0
  232. package/src/svg/icon-b/ic-rotate.svg +7 -0
  233. package/src/svg/icon-b/ic-shape-circle.svg +5 -0
  234. package/src/svg/icon-b/ic-shape-rectangle.svg +5 -0
  235. package/src/svg/icon-b/ic-shape-triangle.svg +5 -0
  236. package/src/svg/icon-b/ic-shape.svg +6 -0
  237. package/src/svg/icon-b/ic-text-align-center.svg +6 -0
  238. package/src/svg/icon-b/ic-text-align-left.svg +6 -0
  239. package/src/svg/icon-b/ic-text-align-right.svg +6 -0
  240. package/src/svg/icon-b/ic-text-bold.svg +7 -0
  241. package/src/svg/icon-b/ic-text-italic.svg +6 -0
  242. package/src/svg/icon-b/ic-text-underline.svg +7 -0
  243. package/src/svg/icon-b/ic-text.svg +7 -0
  244. package/src/svg/icon-b/ic-undo.svg +7 -0
  245. package/src/svg/icon-b/ic-zoom-hand.svg +8 -0
  246. package/src/svg/icon-b/ic-zoom-zoom-in.svg +12 -0
  247. package/src/svg/icon-b/ic-zoom-zoom-out.svg +11 -0
  248. package/src/svg/icon-b/img-bi.svg +5 -0
  249. package/src/svg/icon-c/ic-apply.svg +6 -0
  250. package/src/svg/icon-c/ic-cancel.svg +6 -0
  251. package/src/svg/icon-c/ic-crop.svg +7 -0
  252. package/src/svg/icon-c/ic-delete-all.svg +6 -0
  253. package/src/svg/icon-c/ic-delete.svg +6 -0
  254. package/src/svg/icon-c/ic-draw-free.svg +5 -0
  255. package/src/svg/icon-c/ic-draw-line.svg +5 -0
  256. package/src/svg/icon-c/ic-draw.svg +6 -0
  257. package/src/svg/icon-c/ic-filter.svg +7 -0
  258. package/src/svg/icon-c/ic-flip-reset.svg +7 -0
  259. package/src/svg/icon-c/ic-flip-x.svg +6 -0
  260. package/src/svg/icon-c/ic-flip-y.svg +6 -0
  261. package/src/svg/icon-c/ic-flip.svg +6 -0
  262. package/src/svg/icon-c/ic-history-check.svg +5 -0
  263. package/src/svg/icon-c/ic-history-crop.svg +7 -0
  264. package/src/svg/icon-c/ic-history-delete.svg +9 -0
  265. package/src/svg/icon-c/ic-history-draw.svg +7 -0
  266. package/src/svg/icon-c/ic-history-filter.svg +8 -0
  267. package/src/svg/icon-c/ic-history-flip.svg +6 -0
  268. package/src/svg/icon-c/ic-history-group.svg +9 -0
  269. package/src/svg/icon-c/ic-history-icon.svg +6 -0
  270. package/src/svg/icon-c/ic-history-load.svg +7 -0
  271. package/src/svg/icon-c/ic-history-mask.svg +9 -0
  272. package/src/svg/icon-c/ic-history-resize.svg +12 -0
  273. package/src/svg/icon-c/ic-history-rotate.svg +16 -0
  274. package/src/svg/icon-c/ic-history-shape.svg +7 -0
  275. package/src/svg/icon-c/ic-history-text.svg +8 -0
  276. package/src/svg/icon-c/ic-history.svg +6 -0
  277. package/src/svg/icon-c/ic-icon-arrow-2.svg +5 -0
  278. package/src/svg/icon-c/ic-icon-arrow-3.svg +5 -0
  279. package/src/svg/icon-c/ic-icon-arrow.svg +5 -0
  280. package/src/svg/icon-c/ic-icon-bubble.svg +5 -0
  281. package/src/svg/icon-c/ic-icon-heart.svg +5 -0
  282. package/src/svg/icon-c/ic-icon-load.svg +8 -0
  283. package/src/svg/icon-c/ic-icon-location.svg +8 -0
  284. package/src/svg/icon-c/ic-icon-polygon.svg +5 -0
  285. package/src/svg/icon-c/ic-icon-star-2.svg +5 -0
  286. package/src/svg/icon-c/ic-icon-star.svg +5 -0
  287. package/src/svg/icon-c/ic-icon.svg +5 -0
  288. package/src/svg/icon-c/ic-mask-load.svg +8 -0
  289. package/src/svg/icon-c/ic-mask.svg +6 -0
  290. package/src/svg/icon-c/ic-redo.svg +7 -0
  291. package/src/svg/icon-c/ic-reset.svg +7 -0
  292. package/src/svg/icon-c/ic-resize.svg +13 -0
  293. package/src/svg/icon-c/ic-rotate-clockwise.svg +7 -0
  294. package/src/svg/icon-c/ic-rotate-counterclockwise.svg +7 -0
  295. package/src/svg/icon-c/ic-rotate.svg +7 -0
  296. package/src/svg/icon-c/ic-shape-circle.svg +5 -0
  297. package/src/svg/icon-c/ic-shape-rectangle.svg +5 -0
  298. package/src/svg/icon-c/ic-shape-triangle.svg +5 -0
  299. package/src/svg/icon-c/ic-shape.svg +6 -0
  300. package/src/svg/icon-c/ic-text-align-center.svg +6 -0
  301. package/src/svg/icon-c/ic-text-align-left.svg +6 -0
  302. package/src/svg/icon-c/ic-text-align-right.svg +6 -0
  303. package/src/svg/icon-c/ic-text-bold.svg +7 -0
  304. package/src/svg/icon-c/ic-text-italic.svg +6 -0
  305. package/src/svg/icon-c/ic-text-underline.svg +7 -0
  306. package/src/svg/icon-c/ic-text.svg +7 -0
  307. package/src/svg/icon-c/ic-undo.svg +7 -0
  308. package/src/svg/icon-c/ic-zoom-hand.svg +8 -0
  309. package/src/svg/icon-c/ic-zoom-zoom-in.svg +12 -0
  310. package/src/svg/icon-c/ic-zoom-zoom-out.svg +11 -0
  311. package/src/svg/icon-c/img-bi.svg +5 -0
  312. package/src/svg/icon-d/ic-apply.svg +6 -0
  313. package/src/svg/icon-d/ic-cancel.svg +6 -0
  314. package/src/svg/icon-d/ic-crop.svg +7 -0
  315. package/src/svg/icon-d/ic-delete-all.svg +6 -0
  316. package/src/svg/icon-d/ic-delete.svg +6 -0
  317. package/src/svg/icon-d/ic-draw-free.svg +5 -0
  318. package/src/svg/icon-d/ic-draw-line.svg +5 -0
  319. package/src/svg/icon-d/ic-draw.svg +6 -0
  320. package/src/svg/icon-d/ic-filter.svg +7 -0
  321. package/src/svg/icon-d/ic-flip-reset.svg +7 -0
  322. package/src/svg/icon-d/ic-flip-x.svg +6 -0
  323. package/src/svg/icon-d/ic-flip-y.svg +6 -0
  324. package/src/svg/icon-d/ic-flip.svg +6 -0
  325. package/src/svg/icon-d/ic-history-check.svg +5 -0
  326. package/src/svg/icon-d/ic-history-crop.svg +7 -0
  327. package/src/svg/icon-d/ic-history-delete.svg +9 -0
  328. package/src/svg/icon-d/ic-history-draw.svg +7 -0
  329. package/src/svg/icon-d/ic-history-filter.svg +8 -0
  330. package/src/svg/icon-d/ic-history-flip.svg +6 -0
  331. package/src/svg/icon-d/ic-history-group.svg +9 -0
  332. package/src/svg/icon-d/ic-history-icon.svg +6 -0
  333. package/src/svg/icon-d/ic-history-load.svg +7 -0
  334. package/src/svg/icon-d/ic-history-mask.svg +9 -0
  335. package/src/svg/icon-d/ic-history-resize.svg +12 -0
  336. package/src/svg/icon-d/ic-history-rotate.svg +16 -0
  337. package/src/svg/icon-d/ic-history-shape.svg +7 -0
  338. package/src/svg/icon-d/ic-history-text.svg +8 -0
  339. package/src/svg/icon-d/ic-history.svg +6 -0
  340. package/src/svg/icon-d/ic-icon-arrow-2.svg +5 -0
  341. package/src/svg/icon-d/ic-icon-arrow-3.svg +5 -0
  342. package/src/svg/icon-d/ic-icon-arrow.svg +5 -0
  343. package/src/svg/icon-d/ic-icon-bubble.svg +5 -0
  344. package/src/svg/icon-d/ic-icon-heart.svg +5 -0
  345. package/src/svg/icon-d/ic-icon-load.svg +8 -0
  346. package/src/svg/icon-d/ic-icon-location.svg +8 -0
  347. package/src/svg/icon-d/ic-icon-polygon.svg +5 -0
  348. package/src/svg/icon-d/ic-icon-star-2.svg +5 -0
  349. package/src/svg/icon-d/ic-icon-star.svg +5 -0
  350. package/src/svg/icon-d/ic-icon.svg +5 -0
  351. package/src/svg/icon-d/ic-mask-load.svg +8 -0
  352. package/src/svg/icon-d/ic-mask.svg +6 -0
  353. package/src/svg/icon-d/ic-redo.svg +7 -0
  354. package/src/svg/icon-d/ic-reset.svg +7 -0
  355. package/src/svg/icon-d/ic-resize.svg +13 -0
  356. package/src/svg/icon-d/ic-rotate-clockwise.svg +7 -0
  357. package/src/svg/icon-d/ic-rotate-counterclockwise.svg +7 -0
  358. package/src/svg/icon-d/ic-rotate.svg +7 -0
  359. package/src/svg/icon-d/ic-shape-circle.svg +5 -0
  360. package/src/svg/icon-d/ic-shape-rectangle.svg +5 -0
  361. package/src/svg/icon-d/ic-shape-triangle.svg +5 -0
  362. package/src/svg/icon-d/ic-shape.svg +6 -0
  363. package/src/svg/icon-d/ic-text-align-center.svg +6 -0
  364. package/src/svg/icon-d/ic-text-align-left.svg +6 -0
  365. package/src/svg/icon-d/ic-text-align-right.svg +6 -0
  366. package/src/svg/icon-d/ic-text-bold.svg +7 -0
  367. package/src/svg/icon-d/ic-text-italic.svg +6 -0
  368. package/src/svg/icon-d/ic-text-underline.svg +7 -0
  369. package/src/svg/icon-d/ic-text.svg +7 -0
  370. package/src/svg/icon-d/ic-undo.svg +7 -0
  371. package/src/svg/icon-d/ic-zoom-hand.svg +8 -0
  372. package/src/svg/icon-d/ic-zoom-zoom-in.svg +12 -0
  373. package/src/svg/icon-d/ic-zoom-zoom-out.svg +11 -0
  374. package/src/svg/icon-d/img-bi.svg +5 -0
@@ -0,0 +1,1795 @@
1
+ import { fabric } from 'fabric';
2
+ import extend from 'tui-code-snippet/object/extend';
3
+ import isUndefined from 'tui-code-snippet/type/isUndefined';
4
+ import forEach from 'tui-code-snippet/collection/forEach';
5
+ import CustomEvents from 'tui-code-snippet/customEvents/customEvents';
6
+ import Invoker from '@/invoker';
7
+ import UI from '@/ui';
8
+ import action from '@/action';
9
+ import commandFactory from '@/factory/command';
10
+ import Graphics from '@/graphics';
11
+ import { makeSelectionUndoData, makeSelectionUndoDatum } from '@/helper/selectionModifyHelper';
12
+ import { sendHostName, getObjectType } from '@/util';
13
+ import {
14
+ eventNames as events,
15
+ commandNames as commands,
16
+ keyCodes,
17
+ rejectMessages,
18
+ OBJ_TYPE,
19
+ zoomModes,
20
+ } from '@/consts';
21
+
22
+ const {
23
+ MOUSE_DOWN,
24
+ OBJECT_MOVED,
25
+ OBJECT_SCALED,
26
+ OBJECT_ACTIVATED,
27
+ OBJECT_ROTATED,
28
+ OBJECT_ADDED,
29
+ OBJECT_MODIFIED,
30
+ ADD_TEXT,
31
+ ADD_OBJECT,
32
+ TEXT_EDITING,
33
+ TEXT_CHANGED,
34
+ ICON_CREATE_RESIZE,
35
+ ICON_CREATE_END,
36
+ SELECTION_CLEARED,
37
+ SELECTION_CREATED,
38
+ ADD_OBJECT_AFTER,
39
+ } = events;
40
+
41
+ /**
42
+ * Image filter result
43
+ * @typedef {object} FilterResult
44
+ * @property {string} type - filter type like 'mask', 'Grayscale' and so on
45
+ * @property {string} action - action type like 'add', 'remove'
46
+ */
47
+
48
+ /**
49
+ * Flip status
50
+ * @typedef {object} FlipStatus
51
+ * @property {boolean} flipX - x axis
52
+ * @property {boolean} flipY - y axis
53
+ * @property {Number} angle - angle
54
+ */
55
+ /**
56
+ * Rotation status
57
+ * @typedef {Number} RotateStatus
58
+ * @property {Number} angle - angle
59
+ */
60
+
61
+ /**
62
+ * Old and new Size
63
+ * @typedef {object} SizeChange
64
+ * @property {Number} oldWidth - old width
65
+ * @property {Number} oldHeight - old height
66
+ * @property {Number} newWidth - new width
67
+ * @property {Number} newHeight - new height
68
+ */
69
+
70
+ /**
71
+ * @typedef {string} ErrorMsg - {string} error message
72
+ */
73
+
74
+ /**
75
+ * @typedef {object} ObjectProps - graphics object properties
76
+ * @property {number} id - object id
77
+ * @property {string} type - object type
78
+ * @property {string} text - text content
79
+ * @property {(string | number)} left - Left
80
+ * @property {(string | number)} top - Top
81
+ * @property {(string | number)} width - Width
82
+ * @property {(string | number)} height - Height
83
+ * @property {string} fill - Color
84
+ * @property {string} stroke - Stroke
85
+ * @property {(string | number)} strokeWidth - StrokeWidth
86
+ * @property {string} fontFamily - Font type for text
87
+ * @property {number} fontSize - Font Size
88
+ * @property {string} fontStyle - Type of inclination (normal / italic)
89
+ * @property {string} fontWeight - Type of thicker or thinner looking (normal / bold)
90
+ * @property {string} textAlign - Type of text align (left / center / right)
91
+ * @property {string} textDecoration - Type of line (underline / line-through / overline)
92
+ */
93
+
94
+ /**
95
+ * Shape filter option
96
+ * @typedef {object.<string, number>} ShapeFilterOption
97
+ */
98
+
99
+ /**
100
+ * Shape filter option
101
+ * @typedef {object} ShapeFillOption - fill option of shape
102
+ * @property {string} type - fill type ('color' or 'filter')
103
+ * @property {Array.<ShapeFillFilterOption>} [filter] - {@link ShapeFilterOption} List.
104
+ * only applies to filter types
105
+ * (ex: \[\{pixelate: 20\}, \{blur: 0.3\}\])
106
+ * @property {string} [color] - Shape foreground color (ex: '#fff', 'transparent')
107
+ */
108
+
109
+ /**
110
+ * Image editor
111
+ * @class
112
+ * @param {string|HTMLElement} wrapper - Wrapper's element or selector
113
+ * @param {Object} [options] - Canvas max width & height of css
114
+ * @param {number} [options.includeUI] - Use the provided UI
115
+ * @param {Object} [options.includeUI.loadImage] - Basic editing image
116
+ * @param {string} options.includeUI.loadImage.path - image path
117
+ * @param {string} options.includeUI.loadImage.name - image name
118
+ * @param {Object} [options.includeUI.theme] - Theme object
119
+ * @param {Array} [options.includeUI.menu] - It can be selected when only specific menu is used, Default values are \['crop', 'flip', 'rotate', 'draw', 'shape', 'icon', 'text', 'mask', 'filter'\].
120
+ * @param {string} [options.includeUI.initMenu] - The first menu to be selected and started.
121
+ * @param {Object} [options.includeUI.uiSize] - ui size of editor
122
+ * @param {string} options.includeUI.uiSize.width - width of ui
123
+ * @param {string} options.includeUI.uiSize.height - height of ui
124
+ * @param {string} [options.includeUI.menuBarPosition=bottom] - Menu bar position('top', 'bottom', 'left', 'right')
125
+ * @param {number} options.cssMaxWidth - Canvas css-max-width
126
+ * @param {number} options.cssMaxHeight - Canvas css-max-height
127
+ * @param {Object} [options.selectionStyle] - selection style
128
+ * @param {string} [options.selectionStyle.cornerStyle] - selection corner style
129
+ * @param {number} [options.selectionStyle.cornerSize] - selection corner size
130
+ * @param {string} [options.selectionStyle.cornerColor] - selection corner color
131
+ * @param {string} [options.selectionStyle.cornerStrokeColor] = selection corner stroke color
132
+ * @param {boolean} [options.selectionStyle.transparentCorners] - selection corner transparent
133
+ * @param {number} [options.selectionStyle.lineWidth] - selection line width
134
+ * @param {string} [options.selectionStyle.borderColor] - selection border color
135
+ * @param {number} [options.selectionStyle.rotatingPointOffset] - selection rotating point length
136
+ * @param {Boolean} [options.usageStatistics=true] - Let us know the hostname. If you don't want to send the hostname, please set to false.
137
+ * @example
138
+ * var ImageEditor = require('tui-image-editor');
139
+ * var blackTheme = require('./js/theme/black-theme.js');
140
+ * var instance = new ImageEditor(document.querySelector('#tui-image-editor'), {
141
+ * includeUI: {
142
+ * loadImage: {
143
+ * path: 'img/sampleImage.jpg',
144
+ * name: 'SampleImage'
145
+ * },
146
+ * theme: blackTheme, // or whiteTheme
147
+ * menu: ['shape', 'filter'],
148
+ * initMenu: 'filter',
149
+ * uiSize: {
150
+ * width: '1000px',
151
+ * height: '700px'
152
+ * },
153
+ * menuBarPosition: 'bottom'
154
+ * },
155
+ * cssMaxWidth: 700,
156
+ * cssMaxHeight: 500,
157
+ * selectionStyle: {
158
+ * cornerSize: 20,
159
+ * rotatingPointOffset: 70
160
+ * }
161
+ * });
162
+ */
163
+ class ImageEditor {
164
+ constructor(wrapper, options) {
165
+ options = extend(
166
+ {
167
+ includeUI: false,
168
+ usageStatistics: true,
169
+ },
170
+ options
171
+ );
172
+
173
+ this.mode = null;
174
+
175
+ this.activeObjectId = null;
176
+
177
+ /**
178
+ * UI instance
179
+ * @type {Ui}
180
+ */
181
+ if (options.includeUI) {
182
+ const UIOption = options.includeUI;
183
+ UIOption.usageStatistics = options.usageStatistics;
184
+
185
+ this.ui = new UI(wrapper, UIOption, this.getActions());
186
+ options = this.ui.setUiDefaultSelectionStyle(options);
187
+ }
188
+
189
+ /**
190
+ * Invoker
191
+ * @type {Invoker}
192
+ * @private
193
+ */
194
+ this._invoker = new Invoker();
195
+
196
+ /**
197
+ * Graphics instance
198
+ * @type {Graphics}
199
+ * @private
200
+ */
201
+ this._graphics = new Graphics(this.ui ? this.ui.getEditorArea() : wrapper, {
202
+ cssMaxWidth: options.cssMaxWidth,
203
+ cssMaxHeight: options.cssMaxHeight,
204
+ });
205
+
206
+ /**
207
+ * Event handler list
208
+ * @type {Object}
209
+ * @private
210
+ */
211
+ this._handlers = {
212
+ keydown: this._onKeyDown.bind(this),
213
+ mousedown: this._onMouseDown.bind(this),
214
+ objectActivated: this._onObjectActivated.bind(this),
215
+ objectMoved: this._onObjectMoved.bind(this),
216
+ objectScaled: this._onObjectScaled.bind(this),
217
+ objectRotated: this._onObjectRotated.bind(this),
218
+ objectAdded: this._onObjectAdded.bind(this),
219
+ objectModified: this._onObjectModified.bind(this),
220
+ createdPath: this._onCreatedPath,
221
+ addText: this._onAddText.bind(this),
222
+ addObject: this._onAddObject.bind(this),
223
+ textEditing: this._onTextEditing.bind(this),
224
+ textChanged: this._onTextChanged.bind(this),
225
+ iconCreateResize: this._onIconCreateResize.bind(this),
226
+ iconCreateEnd: this._onIconCreateEnd.bind(this),
227
+ selectionCleared: this._selectionCleared.bind(this),
228
+ selectionCreated: this._selectionCreated.bind(this),
229
+ };
230
+
231
+ this._attachInvokerEvents();
232
+ this._attachGraphicsEvents();
233
+ this._attachDomEvents();
234
+ this._setSelectionStyle(options.selectionStyle, {
235
+ applyCropSelectionStyle: options.applyCropSelectionStyle,
236
+ applyGroupSelectionStyle: options.applyGroupSelectionStyle,
237
+ });
238
+
239
+ if (options.usageStatistics) {
240
+ sendHostName();
241
+ }
242
+
243
+ if (this.ui) {
244
+ this.ui.initCanvas();
245
+ this.setReAction();
246
+ this._attachColorPickerInputBoxEvents();
247
+ }
248
+ fabric.enableGLFiltering = false;
249
+ }
250
+
251
+ _attachColorPickerInputBoxEvents() {
252
+ this.ui.on(events.INPUT_BOX_EDITING_STARTED, () => {
253
+ this.isColorPickerInputBoxEditing = true;
254
+ });
255
+ this.ui.on(events.INPUT_BOX_EDITING_STOPPED, () => {
256
+ this.isColorPickerInputBoxEditing = false;
257
+ });
258
+ }
259
+
260
+ _detachColorPickerInputBoxEvents() {
261
+ this.ui.off(events.INPUT_BOX_EDITING_STARTED);
262
+ this.ui.off(events.INPUT_BOX_EDITING_STOPPED);
263
+ }
264
+
265
+ /**
266
+ * Set selection style by init option
267
+ * @param {Object} selectionStyle - Selection styles
268
+ * @param {Object} applyTargets - Selection apply targets
269
+ * @param {boolean} applyCropSelectionStyle - whether apply with crop selection style or not
270
+ * @param {boolean} applyGroupSelectionStyle - whether apply with group selection style or not
271
+ * @private
272
+ */
273
+ _setSelectionStyle(selectionStyle, { applyCropSelectionStyle, applyGroupSelectionStyle }) {
274
+ if (selectionStyle) {
275
+ this._graphics.setSelectionStyle(selectionStyle);
276
+ }
277
+
278
+ if (applyCropSelectionStyle) {
279
+ this._graphics.setCropSelectionStyle(selectionStyle);
280
+ }
281
+
282
+ if (applyGroupSelectionStyle) {
283
+ this.on('selectionCreated', (eventTarget) => {
284
+ if (eventTarget.type === 'activeSelection') {
285
+ eventTarget.set(selectionStyle);
286
+ }
287
+ });
288
+ }
289
+ }
290
+
291
+ /**
292
+ * Attach invoker events
293
+ * @private
294
+ */
295
+ _attachInvokerEvents() {
296
+ const {
297
+ UNDO_STACK_CHANGED,
298
+ REDO_STACK_CHANGED,
299
+ EXECUTE_COMMAND,
300
+ AFTER_UNDO,
301
+ AFTER_REDO,
302
+ HAND_STARTED,
303
+ HAND_STOPPED,
304
+ } = events;
305
+
306
+ /**
307
+ * Undo stack changed event
308
+ * @event ImageEditor#undoStackChanged
309
+ * @param {Number} length - undo stack length
310
+ * @example
311
+ * imageEditor.on('undoStackChanged', function(length) {
312
+ * console.log(length);
313
+ * });
314
+ */
315
+ this._invoker.on(UNDO_STACK_CHANGED, this.fire.bind(this, UNDO_STACK_CHANGED));
316
+ /**
317
+ * Redo stack changed event
318
+ * @event ImageEditor#redoStackChanged
319
+ * @param {Number} length - redo stack length
320
+ * @example
321
+ * imageEditor.on('redoStackChanged', function(length) {
322
+ * console.log(length);
323
+ * });
324
+ */
325
+ this._invoker.on(REDO_STACK_CHANGED, this.fire.bind(this, REDO_STACK_CHANGED));
326
+
327
+ if (this.ui) {
328
+ const canvas = this._graphics.getCanvas();
329
+
330
+ this._invoker.on(EXECUTE_COMMAND, (command) => this.ui.fire(EXECUTE_COMMAND, command));
331
+ this._invoker.on(AFTER_UNDO, (command) => this.ui.fire(AFTER_UNDO, command));
332
+ this._invoker.on(AFTER_REDO, (command) => this.ui.fire(AFTER_REDO, command));
333
+
334
+ canvas.on(HAND_STARTED, () => this.ui.fire(HAND_STARTED));
335
+ canvas.on(HAND_STOPPED, () => this.ui.fire(HAND_STOPPED));
336
+ }
337
+ }
338
+
339
+ /**
340
+ * Attach canvas events
341
+ * @private
342
+ */
343
+ _attachGraphicsEvents() {
344
+ this._graphics.on({
345
+ [MOUSE_DOWN]: this._handlers.mousedown,
346
+ [OBJECT_MOVED]: this._handlers.objectMoved,
347
+ [OBJECT_SCALED]: this._handlers.objectScaled,
348
+ [OBJECT_ROTATED]: this._handlers.objectRotated,
349
+ [OBJECT_ACTIVATED]: this._handlers.objectActivated,
350
+ [OBJECT_ADDED]: this._handlers.objectAdded,
351
+ [OBJECT_MODIFIED]: this._handlers.objectModified,
352
+ [ADD_TEXT]: this._handlers.addText,
353
+ [ADD_OBJECT]: this._handlers.addObject,
354
+ [TEXT_EDITING]: this._handlers.textEditing,
355
+ [TEXT_CHANGED]: this._handlers.textChanged,
356
+ [ICON_CREATE_RESIZE]: this._handlers.iconCreateResize,
357
+ [ICON_CREATE_END]: this._handlers.iconCreateEnd,
358
+ [SELECTION_CLEARED]: this._handlers.selectionCleared,
359
+ [SELECTION_CREATED]: this._handlers.selectionCreated,
360
+ });
361
+ }
362
+
363
+ /**
364
+ * Attach dom events
365
+ * @private
366
+ */
367
+ _attachDomEvents() {
368
+ // ImageEditor supports IE 9 higher
369
+ document.addEventListener('keydown', this._handlers.keydown);
370
+ }
371
+
372
+ /**
373
+ * Detach dom events
374
+ * @private
375
+ */
376
+ _detachDomEvents() {
377
+ // ImageEditor supports IE 9 higher
378
+ document.removeEventListener('keydown', this._handlers.keydown);
379
+ }
380
+
381
+ /**
382
+ * Keydown event handler
383
+ * @param {KeyboardEvent} e - Event object
384
+ * @private
385
+ */
386
+ /* eslint-disable complexity */
387
+ _onKeyDown(e) {
388
+ const { ctrlKey, keyCode, metaKey } = e;
389
+ const isModifierKey = ctrlKey || metaKey;
390
+
391
+ if (isModifierKey) {
392
+ if (keyCode === keyCodes.C) {
393
+ this._graphics.resetTargetObjectForCopyPaste();
394
+ } else if (keyCode === keyCodes.V) {
395
+ this._graphics.pasteObject();
396
+ this.clearRedoStack();
397
+ } else if (keyCode === keyCodes.Z) {
398
+ // There is no error message on shortcut when it's empty
399
+ this.undo()['catch'](() => {});
400
+ } else if (keyCode === keyCodes.Y) {
401
+ // There is no error message on shortcut when it's empty
402
+ this.redo()['catch'](() => {});
403
+ }
404
+ }
405
+
406
+ const isDeleteKey = keyCode === keyCodes.BACKSPACE || keyCode === keyCodes.DEL;
407
+ const isRemoveReady = this._graphics.isReadyRemoveObject();
408
+
409
+ if (!this.isColorPickerInputBoxEditing && isRemoveReady && isDeleteKey) {
410
+ e.preventDefault();
411
+ this.removeActiveObject();
412
+ }
413
+ }
414
+
415
+ /**
416
+ * Remove Active Object
417
+ */
418
+ removeActiveObject() {
419
+ const activeObjectId = this._graphics.getActiveObjectIdForRemove();
420
+
421
+ this.removeObject(activeObjectId);
422
+ }
423
+
424
+ /**
425
+ * mouse down event handler
426
+ * @param {Event} event - mouse down event
427
+ * @param {Object} originPointer - origin pointer
428
+ * @param {Number} originPointer.x x position
429
+ * @param {Number} originPointer.y y position
430
+ * @private
431
+ */
432
+ _onMouseDown(event, originPointer) {
433
+ /**
434
+ * The mouse down event with position x, y on canvas
435
+ * @event ImageEditor#mousedown
436
+ * @param {Object} event - browser mouse event object
437
+ * @param {Object} originPointer origin pointer
438
+ * @param {Number} originPointer.x x position
439
+ * @param {Number} originPointer.y y position
440
+ * @example
441
+ * imageEditor.on('mousedown', function(event, originPointer) {
442
+ * console.log(event);
443
+ * console.log(originPointer);
444
+ * if (imageEditor.hasFilter('colorFilter')) {
445
+ * imageEditor.applyFilter('colorFilter', {
446
+ * x: parseInt(originPointer.x, 10),
447
+ * y: parseInt(originPointer.y, 10)
448
+ * });
449
+ * }
450
+ * });
451
+ */
452
+
453
+ this.fire(events.MOUSE_DOWN, event, originPointer);
454
+ }
455
+
456
+ /**
457
+ * Add a 'addObject' command
458
+ * @param {Object} obj - Fabric object
459
+ * @private
460
+ */
461
+ _pushAddObjectCommand(obj) {
462
+ const command = commandFactory.create(commands.ADD_OBJECT, this._graphics, obj);
463
+ this._invoker.pushUndoStack(command);
464
+ }
465
+
466
+ /**
467
+ * Add a 'changeSelection' command
468
+ * @param {fabric.Object} obj - selection object
469
+ * @private
470
+ */
471
+ _pushModifyObjectCommand(obj) {
472
+ const { type } = obj;
473
+ const props = makeSelectionUndoData(obj, (item) =>
474
+ makeSelectionUndoDatum(this._graphics.getObjectId(item), item, type === 'activeSelection')
475
+ );
476
+ const command = commandFactory.create(commands.CHANGE_SELECTION, this._graphics, props);
477
+ command.execute(this._graphics, props);
478
+
479
+ this._invoker.pushUndoStack(command);
480
+ }
481
+
482
+ /**
483
+ * 'objectActivated' event handler
484
+ * @param {ObjectProps} props - object properties
485
+ * @private
486
+ */
487
+ _onObjectActivated(props) {
488
+ /**
489
+ * The event when object is selected(aka activated).
490
+ * @event ImageEditor#objectActivated
491
+ * @param {ObjectProps} objectProps - object properties
492
+ * @example
493
+ * imageEditor.on('objectActivated', function(props) {
494
+ * console.log(props);
495
+ * console.log(props.type);
496
+ * console.log(props.id);
497
+ * });
498
+ */
499
+ this.fire(events.OBJECT_ACTIVATED, props);
500
+ }
501
+
502
+ /**
503
+ * 'objectMoved' event handler
504
+ * @param {ObjectProps} props - object properties
505
+ * @private
506
+ */
507
+ _onObjectMoved(props) {
508
+ /**
509
+ * The event when object is moved
510
+ * @event ImageEditor#objectMoved
511
+ * @param {ObjectProps} props - object properties
512
+ * @example
513
+ * imageEditor.on('objectMoved', function(props) {
514
+ * console.log(props);
515
+ * console.log(props.type);
516
+ * });
517
+ */
518
+ this.fire(events.OBJECT_MOVED, props);
519
+ }
520
+
521
+ /**
522
+ * 'objectScaled' event handler
523
+ * @param {ObjectProps} props - object properties
524
+ * @private
525
+ */
526
+ _onObjectScaled(props) {
527
+ /**
528
+ * The event when scale factor is changed
529
+ * @event ImageEditor#objectScaled
530
+ * @param {ObjectProps} props - object properties
531
+ * @example
532
+ * imageEditor.on('objectScaled', function(props) {
533
+ * console.log(props);
534
+ * console.log(props.type);
535
+ * });
536
+ */
537
+ this.fire(events.OBJECT_SCALED, props);
538
+ }
539
+
540
+ /**
541
+ * 'objectRotated' event handler
542
+ * @param {ObjectProps} props - object properties
543
+ * @private
544
+ */
545
+ _onObjectRotated(props) {
546
+ /**
547
+ * The event when object angle is changed
548
+ * @event ImageEditor#objectRotated
549
+ * @param {ObjectProps} props - object properties
550
+ * @example
551
+ * imageEditor.on('objectRotated', function(props) {
552
+ * console.log(props);
553
+ * console.log(props.type);
554
+ * });
555
+ */
556
+ this.fire(events.OBJECT_ROTATED, props);
557
+ }
558
+
559
+ /**
560
+ * Get current drawing mode
561
+ * @returns {string}
562
+ * @example
563
+ * // Image editor drawing mode
564
+ * //
565
+ * // NORMAL: 'NORMAL'
566
+ * // CROPPER: 'CROPPER'
567
+ * // FREE_DRAWING: 'FREE_DRAWING'
568
+ * // LINE_DRAWING: 'LINE_DRAWING'
569
+ * // TEXT: 'TEXT'
570
+ * //
571
+ * if (imageEditor.getDrawingMode() === 'FREE_DRAWING') {
572
+ * imageEditor.stopDrawingMode();
573
+ * }
574
+ */
575
+ getDrawingMode() {
576
+ return this._graphics.getDrawingMode();
577
+ }
578
+
579
+ /**
580
+ * Clear all objects
581
+ * @returns {Promise}
582
+ * @example
583
+ * imageEditor.clearObjects();
584
+ */
585
+ clearObjects() {
586
+ return this.execute(commands.CLEAR_OBJECTS);
587
+ }
588
+
589
+ /**
590
+ * Deactivate all objects
591
+ * @example
592
+ * imageEditor.deactivateAll();
593
+ */
594
+ deactivateAll() {
595
+ this._graphics.deactivateAll();
596
+ this._graphics.renderAll();
597
+ }
598
+
599
+ /**
600
+ * discard selction
601
+ * @example
602
+ * imageEditor.discardSelection();
603
+ */
604
+ discardSelection() {
605
+ this._graphics.discardSelection();
606
+ }
607
+
608
+ /**
609
+ * selectable status change
610
+ * @param {boolean} selectable - selectable status
611
+ * @example
612
+ * imageEditor.changeSelectableAll(false); // or true
613
+ */
614
+ changeSelectableAll(selectable) {
615
+ this._graphics.changeSelectableAll(selectable);
616
+ }
617
+
618
+ /**
619
+ * Init history
620
+ */
621
+ _initHistory() {
622
+ if (this.ui) {
623
+ this.ui.initHistory();
624
+ }
625
+ }
626
+
627
+ /**
628
+ * Clear history
629
+ */
630
+ _clearHistory() {
631
+ if (this.ui) {
632
+ this.ui.clearHistory();
633
+ }
634
+ }
635
+
636
+ /**
637
+ * Invoke command
638
+ * @param {String} commandName - Command name
639
+ * @param {...*} args - Arguments for creating command
640
+ * @returns {Promise}
641
+ * @private
642
+ */
643
+ execute(commandName, ...args) {
644
+ // Inject an Graphics instance as first parameter
645
+ const theArgs = [this._graphics].concat(args);
646
+
647
+ return this._invoker.execute(commandName, ...theArgs);
648
+ }
649
+
650
+ /**
651
+ * Invoke command
652
+ * @param {String} commandName - Command name
653
+ * @param {...*} args - Arguments for creating command
654
+ * @returns {Promise}
655
+ * @private
656
+ */
657
+ executeSilent(commandName, ...args) {
658
+ // Inject an Graphics instance as first parameter
659
+ const theArgs = [this._graphics].concat(args);
660
+
661
+ return this._invoker.executeSilent(commandName, ...theArgs);
662
+ }
663
+
664
+ /**
665
+ * Undo
666
+ * @param {number} [iterationCount=1] - Iteration count of undo
667
+ * @returns {Promise}
668
+ * @example
669
+ * imageEditor.undo();
670
+ */
671
+ undo(iterationCount = 1) {
672
+ let promise = Promise.resolve();
673
+
674
+ for (let i = 0; i < iterationCount; i += 1) {
675
+ promise = promise.then(() => this._invoker.undo());
676
+ }
677
+
678
+ return promise;
679
+ }
680
+
681
+ /**
682
+ * Redo
683
+ * @param {number} [iterationCount=1] - Iteration count of redo
684
+ * @returns {Promise}
685
+ * @example
686
+ * imageEditor.redo();
687
+ */
688
+ redo(iterationCount = 1) {
689
+ let promise = Promise.resolve();
690
+
691
+ for (let i = 0; i < iterationCount; i += 1) {
692
+ promise = promise.then(() => this._invoker.redo());
693
+ }
694
+
695
+ return promise;
696
+ }
697
+
698
+ /**
699
+ * Zoom
700
+ * @param {number} x - x axis of center point for zoom
701
+ * @param {number} y - y axis of center point for zoom
702
+ * @param {number} zoomLevel - level of zoom(1.0 ~ 5.0)
703
+ */
704
+ zoom({ x, y, zoomLevel }) {
705
+ this._graphics.zoom({ x, y }, zoomLevel);
706
+ }
707
+
708
+ /**
709
+ * Reset zoom. Change zoom level to 1.0
710
+ */
711
+ resetZoom() {
712
+ this._graphics.resetZoom();
713
+ }
714
+
715
+ /**
716
+ * start hand mode
717
+ */
718
+ startHandMode() {
719
+ const zoomMode = this._graphics.getZoomMode();
720
+ this.stopDrawingMode();
721
+ if (zoomMode !== zoomModes.HAND) {
722
+ this._graphics.startHandMode();
723
+ }
724
+ }
725
+
726
+ /**
727
+ * end hand mode
728
+ */
729
+ endHandMode() {
730
+ const zoomMode = this._graphics.getZoomMode();
731
+ this.stopDrawingMode();
732
+ if (zoomMode === zoomModes.HAND) {
733
+ this._graphics.endHandMode();
734
+ }
735
+ }
736
+
737
+ /**
738
+ * Load image from file
739
+ * @param {File} imgFile - Image file
740
+ * @param {string} [imageName] - imageName
741
+ * @returns {Promise<SizeChange, ErrorMsg>}
742
+ * @example
743
+ * imageEditor.loadImageFromFile(file).then(result => {
744
+ * console.log('old : ' + result.oldWidth + ', ' + result.oldHeight);
745
+ * console.log('new : ' + result.newWidth + ', ' + result.newHeight);
746
+ * });
747
+ */
748
+ loadImageFromFile(imgFile, imageName) {
749
+ if (!imgFile) {
750
+ return Promise.reject(rejectMessages.invalidParameters);
751
+ }
752
+
753
+ const imgUrl = URL.createObjectURL(imgFile);
754
+ imageName = imageName || imgFile.name;
755
+
756
+ return this.loadImageFromURL(imgUrl, imageName).then((value) => {
757
+ URL.revokeObjectURL(imgFile);
758
+
759
+ return value;
760
+ });
761
+ }
762
+
763
+ /**
764
+ * Load image from url
765
+ * @param {string} url - File url
766
+ * @param {string} imageName - imageName
767
+ * @returns {Promise<SizeChange, ErrorMsg>}
768
+ * @example
769
+ * imageEditor.loadImageFromURL('http://url/testImage.png', 'lena').then(result => {
770
+ * console.log('old : ' + result.oldWidth + ', ' + result.oldHeight);
771
+ * console.log('new : ' + result.newWidth + ', ' + result.newHeight);
772
+ * });
773
+ */
774
+ loadImageFromURL(url, imageName) {
775
+ if (!imageName || !url) {
776
+ return Promise.reject(rejectMessages.invalidParameters);
777
+ }
778
+
779
+ return this.execute(commands.LOAD_IMAGE, imageName, url);
780
+ }
781
+
782
+ /**
783
+ * Add image object on canvas
784
+ * @param {string} imgUrl - Image url to make object
785
+ * @returns {Promise<ObjectProps, ErrorMsg>}
786
+ * @example
787
+ * imageEditor.addImageObject('path/fileName.jpg').then(objectProps => {
788
+ * console.log(ojectProps.id);
789
+ * });
790
+ */
791
+ addImageObject(imgUrl) {
792
+ if (!imgUrl) {
793
+ return Promise.reject(rejectMessages.invalidParameters);
794
+ }
795
+
796
+ return this.execute(commands.ADD_IMAGE_OBJECT, imgUrl);
797
+ }
798
+
799
+ /**
800
+ * Start a drawing mode. If the current mode is not 'NORMAL', 'stopDrawingMode()' will be called first.
801
+ * @param {String} mode Can be one of <I>'CROPPER', 'FREE_DRAWING', 'LINE_DRAWING', 'TEXT', 'SHAPE'</I>
802
+ * @param {Object} [option] parameters of drawing mode, it's available with 'FREE_DRAWING', 'LINE_DRAWING'
803
+ * @param {Number} [option.width] brush width
804
+ * @param {String} [option.color] brush color
805
+ * @param {Object} [option.arrowType] arrow decorate
806
+ * @param {string} [option.arrowType.tail] arrow decorate for tail. 'chevron' or 'triangle'
807
+ * @param {string} [option.arrowType.head] arrow decorate for head. 'chevron' or 'triangle'
808
+ * @returns {boolean} true if success or false
809
+ * @example
810
+ * imageEditor.startDrawingMode('FREE_DRAWING', {
811
+ * width: 10,
812
+ * color: 'rgba(255,0,0,0.5)'
813
+ * });
814
+ * imageEditor.startDrawingMode('LINE_DRAWING', {
815
+ * width: 10,
816
+ * color: 'rgba(255,0,0,0.5)',
817
+ * arrowType: {
818
+ * tail: 'chevron' // triangle
819
+ * }
820
+ * });
821
+ *
822
+ */
823
+ startDrawingMode(mode, option) {
824
+ return this._graphics.startDrawingMode(mode, option);
825
+ }
826
+
827
+ /**
828
+ * Stop the current drawing mode and back to the 'NORMAL' mode
829
+ * @example
830
+ * imageEditor.stopDrawingMode();
831
+ */
832
+ stopDrawingMode() {
833
+ this._graphics.stopDrawingMode();
834
+ }
835
+
836
+ /**
837
+ * Crop this image with rect
838
+ * @param {Object} rect crop rect
839
+ * @param {Number} rect.left left position
840
+ * @param {Number} rect.top top position
841
+ * @param {Number} rect.width width
842
+ * @param {Number} rect.height height
843
+ * @returns {Promise}
844
+ * @example
845
+ * imageEditor.crop(imageEditor.getCropzoneRect());
846
+ */
847
+ crop(rect) {
848
+ const data = this._graphics.getCroppedImageData(rect);
849
+ if (!data) {
850
+ return Promise.reject(rejectMessages.invalidParameters);
851
+ }
852
+
853
+ return this.loadImageFromURL(data.url, data.imageName);
854
+ }
855
+
856
+ /**
857
+ * Get the cropping rect
858
+ * @returns {Object} {{left: number, top: number, width: number, height: number}} rect
859
+ */
860
+ getCropzoneRect() {
861
+ return this._graphics.getCropzoneRect();
862
+ }
863
+
864
+ /**
865
+ * Set the cropping rect
866
+ * @param {number} [mode] crop rect mode [1, 1.5, 1.3333333333333333, 1.25, 1.7777777777777777]
867
+ */
868
+ setCropzoneRect(mode) {
869
+ this._graphics.setCropzoneRect(mode);
870
+ }
871
+
872
+ /**
873
+ * Flip
874
+ * @returns {Promise}
875
+ * @param {string} type - 'flipX' or 'flipY' or 'reset'
876
+ * @returns {Promise<FlipStatus, ErrorMsg>}
877
+ * @private
878
+ */
879
+ _flip(type) {
880
+ return this.execute(commands.FLIP_IMAGE, type);
881
+ }
882
+
883
+ /**
884
+ * Flip x
885
+ * @returns {Promise<FlipStatus, ErrorMsg>}
886
+ * @example
887
+ * imageEditor.flipX().then((status => {
888
+ * console.log('flipX: ', status.flipX);
889
+ * console.log('flipY: ', status.flipY);
890
+ * console.log('angle: ', status.angle);
891
+ * }).catch(message => {
892
+ * console.log('error: ', message);
893
+ * });
894
+ */
895
+ flipX() {
896
+ return this._flip('flipX');
897
+ }
898
+
899
+ /**
900
+ * Flip y
901
+ * @returns {Promise<FlipStatus, ErrorMsg>}
902
+ * @example
903
+ * imageEditor.flipY().then(status => {
904
+ * console.log('flipX: ', status.flipX);
905
+ * console.log('flipY: ', status.flipY);
906
+ * console.log('angle: ', status.angle);
907
+ * }).catch(message => {
908
+ * console.log('error: ', message);
909
+ * });
910
+ */
911
+ flipY() {
912
+ return this._flip('flipY');
913
+ }
914
+
915
+ /**
916
+ * Reset flip
917
+ * @returns {Promise<FlipStatus, ErrorMsg>}
918
+ * @example
919
+ * imageEditor.resetFlip().then(status => {
920
+ * console.log('flipX: ', status.flipX);
921
+ * console.log('flipY: ', status.flipY);
922
+ * console.log('angle: ', status.angle);
923
+ * }).catch(message => {
924
+ * console.log('error: ', message);
925
+ * });;
926
+ */
927
+ resetFlip() {
928
+ return this._flip('reset');
929
+ }
930
+
931
+ /**
932
+ * @param {string} type - 'rotate' or 'setAngle'
933
+ * @param {number} angle - angle value (degree)
934
+ * @param {boolean} isSilent - is silent execution or not
935
+ * @returns {Promise<RotateStatus, ErrorMsg>}
936
+ * @private
937
+ */
938
+ _rotate(type, angle, isSilent) {
939
+ let result = null;
940
+
941
+ if (isSilent) {
942
+ result = this.executeSilent(commands.ROTATE_IMAGE, type, angle);
943
+ } else {
944
+ result = this.execute(commands.ROTATE_IMAGE, type, angle);
945
+ }
946
+
947
+ return result;
948
+ }
949
+
950
+ /**
951
+ * Rotate image
952
+ * @returns {Promise}
953
+ * @param {number} angle - Additional angle to rotate image
954
+ * @param {boolean} isSilent - is silent execution or not
955
+ * @returns {Promise<RotateStatus, ErrorMsg>}
956
+ * @example
957
+ * imageEditor.rotate(10); // angle = 10
958
+ * imageEditor.rotate(10); // angle = 20
959
+ * imageEditor.rotate(5); // angle = 5
960
+ * imageEditor.rotate(-95); // angle = -90
961
+ * imageEditor.rotate(10).then(status => {
962
+ * console.log('angle: ', status.angle);
963
+ * })).catch(message => {
964
+ * console.log('error: ', message);
965
+ * });
966
+ */
967
+ rotate(angle, isSilent) {
968
+ return this._rotate('rotate', angle, isSilent);
969
+ }
970
+
971
+ /**
972
+ * Set angle
973
+ * @param {number} angle - Angle of image
974
+ * @param {boolean} isSilent - is silent execution or not
975
+ * @returns {Promise<RotateStatus, ErrorMsg>}
976
+ * @example
977
+ * imageEditor.setAngle(10); // angle = 10
978
+ * imageEditor.rotate(10); // angle = 20
979
+ * imageEditor.setAngle(5); // angle = 5
980
+ * imageEditor.rotate(50); // angle = 55
981
+ * imageEditor.setAngle(-40); // angle = -40
982
+ * imageEditor.setAngle(10).then(status => {
983
+ * console.log('angle: ', status.angle);
984
+ * })).catch(message => {
985
+ * console.log('error: ', message);
986
+ * });
987
+ */
988
+ setAngle(angle, isSilent) {
989
+ return this._rotate('setAngle', angle, isSilent);
990
+ }
991
+
992
+ /**
993
+ * Set drawing brush
994
+ * @param {Object} option brush option
995
+ * @param {Number} option.width width
996
+ * @param {String} option.color color like 'FFFFFF', 'rgba(0, 0, 0, 0.5)'
997
+ * @example
998
+ * imageEditor.startDrawingMode('FREE_DRAWING');
999
+ * imageEditor.setBrush({
1000
+ * width: 12,
1001
+ * color: 'rgba(0, 0, 0, 0.5)'
1002
+ * });
1003
+ * imageEditor.setBrush({
1004
+ * width: 8,
1005
+ * color: 'FFFFFF'
1006
+ * });
1007
+ */
1008
+ setBrush(option) {
1009
+ this._graphics.setBrush(option);
1010
+ }
1011
+
1012
+ /**
1013
+ * Set states of current drawing shape
1014
+ * @param {string} type - Shape type (ex: 'rect', 'circle', 'triangle')
1015
+ * @param {Object} [options] - Shape options
1016
+ * @param {(ShapeFillOption | string)} [options.fill] - {@link ShapeFillOption} or
1017
+ * Shape foreground color (ex: '#fff', 'transparent')
1018
+ * @param {string} [options.stoke] - Shape outline color
1019
+ * @param {number} [options.strokeWidth] - Shape outline width
1020
+ * @param {number} [options.width] - Width value (When type option is 'rect', this options can use)
1021
+ * @param {number} [options.height] - Height value (When type option is 'rect', this options can use)
1022
+ * @param {number} [options.rx] - Radius x value (When type option is 'circle', this options can use)
1023
+ * @param {number} [options.ry] - Radius y value (When type option is 'circle', this options can use)
1024
+ * @param {number} [options.isRegular] - Whether resizing shape has 1:1 ratio or not
1025
+ * @example
1026
+ * imageEditor.setDrawingShape('rect', {
1027
+ * fill: 'red',
1028
+ * width: 100,
1029
+ * height: 200
1030
+ * });
1031
+ * @example
1032
+ * imageEditor.setDrawingShape('rect', {
1033
+ * fill: {
1034
+ * type: 'filter',
1035
+ * filter: [{blur: 0.3}, {pixelate: 20}]
1036
+ * },
1037
+ * width: 100,
1038
+ * height: 200
1039
+ * });
1040
+ * @example
1041
+ * imageEditor.setDrawingShape('circle', {
1042
+ * fill: 'transparent',
1043
+ * stroke: 'blue',
1044
+ * strokeWidth: 3,
1045
+ * rx: 10,
1046
+ * ry: 100
1047
+ * });
1048
+ * @example
1049
+ * imageEditor.setDrawingShape('triangle', { // When resizing, the shape keep the 1:1 ratio
1050
+ * width: 1,
1051
+ * height: 1,
1052
+ * isRegular: true
1053
+ * });
1054
+ * @example
1055
+ * imageEditor.setDrawingShape('circle', { // When resizing, the shape keep the 1:1 ratio
1056
+ * rx: 10,
1057
+ * ry: 10,
1058
+ * isRegular: true
1059
+ * });
1060
+ */
1061
+ setDrawingShape(type, options) {
1062
+ this._graphics.setDrawingShape(type, options);
1063
+ }
1064
+
1065
+ setDrawingIcon(type, iconColor) {
1066
+ this._graphics.setIconStyle(type, iconColor);
1067
+ }
1068
+
1069
+ /**
1070
+ * Add shape
1071
+ * @param {string} type - Shape type (ex: 'rect', 'circle', 'triangle')
1072
+ * @param {Object} options - Shape options
1073
+ * @param {(ShapeFillOption | string)} [options.fill] - {@link ShapeFillOption} or
1074
+ * Shape foreground color (ex: '#fff', 'transparent')
1075
+ * @param {string} [options.stroke] - Shape outline color
1076
+ * @param {number} [options.strokeWidth] - Shape outline width
1077
+ * @param {number} [options.width] - Width value (When type option is 'rect', this options can use)
1078
+ * @param {number} [options.height] - Height value (When type option is 'rect', this options can use)
1079
+ * @param {number} [options.rx] - Radius x value (When type option is 'circle', this options can use)
1080
+ * @param {number} [options.ry] - Radius y value (When type option is 'circle', this options can use)
1081
+ * @param {number} [options.left] - Shape x position
1082
+ * @param {number} [options.top] - Shape y position
1083
+ * @param {boolean} [options.isRegular] - Whether resizing shape has 1:1 ratio or not
1084
+ * @returns {Promise<ObjectProps, ErrorMsg>}
1085
+ * @example
1086
+ * imageEditor.addShape('rect', {
1087
+ * fill: 'red',
1088
+ * stroke: 'blue',
1089
+ * strokeWidth: 3,
1090
+ * width: 100,
1091
+ * height: 200,
1092
+ * left: 10,
1093
+ * top: 10,
1094
+ * isRegular: true
1095
+ * });
1096
+ * @example
1097
+ * imageEditor.addShape('circle', {
1098
+ * fill: 'red',
1099
+ * stroke: 'blue',
1100
+ * strokeWidth: 3,
1101
+ * rx: 10,
1102
+ * ry: 100,
1103
+ * isRegular: false
1104
+ * }).then(objectProps => {
1105
+ * console.log(objectProps.id);
1106
+ * });
1107
+ * @example
1108
+ * imageEditor.addShape('rect', {
1109
+ * fill: {
1110
+ * type: 'filter',
1111
+ * filter: [{blur: 0.3}, {pixelate: 20}]
1112
+ * },
1113
+ * stroke: 'blue',
1114
+ * strokeWidth: 3,
1115
+ * rx: 10,
1116
+ * ry: 100,
1117
+ * isRegular: false
1118
+ * }).then(objectProps => {
1119
+ * console.log(objectProps.id);
1120
+ * });
1121
+ */
1122
+ addShape(type, options) {
1123
+ options = options || {};
1124
+
1125
+ this._setPositions(options);
1126
+
1127
+ return this.execute(commands.ADD_SHAPE, type, options);
1128
+ }
1129
+
1130
+ /**
1131
+ * Change shape
1132
+ * @param {number} id - object id
1133
+ * @param {Object} options - Shape options
1134
+ * @param {(ShapeFillOption | string)} [options.fill] - {@link ShapeFillOption} or
1135
+ * Shape foreground color (ex: '#fff', 'transparent')
1136
+ * @param {string} [options.stroke] - Shape outline color
1137
+ * @param {number} [options.strokeWidth] - Shape outline width
1138
+ * @param {number} [options.width] - Width value (When type option is 'rect', this options can use)
1139
+ * @param {number} [options.height] - Height value (When type option is 'rect', this options can use)
1140
+ * @param {number} [options.rx] - Radius x value (When type option is 'circle', this options can use)
1141
+ * @param {number} [options.ry] - Radius y value (When type option is 'circle', this options can use)
1142
+ * @param {boolean} [options.isRegular] - Whether resizing shape has 1:1 ratio or not
1143
+ * @param {boolean} isSilent - is silent execution or not
1144
+ * @returns {Promise}
1145
+ * @example
1146
+ * // call after selecting shape object on canvas
1147
+ * imageEditor.changeShape(id, { // change rectagle or triangle
1148
+ * fill: 'red',
1149
+ * stroke: 'blue',
1150
+ * strokeWidth: 3,
1151
+ * width: 100,
1152
+ * height: 200
1153
+ * });
1154
+ * @example
1155
+ * // call after selecting shape object on canvas
1156
+ * imageEditor.changeShape(id, { // change circle
1157
+ * fill: 'red',
1158
+ * stroke: 'blue',
1159
+ * strokeWidth: 3,
1160
+ * rx: 10,
1161
+ * ry: 100
1162
+ * });
1163
+ */
1164
+ changeShape(id, options, isSilent) {
1165
+ const executeMethodName = isSilent ? 'executeSilent' : 'execute';
1166
+
1167
+ return this[executeMethodName](commands.CHANGE_SHAPE, id, options);
1168
+ }
1169
+
1170
+ /**
1171
+ * Add text on image
1172
+ * @param {string} text - Initial input text
1173
+ * @param {Object} [options] Options for generating text
1174
+ * @param {Object} [options.styles] Initial styles
1175
+ * @param {string} [options.styles.fill] Color
1176
+ * @param {string} [options.styles.fontFamily] Font type for text
1177
+ * @param {number} [options.styles.fontSize] Size
1178
+ * @param {string} [options.styles.fontStyle] Type of inclination (normal / italic)
1179
+ * @param {string} [options.styles.fontWeight] Type of thicker or thinner looking (normal / bold)
1180
+ * @param {string} [options.styles.textAlign] Type of text align (left / center / right)
1181
+ * @param {string} [options.styles.textDecoration] Type of line (underline / line-through / overline)
1182
+ * @param {{x: number, y: number}} [options.position] - Initial position
1183
+ * @param {boolean} [options.autofocus] - text autofocus, default is true
1184
+ * @returns {Promise}
1185
+ * @example
1186
+ * imageEditor.addText('init text');
1187
+ * @example
1188
+ * imageEditor.addText('init text', {
1189
+ * styles: {
1190
+ * fill: '#000',
1191
+ * fontSize: 20,
1192
+ * fontWeight: 'bold'
1193
+ * },
1194
+ * position: {
1195
+ * x: 10,
1196
+ * y: 10
1197
+ * }
1198
+ * }).then(objectProps => {
1199
+ * console.log(objectProps.id);
1200
+ * });
1201
+ */
1202
+ addText(text, options) {
1203
+ text = text || '';
1204
+ options = options || {};
1205
+
1206
+ return this.execute(commands.ADD_TEXT, text, options);
1207
+ }
1208
+
1209
+ /**
1210
+ * Change contents of selected text object on image
1211
+ * @param {number} id - object id
1212
+ * @param {string} text - Changing text
1213
+ * @returns {Promise<ObjectProps, ErrorMsg>}
1214
+ * @example
1215
+ * imageEditor.changeText(id, 'change text');
1216
+ */
1217
+ changeText(id, text) {
1218
+ text = text || '';
1219
+
1220
+ return this.execute(commands.CHANGE_TEXT, id, text);
1221
+ }
1222
+
1223
+ /**
1224
+ * Set style
1225
+ * @param {number} id - object id
1226
+ * @param {Object} styleObj - text styles
1227
+ * @param {string} [styleObj.fill] Color
1228
+ * @param {string} [styleObj.fontFamily] Font type for text
1229
+ * @param {number} [styleObj.fontSize] Size
1230
+ * @param {string} [styleObj.fontStyle] Type of inclination (normal / italic)
1231
+ * @param {string} [styleObj.fontWeight] Type of thicker or thinner looking (normal / bold)
1232
+ * @param {string} [styleObj.textAlign] Type of text align (left / center / right)
1233
+ * @param {string} [styleObj.textDecoration] Type of line (underline / line-through / overline)
1234
+ * @param {boolean} isSilent - is silent execution or not
1235
+ * @returns {Promise}
1236
+ * @example
1237
+ * imageEditor.changeTextStyle(id, {
1238
+ * fontStyle: 'italic'
1239
+ * });
1240
+ */
1241
+ changeTextStyle(id, styleObj, isSilent) {
1242
+ const executeMethodName = isSilent ? 'executeSilent' : 'execute';
1243
+
1244
+ return this[executeMethodName](commands.CHANGE_TEXT_STYLE, id, styleObj);
1245
+ }
1246
+
1247
+ /**
1248
+ * change text mode
1249
+ * @param {string} type - change type
1250
+ * @private
1251
+ */
1252
+ _changeActivateMode(type) {
1253
+ if (type !== 'ICON' && this.getDrawingMode() !== type) {
1254
+ this.startDrawingMode(type);
1255
+ }
1256
+ }
1257
+
1258
+ /**
1259
+ * 'textChanged' event handler
1260
+ * @param {Object} target - changed text object
1261
+ * @private
1262
+ */
1263
+ _onTextChanged(target) {
1264
+ this.fire(events.TEXT_CHANGED, target);
1265
+ }
1266
+
1267
+ /**
1268
+ * 'iconCreateResize' event handler
1269
+ * @param {Object} originPointer origin pointer
1270
+ * @param {Number} originPointer.x x position
1271
+ * @param {Number} originPointer.y y position
1272
+ * @private
1273
+ */
1274
+ _onIconCreateResize(originPointer) {
1275
+ this.fire(events.ICON_CREATE_RESIZE, originPointer);
1276
+ }
1277
+
1278
+ /**
1279
+ * 'iconCreateEnd' event handler
1280
+ * @param {Object} originPointer origin pointer
1281
+ * @param {Number} originPointer.x x position
1282
+ * @param {Number} originPointer.y y position
1283
+ * @private
1284
+ */
1285
+ _onIconCreateEnd(originPointer) {
1286
+ this.fire(events.ICON_CREATE_END, originPointer);
1287
+ }
1288
+
1289
+ /**
1290
+ * 'textEditing' event handler
1291
+ * @private
1292
+ */
1293
+ _onTextEditing() {
1294
+ /**
1295
+ * The event which starts to edit text object
1296
+ * @event ImageEditor#textEditing
1297
+ * @example
1298
+ * imageEditor.on('textEditing', function() {
1299
+ * console.log('text editing');
1300
+ * });
1301
+ */
1302
+
1303
+ this.fire(events.TEXT_EDITING);
1304
+ }
1305
+
1306
+ /**
1307
+ * Mousedown event handler in case of 'TEXT' drawing mode
1308
+ * @param {fabric.Event} event - Current mousedown event object
1309
+ * @private
1310
+ */
1311
+ _onAddText(event) {
1312
+ /**
1313
+ * The event when 'TEXT' drawing mode is enabled and click non-object area.
1314
+ * @event ImageEditor#addText
1315
+ * @param {Object} pos
1316
+ * @param {Object} pos.originPosition - Current position on origin canvas
1317
+ * @param {Number} pos.originPosition.x - x
1318
+ * @param {Number} pos.originPosition.y - y
1319
+ * @param {Object} pos.clientPosition - Current position on client area
1320
+ * @param {Number} pos.clientPosition.x - x
1321
+ * @param {Number} pos.clientPosition.y - y
1322
+ * @example
1323
+ * imageEditor.on('addText', function(pos) {
1324
+ * console.log('text position on canvas: ' + pos.originPosition);
1325
+ * console.log('text position on brwoser: ' + pos.clientPosition);
1326
+ * });
1327
+ */
1328
+
1329
+ this.fire(events.ADD_TEXT, {
1330
+ originPosition: event.originPosition,
1331
+ clientPosition: event.clientPosition,
1332
+ });
1333
+ }
1334
+
1335
+ /**
1336
+ * 'addObject' event handler
1337
+ * @param {Object} objectProps added object properties
1338
+ * @private
1339
+ */
1340
+ _onAddObject(objectProps) {
1341
+ const obj = this._graphics.getObject(objectProps.id);
1342
+ this._invoker.fire(events.EXECUTE_COMMAND, getObjectType(obj.type));
1343
+ this._pushAddObjectCommand(obj);
1344
+ }
1345
+
1346
+ /**
1347
+ * 'objectAdded' event handler
1348
+ * @param {Object} objectProps added object properties
1349
+ * @private
1350
+ */
1351
+ _onObjectAdded(objectProps) {
1352
+ /**
1353
+ * The event when object added
1354
+ * @event ImageEditor#objectAdded
1355
+ * @param {ObjectProps} props - object properties
1356
+ * @example
1357
+ * imageEditor.on('objectAdded', function(props) {
1358
+ * console.log(props);
1359
+ * });
1360
+ */
1361
+ this.fire(OBJECT_ADDED, objectProps);
1362
+
1363
+ /**
1364
+ * The event when object added (deprecated)
1365
+ * @event ImageEditor#addObjectAfter
1366
+ * @param {ObjectProps} props - object properties
1367
+ * @deprecated
1368
+ */
1369
+ this.fire(ADD_OBJECT_AFTER, objectProps);
1370
+ }
1371
+
1372
+ /**
1373
+ * 'objectModified' event handler
1374
+ * @param {fabric.Object} obj - selection object
1375
+ * @private
1376
+ */
1377
+ _onObjectModified(obj) {
1378
+ if (obj.type !== OBJ_TYPE.CROPZONE) {
1379
+ this._invoker.fire(events.EXECUTE_COMMAND, getObjectType(obj.type));
1380
+ this._pushModifyObjectCommand(obj);
1381
+ }
1382
+ }
1383
+
1384
+ /**
1385
+ * 'selectionCleared' event handler
1386
+ * @private
1387
+ */
1388
+ _selectionCleared() {
1389
+ this.fire(SELECTION_CLEARED);
1390
+ }
1391
+
1392
+ /**
1393
+ * 'selectionCreated' event handler
1394
+ * @param {Object} eventTarget - Fabric object
1395
+ * @private
1396
+ */
1397
+ _selectionCreated(eventTarget) {
1398
+ this.fire(SELECTION_CREATED, eventTarget);
1399
+ }
1400
+
1401
+ /**
1402
+ * Register custom icons
1403
+ * @param {{iconType: string, pathValue: string}} infos - Infos to register icons
1404
+ * @example
1405
+ * imageEditor.registerIcons({
1406
+ * customIcon: 'M 0 0 L 20 20 L 10 10 Z',
1407
+ * customArrow: 'M 60 0 L 120 60 H 90 L 75 45 V 180 H 45 V 45 L 30 60 H 0 Z'
1408
+ * });
1409
+ */
1410
+ registerIcons(infos) {
1411
+ this._graphics.registerPaths(infos);
1412
+ }
1413
+
1414
+ /**
1415
+ * Change canvas cursor type
1416
+ * @param {string} cursorType - cursor type
1417
+ * @example
1418
+ * imageEditor.changeCursor('crosshair');
1419
+ */
1420
+ changeCursor(cursorType) {
1421
+ this._graphics.changeCursor(cursorType);
1422
+ }
1423
+
1424
+ /**
1425
+ * Add icon on canvas
1426
+ * @param {string} type - Icon type ('arrow', 'cancel', custom icon name)
1427
+ * @param {Object} options - Icon options
1428
+ * @param {string} [options.fill] - Icon foreground color
1429
+ * @param {number} [options.left] - Icon x position
1430
+ * @param {number} [options.top] - Icon y position
1431
+ * @returns {Promise<ObjectProps, ErrorMsg>}
1432
+ * @example
1433
+ * imageEditor.addIcon('arrow'); // The position is center on canvas
1434
+ * @example
1435
+ * imageEditor.addIcon('arrow', {
1436
+ * left: 100,
1437
+ * top: 100
1438
+ * }).then(objectProps => {
1439
+ * console.log(objectProps.id);
1440
+ * });
1441
+ */
1442
+ addIcon(type, options) {
1443
+ options = options || {};
1444
+
1445
+ this._setPositions(options);
1446
+
1447
+ return this.execute(commands.ADD_ICON, type, options);
1448
+ }
1449
+
1450
+ /**
1451
+ * Change icon color
1452
+ * @param {number} id - object id
1453
+ * @param {string} color - Color for icon
1454
+ * @returns {Promise}
1455
+ * @example
1456
+ * imageEditor.changeIconColor(id, '#000000');
1457
+ */
1458
+ changeIconColor(id, color) {
1459
+ return this.execute(commands.CHANGE_ICON_COLOR, id, color);
1460
+ }
1461
+
1462
+ /**
1463
+ * Remove an object or group by id
1464
+ * @param {number} id - object id
1465
+ * @returns {Promise}
1466
+ * @example
1467
+ * imageEditor.removeObject(id);
1468
+ */
1469
+ removeObject(id) {
1470
+ const { type } = this._graphics.getObject(id);
1471
+
1472
+ return this.execute(commands.REMOVE_OBJECT, id, getObjectType(type));
1473
+ }
1474
+
1475
+ /**
1476
+ * Whether it has the filter or not
1477
+ * @param {string} type - Filter type
1478
+ * @returns {boolean} true if it has the filter
1479
+ */
1480
+ hasFilter(type) {
1481
+ return this._graphics.hasFilter(type);
1482
+ }
1483
+
1484
+ /**
1485
+ * Remove filter on canvas image
1486
+ * @param {string} type - Filter type
1487
+ * @returns {Promise<FilterResult, ErrorMsg>}
1488
+ * @example
1489
+ * imageEditor.removeFilter('Grayscale').then(obj => {
1490
+ * console.log('filterType: ', obj.type);
1491
+ * console.log('actType: ', obj.action);
1492
+ * }).catch(message => {
1493
+ * console.log('error: ', message);
1494
+ * });
1495
+ */
1496
+ removeFilter(type) {
1497
+ return this.execute(commands.REMOVE_FILTER, type);
1498
+ }
1499
+
1500
+ /**
1501
+ * Apply filter on canvas image
1502
+ * @param {string} type - Filter type
1503
+ * @param {object} options - Options to apply filter
1504
+ * @param {boolean} isSilent - is silent execution or not
1505
+ * @returns {Promise<FilterResult, ErrorMsg>}
1506
+ * @example
1507
+ * imageEditor.applyFilter('Grayscale');
1508
+ * @example
1509
+ * imageEditor.applyFilter('mask', {maskObjId: id}).then(obj => {
1510
+ * console.log('filterType: ', obj.type);
1511
+ * console.log('actType: ', obj.action);
1512
+ * }).catch(message => {
1513
+ * console.log('error: ', message);
1514
+ * });;
1515
+ */
1516
+ applyFilter(type, options, isSilent) {
1517
+ const executeMethodName = isSilent ? 'executeSilent' : 'execute';
1518
+
1519
+ return this[executeMethodName](commands.APPLY_FILTER, type, options);
1520
+ }
1521
+
1522
+ /**
1523
+ * Get data url
1524
+ * @param {Object} options - options for toDataURL
1525
+ * @param {String} [options.format=png] The format of the output image. Either "jpeg" or "png"
1526
+ * @param {Number} [options.quality=1] Quality level (0..1). Only used for jpeg.
1527
+ * @param {Number} [options.multiplier=1] Multiplier to scale by
1528
+ * @param {Number} [options.left] Cropping left offset. Introduced in fabric v1.2.14
1529
+ * @param {Number} [options.top] Cropping top offset. Introduced in fabric v1.2.14
1530
+ * @param {Number} [options.width] Cropping width. Introduced in fabric v1.2.14
1531
+ * @param {Number} [options.height] Cropping height. Introduced in fabric v1.2.14
1532
+ * @returns {string} A DOMString containing the requested data URI
1533
+ * @example
1534
+ * imgEl.src = imageEditor.toDataURL();
1535
+ *
1536
+ * imageEditor.loadImageFromURL(imageEditor.toDataURL(), 'FilterImage').then(() => {
1537
+ * imageEditor.addImageObject(imgUrl);
1538
+ * });
1539
+ */
1540
+ toDataURL(options) {
1541
+ return this._graphics.toDataURL(options);
1542
+ }
1543
+
1544
+ /**
1545
+ * Get image name
1546
+ * @returns {string} image name
1547
+ * @example
1548
+ * console.log(imageEditor.getImageName());
1549
+ */
1550
+ getImageName() {
1551
+ return this._graphics.getImageName();
1552
+ }
1553
+
1554
+ /**
1555
+ * Clear undoStack
1556
+ * @example
1557
+ * imageEditor.clearUndoStack();
1558
+ */
1559
+ clearUndoStack() {
1560
+ this._invoker.clearUndoStack();
1561
+ }
1562
+
1563
+ /**
1564
+ * Clear redoStack
1565
+ * @example
1566
+ * imageEditor.clearRedoStack();
1567
+ */
1568
+ clearRedoStack() {
1569
+ this._invoker.clearRedoStack();
1570
+ }
1571
+
1572
+ /**
1573
+ * Whehter the undo stack is empty or not
1574
+ * @returns {boolean}
1575
+ * imageEditor.isEmptyUndoStack();
1576
+ */
1577
+ isEmptyUndoStack() {
1578
+ return this._invoker.isEmptyUndoStack();
1579
+ }
1580
+
1581
+ /**
1582
+ * Whehter the redo stack is empty or not
1583
+ * @returns {boolean}
1584
+ * imageEditor.isEmptyRedoStack();
1585
+ */
1586
+ isEmptyRedoStack() {
1587
+ return this._invoker.isEmptyRedoStack();
1588
+ }
1589
+
1590
+ /**
1591
+ * Resize canvas dimension
1592
+ * @param {{width: number, height: number}} dimension - Max width & height
1593
+ * @returns {Promise}
1594
+ */
1595
+ resizeCanvasDimension(dimension) {
1596
+ if (!dimension) {
1597
+ return Promise.reject(rejectMessages.invalidParameters);
1598
+ }
1599
+
1600
+ return this.execute(commands.RESIZE_CANVAS_DIMENSION, dimension);
1601
+ }
1602
+
1603
+ /**
1604
+ * Destroy
1605
+ */
1606
+ destroy() {
1607
+ this.stopDrawingMode();
1608
+ this._detachDomEvents();
1609
+ this._graphics.destroy();
1610
+ this._graphics = null;
1611
+
1612
+ if (this.ui) {
1613
+ this._detachColorPickerInputBoxEvents();
1614
+ this.ui.destroy();
1615
+ }
1616
+
1617
+ forEach(
1618
+ this,
1619
+ (value, key) => {
1620
+ this[key] = null;
1621
+ },
1622
+ this
1623
+ );
1624
+ }
1625
+
1626
+ /**
1627
+ * Set position
1628
+ * @param {Object} options - Position options (left or top)
1629
+ * @private
1630
+ */
1631
+ _setPositions(options) {
1632
+ const centerPosition = this._graphics.getCenter();
1633
+
1634
+ if (isUndefined(options.left)) {
1635
+ options.left = centerPosition.left;
1636
+ }
1637
+
1638
+ if (isUndefined(options.top)) {
1639
+ options.top = centerPosition.top;
1640
+ }
1641
+ }
1642
+
1643
+ /**
1644
+ * Set properties of active object
1645
+ * @param {number} id - object id
1646
+ * @param {Object} keyValue - key & value
1647
+ * @returns {Promise}
1648
+ * @example
1649
+ * imageEditor.setObjectProperties(id, {
1650
+ * left:100,
1651
+ * top:100,
1652
+ * width: 200,
1653
+ * height: 200,
1654
+ * opacity: 0.5
1655
+ * });
1656
+ */
1657
+ setObjectProperties(id, keyValue) {
1658
+ return this.execute(commands.SET_OBJECT_PROPERTIES, id, keyValue);
1659
+ }
1660
+
1661
+ /**
1662
+ * Set properties of active object, Do not leave an invoke history.
1663
+ * @param {number} id - object id
1664
+ * @param {Object} keyValue - key & value
1665
+ * @example
1666
+ * imageEditor.setObjectPropertiesQuietly(id, {
1667
+ * left:100,
1668
+ * top:100,
1669
+ * width: 200,
1670
+ * height: 200,
1671
+ * opacity: 0.5
1672
+ * });
1673
+ */
1674
+ setObjectPropertiesQuietly(id, keyValue) {
1675
+ this._graphics.setObjectProperties(id, keyValue);
1676
+ }
1677
+
1678
+ /**
1679
+ * Get properties of active object corresponding key
1680
+ * @param {number} id - object id
1681
+ * @param {Array<string>|ObjectProps|string} keys - property's key
1682
+ * @returns {ObjectProps} properties if id is valid or null
1683
+ * @example
1684
+ * var props = imageEditor.getObjectProperties(id, 'left');
1685
+ * console.log(props);
1686
+ * @example
1687
+ * var props = imageEditor.getObjectProperties(id, ['left', 'top', 'width', 'height']);
1688
+ * console.log(props);
1689
+ * @example
1690
+ * var props = imageEditor.getObjectProperties(id, {
1691
+ * left: null,
1692
+ * top: null,
1693
+ * width: null,
1694
+ * height: null,
1695
+ * opacity: null
1696
+ * });
1697
+ * console.log(props);
1698
+ */
1699
+ getObjectProperties(id, keys) {
1700
+ const object = this._graphics.getObject(id);
1701
+ if (!object) {
1702
+ return null;
1703
+ }
1704
+
1705
+ return this._graphics.getObjectProperties(id, keys);
1706
+ }
1707
+
1708
+ /**
1709
+ * Get the canvas size
1710
+ * @returns {Object} {{width: number, height: number}} canvas size
1711
+ * @example
1712
+ * var canvasSize = imageEditor.getCanvasSize();
1713
+ * console.log(canvasSize.width);
1714
+ * console.height(canvasSize.height);
1715
+ */
1716
+ getCanvasSize() {
1717
+ return this._graphics.getCanvasSize();
1718
+ }
1719
+
1720
+ /**
1721
+ * Get object position by originX, originY
1722
+ * @param {number} id - object id
1723
+ * @param {string} originX - can be 'left', 'center', 'right'
1724
+ * @param {string} originY - can be 'top', 'center', 'bottom'
1725
+ * @returns {Object} {{x:number, y: number}} position by origin if id is valid, or null
1726
+ * @example
1727
+ * var position = imageEditor.getObjectPosition(id, 'left', 'top');
1728
+ * console.log(position);
1729
+ */
1730
+ getObjectPosition(id, originX, originY) {
1731
+ return this._graphics.getObjectPosition(id, originX, originY);
1732
+ }
1733
+
1734
+ /**
1735
+ * Set object position by originX, originY
1736
+ * @param {number} id - object id
1737
+ * @param {Object} posInfo - position object
1738
+ * @param {number} posInfo.x - x position
1739
+ * @param {number} posInfo.y - y position
1740
+ * @param {string} posInfo.originX - can be 'left', 'center', 'right'
1741
+ * @param {string} posInfo.originY - can be 'top', 'center', 'bottom'
1742
+ * @returns {Promise}
1743
+ * @example
1744
+ * // align the object to 'left', 'top'
1745
+ * imageEditor.setObjectPosition(id, {
1746
+ * x: 0,
1747
+ * y: 0,
1748
+ * originX: 'left',
1749
+ * originY: 'top'
1750
+ * });
1751
+ * @example
1752
+ * // align the object to 'right', 'top'
1753
+ * var canvasSize = imageEditor.getCanvasSize();
1754
+ * imageEditor.setObjectPosition(id, {
1755
+ * x: canvasSize.width,
1756
+ * y: 0,
1757
+ * originX: 'right',
1758
+ * originY: 'top'
1759
+ * });
1760
+ * @example
1761
+ * // align the object to 'left', 'bottom'
1762
+ * var canvasSize = imageEditor.getCanvasSize();
1763
+ * imageEditor.setObjectPosition(id, {
1764
+ * x: 0,
1765
+ * y: canvasSize.height,
1766
+ * originX: 'left',
1767
+ * originY: 'bottom'
1768
+ * });
1769
+ * @example
1770
+ * // align the object to 'right', 'bottom'
1771
+ * var canvasSize = imageEditor.getCanvasSize();
1772
+ * imageEditor.setObjectPosition(id, {
1773
+ * x: canvasSize.width,
1774
+ * y: canvasSize.height,
1775
+ * originX: 'right',
1776
+ * originY: 'bottom'
1777
+ * });
1778
+ */
1779
+ setObjectPosition(id, posInfo) {
1780
+ return this.execute(commands.SET_OBJECT_POSITION, id, posInfo);
1781
+ }
1782
+
1783
+ /**
1784
+ * @param {object} dimensions - Image Dimensions
1785
+ * @returns {Promise<ErrorMsg>}
1786
+ */
1787
+ resize(dimensions) {
1788
+ return this.execute(commands.RESIZE_IMAGE, dimensions);
1789
+ }
1790
+ }
1791
+
1792
+ action.mixin(ImageEditor);
1793
+ CustomEvents.mixin(ImageEditor);
1794
+
1795
+ export default ImageEditor;