用JavaScript写抖音很火的罗盘时钟,附源码

原生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+"年";
	}

源码下载,不要积分

兄弟们给个三连咯

猜你喜欢

转载自blog.csdn.net/dkm123456/article/details/115219368