|
@@ -0,0 +1,336 @@
|
|
|
+<template>
|
|
|
+ <div class="landmark-editor">
|
|
|
+ <div class="group-photo-wrapper">
|
|
|
+ <img
|
|
|
+ src="@/assets/images/entries/wen-wu-shang-xi.png"
|
|
|
+ alt=""
|
|
|
+ class="bg"
|
|
|
+ draggable="false"
|
|
|
+ >
|
|
|
+ <img
|
|
|
+ ref="person"
|
|
|
+ class="person"
|
|
|
+ :src="personImgUrl"
|
|
|
+ alt=""
|
|
|
+ draggable="false"
|
|
|
+ >
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="button-wrapper">
|
|
|
+ <div class="line1">
|
|
|
+ <button
|
|
|
+ class="give-up"
|
|
|
+ @click="$router.go(-2)"
|
|
|
+ >
|
|
|
+ 放弃
|
|
|
+ </button>
|
|
|
+ <button
|
|
|
+ class="redo"
|
|
|
+ @click="onClickRedo"
|
|
|
+ >
|
|
|
+ 重拍
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ <button
|
|
|
+ class="save"
|
|
|
+ @click="onClickSave"
|
|
|
+ >
|
|
|
+ 保存
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ <a
|
|
|
+ v-show="false"
|
|
|
+ ref="for-download"
|
|
|
+ :href="aDownloadHref"
|
|
|
+ download="photo.jpg"
|
|
|
+ />
|
|
|
+ <van-popup
|
|
|
+ v-model="isShowPopup"
|
|
|
+ class="popup-bottom"
|
|
|
+ round
|
|
|
+ position="bottom"
|
|
|
+ >
|
|
|
+ <button @click="$router.go(-1)">
|
|
|
+ 重选场景
|
|
|
+ </button>
|
|
|
+ <button @click="onClickReshot">
|
|
|
+ 重新拍摄
|
|
|
+ </button>
|
|
|
+ <button @click="isShowPopup = false">
|
|
|
+ 取消
|
|
|
+ </button>
|
|
|
+ </van-popup>
|
|
|
+ <input
|
|
|
+ id="input"
|
|
|
+ ref="input"
|
|
|
+ type="file"
|
|
|
+ accept="image/*"
|
|
|
+ capture="user"
|
|
|
+ @input="onInput"
|
|
|
+ >
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+const AlloyFinger = require("alloyfinger")
|
|
|
+const Transform = require("css3transform")
|
|
|
+const To = require("@/utils/to.js")
|
|
|
+import html2canvas from "html2canvas"
|
|
|
+
|
|
|
+export default {
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ aDownloadHref: '',
|
|
|
+ isShowPopup: false,
|
|
|
+ }
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ personImgUrl() {
|
|
|
+ return decodeURI(this.$route.query.personImgUrl)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ function ease(x) {
|
|
|
+ return Math.sqrt(1 - Math.pow(x - 1, 2))
|
|
|
+ }
|
|
|
+
|
|
|
+ var initScale = 1
|
|
|
+
|
|
|
+ const target = this.$refs.person
|
|
|
+
|
|
|
+ Transform(target)
|
|
|
+
|
|
|
+ new AlloyFinger(target, {
|
|
|
+ // 多点触摸时重置状态
|
|
|
+ multipointStart: function() {
|
|
|
+ To.stopAll()
|
|
|
+ initScale = target.scaleX
|
|
|
+ },
|
|
|
+ // 旋转
|
|
|
+ rotate: function(evt) {
|
|
|
+ target.rotateZ += evt.angle
|
|
|
+ },
|
|
|
+ // 缩放
|
|
|
+ pinch: function(evt) {
|
|
|
+ target.scaleX = target.scaleY = initScale * evt.zoom
|
|
|
+ },
|
|
|
+ // 触摸结束时的动画
|
|
|
+ multipointEnd: function() {
|
|
|
+ // 使用To.js来管理js开启的动画
|
|
|
+ To.stopAll()
|
|
|
+
|
|
|
+ // // 最小缩放到0.5倍
|
|
|
+ // if (target.scaleX < 0.5) {
|
|
|
+ // new To(target, "scaleX", 0.5, 500, ease)
|
|
|
+ // new To(target, "scaleY", 0.5, 500, ease)
|
|
|
+ // }
|
|
|
+ // // 最大2倍
|
|
|
+ // if (target.scaleX > 2) {
|
|
|
+ // new To(target, "scaleX", 2, 500, ease)
|
|
|
+ // new To(target, "scaleY", 2, 500, ease)
|
|
|
+ // }
|
|
|
+
|
|
|
+ // 取旋转角度
|
|
|
+ var rotation = target.rotateZ % 360
|
|
|
+
|
|
|
+ if (rotation < 0) rotation = 360 + rotation
|
|
|
+ target.rotateZ = rotation
|
|
|
+
|
|
|
+ // // 角度回弹
|
|
|
+ // if (rotation > 0 && rotation < 45) {
|
|
|
+ // new To(target, "rotateZ", 0, 500, ease)
|
|
|
+ // } else if (rotation >= 315) {
|
|
|
+ // new To(target, "rotateZ", 360, 500, ease)
|
|
|
+ // } else if (rotation >= 45 && rotation < 135) {
|
|
|
+ // new To(target, "rotateZ", 90, 500, ease)
|
|
|
+ // } else if (rotation >= 135 && rotation < 225) {
|
|
|
+ // new To(target, "rotateZ", 180, 500, ease)
|
|
|
+ // } else if (rotation >= 225 && rotation < 315) {
|
|
|
+ // new To(target, "rotateZ", 270, 500, ease)
|
|
|
+ // }
|
|
|
+ },
|
|
|
+ // 拖拽
|
|
|
+ pressMove: function(evt) {
|
|
|
+ target.translateX += evt.deltaX
|
|
|
+ target.translateY += evt.deltaY
|
|
|
+ evt.preventDefault()
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ onClickRedo() {
|
|
|
+ this.isShowPopup = true
|
|
|
+ },
|
|
|
+ garenteeValid(originalFile) { // 确保格式为jpg
|
|
|
+ return new Promise((resolve) => {
|
|
|
+ // 选中的图片以dataUrl形式存入FileReader,
|
|
|
+ let imgFile = new FileReader()
|
|
|
+ imgFile.readAsDataURL(originalFile)
|
|
|
+ imgFile.onload = function (loadEvent) {
|
|
|
+ // 把FileReader中的dataUrl转换成一个Image对象
|
|
|
+ let image = new Image()
|
|
|
+ image.src = loadEvent.target.result
|
|
|
+ image.onload = function () {
|
|
|
+ // 计算理想尺寸
|
|
|
+ let newWidth = image.width
|
|
|
+ let newHeight = image.height
|
|
|
+ if (image.width >= 2000 || image.height >= 2000) {
|
|
|
+ if (image.width > image.height) {
|
|
|
+ newWidth = 1999
|
|
|
+ newHeight = image.height / image.width * newWidth
|
|
|
+ } else {
|
|
|
+ newHeight = 1999
|
|
|
+ newWidth = image.width / image.height * newHeight
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 把Image画到canvas上
|
|
|
+ let canvas = document.createElement("canvas")
|
|
|
+ // document.body.append(canvas)
|
|
|
+ // canvas.style.position = 'absolute'
|
|
|
+ // canvas.style.top = 0
|
|
|
+ // canvas.style.left = 0
|
|
|
+ // canvas.style.zIndex = 999999999
|
|
|
+ canvas.width = newWidth
|
|
|
+ canvas.height = newHeight
|
|
|
+ canvas.getContext("2d").drawImage(image, 0, 0, newWidth, newHeight)
|
|
|
+ // canvas转为jpg格式的blob
|
|
|
+ canvas.toBlob((blob) => {
|
|
|
+ // Blob转为File
|
|
|
+ const fileToSend = new File([blob], `1.jpg`, { type: blob.type })
|
|
|
+ resolve(fileToSend)
|
|
|
+ }, 'image/jpeg')
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ onClickReshot() {
|
|
|
+ this.$refs.input.click()
|
|
|
+ },
|
|
|
+ onInput(e) {
|
|
|
+ if (!e.target.value) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const loadingHandler = this.$loading({
|
|
|
+ lock: true,
|
|
|
+ text: 'Loading',
|
|
|
+ spinner: 'el-icon-loading',
|
|
|
+ background: 'rgba(0, 0, 0, 0.7)',
|
|
|
+ customClass: 'element-ui-loading'
|
|
|
+ })
|
|
|
+ this.garenteeValid(e.target.files[0]).then((jpgFile) => {
|
|
|
+ return globalApi.getPersonInImage(jpgFile)
|
|
|
+ }).then((url) => {
|
|
|
+ loadingHandler.close()
|
|
|
+ // 不能直接该query.personImgUrl的值,会不生效。
|
|
|
+ this.$router.replace({
|
|
|
+ name: this.$route.name,
|
|
|
+ query: {
|
|
|
+ personImgUrl: encodeURI(url)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ this.isShowPopup = false
|
|
|
+ }).catch((err) => {
|
|
|
+ loadingHandler.close()
|
|
|
+ console.error(err)
|
|
|
+ window.alert('请上传包含人物的图片')
|
|
|
+ })
|
|
|
+ },
|
|
|
+ onClickSave() {
|
|
|
+ html2canvas(document.querySelector('.group-photo-wrapper'), {
|
|
|
+ useCORS: true, // 【重要】开启跨域配置
|
|
|
+ scale: 1,
|
|
|
+ allowTaint: true, // 允许跨域图片
|
|
|
+ preserveDrawingBuffer: true,
|
|
|
+ }).then((canvas) => {
|
|
|
+ this.aDownloadHref = canvas.toDataURL('image/jpeg', 1.0)
|
|
|
+ this.$nextTick(() => {
|
|
|
+ this.$refs['for-download'].click()
|
|
|
+ })
|
|
|
+ })
|
|
|
+ },
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="less" scoped>
|
|
|
+.landmark-editor {
|
|
|
+ position: absolute;
|
|
|
+ left: 0;
|
|
|
+ top: 0;
|
|
|
+ right: 0;
|
|
|
+ bottom: 0;
|
|
|
+ z-index: 9999;
|
|
|
+ background: #E7DDD6;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ justify-content: space-evenly;
|
|
|
+ > .group-photo-wrapper {
|
|
|
+ width: 92.4vw;
|
|
|
+ height: fit-content;
|
|
|
+ overflow: hidden;
|
|
|
+ position: relative;
|
|
|
+ > img.bg {
|
|
|
+ width: 100%;
|
|
|
+ }
|
|
|
+ > img.person {
|
|
|
+ position: absolute;
|
|
|
+ left: 60%;
|
|
|
+ top: 40%;
|
|
|
+ width: 30vw;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ > .button-wrapper {
|
|
|
+ > .line1 {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ button.give-up {
|
|
|
+ width: 42.7vw;
|
|
|
+ height: 16vw;
|
|
|
+ border-radius: 8vw;
|
|
|
+ border: 0.3vw solid #A33328;
|
|
|
+ font-size: 4.3vw;
|
|
|
+ color: #A33328;
|
|
|
+ }
|
|
|
+ button.redo {
|
|
|
+ width: 42.7vw;
|
|
|
+ height: 16vw;
|
|
|
+ border-radius: 8vw;
|
|
|
+ border: 0.3vw solid #A33328;
|
|
|
+ font-size: 4.3vw;
|
|
|
+ color: #A33328;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ > .save {
|
|
|
+ margin-top: 4.5vw;
|
|
|
+ width: 91.1vw;
|
|
|
+ height: 16vw;
|
|
|
+ background: #A33328;
|
|
|
+ border-radius: 8vw;
|
|
|
+ font-size: 4.3vw;
|
|
|
+ color: #fff;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ > .popup-bottom {
|
|
|
+ height: 63.1vw;
|
|
|
+ > button {
|
|
|
+ height: 33.333%;
|
|
|
+ width: 100%;
|
|
|
+ border-bottom: 1px solid #ccc;
|
|
|
+ color: black;
|
|
|
+ &:last-of-type {
|
|
|
+ border-bottom: none;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ > #input {
|
|
|
+ display: none;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|
|
|
+
|
|
|
+http://vibktprfx-prod-prod-damo-eas-cn-shanghai.oss-cn-shanghai.aliyuncs.com/segment-body/2023-05-17/a22f4727-a9e8-47f0-bd9c-ad71bfb0d237/image.png?Expires=1684313991&OSSAccessKeyId=LTAI4FoLmvQ9urWXgSRpDvh1&Signature=galFAcHHalE%2Bm39ckgeyep4OD6o%3D
|
|
|
+http%3A%2F%2Fvibktprfx-prod-prod-damo-eas-cn-shanghai.oss-cn-shanghai.aliyuncs.com%2Fsegment-body%2F2023-05-17%2F082bc112-522a-40e6-90c7-aeca0baf899d%2Fimage.png%3FExpires%3D1684313986%26OSSAccessKeyId%3DLTAI4FoLmvQ9urWXgSRpDvh1%26Signature%3DCgwrX3t%25252BllmZxlZHfCPoxnZNJK4%25253D
|