You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
204 lines
6.1 KiB
204 lines
6.1 KiB
const app = getApp(); |
|
/** |
|
* >=min && <=max |
|
* @param min |
|
* @param max |
|
*/ |
|
function getRandom(min, max) { |
|
return min + Math.floor(Math.random() * (max - min + 1)); |
|
} |
|
Component({ |
|
options: {}, |
|
lifetimes: { |
|
attached() { |
|
const query = wx.createSelectorQuery().in(this); |
|
query |
|
.select("#thumsCanvas") |
|
.fields({ node: true, size: true }) |
|
.exec((res) => { |
|
const canvas = res[0].node; |
|
const context = canvas.getContext("2d"); |
|
this.setData({ |
|
context: context, |
|
}); |
|
|
|
const dpr = wx.getSystemInfoSync().pixelRatio; |
|
canvas.width = res[0].width * dpr; |
|
canvas.height = res[0].height * dpr; |
|
this.data.width = res[0].width * dpr; |
|
this.data.height = res[0].height * dpr; |
|
// context.fillStyle = "rgba(255, 255, 255, 0)"; |
|
const images = [ |
|
"star/icon1.png?r=1", |
|
"star/icon2.png?r=1", |
|
"star/icon3.png?r=1", |
|
"star/icon4.png?r=1", |
|
"star/icon5.png?r=1", |
|
"star/icon6.png?r=1", |
|
"star/icon7.png?r=1", |
|
"star/icon8.png?r=1", |
|
]; |
|
const promiseAll = [] as Array<Promise<any>>; |
|
images.forEach((src) => { |
|
const p = new Promise(function (resolve) { |
|
const img = canvas.createImage(); |
|
img.onerror = img.onload = resolve.bind(null, img); |
|
img.src = app.globalData.imageUrl + src; |
|
}); |
|
promiseAll.push(p); |
|
}); |
|
Promise.all(promiseAll).then((imgsList) => { |
|
const imgsLists = imgsList.filter((d) => { |
|
if (d && d.width > 0) return true; |
|
return false; |
|
}); |
|
this.setData({ |
|
imgsList: imgsLists, |
|
}); |
|
if (this.data.imgsList.length == 0) { |
|
// logger.error("imgsList load all error"); |
|
wx.showToast({ |
|
icon: "none", |
|
title: "imgsList load all error", |
|
}); |
|
return; |
|
} |
|
}); |
|
}); |
|
}, |
|
}, |
|
properties: {}, |
|
data: { |
|
imgsList: [] as WechatMiniprogram.ImageData[], |
|
width: 0, |
|
height: 0, |
|
context: null as any, |
|
scanning: false, |
|
renderList: [], |
|
scaleTime: 0.1, // 百分比 |
|
}, |
|
methods: { |
|
handleTap() { |
|
this.start(); |
|
}, |
|
createRender() { |
|
if (this.data.imgsList.length == 0) return null; |
|
const basicScale = [0.4, 0.5, 0.6][getRandom(0, 2)]; |
|
|
|
const getScale = (diffTime) => { |
|
if (diffTime < this.data.scaleTime) { |
|
return +(diffTime / this.data.scaleTime).toFixed(2) * basicScale; |
|
} else { |
|
return basicScale; |
|
} |
|
}; |
|
const context = this.data.context; |
|
// 随机读取一个图片来渲染 |
|
const image: any = this.data.imgsList[getRandom(0, this.data.imgsList.length - 1)]; |
|
const offset = 20; |
|
const basicX = this.data.width / 2 + getRandom(-offset, offset); |
|
const angle = getRandom(2, 10); |
|
let ratio = getRandom(10, 30) * (getRandom(0, 1) ? 1 : -1); |
|
const getTranslateX = (diffTime) => { |
|
if (diffTime < this.data.scaleTime) { |
|
// 放大期间,不进行摇摆位移 |
|
return basicX; |
|
} else { |
|
return basicX + ratio * Math.sin(angle * (diffTime - this.data.scaleTime)); |
|
} |
|
}; |
|
|
|
const getTranslateY = (diffTime) => { |
|
return image.height / 2 + (this.data.height - image.height / 2) * (1 - diffTime); |
|
}; |
|
|
|
const fadeOutStage = getRandom(14, 18) / 100; |
|
const getAlpha = (diffTime) => { |
|
let left = 1 - +diffTime; |
|
if (left > fadeOutStage) { |
|
return 1; |
|
} else { |
|
return 1 - +((fadeOutStage - left) / fadeOutStage).toFixed(2); |
|
} |
|
}; |
|
|
|
return (diffTime) => { |
|
// 差值满了,即结束了 0 ---》 1 |
|
if (diffTime >= 1) return true; |
|
context.save(); |
|
const scale = getScale(diffTime); |
|
// const rotate = getRotate(); |
|
const translateX = getTranslateX(diffTime); |
|
const translateY = getTranslateY(diffTime); |
|
context.translate(translateX, translateY); |
|
context.scale(scale, scale); |
|
// context.rotate(rotate * Math.PI / 180); |
|
context.globalAlpha = getAlpha(diffTime); |
|
context.drawImage(image, -image.width / 2, -image.height / 2, image.width, image.height); |
|
context.restore(); |
|
}; |
|
}, |
|
scan() { |
|
this.data.context.clearRect(0, 0, this.data.width, this.data.height); |
|
this.data.context.fillStyle = "rgba(255, 255, 255, 0)"; |
|
this.data.context.fillRect(0, 0, 200, 400); |
|
let index = 0; |
|
let length = this.data.renderList.length; |
|
if (length > 0) { |
|
this.requestFrame(this.scan.bind(this)); |
|
this.setData({ |
|
scanning: true, |
|
}); |
|
} else { |
|
this.setData({ |
|
scanning: false, |
|
}); |
|
} |
|
while (index < length) { |
|
const child = this.data.renderList[index]; |
|
if (!child || !child.render || child.render.call(null, (Date.now() - child.timestamp) / child.duration)) { |
|
// 结束了,删除该动画 |
|
this.setData({ |
|
renderList: [...this.data.renderList].filter((_item, fIndex) => fIndex != index), |
|
}); |
|
length--; |
|
} else { |
|
// continue |
|
index++; |
|
} |
|
} |
|
}, |
|
start() { |
|
const render = this.createRender(); |
|
const duration = getRandom(1500, 3000); |
|
this.setData({ |
|
renderList: [ |
|
...this.data.renderList, |
|
{ |
|
render, |
|
duration, |
|
timestamp: Date.now(), |
|
}, |
|
], |
|
}); |
|
|
|
if (!this.data.scanning) { |
|
this.setData({ |
|
scanning: true, |
|
}); |
|
|
|
this.requestFrame(this.scan.bind(this)); |
|
// this.scan.bind(this)(); |
|
} |
|
return this; |
|
}, |
|
requestFrame(cb) { |
|
return ( |
|
this.data.context.requestAnimationFrame || |
|
(function (callback) { |
|
setTimeout(callback, 1000 / 60); |
|
})(cb) |
|
); |
|
}, |
|
}, |
|
});
|
|
|