當前為10.0版本文檔,更多實例內容將在最新幫助文檔中展現,點選跳轉至 最新版幫助文檔

JS實現時間煙花特效

1. 概述

1.1 預期效果

有時候需要在決策報表集成一些特效,如下圖,集成一個時間煙花效果。

時間煙花.gif

1.2 實現思路

通過 HTIML 和 JS 可以實現時間獲取以及添加粒子煙花效果。

2. 示例

2.1 準備模板

新建決策報表,添加一個報表塊,在報表單元格中輸入 HTML 代碼,單元格顯示方式選擇「用 HTML 顯示内容」,如下圖所示:

HTML 代碼如下:

<canvas id="canvas" height="800" width="1200"></canvas>

2.2 添加事件

點擊報表塊,爲報表塊添加「初始化後」事件。如下圖所示:

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);
顯示代碼

2.3 效果預覽

保存模板,點擊「分頁預覽」,效果如下圖所示:

2021-02-02_13-29-48.gif

注:不支持移動端

3. 模板下載

點擊可下載模板:時間煙花效果.frm

附件列表


主題: 原簡體文檔
  • 有幫助
  • 沒幫助
  • 只是瀏覽

文 檔回 饋

滑鼠選中內容,快速回饋問題

滑鼠選中存在疑惑的內容,即可快速回饋問題,我們將會跟進處理。

不再提示

9s后關閉

反饋已提交

網絡繁忙