使用Pixi擼一款「勞力士綠水鬼」!

先上效果圖:
javascript


預覽地址: rzeey.github.io/pixi-clock/…
源碼: github.com/RZeeY/pixi-…

1. 定義一些常量以及須要使用到的工具方法

爲了方便書寫PIXI的方法等,咱們先定義一些常量和工具方法html

const Application = PIXI.Application;
const Container = PIXI.Container;
const Container3d = PIXI.projection.Container3d;
const Loader = PIXI.loader;
const Resources = PIXI.loader.resources;
const Graphics = PIXI.Graphics;
const TextureCache = PIXI.utils.TextureCache;
const Sprite = PIXI.Sprite;
const Text = PIXI.Text;
const TextStyle = PIXI.TextStyle;
let utils = {
  /** * 角度轉弧度 * @param angle 角度 * @return 弧度 */
  angleToRadian: function(angle) {
    return (Math.PI * angle) / 180;
  },
  /** * 格式化時間戳 * @param timestamp 時間戳 * @return 格式化後的對象(包括是時分秒等) */
  formatTimestamp: function(timestamp) {
    var date = new Date(timestamp);
    return {
      Y: date.getFullYear(),
      M: date.getMonth() + 1,
      D: date.getDate(),
      h: date.getHours(),
      m: date.getMinutes(),
      s: date.getSeconds(),
    };
  },
  getTanDeg: function(tan) {
    var result = Math.atan(tan) / (Math.PI / 180);
    result = Math.round(result);
    return result;
  },
};
複製代碼

2. 定義Clock類

定義一個「Clock」類,同時建立實例的時候咱們給予一個配置參數「option」(用於配置錶盤、指針等)。java

class Clock {
    constructor(option) {
    }
}
複製代碼

3. 爲Clock類添加必要的方法

而後咱們思考一下,建立一個表須要哪些方法git

  • 建立錶盤的容器
  • 建立刻度的容器
  • 建立包含全部指針的容器
  • 建立時針的容器
  • 建立分針的容器
  • 建立秒針的容器

若是要讓時針、分針、秒針根據時間轉動起來還要給予Clock下面三個方法github

  • 根據時間調整時針的角度
  • 根據時間調整分針的角度
  • 根據時間調整秒針的角度
class Clock {
    constructor(option) {
    }
    // 建立錶盤
    createClockDial() {}
    // 建立刻度
    createClockScale() {}
    // 建立指針
    createHand() {}
    // 建立時針
    createHourHand() {}
    // 建立分針
    createMinuteHand() {}
    // 建立秒針
    createSecondHand() {}
    // 根據時間戳設置時針角度
    setHourHandAngleByTime(timestamp) {}
    // 根據時間戳設置分針角度
    setMinuteHandAngleByTime(timestamp) {}
    // 根據時間戳設置秒針角度
    setSecondHandAngleByTime(timestamp) {} 
}
複製代碼

3.1 構造函數 constructor

咱們再看看構造函數裏咱們須要處理的事情。首先咱們須要拿到配置項"option",接着咱們應該定義一些屬性如錶盤的對象、刻度的對象、指針的對象等。而且還要建立PIXI Application的實例。
以上步驟完成後咱們再依次建立錶盤、刻度、指針、時針、分針、秒針。canvas

class Clock {
    constructor(option) {
        const _this = this;
        _this.option = option;
        _this.clockDial = null; // 錶盤
        _this.clockScale = null; // 刻度
        _this.secondHand = null; // 秒針
        _this.minuteHand = null; // 分針
        _this.hourHand = null; // 時針
        _this.hand = null; // 指針組
        _this.pixiApp = new Application(_this.option.pixi); // 根據option中pixi的配置來建立PIXI Application的實例
        document.body.appendChild(_this.pixiApp.view);
        // 建立錶盤、刻度、指針、時針、分針、秒針
        _this.createClockDial();
        _this.createClockScale();
        _this.createHand();
        _this.createHourHand();
        _this.createMinuteHand();
        _this.createSecondHand();
    }
    // ...
}
複製代碼

3.2 建立錶盤 createClockDial

這一步用於建立錶盤容器,錶盤容器裏面包括刻度、指針、時針、分針、秒針等5個組。瀏覽器

class Clock {
    constructor(option) {
        const _this = this;
        // 建立錶盤組
        _this.clockDial = new Container3d();
        // 將錶盤組添加到舞臺中
        _this.pixiApp.stage.addChild(_this.clockDial);
    }
}
複製代碼

3.3 建立刻度 createClockScale

這一步用於建立刻度。咱們將鐘錶的圓心建立在瀏覽器的中心即x = window.innerWidth / 2,y = window.innerHeight / 2。
隨後在圓心的四周建立12個實心矩形,用於表示鐘錶的刻度。因此咱們須要分別計算十二個矩形所在的x座標和y座標。
在已知半徑r,圓心座標x0、y0,角度angle的狀況下,可採用 x1 = x0 + r * cos(ao * PI / 180)y1 = y0 + r * sin(ao * PI /180) 計算出每一個刻度所處的x和y座標。app

