
回复
添加资源
添加资源将有机会获得更多曝光,你也可以直接关联已上传资源 去关联
作者:杨尚晓
之前在web中实现过该功能,想着直接搬过来修改一下,也能在OpenHarmony上跑起来。其实360度全景展示功能的用途还是挺多的,比如一些购物平台用于全面展示一件商品,这样可以更全面直观的了解这件商品;还有一些售楼平台,可以去展示一些全景户型等等。
基于canvas画布,通过绘制一个360°的序列帧图片实现的。 通过监听手势滑动来实现图片帧切换。
touchstart
和touchmove
<div class="container">
<div class="tt" id="tt"></div>
<canvas
id="canvas"
ref="canvas"
@touchstart="touchStart"
@touchmove="touchMove"
></canvas>
</div>
因为是通过图片序列帧实现的,所以需要预加载完成所有序列帧图片才能进行后续操作,否则会出现在切换图片的时候还没加载出来导致空白问题。
下面封装了一个imgLoad方法来处理所有图片预加载
/**
* @param {Array} imgList 需要预加载图片的数组
* @param {Function} progressCb 加载进度回调方法
* @param {Function} completeCb 全部加载完成回调
*/
const imgLoad = (imgList = [], progressCb, completeCb) => {
let len = imgList.length;
let num = 0;
let progress = 0;
var loadImage = function (src) {
return new Promise(function (resolve, reject) {
let img = new Image();
img.onload = function () {
resolve(img); //加载时执行resolve函数
};
img.onerror = function () {
reject('地址错误:' + src); //抛出异常时执行reject函数
};
img.src = src;
});
};
function* fn() {
for (let i = 0; i < len; i++) {
yield loadImage(imgList[i]);
}
}
let g = fn();
let value = g.next().value;
resume();
function resume() {
console.log('====')
value.then((img) => {
// 单张加载完成
num++;
progress = parseFloat((100 / len) * num).toFixed(2);
progressCb && progressCb(img, progress);
value = g.next().value;
if (value) {
resume();
} else {
// 全部加载完成
completeCb && completeCb();
}
}).catch((err)=>{
console.log(err)
});
}
}
上面方法有两个回调
这里有一个比较少见的函数,fn* :生成器函数(generator function)。
yield
关键字可以暂停函数initCanvas(){
let c = this.$refs.canvas;
this.ctx = c.getContext('2d');
let arr = [];
for(var i = 1; i <= this.imgLen; i++){
arr.push(`common/images/car/${i}.png`)
}
imgLoad(arr,(img, progress) => {
lg.log('进度:' + progress);
this.imgList.push(img);
},() => {
lg.log('全部加载完成')
this.cutSpirit();
})
},
touchStart方法监听触摸开始时手势,缓存当前触摸位置的x轴数据作为开始数据
touchMove方法是监听滑动中的手势监听
360/(64 * 2)
,就是从x轴为0到屏幕最右边可以完成2次序列帧旋转。分子越大,滑动越快。touchStart(e){
let s = e.touches[0].localX;
this.startPoint = s;
// lg.log('触摸开始:',s);
},
touchMove(e){
let s = e.touches[0].localX;
if((s - this.startPoint) > this.unit){
this.drawImg(this.imgIndex, 'right')
this.startPoint = s;
lg.log('向右:',s)
} else if((s - this.startPoint) < -this.unit){
this.drawImg(this.imgIndex, 'left')
this.startPoint = s;
lg.log('向左:',s)
}
this.startPoint = s;
},
/**
* @param {Number} n 当前绘制的序列帧下标
* @param {String} type 当前手指滑动的方向
*/
drawImg(n,type){
if(type == "right"){
if(this.imgIndex > 0){
this.imgIndex--;
}else{
this.imgIndex = this.imgLen;
}
}else if(type == "left"){
if(this.imgIndex < this.imgLen){
this.imgIndex++;
}else{
this.imgIndex = this.startIndex;
}
}
this.ctx.clearRect(0,0,this.w,this.h);
this.ctx.drawImage(this.imgList[this.imgIndex],0,0,this.w,this.h);
},
https://gitee.com/yango520/ohos-panoramic
到这里就基本完成,主要的技术点在于预加载所有序列帧图片和监听手势来绘制序列帧的。
入门到精通、技巧到案例,系统化分享HarmonyOS开发技术,欢迎投稿和订阅,让我们一起携手前行共建鸿蒙生态。