123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410 |
- <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"
- crossOrigin="anonymous"
- >
- </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
- v-if="!isWeixin"
- class="save"
- @click="onClickSave"
- >
- 保存
- </button>
- <button
- v-if="isWeixin"
- class="generate"
- @click="onClickGenerateGroupPhoto"
- >
- 生成合影
- </button>
- </div>
- <a
- v-show="false"
- ref="for-download"
- :href="aDownloadHref"
- download="photo.jpg"
- />
- <div
- v-if="isWeixin"
- v-show="isShowResult"
- class="resultWrapper"
- >
- <button
- class="close"
- @click="isShowResult = false"
- >
- <img
- class=""
- src="@/assets/images/close.png"
- alt=""
- draggable="false"
- >
- </button>
- <img
- class="result"
- :src="aDownloadHref"
- alt=""
- draggable="false"
- >
- <div class="tip">
- 长按图片保存
- </div>
- </div>
- <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,
- isShowResult: 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 fileReader = new FileReader()
- fileReader.readAsDataURL(originalFile)
- fileReader.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('请上传包含人物的图片')
- })
- },
- async getGroupPhotoDataUrl() {
- const canvas = await html2canvas(document.querySelector('.group-photo-wrapper'), {
- useCORS: true, // 【重要】开启跨域配置
- scale: 1,
- allowTaint: true, // 允许跨域图片
- preserveDrawingBuffer: true,
- })
- this.aDownloadHref = canvas.toDataURL('image/jpeg', 1.0)
- },
- onClickSave() {
- this.getGroupPhotoDataUrl().then(() => {
- this.$nextTick(() => {
- this.$refs['for-download'].click()
- })
- })
- },
- onClickGenerateGroupPhoto() {
- this.getGroupPhotoDataUrl().then(() => {
- this.isShowResult = true
- })
- }
- }
- }
- </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, .generate {
- margin-top: 4.5vw;
- width: 91.1vw;
- height: 16vw;
- background: #A33328;
- border-radius: 8vw;
- font-size: 4.3vw;
- color: #fff;
- }
- }
- .resultWrapper {
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- z-index: 1;
- background: rgba(0, 0, 0, 0.9);
- > button.close {
- position: absolute;
- top: 2vw;
- right: 2vw;
- width: 10vw;
- height: 10vw;
- > img {
- width: 100%;
- height: 100%;
- }
- }
- > img {
- position: absolute;
- left: 50%;
- top: 50%;
- transform: translate(-50%, -50%);
- width: 100%;
- }
- > .tip {
- position: absolute;
- width: 100%;
- text-align: center;
- bottom: 5vh;
- }
- }
- > .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>
|