index.js 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. // 宽高比
  2. const aspectRatio = 3 / 4;
  3. // 自动裁剪区域, 默认为 50%
  4. const autoCropAre = 0.5;
  5. // 裁剪宽度
  6. const croppedWidth = 200;
  7. // 裁剪高度
  8. const croppedHeight = croppedWidth * aspectRatio;
  9. // 是否裁剪为圆形
  10. const roundedCrop = false;
  11. // 导出图片格式
  12. const imgType ='image/jpeg';
  13. let cropper = ''; //保存cropee对象
  14. // 旋转
  15. function spin(e) {
  16. cropper.rotate(90)
  17. }
  18. const fileUploadBox = document.querySelector(".file-upload-box");
  19. const spinBtn = document.querySelector("#spin"); //获取旋转按钮对象
  20. const saveBtn = document.querySelector("#save");
  21. const previews = document.querySelectorAll(".preview");
  22. let previewReady = false;
  23. let croppable = false;
  24. document.addEventListener("UniAppJSBridgeReady", Init);
  25. // 初始化
  26. async function Init(params) {
  27. console.log(`uniAppSDK loaded`);
  28. const env = await getEnv();
  29. console.log("当前环境:" + JSON.stringify(env));
  30. const imgDataUrl = await selectFile(env);
  31. // hidden input box
  32. fileUploadBox.style.display = "none";
  33. // create image
  34. const image = new Image();
  35. image.src = imgDataUrl;
  36. image.crossorigin = true;
  37. document.querySelector(".img-crop-area").appendChild(image);
  38. image.onload = function() {
  39. const options = {
  40. aspectRatio: aspectRatio,
  41. autoCropAre: autoCropAre,
  42. viewMode: 1,
  43. ready: function() {
  44. let clone = this.cloneNode();
  45. clone.className = "";
  46. clone.style.cssText =
  47. "display: block;" +
  48. "width: 100%;" +
  49. "min-width: 0;" +
  50. "min-height: 0;" +
  51. "max-width: none;" +
  52. "max-height: none;";
  53. each(previews, function(elem) {
  54. elem.appendChild(clone.cloneNode());
  55. });
  56. croppable = true;
  57. previewReady = true;
  58. saveBtn.classList.remove("disabled");
  59. spinBtn.classList.remove("disabled");
  60. if (roundedCrop) {
  61. const elements = document.querySelectorAll(
  62. ".cropper-view-box, .cropper-face"
  63. );
  64. for (let item of elements) {
  65. item.style.borderRadius = "50%";
  66. }
  67. }
  68. },
  69. crop: function(event) {
  70. if (!previewReady) {
  71. return;
  72. }
  73. let data = event.detail;
  74. let cropper = this.cropper;
  75. let imageData = cropper.getImageData();
  76. let previewAspectRatio = data.width / data.height;
  77. each(previews, function(elem) {
  78. let previewImage = elem.getElementsByTagName("img").item(0);
  79. let previewWidth = elem.offsetWidth;
  80. let previewHeight = previewWidth / previewAspectRatio;
  81. let imageScaledRatio = data.width / previewWidth;
  82. if (roundedCrop) {
  83. elem.style.borderRadius = "50%";
  84. }
  85. elem.style.height = previewHeight + "px";
  86. previewImage.style.width =
  87. imageData.naturalWidth / imageScaledRatio + "px";
  88. previewImage.style.height =
  89. imageData.naturalHeight / imageScaledRatio + "px";
  90. previewImage.style.marginLeft = -data.x / imageScaledRatio + "px";
  91. previewImage.style.marginTop = -data.y / imageScaledRatio + "px";
  92. });
  93. },
  94. };
  95. // 保存cropper对象
  96. cropper = new Cropper(image, options);
  97. save.addEventListener("click", () => {
  98. if (!croppable) {
  99. return;
  100. }
  101. let croppedCanvas = cropper.getCroppedCanvas({
  102. width: croppedWidth,
  103. height: croppedHeight,
  104. });
  105. if (roundedCrop) {
  106. croppedCanvas = getRoundedCanvas(croppedCanvas);
  107. }
  108. const postData = {
  109. data: {
  110. type: "croppedData",
  111. dataUrl: croppedCanvas.toDataURL(imgType),
  112. },
  113. };
  114. if (env.plus) {
  115. uni.postMessage(postData);
  116. } else if (env.h5) {
  117. top.postMessage(postData);
  118. } else if (env.miniprogram) {
  119. // 小程序
  120. top.postMessage(postData);
  121. }
  122. // // // back to previous page
  123. uni.navigateBack({
  124. delta: 1,
  125. });
  126. });
  127. };
  128. }
  129. function getRoundedCanvas(sourceCanvas) {
  130. let canvas = document.createElement("canvas");
  131. let context = canvas.getContext("2d");
  132. let width = sourceCanvas.width;
  133. let height = sourceCanvas.height;
  134. canvas.width = width;
  135. canvas.height = height;
  136. context.imageSmoothingEnabled = true;
  137. context.drawImage(sourceCanvas, 0, 0, width, height);
  138. context.globalCompositeOperation = "destination-in";
  139. context.beginPath();
  140. context.arc(
  141. width / 2,
  142. height / 2,
  143. Math.min(width, height) / 2,
  144. 0,
  145. 2 * Math.PI,
  146. true
  147. );
  148. context.fill();
  149. return canvas;
  150. }
  151. function each(arr, callback) {
  152. let length = arr.length;
  153. let i;
  154. for (i = 0; i < length; i++) {
  155. callback.call(arr, arr[i], i, arr);
  156. }
  157. return arr;
  158. }
  159. async function selectFile(env) {
  160. const fileInput = document.querySelector("#my-input");
  161. return new Promise((resolve, reject) => {
  162. fileInput.addEventListener("change", async (event) => {
  163. let result;
  164. result = await getDataUrlFromReader(event);
  165. resolve(result);
  166. });
  167. });
  168. }
  169. async function getDataUrlFromReader(event) {
  170. const files = event.target.files;
  171. return new Promise((resolve, reject) => {
  172. const reader = new FileReader();
  173. reader.addEventListener("loadend", () => {
  174. resolve(reader.result);
  175. });
  176. reader.readAsDataURL(files[0]);
  177. });
  178. }
  179. async function getEnv() {
  180. return new Promise((resolve, reject) => {
  181. uni.getEnv((res) => {
  182. resolve(res);
  183. });
  184. });
  185. }
  186. // TODO:
  187. async function chooseWithPlusApi() {
  188. const btnArray = [{
  189. title: "拍照",
  190. },
  191. {
  192. title: "从手机相册选择",
  193. },
  194. ];
  195. return new Promise((resolve, reject) => {
  196. plus.nativeUI.actionSheet({
  197. cancel: "取消",
  198. buttons: btnArray,
  199. },
  200. function(e) {
  201. let index = e.index;
  202. switch (index) {
  203. case 0:
  204. break;
  205. case 1:
  206. let camera = plus.camera.getCamera();
  207. camera.captureImage(
  208. function(file) {
  209. resolve(file);
  210. },
  211. function() {
  212. console.log("从相机获取照片失败");
  213. reject("从相机获取照片失败");
  214. }, {
  215. filename: "_doc/photo/",
  216. index: 1,
  217. }
  218. );
  219. break;
  220. case 2:
  221. plus.gallery.pick(
  222. function(file) {
  223. resolve(file);
  224. },
  225. function() {
  226. console.log("取消图片选择");
  227. reject("取消图片选择");
  228. }, {
  229. multiple: false,
  230. }
  231. );
  232. break;
  233. }
  234. }
  235. );
  236. });
  237. }