原生js制作在抖音上很火的罗盘布局时钟代码。带日期、月份、星期、时分秒圆盘时钟。
效果图:
3个构造函数
文本构造函数
//文字的构造函数
function Text(o){
this.x=0,//x坐标
this.y=0,//y坐标
this.disX=0,//x坐标偏移量
this.disY=0,//y坐标偏移量
this.text='',//内容
this.font=null;//字体
this.textAlign=null;//对齐方式
this.init(o);
}
Text.prototype.init=function(o){
for(var key in o){
this[key]=o[key];
}
}
Text.prototype.render=function(context){
this.ctx=context;
innerRender(this);
function innerRender(obj){
var ctx=obj.ctx;
ctx.save()
ctx.beginPath();
ctx.translate(obj.x,obj.y);
if(obj.angle){//根据旋转角度来执行旋转
ctx.rotate(-obj.angle*Math.PI/180);
}
if(obj.font){
ctx.font=obj.font;
}
if(obj.textAlign){
ctx.textAlign=obj.textAlign;
}
if(obj.fill){//是否填充
obj.fillStyle?(ctx.fillStyle=obj.fillStyle):null;
ctx.fillText(obj.text,obj.disX,obj.disY);
}
if(obj.stroke){//是否描边
obj.strokeStyle?(ctx.strokeStyle=obj.strokeStyle):null;
ctx.strokeText(obj.text,obj.disX,obj.disY);
}
ctx.restore();
}
return this;
}
线段构造函数
//直线的构造
function Line(o){
this.x=0,//x坐标
this.y=0,//y坐标
this.startX=0,//开始点x位置
this.startY=0, //开始点y位置
this.endX=0,//结束点x位置
this.endY=0;//结束点y位置
this.thin=false;//设置变细系数
this.init(o);
}
Line.prototype.init=function(o){
for(var key in o){
this[key]=o[key];
}
}
Line.prototype.render=function(ctx){
innerRender(this);
function innerRender(obj){
ctx.save()
ctx.beginPath();
ctx.translate(obj.x,obj.y);
if(obj.thin){
ctx.translate(0.5,0.5);
}
if(obj.lineWidth){//设定线宽
ctx.lineWidth=obj.lineWidth;
}
if(obj.strokeStyle){
ctx.strokeStyle=obj.strokeStyle;
}
//划线
ctx.moveTo(obj.startX, obj.startY);
ctx.lineTo(obj.endX, obj.endY);
ctx.stroke();
ctx.restore();
}
return this;
}
圆构造函数
//构造函数
function Circle(o){
this.x=0,//圆心X坐标
this.y=0,//圆心Y坐标
this.r=0,//半径
this.startAngle=0,//开始角度
this.endAngle=0,//结束角度
this.anticlockwise=false;//顺时针,逆时针方向指定
this.stroke=false;//是否描边
this.fill=false;//是否填充
this.scaleX=1;//缩放X比例
this.scaleY=1;//缩放Y比例
this.rotate=0;
this.init(o);
}
//初始化
Circle.prototype.init=function(o){
for(var key in o){
this[key]=o[key];
}
}
//绘制
Circle.prototype.render=function(context){
var ctx=context;//获取上下文
ctx.save();
ctx.beginPath();
ctx.translate(this.x,this.y);
if(this.fill){
ctx.moveTo(0,0);
}
//ctx.moveTo(this.x,this.y);
ctx.scale(this.scaleX,this.scaleY);//设定缩放
ctx.arc(0,0,this.r,this.startAngle,this.endAngle);//画圆
if(this.lineWidth){//线宽
ctx.lineWidth=this.lineWidth;
}
if(this.fill){//是否填充
this.fillStyle?(ctx.fillStyle=this.fillStyle):null;
ctx.fill();
}
if(this.stroke){//是否描边
this.strokeStyle?(ctx.strokeStyle=this.strokeStyle):null;
ctx.stroke();
}
ctx.restore();
return this;
}
绘制
绘制年
//绘制年
Clock.prototype.drawYear=function(){
//绘制年
var content=this.year+"年",x=y=0;
x=this.w/2;y=this.h/2;
var year = new Text({
x:x,
y:y,
text:content,
font:'18px ans-serif',
textAlign:'center',
fill:true,
fillStyle:'white'
});
this.renderYear=year;
}
绘制星期
//绘制星期
Clock.prototype.drawWeekDay=function(){
var x=this.w/2,y=this.h/2;
var disX=0,disY=30,content=this.weekArr[this.day];
var weekDay = new Text({
x:x,
y:y,
disX:disX,
disY:disY,
text:content,
font:'18px ans-serif',
textAlign:'center',
fill:true,
fillStyle:'white'
});
this.weekDay=weekDay;
}
绘制月份
//绘制月
Clock.prototype.drawMonth=function(){
var content="",x=y=0,month,fillStyle,color='pink',index;
x=this.w/2;y=this.h/2,disX=60,disY=0;
var angleIncre= 360/12,//每次递增角度
angle=0;//初始
for(var i=0;i<12;i++){
index=i+1;
if(index<this.month){
angle = 360-(this.month-index)*angleIncre;
}else{
angle = (index-this.month)*angleIncre;
}
content=index+"月";
if(index==this.month){//当前设置成白色
fillStyle="white";
}else{//其他为灰色
fillStyle=color;
}
month = new Text({
x:x,
y:y,
disX:disX,
disY:disY,
text:content,
font:'14px ans-serif',
textAlign:'center',
fill:true,
fillStyle:fillStyle,
color:color,
angle:angle,
angleIncre:angleIncre,
});
this.renderMonth.push(month);
}
}
绘制日期
//绘制日
Clock.prototype.drawDate=function(){
var content="",x=y=0,date,fillStyle,color='orange',disabled=false,index=0;
x=this.w/2;y=this.h/2,disX=110,disY=0;
var angleIncre= 360/31,//每次递增角度
angle=0;//初始
for(var i=0;i<31;i++){
index=i+1;
if(index<this.date){
angle = 360-(this.date-index)*angleIncre;
}else{
angle = (index-this.date)*angleIncre;
}
content=index+"日";
if(index==this.date){//当前设置成白色
fillStyle="white";
}else{//其他为灰色
fillStyle=color;
}
if(index>this.currentMonthDayLength){
disabled=true;
}else{
disabled=false;
}
date = new Text({
x:x,
y:y,
disX:disX,
disY:disY,
text:content,
font:'14px ans-serif',
textAlign:'center',
fill:true,
fillStyle:fillStyle,
color:color,
angle:angle,
angleIncre:angleIncre,
disabled:disabled,
day:index
});
this.renderDate.push(date);
}
}
目前的效果
绘制小时
//绘制小时
Clock.prototype.drawHour=function(){
var content="",index,x=y=0,hour,fillStyle,color='yellow';
x=this.w/2;y=this.h/2,disX=160,disY=0;
var angleIncre= 360/24,//每次递增角度
angle=0;//初始
for(var i=0;i<24;i++){
if(i<this.hour){
angle = 360-(this.hour-i)*angleIncre;
}else{
angle = (i-this.hour)*angleIncre;
}
content=i+"";//到60就切换成00
content=(content.length==1?(0+content):content)+"时";
if(i==this.hour){//当前设置成白色
fillStyle="white";
}else{//其他为灰色
fillStyle=color;
}
hour = new Text({
x:x,
y:y,
disX:disX,
disY:disY,
text:content,
font:'14px ans-serif',
textAlign:'center',
fill:true,
fillStyle:fillStyle,
color:color,
angle:angle,
angleIncre:angleIncre
});
this.renderHour.push(hour);
}
}
绘制分钟
//绘制分钟
Clock.prototype.drawMinute=function(){
var content="",x=y=0,minute,fillStyle,color='#6EDBBC';
x=this.w/2;y=this.h/2,disX=220,disY=0;
var angleIncre= 360/60,//每次递增角度
angle=0;//初始
for(var i=0;i<60;i++){
if(i<this.minute){
angle = 360-(this.minute-i)*angleIncre;
}else{
angle = (i-this.minute)*angleIncre;
}
content=i+"";//到60就切换成00
content=(content.length==1?(0+content):content)+"分";
if(i==this.minute){//当前设置成白色
fillStyle="white";
}else{//其他为灰色
fillStyle=color;
}
minute = new Text({
x:x,
y:y,
disX:disX,
disY:disY,
text:content,
font:'14px ans-serif',
textAlign:'center',
fill:true,
fillStyle:fillStyle,
color:color,
angle:angle,
angleIncre:angleIncre
});
this.renderMinute.push(minute);
}
}
绘制秒钟
//绘制秒钟
Clock.prototype.drawSecond=function(){
var content="",x=y=0,second,fillStyle,color='skyblue';
x=this.w/2,//x坐标
y=this.h/2,//y坐标
disX=280,//x方向偏移
disY=0;//y方向偏移
var angleIncre= 360/60,//每次递增角度
angle=0;//初始
for(var i=0;i<60;i++){
/**
角度是0-360,60份,每份为6度,当前是this.second ,所以this.second 的角度应该是0,
大于它的是从0开始递增6,依次是6-12-18...,计算:360-(this.second-i)*angleIncre
小于它的是依次递减6,依次是354-348-342...,计算:(i-this.second)*angleIncre
*/
if(i<this.second){//小于当前秒则
angle = 360-(this.second-i)*angleIncre;
}else{//大于当前秒
angle = (i-this.second)*angleIncre;
}
content=i+"";//到60就切换成00
content=(content.length==1?(0+content):content)+"秒";
if(i==this.second){//当前设置成白色
fillStyle="white";
}else{//其他为灰色
fillStyle=color;
}
//创建秒
second = new Text({
x:x,
y:y,
disX:disX,
disY:disY,
text:content,
font:'14px ans-serif',
textAlign:'center',
fill:true,
fillStyle:fillStyle,
color:color,
angle:angle,
angleIncre:angleIncre
});
this.renderSecond.push(second);
}
}
此时的效果
加入指示线
//线
Clock.prototype.drawMarkLine=function(){
var x=y=0;
x=this.w/2;y=this.h/2;
var line = new Line({
x:x,
y:y,
startX:2,
startY:2,
endX:297,
endY:2,
thin:true,
strokeStyle:'white'
})
this.renderLine=line;
}
绘制多条圆弧
//绘制圆
Clock.prototype.drawCircle=function(){
var x=y=0,cilcle,color;
x=this.w/2;y=this.h/2;
cilcle = new Circle({
x:x+2,//圆心X坐标
y:y+3,//圆心X坐标
r:3,//半径
startAngle:0,//开始角度
endAngle:2*Math.PI,//结束角度
lineWidth:2,
fill:true,
fillStyle:'white'
});
this.renderCircle.push(cilcle);
color=_.getRandomColor();
cilcle = new Circle({
x:x,//圆心X坐标
y:y,//圆心X坐标
r:42,//半径
startAngle:0,//开始角度
endAngle:2*Math.PI,//结束角度
lineWidth:0.5,
stroke:true,//是否描边
strokeStyle:color
});
this.renderCircle.push(cilcle);
color=_.getRandomColor();
cilcle = new Circle({
x:x,//圆心X坐标
y:y,//圆心X坐标
r:80,//半径
startAngle:0,//开始角度
endAngle:2*Math.PI,//结束角度
lineWidth:0.5,
stroke:true,//是否描边
strokeStyle:color
});
this.renderCircle.push(cilcle);
color=_.getRandomColor();
cilcle = new Circle({
x:x,//圆心X坐标
y:y,//圆心X坐标
r:90,//半径
startAngle:0,//开始角度
endAngle:2*Math.PI,//结束角度
lineWidth:0.5,
stroke:true,//是否描边
strokeStyle:color
});
this.renderCircle.push(cilcle);
color=_.getRandomColor();
cilcle = new Circle({
x:x,//圆心X坐标
y:y,//圆心X坐标
r:130,//半径
startAngle:0,//开始角度
endAngle:2*Math.PI,//结束角度
lineWidth:0.5,
stroke:true,//是否描边
strokeStyle:color
});
this.renderCircle.push(cilcle);
color=_.getRandomColor();
cilcle = new Circle({
x:x,//圆心X坐标
y:y,//圆心X坐标
r:140,//半径
startAngle:0,//开始角度
endAngle:2*Math.PI,//结束角度
lineWidth:0.5,
stroke:true,//是否描边
strokeStyle:color
});
this.renderCircle.push(cilcle);
color=_.getRandomColor();
cilcle = new Circle({
x:x,//圆心X坐标
y:y,//圆心X坐标
r:180,//半径
startAngle:0,//开始角度
endAngle:2*Math.PI,//结束角度
lineWidth:0.5,
stroke:true,//是否描边
strokeStyle:color
});
this.renderCircle.push(cilcle);
color=_.getRandomColor();
cilcle = new Circle({
x:x,//圆心X坐标
y:y,//圆心X坐标
r:200,//半径
startAngle:0,//开始角度
endAngle:2*Math.PI,//结束角度
lineWidth:0.5,
stroke:true,//是否描边
strokeStyle:color
});
this.renderCircle.push(cilcle);
color=_.getRandomColor();
cilcle = new Circle({
x:x,//圆心X坐标
y:y,//圆心X坐标
r:240,//半径
startAngle:0,//开始角度
endAngle:2*Math.PI,//结束角度
lineWidth:0.5,
stroke:true,//是否描边
strokeStyle:color
});
this.renderCircle.push(cilcle);
color=_.getRandomColor();
cilcle = new Circle({
x:x,//圆心X坐标
y:y,//圆心X坐标
r:260,//半径
startAngle:0,//开始角度
endAngle:2*Math.PI,//结束角度
lineWidth:0.5,
stroke:true,//是否描边
strokeStyle:color
});
this.renderCircle.push(cilcle);
color=_.getRandomColor();
cilcle = new Circle({
x:x,//圆心X坐标
y:y,//圆心X坐标
r:298,//半径
startAngle:0,//开始角度
endAngle:2*Math.PI,//结束角度
lineWidth:0.5,
stroke:true,//是否描边
strokeStyle:color
});
this.renderCircle.push(cilcle);
}
此时图形已经基本完成
加入定时任务让它转起来
秒钟转动
//开始转动
Clock.prototype.start=function(){
//100毫秒执行一次
setInterval(this.updateSecond.bind(this),100);
}
//秒钟转动
Clock.prototype.updateSecond=function(){
var that=this,secondFlag=false;
//计数器递增
this.timeCount++;
//100毫秒执行一次,所以10次才是1秒
if(this.timeCount==10){//计数器生效
this.timeCount=0;//计数器清零
secondFlag=true;//秒钟+1标记
this.second+=1;//秒钟+1
if(this.second==60){//到达60以后设置为0
this.second=0;
setTimeout(this.updateMinute.bind(this),0)
}
}
doUpdate.call(this);
function doUpdate(){
//秒钟update
_.each(this.renderSecond,function(item){
if(secondFlag){//秒钟计数生效
if(item.text==that.second+"秒"||item.text=="0"+that.second+"秒"){
item.fillStyle="white";
}else{
item.fillStyle=item.color;
}
}
//角度旋转
item.angle = (item.angle*10 - item.angleIncre)/10;//因item.angleIncre是6,除以10会有小数,这里采取乘10,再除以10的方式来操作
//达到最大角度则重置角度
if(item.angle<=0){
item.angle=(3600+item.angle*10)/10;
}
});
this.render2();
}
}
分钟转动
//分钟转动
Clock.prototype.updateMinute=function(){
var that=this;
this.minute+=1;
if(this.minute==60){
this.minute=0;
this.updateHour();
}
_.each(this.renderMinute,function(item){
if(item.text==that.minute+"分"||item.text=="0"+that.minute+"分"){
item.fillStyle="white";
}else{
item.fillStyle=item.color;
}
//角度旋转
item.angle -= item.angleIncre;
达到最大角度则重置角度
if(item.angle<0){
item.angle=360+item.angle;
}
});
this.render();
}
时钟转动
//时钟转动
Clock.prototype.updateHour=function(){
var that=this;
this.hour+=1;
if(this.hour==24){
this.hour=0;
this.updateDate();
}
_.each(this.renderHour,function(item){
if(item.text==that.hour+"时"||item.text=="0"+that.hour+"时"){
item.fillStyle="white";
}else{
item.fillStyle=item.color;
}
item.angle -= item.angleIncre;
达到最大角度则重置角度
if(item.angle<0){
item.angle=360+item.angle;
}
});
}
日期转动
//日转动
Clock.prototype.updateDate=function(){
var that=this,dateUpdateFlag=false,lastMonthDayLength,angleDis;
this.date+=1;//日期递增1
this.updateWeekDay();//更新周几
if(this.date>this.currentMonthDayLength){//大于本月最大天数就切换到1日
this.date=1;
this.updateMonth();//更新月份
dateUpdateFlag=true;//更新日
lastMonthDayLength=that.currentMonthDayLength;//当月月最大天数
that.getCurrentMonthDayLength();//重新获取月份的最大天数
angleDis = lastMonthDayLength-that.currentMonthDayLength;//计算两月之间天数的差值
}
_.each(this.renderDate,function(item){
if(item.text==that.date+"日"){
item.fillStyle="white";
}else{
item.fillStyle=item.color;
}
//旋转角度
item.angle -= item.angleIncre;
if(dateUpdateFlag){//本月的最后一天,可能要更新
if(lastMonthDayLength!=31){//当前月天数不等于31,则表示要多旋转角度,比如当月总共30天,今天是30号,则直接跳转到1号,31号被跳过
item.angle+=angleDis*item.angleIncre;
}
//超过最新天数的要隐藏,比如当月总共30天,今天是30号,31号要被隐藏
if(item.day>that.currentMonthDayLength){
item.disabled=true;
}else{
item.disabled=false;
}
}
//达到最大角度则重置角度
if(item.angle<0){
item.angle=360+item.angle;
}
});
}
星期变更
//更新星期几
Clock.prototype.updateWeekDay=function(){
this.day+=1;
//大于6则重置
if(this.day>6){
this.day=0;
}
//数组中获取周几
this.weekDay.text=this.weekArr[this.day];
}
月转动
//月转动
Clock.prototype.updateMonth=function(){
var that=this;
this.month+=1;
if(this.month>12){
this.month=1;
this.updateYear();
}
_.each(this.renderMonth,function(item){
if(item.text==that.month+"月"){
item.fillStyle="white";
}else{
item.fillStyle=item.color;
}
//旋转角度
item.angle -= item.angleIncre;
达到最大角度则重置角度
if(item.angle<0){
item.angle=360+item.angle;
}
});
}
年更新
//年转动
Clock.prototype.updateYear=function(){
this.year+=1;
this.renderYear.text=this.year+"年";
}
兄弟们给个三连咯