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>; 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) ); }, }, });