先上效果图:
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实例就大功告成了!