a***@163.com
a***@163.com
  • 发布:2022-06-08 10:24
  • 更新:2022-12-17 16:14
  • 阅读:1330

图片在容器下自由缩放旋转拖动Demo

分类:uni-app

先实现如下效果,图片可自由缩放旋转删除移动。通过两个点控制。


实现效果Demo如下:

这是Demo代码,可直接复制到项目中运行看效果。
支持小程序、APP。
一开始考虑使用的movable-area+movable-view。但因为需要先禁用移动,当点击的是右下角旋转按钮时才允许移动,所以需要在touchstart里面disabled改为false,然后再touchend中再次修改为禁止移动。
但movable-view不支持在touchstart中修改disabled立刻生效,只能在下次点击时生效,所以使用view+css实现。

<template>  
    <view class="page-body">  
        <view class="move-area">  
            <view v-if="!isHide" class="move-box" style="transform-origin:center;"  
                @touchmove="itemMove" @touchstart="itemtouch" @touchend="itemend"   
                :style="{transform: 'translate(' + itemX + 'px, ' + itemY +'px) rotate('+tmpRotate+'deg) scale('+tmpScale+')'}">  
                <view class="opt-icon del-icon" :style="{transform: 'scale(' + (1 / tmpScale) + ')'}" @touchstart="startMode(2)"></view>  
                <view class="opt-icon edit-icon" :style="{transform: 'scale(' + (1 / tmpScale) + ')'}" @touchstart="startMode(1)"></view>  
                <view class="move-body" @touchstart="startMode(0)">这是内容</view>  
            </view>  
        </view>  
    </view>  
</template>  

<script>  
    const nearDg = 7; // 用于控制当近似垂直或水平时,视为垂直或水平的容差。  
    let lastX = 0, lastY = 0;  
    export default {  
        data() {  
            return {  
                itemX: 0,  
                itemY: 0,  
                realCenterX: 0,  
                realCenterY: 0,  
                halfWidth: 75, // px  
                halfHeight: 75, // px  
                realWidth: 0,  
                realHeight: 0,  
                offset: 12.5, // px  
                touchMode: 0, // 0移动 1缩放旋转  2删除  
                startX: 0,  
                startY: 0,  
                startAngle: 0,  
                startDist: 0,  
                tmpRotate: 0,  
                initRotate: 0,  
                tmpScale: 1,  
                initScale: 1,  
                isHide: false,  
            }  
        },  
        onLoad:function(){  
            this.itemX = 70;  
            this.itemY = 100;  
        },  
        mounted:function(){  
            let view = uni.createSelectorQuery().in(this).select(".move-box");  
            view.boundingClientRect(data => {  
                this.realWidth = data.width;  
                this.realHeight = data.height;  
                this.realCenterX = data.right - data.width / 2;  
                this.realCenterY = data.bottom - data.height / 2;  
            }).exec();  
        },  
        methods: {  
            itemMove: function(e){  
                let curX = e.touches[0].clientX;  
                let curY = e.touches[0].clientY;  
                if(this.touchMode === 0){  
                    this.itemX += curX - lastX;  
                    this.itemY += curY - lastY;  
                    this.realCenterX += curX - lastX;  
                    this.realCenterY += curY - lastY;  
                    lastX = curX;  
                    lastY = curY;  
                }  
                if(this.touchMode !== 1)return;  
                let angle = this.angle(this.realCenterX, this.realCenterY, curX, curY);  
                if(this.startAngle === 0){  
                    this.startX = curX;  
                    this.startY = curY;  
                    this.startAngle = angle;  
                    this.startDist = Math.hypot(this.startX - this.realCenterX, this.startY - this.realCenterY);  
                }  
                else{  
                    let rotate = this.initRotate + Math.round(angle - this.startAngle);  
                    let leftDg = Math.abs(rotate % 90);  
                    if(leftDg < nearDg || 90 - leftDg < nearDg){  
                        rotate = Math.round(rotate / 90) * 90;  
                    }  
                    this.tmpRotate = rotate;  
                    let curDist = Math.hypot(curX - this.realCenterX, curY - this.realCenterY);  
                    this.tmpScale = this.initScale * curDist / this.startDist;  
                }  
            },  
            itemtouch: function(e){  
                lastX = e.touches[0].clientX;  
                lastY = e.touches[0].clientY;  
            },  
            itemend: function(e){  
                this.startAngle = 0;  
                this.initRotate = this.tmpRotate;  
                this.initScale = this.tmpScale;  
            },  
            startMode: function(mode){  
                this.touchMode = mode;  
                if(this.touchMode === 2){  
                    this.isHide = true;  
                }  
            },  
            angle: function(cx, cy, ex, ey){  
                var dy = ey - cy;  
                var dx = ex - cx;  
                var theta = Math.atan2(dy, dx); // range (-PI, PI]  
                theta *= 180 / Math.PI; // rads to degs, range (-180, 180]  
                if (theta < 0) theta = 360 + theta; // range [0, 360)  
                return theta;  
            }  
        }  
    }  
</script>  

<style lang="scss">  
.page-body{  
    padding: 5px;  
}  
.move-area{  
    width: 365px;  
    height: 500px;  
}  
.move-box{  
    position: relative;  
    width: 175px;  
    height: 175px;  
    padding: 1px;  
}  
.opt-icon{  
    position: absolute;  
    width: 25px;  
    height: 25px;  
    border-radius: 50%;  
}  
.del-icon{  
    background-color: red;  
    left: 0;  
    top: 0;  
}  
.edit-icon{  
    background-color: green;  
    right: 0;  
    bottom: 0;  
}  
.move-body{  
    margin: 12.5px;  
    width: 150px;  
    height: 150px;  
    border: 2px solid green;  
}  
</style>
3 关注 分享
1***@qq.com 一抱一个胖猪猪 2***@qq.com

要回复文章请先登录注册

YDH

YDH

你好,多张图片的案例有吗,我使用你的demo引入多张图片缩放不生效了
2022-12-17 16:14
a***@163.com

a***@163.com (作者)

回复 1***@qq.com :
tmpScale 就是显示的缩放值。在tmpScale 赋值的地方给个最小值就行。比如最小0.3:Math.max(0.3, ...)
2022-07-05 20:31
1***@qq.com

1***@qq.com

如何设置最小缩放值
2022-06-29 19:13