|
- <template>
- <view class="container">
- <view class="image-box" :style="{
- backgroundImage: 'url(' + src + ')',
- backgroundSize: imageBoxWidth + 'rpx' + ' ' + imageBoxHeight + 'rpx',
- width: imageBoxWidth + 'rpx',
- height: imageBoxHeight + 'rpx',
- borderRadius: cropShape == 'rect' ? '' : '',
- }">
- <view class="mask"></view>
- <view class="cropping-box" @touchstart.stop="touchstart" @touchmove.stop="touchmove"
- @touchend.stop="touchend" :style="{
- top: cropBoxY + 'rpx',
- left: cropBoxX + 'rpx',
- width: cropBoxWidth + 'rpx',
- height: cropBoxHeight + 'rpx',
- backgroundImage: 'url(' + src + ')',
- backgroundSize: imageBoxWidth + 'rpx' + ' ' + imageBoxHeight + 'rpx',
- backgroundPositionX: (-cropBoxX - 4) + 'rpx',
- backgroundPositionY: (-cropBoxY - 4) + 'rpx',
- borderRadius: cropShape == 'rect' ? '' : '50%'
- }">
- <!-- 裁剪小组件 -->
- <!-- <view v-if="cropShape == 'rect' && !isFixedSize" class="zoom-handle-rect" data-body="handle"></view> -->
- <!-- <view v-if="cropShape == 'circular'" class="zoom-chandle-circular" data-body="handle"></view> -->
- </view>
- </view>
- <!-- <canvas class="canvas" canvas-id="canvas" id="canvas" :style="{width: canvasWidth + 'px', height: canvasHeight + 'px'}"></canvas> -->
- <view class="operation-area">
- <view class="crop-area">
- <u--image :src="cropImgPath" mode="widthFix" :customStyle="{ border: '2px solid #F3D4A3' }"
- shape="circle" width="100px" height="100px" @click="onPre"></u--image>
- </view>
- <view class="action">
- <!-- <view shape="circle" hover-class="none" class="btn" @click="cancel">取消</view> -->
- <view shape="circle" hover-class="none" class="btn full" @click="cropping(true)">继续</view>
- </view>
- </view>
- </view>
- </template>
- <script>
-
- let startX, startY;
- let boxX, boxY, boxWidth, boxHeight;
- let imageOriginalWidth, imageOriginalHeight;
- let imageZoomRatio;
- let windowInfo;
-
- export default {
- name: 'imageCropping',
- props: {
- src: {
- type: String,
- },
- ratioGroup: {
- type: Array,
- default() {
- return []
- }
- },
- isFixedSize: {
- type: Boolean,
- default: false
- },
- cropShape: {
- type: String,
- default: 'circular' // 'rect' , 'circular'
- }
- },
- data() {
- return {
- imageBoxWidth: 0,
- imageBoxHeight: 0,
- cropBoxX: 0,
- cropBoxY: 0,
- cropBoxWidth: 0,
- cropBoxHeight: 0,
- // move: 移动 , zoom: 缩放
- mode: '',
- cropSize: 100,
- cropImgPath: ''
- }
- },
- mounted() {
- this.getImageInfo();
- },
-
- methods: {
- // 获取图片尺寸
- getImageInfo() {
- windowInfo = uni.getWindowInfo();
- if (this.src) {
- uni.getImageInfo({
- src: this.src,
- success: (res) => {
- console.log("图片尺寸信息", res);
- console.log("当前屏幕尺寸", windowInfo);
- imageOriginalWidth = (res.width)/* 300 */;
- imageOriginalHeight = (res.height)/* 300 */;
- let widthZoomRatio = imageOriginalWidth / windowInfo.windowWidth;
- let heightZoomRatio = imageOriginalHeight / windowInfo.windowHeight;
- imageZoomRatio = widthZoomRatio > heightZoomRatio ? widthZoomRatio : heightZoomRatio;
- this.imageBoxWidth = (imageOriginalWidth / imageZoomRatio);
- this.imageBoxHeight = (imageOriginalHeight / imageZoomRatio);
- console.log("this.imageBoxWidth", this.imageBoxWidth);
- console.log("this.imageBoxHeight", this.imageBoxHeight);
- this.setRatio('1:1');
- },
- fail: (error) => {
- console.log("error", error);
- }
- })
- }
-
- },
- touchstart(event) {
- startX = event.touches[0].clientX;
- startY = event.touches[0].clientY;
-
- if (event.target.dataset.body == "handle") {
- this.mode = 'zoom';
- boxWidth = this.cropBoxWidth;
- boxHeight = this.cropBoxHeight;
- } else {
- this.mode = 'move';
- boxX = this.cropBoxX;
- boxY = this.cropBoxY;
- }
- },
- touchmove(event) {
- let distanceX = event.touches[0].clientX - startX;
- let distanceY = event.touches[0].clientY - startY;
-
- let x = boxX + distanceX;
- let y = boxY + distanceY;
- let width = boxWidth + distanceX;
- let height = boxHeight + distanceY;
-
- let maxX = this.imageBoxWidth - this.cropBoxWidth;
- let maxY = this.imageBoxHeight - this.cropBoxHeight;
- let maxWidth = this.imageBoxWidth - this.cropBoxX;
- let maxHeight = this.imageBoxHeight - this.cropBoxY;
-
- switch (this.mode) {
- case 'move':
- this.cropBoxX = x < 0 ? 0 : (x > maxX ? maxX : x);
- this.cropBoxY = y < 0 ? 0 : (y > maxY ? maxY : y);
- break;
- case 'zoom':
- if (this.cropShape == 'rect') {
- this.cropBoxWidth = width > maxWidth ? maxWidth : width;
- this.cropBoxHeight = height > maxHeight ? maxHeight : height;
- } else {
- this.cropBoxHeight = height > maxHeight ? maxHeight : height;
- this.cropBoxWidth = height > maxHeight ? maxHeight : height;
- }
- break;
- }
- },
- touchend() {
- setTimeout(() => {
- this.cropping(false);
- }, 500)
-
- },
- setRatio(ratio) {
- if (ratio === 'full') {
- this.cropBoxWidth = this.imageBoxWidth;
- this.cropBoxHeight = this.imageBoxHeight;
- this.cropBoxX = 0;
- this.cropBoxY = 0;
- } else {
- let x = ratio.split(':')[0];
- let y = ratio.split(':')[1];
- let r1 = (x / y);
- let r2 = (y / x);
-
- if (this.imageBoxWidth < this.imageBoxHeight) {
- console.log("1");
- let size = this.imageBoxWidth;
- if (size / r1 > this.imageBoxHeight) {
- size = this.imageBoxHeight;
- this.cropBoxWidth = ((size / r2) - this.cropSize) / 2;
- this.cropBoxHeight = (size - this.cropSize) / 2;
- this.cropBoxX = this.cropSize / 2;
- this.cropBoxY = (this.imageBoxWidth - this.imageBoxWidth) / 2;
- } else {
- this.cropBoxWidth = (size - this.cropSize) / 2;
- this.cropBoxHeight = ((size / r1) - this.cropSize) / 2;
- this.cropBoxX = this.cropSize / 2;
- this.cropBoxY = (this.imageBoxHeight - this.cropBoxHeight) / 2;
- }
- } else {
- console.log("2");
- let size = this.imageBoxHeight;
- if (size / r1 > this.imageBoxWidth) {
- size = this.imageBoxWidth;
- this.cropBoxWidth = (size - this.cropSize) / 2;
- this.cropBoxHeight = ((size / r2) - this.cropSize);
- this.cropBoxX = ((this.imageBoxWidth - this.cropBoxWidth)) / 2;
- this.cropBoxY = ((this.imageBoxHeight - this.cropBoxHeight)) / 2;
- } else {
- this.cropBoxWidth = ((size / r1) - this.cropSize) / 2;
- this.cropBoxHeight = (size - this.cropSize) / 2;
- this.cropBoxX = ((this.imageBoxWidth - this.cropBoxWidth)) / 2;
- this.cropBoxY = ((this.imageBoxWidth - this.cropBoxWidth)) / 2;
- }
- }
- }
-
- },
- async cropping(state) {
- let that = this;
- let x = this.cropBoxX * imageZoomRatio;
- let y = this.cropBoxY * imageZoomRatio;
- let w = this.cropBoxWidth * imageZoomRatio;
- let h = this.cropBoxHeight * imageZoomRatio;
- // 方式2:
- const canvas = uni.createOffscreenCanvas({ type: '2d', width: w, height: h });
- const context = canvas.getContext('2d');
- context.fillStyle = '#fff'; // 设置绘制后的填充颜色
- context.globalCompositeOperation = 'source-over';
- const image = canvas.createImage();
- await new Promise((resolve, reject) => {
- image.onload = resolve
- image.onerror = reject
- image.src = this.src;
- })
- context.clearRect(0, 0, w, h);
- if (this.cropShape == 'circular') {
- context.beginPath();
- context.arc(w / 2, h / 2, w / 2, 0, Math.PI * 2);
- context.fill();
- context.clip();
- context.clip();
- }
- context.drawImage(image, x, y, w, h, 0, 0, w, h);
-
- const DataURL = canvas.toDataURL();
-
-
- const fs = wx.getFileSystemManager();
- let tempFilePath = `${wx.env.USER_DATA_PATH}/` + new Date().getTime() + '.jpg'
- fs.writeFile({
- filePath: tempFilePath,
- data: DataURL.replace('data:image/png;base64,', ''),
- encoding: 'base64',
- success: res => {
- that.$emit('completed', {
- tempFilePath
- });
- that.cropImgPath = tempFilePath;
- },
- fail(res) {
- console.error(res)
- }
- })
- setTimeout(() => {
- if (state) {
- // TODO 对接接口
- /* let image = await this.$api.upload(
- that.$util.tempUrlToUpload(that.cropImgPath, `${that.$util.formateDate('yyyy-mm-dd-HH:MM:SS')}_result.jpg`,)
- );
- let imgUrl = image.data.fileUrl;
- console.log("imgUrl", imgUrl); */
- that.$store.commit('setResultPath', that.cropImgPath);
- uni.navigateTo({
- url: '/pages/details/index',
- })
- }
- }, 800)
-
-
- // 方式一:
- // const context = uni.createCanvasContext('canvas', this)
- // context.drawImage(this.src,x,y,w,h,0, 0, w, h)
- // context.draw(false, ()=>{
- // console.log(123);
- // uni.canvasToTempFilePath({
- // canvas: context,
- // success: function(res) {
- // console.log(res)
- // },
- // complete: function(res){
- // console.log(res)
- // }
- // },this)
- // })
-
- },
- yuantu() {
- this.$emit('completed', {
- tempFilePath: this.src
- })
- },
- cancel() {
- this.$emit('cancel')
- },
- onPre() {
- if (!this.cropImgPath) return;
- uni.previewImage({
- urls: [this.cropImgPath]
- })
- }
- }
- }
-
- </script>
- <style lang="scss" scoped>
- .container {
- width: 100vw;
- height: 100vh;
- overflow: scroll;
- /* position: fixed;
- left: 0;
- bottom: 400rpx; */
- z-index: 99;
- display: flex;
- align-items: center;
- justify-content: center;
- background-color: #fff;
- flex-direction: column;
-
- .image-box {
- position: fixed;
- left: 25%;
- bottom: 400rpx;
- background-size: contain;
- background-repeat: no-repeat;
- // filter: invert(1);
- z-index: 999;
- background-color: #fff;
-
- .mask {
- width: 100%;
- height: 100%;
- position: absolute;
- left: 0;
- top: 0;
- background-color: rgba(0, 0, 0, 0.3);
- z-index: 99;
- }
-
- .cropping-box {
- position: absolute;
- border: 6rpx solid #F3D4A3;
- box-sizing: border-box;
- background-repeat: no-repeat;
- z-index: 9999;
-
- // .zoom-handle-rect,
- // .zoom-chandle-circular{
- // width: 10px;
- // height: 10px;
- // background-color: springgreen;
- // border-radius: 50%;
- // position: absolute;
- // right: -6px;
- // bottom: -6px;
- // }
- /* .zoom-chandle-circular{
- right: 50%;
- transform: translateX(5px);
- } */
-
- }
- }
- }
-
- .operation-area {
- position: absolute;
- left: 0;
- bottom: 20rpx;
- z-index: 99999;
- width: 100%;
- padding: 10rpx 0;
- display: flex;
- flex-direction: column;
- align-items: flex-start;
- justify-content: center;
- overflow: scroll;
- padding-bottom: env(safe-area-inset-bottom);
-
- .crop-area {
- width: 100%;
- display: flex;
- justify-content: center;
- align-items: center;
- }
-
- .ratio-area {
- display: flex;
- align-items: center;
- justify-content: center;
- margin-bottom: 16rpx;
-
- .ratio-btn {
- display: inline-block;
- padding: 8rpx 20rpx;
- border: 2rpx solid white;
- color: white;
- margin: 0 10rpx;
- font-size: 12px;
- }
- }
-
- .bottom {
- height: 120rpx;
- width: 100%;
- display: flex;
- align-items: center;
- justify-content: center;
-
- button {
- display: inline-block;
- margin: 0 20rpx;
- }
- }
-
- .action {
- height: 120rpx;
- width: 100vw;
- position: relative;
- /* bottom: 60rpx;
- left: 0; */
- display: flex;
- justify-content: center;
- align-items: center;
- background: none;
- z-index: 99999;
-
- .btn {
- height: 70rpx;
- line-height: 70rpx;
- width: 80vw;
- border: 4rpx solid #333;
- text-align: center;
- border-radius: 60rpx;
- font-family: OPPOSans;
- font-weight: bold;
- font-size: 32rpx;
- color: #333;
-
- &.full {
- background-color: #333;
- color: #F3D4A3;
- margin-left: 30rpx;
- font-weight: bold;
- }
- }
-
-
- }
-
- }
-
- .canvas {
- position: absolute;
- bottom: 0;
- left: 0;
- z-index: 1;
- border: 1px solid;
- // display: none;
- }
- </style>
|