反饋已提交
網絡繁忙
有时候需要在决策报表集成一些特效,如下图,集成一个时间烟花效果。
通过 HTIML 和 JS 可以实现时间获取以及添加粒子烟花效果。
新建决策报表,添加一个报表块,在报表单元格中输入 HTML 代码,单元格显示方式选择「用 HTML 显示内容」,如下图所示:
HTML 代码如下:
<canvas id="canvas" height="800" width="1200"></canvas>
点击报表块,为报表块添加「初始化后」事件。如下图所示:
JavaScript 代码如下:
setTimeout(function(){let dt = 0.1;//每帧表示的时间间隔//球体class Ball{ constructor(x,y,r,id){ this.pos = new Vector2(x,y);//记录当前坐标 this.id = id; this.color = ''; this.r = r; this.velocity = null; this.life = true; } //更新粒子坐标 update(){ //重力加速度影响速度 this.velocity = this.velocity.add(g.multiply(dt)); //速度影响位移 this.pos = this.pos.add(this.velocity.multiply(dt)); //如果粒子已经出界则标记生命耗尽 if(this.pos.y > 280){ this.life = false; } } paint(){ if(!this.life)return; context.beginPath(); context.fillStyle = this.color; context.arc(this.pos.x ,this.pos.y, this.r, 0, Math.PI * 2 , false); context.fill(); }}class Timer{ constructor(){ this.lastTime = Date.now(); this.label = new Date(this.lastTime).Format('hh:mm:ss'); this.step = 0; this.shouldAnim = 0; } update(){ this.step = (this.step + 1) % 60; this.shouldAnim = (this.shouldAnim + 1) % 120; if (!this.step) { this.lastTime = Date.now(); this.label = new Date(this.lastTime).Format('hh:mm:ss'); } } paint(ctx){ context.fillStyle = "#353535"; ctx.fillText(this.label, 200, 100); }}//二维向量定义Vector2 = function(x, y) { this.x = x; this.y = y; };Vector2.prototype = { copy: function() { return new Vector2(this.x, this.y); }, length: function() { return Math.sqrt(this.x * this.x + this.y * this.y); }, sqrLength: function() { return this.x * this.x + this.y * this.y; }, normalize: function() { var inv = 1 / this.length(); return new Vector2(this.x * inv, this.y * inv); }, negate: function() { return new Vector2(-this.x, -this.y); }, add: function(v) { return new Vector2(this.x + v.x, this.y + v.y); }, subtract: function(v) { return new Vector2(this.x - v.x, this.y - v.y); }, multiply: function(f) { return new Vector2(this.x * f, this.y * f); }, divide: function(f) { var invf = 1 / f; return new Vector2(this.x * invf, this.y * invf); }, dot: function(v) { return this.x * v.x + this.y * v.y; }}; const canvas = document.getElementById('canvas');const context = canvas.getContext('2d');// 日期格式化工具Date.prototype.Format = function(fmt) { //author: meizz var o = { "M+" : this.getMonth()+1, //月份 "d+" : this.getDate(), //日 "h+" : this.getHours(), //小时 "m+" : this.getMinutes(), //分 "s+" : this.getSeconds(), //秒 "q+" : Math.floor((this.getMonth()+3)/3), //季度 "S" : this.getMilliseconds() //毫秒 }; if(/(y+)/.test(fmt)) fmt=fmt.replace(RegExp.$1, (this.getFullYear()+"").substr(4 - RegExp.$1.length)); for(var k in o) if(new RegExp("("+ k +")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length==1) ? (o[k]) : (("00"+ o[k]).substr((""+ o[k]).length))); return fmt; } var colorPalette = [ "#2ec7c9", "#b6a2de", "#5ab1ef", "#ffb980", "#d87a80", "#8d98b3", "#e5cf0d", "#97b552", "#95706d", "#dc69aa", "#07a2a4", "#9a7fd1", "#588dd5", "#f5994e", "#c05050", "#59678c", "#c9ab00", "#7eb00a", "#6f5553", "#c14089"];let balls = [];let timer = new Timer();let rightBorder = 800;let bottomBorder = 300;let gap = 5;let xs = 380; //文字所占区域宽度let ys = 120; //文字所占区域高度let imgData =[];//覆盖文字的矩形区域的像素点信息let checkPercent = 0.4;//检测区域中非白色像素点的比例小于限制时需要生成烟花let textLeft = 180; //文字距离画布左侧距离let textTop = 80;//文字距离画布上侧距离let g = new Vector2(0,9.8);//重力加速度start();function start() { init(); requestAnimationFrame(startAnim);}//初始化设置function init(){ // 设置字体 context.font = "80px bold impact"; // 设置颜色 context.fillStyle = "black"; // 设置水平对齐方式 context.textAlign = "left"; // 设置垂直对齐方式 context.textBaseline = "top";}//绘制背景function paintBg() { context.strokeStyle = "#353535"; context.lineWidth = 1; context.fillStyle = "white"; context.fillRect(1,1,rightBorder - 1, bottomBorder - 1); context.strokeRect(0,0,rightBorder,bottomBorder);}//帧动画function startAnim() { //重绘背景 paintBg(); //更新计时器状态 timer.update(); timer.paint(context); //时间发生变化时,生成新的小球并推入数组 handleTimerChange(); //更新每个小球的状态 balls = balls.map(ball=>{ ball.update(); ball.paint();//描线但不在画布上绘制 return ball; }); //绘制每个小球位置requestAnimationFrame(startAnim);}//时间变化时生成爆破function handleTimerChange() { let position; //如果时间变化,则生成新的爆破小球 if (!timer.shouldAnim) { //过滤掉生命耗尽的粒子 balls = balls.filter(ball=>ball.life); //生成新的文字烟花 for(let y = 0; y < ys / gap; y++){ for(let x= 0; x < xs / gap ; x++){ position = shouldAddBall(x, y); if (position) { addBall(position); } } } }}//检测指定区块是否需要生成烟花圆function shouldAddBall(x, y) { let pixels = context.getImageData(textLeft + x*gap, textTop + y*gap, 5, 5); if(!count(pixels)) return return { x:textLeft + x*gap, y:textTop + y*gap }}function count(pixels) { let data = pixels.data; let total = data.length; let num = data.filter(item=>item !== 255).length; return (num / total) > checkPercent;}//每隔一定时间增加一个新的球体function addBall(pos) { let {x,y} = pos; let r = Math.ceil(Math.random() * 4+1); let i = Math.ceil(Math.random() * 16); let left = pos.x < (textLeft + xs / 2) ? -1 : 1; let ball = new Ball(x,y,r,balls.length); ball.color = colorPalette[i]; ball.velocity = new Vector2(left * 10 *Math.random(), -20 * Math.random()); balls.push(ball);}},1000);
保存模板,点击「分页预览」,效果如下图所示:
注:不支持移动端
点击可下载模板:时间烟花效果.frm
文 檔回 饋
滑鼠選中內容,快速回饋問題
滑鼠選中存在疑惑的內容,即可快速回饋問題,我們將會跟進處理。
不再提示
10s後關閉