黑客帝国|typescript

123 阅读1分钟

把javascript写的黑客帝国改成typescript

主要用到:类型别名声明类型、基元类型声明、联合类型、类型断言

type canvasDom =  null | HTMLElement;
type Word = {
  x: number,
  y: number,
  recordY: number,
  fontSize: number,
  text: string,
  textHeight: number,
  speed: number
}
class Matrix {
  canvasEle: canvasDom;
  ctx: any;
  bodyEle: HTMLElement | null;
  canvasWidth: number;
  canvasHeight: number;
  fontSize: number;
  xMalPositions: number[];
  maxCount: number;
  wordPool: Array<Word>;
  words: string[]
  constructor() {
    this.canvasEle = null;
    this.bodyEle = null;
    this.canvasWidth = 150;
    this.canvasHeight = 150;
    this.fontSize = 20;
    this.xMalPositions = [-5, 0, 5]; // x坐标偏移
    this.maxCount = 300; // 限制词条个数,防止太多导致卡顿
    this.wordPool = []; // 词条数组
    this.words = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'];
    window.addEventListener('load', () => {
      this._init();
    });
  }
  _init(){
    this.canvasEle= document.getElementById('canvas');
    this.ctx = (this.canvasEle as HTMLCanvasElement).getContext('2d');
    this.bodyEle = document.getElementsByTagName('body')[0];
    this.setCanvasSize();
    window.addEventListener('resize', () => {
      this.setCanvasSize();
    });
    this._initWordPool();
    this.setTimer(() => {
      for(let i = 0; i < this.wordPool.length; i++) {
        let curWord: Word = this.wordPool[i];
        curWord.y += curWord.speed;
        if(curWord.y  >= this.canvasHeight) {
          this.wordPool.splice(i, 1);
        };
        const needAddNewWoed = Math.random() > 0.6;
        if(this.wordPool.length < this.maxCount && needAddNewWoed && (curWord.y + curWord.textHeight) > this.canvasHeight) {
          console.log(this.wordPool.length, '长度');
          const malPosition = this.xMalPositions[parseInt(String(Math.random() * this.xMalPositions.length))];
          const newX = this.fontSize * i + malPosition;
          const word = this._generateWord(i, newX);
          this.wordPool.push(word);
        }
        this.drawWord(curWord);
      }
    });
  }
  // 初始化 词条池
  _initWordPool() {
    const poolLen = parseInt(String(this.canvasWidth / this.fontSize));
    for(let i = 0; i < poolLen; i++) {
      const oneWord = this._generateWord(i);
      this.wordPool.push(oneWord);
    }
  }
  // 生成词条
  _generateWord(index: number, newX?: number | undefined) {
    const text = this.getRandomWord();
    const textHeight = text.length * this.fontSize;
    const malPosition = this.xMalPositions[parseInt(String(Math.random() * this.xMalPositions.length))];
    const startY = 0 - textHeight;
    const word = {
      x: newX || (this.fontSize * index + malPosition),
      y: startY,
      recordY: startY,
      fontSize: this.fontSize,
      text,
      textHeight,
      speed: [5, 6, 7][parseInt(String(Math.random() * 3))], // 随机速度
    }
    return word;
  }
  // 设置计时器
  setTimer(cb: () => void) {
    return setInterval(() => {
      cb()
    }, 30);
  }
  // 设置canvas大小
  setCanvasSize(){
    const { clientWidth, clientHeight } = this.bodyEle as HTMLElement;
    this.canvasWidth = clientWidth;
    this.canvasHeight = clientHeight;
    (this.canvasEle as HTMLCanvasElement).width = clientWidth;
    (this.canvasEle as HTMLCanvasElement).height = clientHeight;
  }
  // 随机生成句子
  getRandomWord() {
    let count = parseInt(String(Math.random() * 20 + 10)); // [20, 30)
    let word = '';
    while(count >= 0) {
      word += this.words[parseInt(String(Math.random() * (this.words.length + 1)))];
      count -= 1;
    }
    return word;
  };
  // 绘制词条
  drawWord(oneWord: Word) {
    const len = oneWord.text.length;
    this.ctx.clearRect(oneWord.x - 2, oneWord.recordY, oneWord.fontSize + 2, oneWord.textHeight);
    if(oneWord.y >= this.canvasHeight) return;
    oneWord.recordY = oneWord.y;
    this.ctx.textBaseline = "top";
    this.ctx.font = `${oneWord.fontSize}px Microsoft YaHei`;
    
    let startY = oneWord.y;
    for(let i = 0; i < len; i ++) {
      const opacity = i / (len - 1);
      this.ctx.fillStyle = `rgba(49, 117, 51, ${opacity})`;
      this.ctx.fillText(oneWord.text[i], oneWord.x, startY);
      startY += oneWord.fontSize;
    }
  }
}
const matrix = new Matrix();