class Clock {
    // ...
    // 建立刻度
    createClockScale() {
        const _this = this;
        let { option } = _this;
        // 建立刻度組
        _this.clockScale = new Container3d();
        // 設置刻度組的中心點,即錶盤圓心座標
        _this.clockScale.pivot.set(-option.clock.center.x, -option.clock.center.y);
        // 循環建立12個刻度矩形
        for (let i = 0; i < 12; i++) {
            // 建立圖形
            let clockScaleItem = new Graphics();
            clockScaleItem.beginFill(option.clock.scale.color);
            clockScaleItem.drawRect(0, 0, option.clock.scale.width, option.clock.scale.height);
            clockScaleItem.endFill();
            // 設置每一個刻度的中心點位置,以便於按刻度中心旋轉
            clockScaleItem.pivot.set(option.clock.scale.width / 2, option.clock.scale.height / 2);
            // 計算刻度座標
            // x1 = x0 + r * cos(ao * PI / 180)
            // y1 = y0 + r * sin(ao * PI /180)
            clockScaleItem.position.x = option.clock.radius * Math.cos((Math.PI * i * 30) / 180);
            clockScaleItem.position.y = option.clock.radius * Math.sin((Math.PI * i * 30) / 180);
            // 旋轉刻度
            clockScaleItem.rotation = utils.angleToRadian(i * 30 + 90);
            // 將每一個刻度圖形添加進刻度組
            _this.clockScale.addChild(clockScaleItem);
        }
        // 將刻度組添加進錶盤容器中
        _this.clockDial.addChild(_this.clockScale);
    }
    // ...
}
複製代碼

3.4 建立指針 createHand

建立指針組,並添加到舞臺中函數

class Clock {
    // ...
    // 建立指針
    createHand() {
        const _this = this;
        let { option } = _this;
        _this.hand = new Container3d();
        _this.pixiApp.stage.addChild(_this.hand);
    }
    // ...
}
複製代碼

3.5 建立時針 createHourHand

class Clock {
    // ...
    // 建立時針
    createHourHand() {
        const _this = this;
        let { option } = _this;
        // 建立時針組
        _this.hourHand = new Container3d();
        _this.hand.addChild(_this.hourHand);
        _this.hourHand.pivot.set(-option.clock.center.x, -option.clock.center.y);
        let hourHandItem = new Graphics();
        hourHandItem.beginFill(option.clock.hourHand.color);
        hourHandItem.drawRect(0, 0, option.clock.hourHand.width, option.clock.hourHand.height);
        hourHandItem.endFill();
        hourHandItem.pivot.set(option.clock.hourHand.width / 2, option.clock.hourHand.height / 1.2);
        // 旋轉刻度
        hourHandItem.rotation = utils.angleToRadian(0);
        // 陰影
        let dropShadowFilter = new PIXI.filters.DropShadowFilter({
            color: option.clock.hourHand.shadow.color,
            alpha: 0.65,
            blur: 4,
            distance: 8,
        });
        hourHandItem.filters = [dropShadowFilter];
        _this.hourHand.addChild(hourHandItem);
    }
    // ...
}
複製代碼

3.6 建立分針 createMinuteHand

class Clock {
    // ...
    // 建立分針
    createMinuteHand() {
        const _this = this;
        let { option } = _this;
        // 建立分針組
        _this.minuteHand = new Container3d();
        // 將分針組添加進指針組中
        _this.hand.addChild(_this.minuteHand);
        _this.minuteHand.pivot.set(-option.clock.center.x, -option.clock.center.y);
        // 建立分針圖形
        let minuteHandItem = new Graphics();
        minuteHandItem.beginFill(option.clock.minuteHand.color);
        minuteHandItem.drawRect(0, 0, option.clock.minuteHand.width, option.clock.minuteHand.height);
        minuteHandItem.endFill();
        minuteHandItem.pivot.set(option.clock.minuteHand.width / 2, option.clock.minuteHand.height / 1.2);
        // 旋轉刻度
        minuteHandItem.rotation = utils.angleToRadian(0);
        // 陰影
        let dropShadowFilter = new PIXI.filters.DropShadowFilter({
            color: option.clock.minuteHand.shadow.color,
            alpha: 0.5,
            blur: 6,
            distance: 10,
        });
        minuteHandItem.filters = [dropShadowFilter];
        // 將分針圖形添加進分針組中
        _this.minuteHand.addChild(minuteHandItem);
    }
    // ...
}
複製代碼

3.7 建立秒針 createSecondHand

