先上效果圖:
javascript
爲了方便書寫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;
},
};
複製代碼
定義一個「Clock」類,同時建立實例的時候咱們給予一個配置參數「option」(用於配置錶盤、指針等)。java
class Clock {
constructor(option) {
}
}
複製代碼
而後咱們思考一下,建立一個表須要哪些方法git
若是要讓時針、分針、秒針根據時間轉動起來還要給予Clock下面三個方法github
class Clock {
constructor(option) {
}
// 建立錶盤
createClockDial() {}
// 建立刻度
createClockScale() {}
// 建立指針
createHand() {}
// 建立時針
createHourHand() {}
// 建立分針
createMinuteHand() {}
// 建立秒針
createSecondHand() {}
// 根據時間戳設置時針角度
setHourHandAngleByTime(timestamp) {}
// 根據時間戳設置分針角度
setMinuteHandAngleByTime(timestamp) {}
// 根據時間戳設置秒針角度
setSecondHandAngleByTime(timestamp) {}
}
複製代碼
咱們再看看構造函數裏咱們須要處理的事情。首先咱們須要拿到配置項"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();
}
// ...
}
複製代碼
這一步用於建立錶盤容器,錶盤容器裏面包括刻度、指針、時針、分針、秒針等5個組。瀏覽器
class Clock {
constructor(option) {
const _this = this;
// 建立錶盤組
_this.clockDial = new Container3d();
// 將錶盤組添加到舞臺中
_this.pixiApp.stage.addChild(_this.clockDial);
}
}
複製代碼
這一步用於建立刻度。咱們將鐘錶的圓心建立在瀏覽器的中心即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);
}
// ...
}
複製代碼
建立指針組,並添加到舞臺中函數
class Clock {
// ...
// 建立指針
createHand() {
const _this = this;
let { option } = _this;
_this.hand = new Container3d();
_this.pixiApp.stage.addChild(_this.hand);
}
// ...
}
複製代碼
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);
}
// ...
}
複製代碼
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);
}
// ...
}
複製代碼
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);
}
// ...
}
複製代碼
咱們以時針爲例。首先時針不是一直都的對準某一刻度的,好比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);
}
// ...
}
複製代碼
再回到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);
});
}
// ...
}
複製代碼
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實例就大功告成了!