微信小程序canvas拖拽、截图组件功能

前端之家收集整理的这篇文章主要介绍了微信小程序canvas拖拽、截图组件功能前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

先看下微信小程序canvas拖拽功能

组件地址

近期补上

实现效果

如何实现

  1. 使用canvas
  2. 使用movable-view标签

由于movable-view无法实现旋转,所以选择使用canvas

需要解决的问题

  • 如何将多个元素渲染到canvas上
  • 如何知道手指在元素上、如果多个元素重叠如何知道哪个元素在最上层
  • 如何实现拖拽元素
  • 如何缩放、旋转、删除元素

看起来挺简单的嘛,就把上面这几个问题解决了,就可以实现功能了;接下来我们一一解决

如何将多个元素渲染到canvas上

定义一个DragGraph类,传入元素的各种属性(坐标、尺寸…)实例化后推入一个 渲染数组 里,然后再循环这个数组调用实例中的渲染方法,这样就可以把多个元素渲染到canvas上了。

如何知道手指在元素上、如果多个元素重叠如何知道哪个元素在最上层

在DragGraph类中定义了判断点击位置的方法,我们在canvas上绑定touchstart事件,将手指的坐标传入上面的方法,我们就可以知道手指是点击到元素本身,还是删除图标或者变换大小的图标上了,这个方法具体怎么判断后面会讲解。

通过循环 渲染数组 判断是非点击到哪个元素到,如果点击中了多个元素,也就是多个元素重叠,那第一个元素就是最上层的元素啦。

###如何实现拖拽元素

通过上面我们可以判断手指是否在元素上,当touchstart事件触发时我们记录当前的手指坐标,当touchmove事件触发时,我们也知道这时的坐标,两个坐标取差值,就可以得出元素位移的距离啦,修改这个元素实例的x和y,再重新循环渲染 渲染数组 就可以实现拖拽的功能

如何缩放、旋转、删除元素

这一步相对比较难一点,我会通过示意图跟大家讲解。

我们先讲缩放和旋转

通过touchstart和touchmove我们可以获得旋转前的旋转后的坐标,图中的线A为元素的中点和旋转前点的连线;线B为元素中点和旋转后点的连线;我们只需要求A和B两条线的夹角就可以知道元素旋转的角度。缩放尺寸为A和B两条线长度之差。

计算旋转角度的代码如下:

atan2(diffYBefore,diffXBefore) / Math.PI * 180; const angleAfter = Math.atan2(diffYAfter,diffXAfter) / Math.PI * 180; // 旋转的角度 this.rotate = currentGraph.rotate + angleAfter - angleBefore;

计算缩放尺寸的代码如下:

下面介绍下小程序canvas截图组件

最近做一个小程序的过程中,需要用到截图功能,网上搜了一下,发现没有符合要求的,就自己搞了个组件,方便复用。

目前功能很简单,传入宽高和图片路径即可,宽高是为了计算截图的比例,只支持缩放和移动。

实现思路是:

1.模拟一个截取框;

2.移动图片位置,缩放图片

3.获取图片在其中的位置(left,top,width,height);

4.使用canvas绘制图片,然后截取就ok了。

其中第二步的缩放图片比较麻烦,缩放中心点以及平滑缩放

以下是我的实现方式

wxml:

wxss:(其中引入了一个公共样式,关于flex布局的,看样式名也能猜到)

Box-shadow: 0 0 4px rgba(0,0.5) inset; } .inner_item{ width: 8px; height: 8px; } .inner_item.left_top{ border-left: 3px solid white; border-top: 3px solid white; left: -3px; top: -3px; } .inner_item.right_top{ border-right: 3px solid white; border-top: 3px solid white; right: -3px; top: -3px; } .inner_item.right_bottom{ border-right: 3px solid white; border-bottom: 3px solid white; right: -3px; bottom: -3px; } .inner_item.left_bottom{ border-left: 3px solid white; border-bottom: 3px solid white; left: -3px; bottom: -3px; } .img{ z-index: -1; } .bg_black{ background-color:black; z-index: -2; } .text_bg{ padding-bottom: 2em; font-size: 0.9em; } .img_canvas{ opacity: 0.5; } .newImg{ z-index: 2 }

js:

{ console.log('ccc') },this); },/** * 组件的初始数据 */ data: { touchRange: 8,img: { width: 0,canvas: {},ratio: 0,originImg: { width: 0,height: 0 } },/** * 组件的方法列表 */ methods: { touchstart(e) { // console.log("touchstart",e);

},touchmove(e) {
if (e.touches.length === 1) { this.singleSlip(e.touches[0]) } else {
this.doubleSlip(e.touches)
}
},touchend(e) {
// console.log("touchend",e);
const x = 0,y = 0;
state.touchLast = { x,y };
state.touchMove = { x,y };
state.touchList = [{ x,y },{ x,y }];
state.moveImgState = this.data.img;
// console.log(this.data.img);
},// 单手滑动操作
singleSlip(e) {
const { clientX: x,clientY: y } = e;
const that = this;
if (state.touchLast.x && state.touchLast.y) {
state.touchMove = { x: x - state.touchLast.x,y: y - state.touchLast.y };
state.touchLast = { x,y };
const move = (_x = false,_y = false) => {
const bottom = that.data.img.height + that.data.img.top;
const right = that.data.img.width + that.data.img.left;
const h = state.interArea.height;
const w = state.interArea.width;
const param = {};
if (_x) {
if (right > w && that.data.img.left < 0) {
param.left = that.data.img.left + state.touchMove.x 0.1
} else if (right <= w && state.touchMove.x > 0) {
param.left = that.data.img.left + state.touchMove.x
0.1
} else if (that.data.img.left >= 0 && state.touchMove.x < 0) {
param.left = that.data.img.left + state.touchMove.x 0.1
}
};
if (_y) {
if (bottom > h && that.data.img.top < 0) {
param.top = that.data.img.top + state.touchMove.y
0.1
} else if (bottom <= h && state.touchMove.y > 0) {
param.top = that.data.img.top + state.touchMove.y 0.1
} else if (that.data.img.top >= 0 && state.touchMove.y < 0) {
param.top = that.data.img.top + state.touchMove.y
0.1
}
};
// console.log(param);
that.setImgPos(param)
};
if (state.scale == 1) {
if (that.data.img.width == state.interArea.width) {
move(false,true)
} else {
move(true,false)
}
} else {
move(true,true)
}
} else {
state.touchLast = { x,y }
}
},// 双手缩放操作
doubleSlip(e) {
const that = this;
const { clientX: x0,clientY: y0 } = e[0];
const { clientX: x1,clientY: y1 } = e[1];
if (state.touchList[0].x && state.touchList[0].y) {
let changeScale = (Math.sqrt((x1 - x0) (x1 - x0) + (y1 - y0) (y1 - y0)) - Math.sqrt((state.touchList[1].x - state.touchList[0].x) (state.touchList[1].x - state.touchList[0].x) + (state.touchList[1].y - state.touchList[0].y) (state.touchList[1].y - state.touchList[0].y))) 0.0005;
changeScale = changeScale >= 1.5 ? 1.5 : (changeScale <= -1 ? -1 : changeScale);
state.scale = that.data.img.width / state.firstScaleImg.width < 1 ? 1 : (state.scale > 2.5 ? 2.5 : 1 + changeScale);
let width = state.firstScaleImg.width
(state.scale - 1) + state.moveImgState.width;
width = width < state.firstScaleImg.width ? state.firstScaleImg.width : width;
let height = state.firstScaleImg.height (state.scale - 1) + state.moveImgState.height;
height = height < state.firstScaleImg.height ? state.firstScaleImg.height : height;
let left = width
(1 - state.scale) / 4 + state.moveImgState.left;
left = left (-1) > width - state.interArea.width ? state.interArea.width - width: left > 0 ? 0 : left;
let top = height
(1 - state.scale) / 4 + state.moveImgState.top;
top = top (-1) > height - state.interArea.height ?state.interArea.height - height : top > 0 ? 0 : top;
const setImgObj = { width,height,left,top };
that.setImgPos(setImgObj)
} else {
state.touchList = [{ x: x0,y: y0 },{ x: x1,y: y1 }]
}
},// 获取可用区域宽高
getScreenInfo() {
const that = this;
return new Promise((resolve,reject) => {
wx.getSystemInfo({
success: function (res) {
const { windowHeight,windowWidth } = res;
state.window = { windowHeight,windowWidth };
that.setData({ windowHeight,windowWidth })
// console.log(state.window);
resolve(res);
},})
})
},setShowArea() {
const that = this;
const w = state.window.windowWidth - that.data.margin.left - that.data.margin.right;
const h = (that.data.height / that.data.width)
w;
},outputImg() {
this.setData({
hidden: true,})
},getImgInfo(path) {
return new Promise((resolve,reject) => {
wx.getImageInfo({
src: path,success(res) {
console.log(res);
resolve(res);
},fail(err) {
reject(err)
}
})
})
},// 设置图片
setImgPos({ width,top,left }) {
width = width || this.data.img.width;
height = height || this.data.img.height;
top = top || this.data.img.top;
left = left || this.data.img.left
this.setData({
img: { width,left }
})
},// 初始化图片位置大小
initialize() {
const that = this;
const ratio = that.data.width / that.data.height;
this.getScreenInfo().then(res => {
console.log(res);
state.interArea = { width: res.windowWidth - that.data.margin.left - that.data.margin.right + 2,height: (res.windowWidth - that.data.margin.left - that.data.margin.right) / ratio };
console.log("interArea",state.interArea)
that.getImgInfo(that.data.src).then(imgInfo => {
const { width,height } = imgInfo;
const imgRatio = width / height;
state.originImg = { width,height };
that.setData({
ratio: ratio
});
if (imgRatio > ratio) {
that.setImgPos({
height: state.interArea.height,width: state.interArea.height * imgRatio
})
} else {
that.setImgPos({
height: state.interArea.width / imgRatio,width: state.interArea.width,})
};
state.firstScaleImg = { width: that.data.img.width,height: that.data.img.height }
});
});
},// 截图
getImg(){
const that = this;
// console.log('dudu',that.data.img);
const canvas = wx.createCanvasContext('imgCanvas',this);
const {width,top} = that.data.img;
const saveImg = ()=>{
console.log('开始截取图片');
wx.canvasToTempFilePath({
canvasId:"imgCanvas",success(res){
// console.log(res);
that.setData({
hidden:true,// src:""
});
that.triggerEvent("putimg",{ imgUrl: res.tempFilePath},{});
},fail(err){
console.log(err)
}
},that)
};
canvas.drawImage(that.data.src,width,height);
canvas.draw(false,() => { saveImg() },that)
}
}
})

引用的时候除了宽高路径以外,需要wx:if;如果不卸载组件,会出现只能截一次的bug

因为小程序里面没有类似vue中catch的观测数据变化的东西,也不想为了个组件专门去搞一个,就用这种方式代替了,嘻嘻,好敷衍。。

总结

以上所述是小编给大家介绍的微信小程序canvas拖拽、截图组件功能。编程之家 jb51.cc 收集整理的教程希望能对你有所帮助,如果觉得编程之家不错,可分享给好友!感谢支持

猜你在找的微信小程序相关文章