index.js 6.4 KB

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