小程序实现手势地图缩放平移,屏幕中心不动
看了很多的图像手势缩放方式,发现都不是根据屏幕中心位置,大多是图片中心位置不动或者图片左上角位置不动。
所以想实现图像屏幕中心的点不动来进行缩放。
之前有用过通过设置 scrollTop和scrollLeft来实现图像移动到固定位置,但是效果和稳定性不好。
以下通过style里的translate设置图像偏移和大小来实现地图缩放平移
项目中还加了字体随缩放选择显示,这里不放代码了
直接上代码
JS部分:
Page({
data:{
backUrl:'../../images/-1F.png', //地图
desUrl:"../../images/icon.png", //目标位置
touch: {
offsetX: 0,
offsetY: 0,
zoom: false, //是否缩放状态
distance: 0, //两指距离
scale: 1, //缩放倍数
},
mydata:{
des:{
left:0.2,
top:0.4
}
}
},
//目标点跳转屏幕中心
mydes(){
var that=this
var left=this.data.mydata.des.left
var top=this.data.mydata.des.top
var touch=this.data.touch
// 目前滑动的位置
var scroll_h=this.data.scrollHeight
var scroll_w=this.data.scrollWidth
/**
* 0.5*(scroll_w-touch.baseWidth) 滑动的位置到图片中心的距离
* (left-0.5)*touch.baseWidth*touch.scale 目标点到图片中心的距离
* 0.5*touch.baseWidth 图片中心
* left*touch*baseWidth 目标点在图片位置
*/
that.setData({
'touch.offsetX':0.5*(scroll_w-touch.baseWidth)-(left-0.5)*touch.baseWidth*touch.scale,
'touch.offsetY':0.5*(scroll_h-touch.baseHeight)-(top-0.5)*touch.baseHeight*touch.scale,
})
},
//事件处理函数
touchstartCallback: function(e) {
//触摸开始
console.log('touchstartCallback');
console.log(e);
if (e.touches.length === 1) {
let {clientX, clientY} = e.touches[0];
this.startX = clientX;
this.startY = clientY;
this.touchStartEvent = e.touches;
} else {
let xMove = e.touches[1].clientX - e.touches[0].clientX;
let yMove = e.touches[1].clientY - e.touches[0].clientY;
let distance = Math.sqrt(xMove * xMove + yMove * yMove);
this.setData({
'touch.distance': distance,
'touch.zoom': true, //缩放状态
})
}
},
touchmoveCallback: function(e) {
//触摸移动中
//console.log('touchmoveCallback');
//console.log(e);
if (e.touches.length === 1) {
//单指移动
if (this.data.touch.zoom) {
//缩放状态,不处理单指
return ;
}
let {clientX, clientY} = e.touches[0];
let offsetX = clientX - this.startX;
let offsetY = clientY- this.startY;
this.startX = clientX;
this.startY = clientY;
let touch = this.data.touch;
touch.offsetX += offsetX;
touch.offsetY += offsetY;
touch.offsetLeftX = -touch.offsetX;
touch.offsetLeftY = -touch.offsetLeftY;
this.setData({
touch: touch
});
} else {
//双指缩放
let xMove = e.touches[1].clientX - e.touches[0].clientX;
let yMove = e.touches[1].clientY - e.touches[0].clientY;
let distance = Math.sqrt(xMove * xMove + yMove * yMove);
var that = this
var scroll_h=this.data.scrollHeight
var scroll_w=this.data.scrollWidth
let touch = this.data.touch
let distanceDiff = distance - this.data.touch.distance;
let newScale = this.data.touch.scale + 0.005 * distanceDiff;
let c_w = 0.5*(scroll_w-touch.baseWidth) //缩放的偏移距离
let c_h = 0.5*(scroll_h-touch.baseHeight)
if (newScale >= 2) {
newScale = 2
}
if (newScale <= 0.2) {
newScale = 0.2
}
console.log("scale"+newScale)
// 生成新的偏移量
let offsetX = (touch.offsetX-c_w)*newScale/touch.scale+c_w
let offsetY = (touch.offsetY-c_h)*newScale/touch.scale+c_h
that.setData({
'touch.distance': distance,
'touch.scale': newScale,
'touch.offsetX':offsetX,
'touch.offsetY':offsetY
})
}
},
touchendCallback: function(e) {
//触摸结束
//console.log('touchendCallback');
//console.log(e);
if (e.touches.length === 0) {
this.setData({
'touch.zoom': false, //重置缩放状态
})
}
},
load: function (e) {
// bindload 这个api是<image>组件的api类似<img>的onload属性
var that =this
var scroll_h=this.data.scrollHeight
var scroll_w=this.data.scrollWidth
var width = e.detail.width
var height = e.detail.height
var scale = scroll_w/width
var iconscale
if(scale>0.5){
iconscale=1/scale
}else{
iconscale=0.5/scale
}
that.setData({
'touch.baseWidth': width,
'touch.baseHeight': height,
'touch.offsetX':0.5*(scroll_w-width),
'touch.offsetY':0.5*(scroll_h-height),
'touch.scale':scale,
"touch.iconscale":iconscale,
show:true
});
//加载图像就把目标点居中
//this.mydes()
},
//点击放大
imgUp(){
var that = this
//console.log("up")
var scroll_h=this.data.scrollHeight
var scroll_w=this.data.scrollWidth
let touch = this.data.touch
let newScale = touch.scale+0.2
let c_w = 0.5*(scroll_w-touch.baseWidth)
let c_h = 0.5*(scroll_h-touch.baseHeight)
//console.log(newScale)
if (newScale >= 2) {
newScale = 2
}
if (newScale <= 0.2) {
newScale = 0.2
}
let offsetX = (touch.offsetX-c_w)*newScale/touch.scale+c_w
let offsetY = (touch.offsetY-c_h)*newScale/touch.scale+c_h
// 赋值 新的 => 旧的
that.setData({
'touch.scale': newScale,
'touch.offsetX':offsetX,
'touch.offsetY':offsetY
})
},
//点击缩小
imgDn(){
var that = this
var scroll_h=this.data.scrollHeight
var scroll_w=this.data.scrollWidth
let touch = this.data.touch
let newScale = touch.scale-0.2
let c_w = 0.5*(scroll_w-touch.baseWidth)
let c_h = 0.5*(scroll_h-touch.baseHeight)
if (newScale >= 2) {
newScale = 2
}
if (newScale <= 0.2) {
newScale = 0.2
}
let offsetX = (touch.offsetX-c_w)*newScale/touch.scale+c_w
let offsetY = (touch.offsetY-c_h)*newScale/touch.scale+c_h
// 赋值 新的 => 旧的
that.setData({
'touch.scale': newScale,
'touch.offsetX':offsetX,
'touch.offsetY':offsetY
})
},
onLoad(){
var that = this
//获取屏幕宽和高
wx.getSystemInfo({
success: function (res) {
that.setData({
scrollHeight: res.windowHeight,
scrollWidth:res.windowWidth
});
}
});
},
})
wxml部分:
<!--pages/test/test.wxml-->
<view class="container">
<view class="page-body" >
<view class="page-layer">
<view class ='touch' catchtouchstart="touchstartCallback" catchtouchmove="touchmoveCallback" catchtouchend="touchendCallback" style="width:100%;height: {{scrollHeight }}px">
<view class ='canvas' style="width: {{touch.baseWidth }}px;height: {{touch.baseHeight }}px;transform:translate({{touch.offsetX}}px,{{touch.offsetY}}px) scale({{touch.scale}})">
<view class='box' style='top:{{mydata.des.top*touch.baseHeight-10}}px;left:{{mydata.des.left*touch.baseWidth-7.5}}px;transform:scale({{1/touch.scale}})'>
<image class='icon' id='con' src='{{desUrl}}' mode="widthFix">
</image>
</view>
<image class='back' src='{{backUrl}}' mode="widthFix" bindload='load' style="width: {{ touch.baseWidth }}px;height: {{ touch.baseeHeight }}px">
</image>
</view>
</view>
</view>
<view class='page-scale'>
<view class='scale' bindtap="imgUp">+</view>
<view class='line'></view>
<view class='scale' bindtap="imgDn">-</view>
</view>
<view class="page-des">
<view class='btn' bindtap="mydes">
<view class='mydes'>我的位置</view>
</view>
</view>
</view>
</view>
CSS部分:
/* pages/test/test.wxss */
.container {
height: 100%;
width: 100%;
display: flex;
flex-direction: column;
box-sizing: border-box;
}
.page-body {
width: 100%;
overflow:hidden;
}
/*图片部分*/
.page-layer {
width: 100%;
overflow:hidden;
white-space:nowrap;
text-align: center;
}
.page-layer .touch{
position: relative;
}
.page-layer .touch .box{
position: relative;
width:15px;
}
.page-layer .touch .canvas{
display: inline-block
}
.page-layer .touch .canvas .box .icon{
width: 15px;
height: 15px;
}
/*目标锁定*/
.page-des{
text-align: center;
bottom: 10px;
left:5px;
width:30px;
position: fixed;
}
.page-des .btn{
display:inline-block;
background:rgb(14, 204, 233);
width: 40px;
height: 40px;
margin:10px auto;
border-radius: 40px;
}
.page-des .btn .mydes{
margin:5px 5px;
color: aliceblue;
font-size: 12px;
text-align: center;
line-height: 15px;
}
/*按键缩放*/
.page-scale{
text-align: center;
justify-content: center;
align-items: center;
top: 10px;
left:10px;
width:40px;
position: fixed;
background: white;
border:gray solid 0.5px;
display: inline-block;
}
.page-scale .scale{
height: 40px;
width: 40px;
justify-content: center;
align-items: center;
display: flex;
font-size: 25px;
}
.page-scale .line{
margin:auto 5px ;
height:2px;
background: gray;
}
至此一个地图预览缩放定位的基本功能即可实现 ,也可以改变代码通过手势做旋转的功能;