class Clock {
    // ...
    // 建立秒針
    createSecondHand() {
        const _this = this;
        let { option } = _this;
        // 建立秒針組
        _this.secondHand = new Container3d();
        // 將秒針組添加到指針組中
        _this.hand.addChild(_this.secondHand);
        _this.secondHand.pivot.set(-option.clock.center.x, -option.clock.center.y);
        // 建立指針圖形
        let secondHandItem = new Graphics();
        secondHandItem.beginFill(option.clock.secondHand.color);
        secondHandItem.drawRect(0, 0, option.clock.secondHand.width, option.clock.secondHand.height);
        secondHandItem.endFill();
        secondHandItem.pivot.set(option.clock.secondHand.width / 2, option.clock.secondHand.height / 1.2);
        // 旋轉刻度
        secondHandItem.rotation = utils.angleToRadian(0);
        // 陰影
        let dropShadowFilter = new PIXI.filters.DropShadowFilter({
            color: option.clock.secondHand.shadow.color,
            alpha: 0.5,
            blur: 10,
            distance: 10,
        });
        secondHandItem.filters = [dropShadowFilter];
        // 將秒針圖形添加進秒針組中
        _this.secondHand.addChild(secondHandItem);
    }
    // ...
}
複製代碼

3.8 根據時間戳設置三個指針角度 setHourHandAngleByTime、setMinuteHandAngleByTime、setSecondHandAngleByTime

咱們以時針爲例。首先時針不是一直都的對準某一刻度的,好比2:30,時針就指向了2點和1點的中間,因此咱們要將整數「時」轉換爲小數「時」。好比2:30就是2.5時。咱們採用 h = h + (5 * m) / 3 / 100 這樣的公式轉換小數。再經過Container對象的rotation屬性設置當前時針所處的角度。工具

class Clock {
    // ...
    // 根據時間戳設置時針角度
        setHourHandAngleByTime(timestamp) {
        const _this = this;
        let { option } = _this;
        let _formatTimestamp = utils.formatTimestamp(timestamp);
        let h = _formatTimestamp.h;
        let m = _formatTimestamp.m;
        h = h + (5 * m) / 3 / 100;
        _this.hourHand.getChildAt(0).rotation = utils.angleToRadian((360 / 12) * h);
    }
    // 根據時間戳設置分針角度
    setMinuteHandAngleByTime(timestamp) {
        const _this = this;
        let { option } = _this;
        let _formatTimestamp = utils.formatTimestamp(timestamp);
        let h = _formatTimestamp.h;
        let m = _formatTimestamp.m;
        let s = _formatTimestamp.s;
        m = m + (5 * s) / 3 / 100;
        _this.minuteHand.getChildAt(0).rotation = utils.angleToRadian((360 / 60) * m);
    }
    // 根據時間戳設置秒針角度
    setSecondHandAngleByTime(timestamp) {
        const _this = this;
        let { option } = _this;
        let _formatTimestamp = utils.formatTimestamp(timestamp);
        let h = _formatTimestamp.h;
        let m = _formatTimestamp.m;
        let s = _formatTimestamp.s;
        _this.secondHand.getChildAt(0).rotation = utils.angleToRadian((360 / 60) * s);
    }
    // ...
}
複製代碼

4. 讓指針動起來

再回到Clock的構造函數中,咱們建立了鐘錶所需的各個元素,但並無讓指針動起來。
經過調用PIXI.Application對象的ticker.add方法可實現動畫。
在ticker.add的每次一回調函數中都獲取一次當前時間戳,並經過時間戳更改時分秒的指針角度。

class Clock {
    constructor(option) {
        // ...
        _this.pixiApp.ticker.add(delta => {
            // 獲取時間戳
            let timestamp = new Date().getTime();
            // 根據時間戳設置時分秒針的角度
            _this.setHourHandAngleByTime(timestamp);
            _this.setMinuteHandAngleByTime(timestamp);
            _this.setSecondHandAngleByTime(timestamp);
        });
    }
    // ...
}
複製代碼

5. 再添加一個視差效果!

class Clock {
    constructor(option) {
        // ...
        // 給canvas綁定mousemove事件
        _this.pixiApp.view.addEventListener('mousemove', ev => {
            let offset = {
                x: ev.offsetX / option.pixi.resolution,
                y: ev.offsetY / option.pixi.resolution,
            };
            // 讓刻度組根據鼠標和圓心的位置,向鼠標的反方向移動
            _this.clockScale.position3d.x = -(offset.x - option.clock.center.x) * 0.01;
            _this.clockScale.position3d.y = -(offset.y - option.clock.center.y) * 0.01;
            // 讓指針組根據鼠標和圓心的位置,向鼠標的正方向移動
            _this.hand.position3d.x = (offset.x - option.clock.center.x) * 0.016;
            _this.hand.position3d.y = (offset.y - option.clock.center.y) * 0.016;
        });
    }
    // ...
}
複製代碼

最後new一個Clock實例就大功告成了!

相關文章
相關標籤/搜索