废话开篇:简单的用 js 实现一下光的魔法阵
一、实现效果
二、步骤分析
1、全局定时任务执行
2、绘制内、外圆弧
3、绘制正、反内接三角形
三、代码总览
1、HTML 部分
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<script src="./main.js"></script>
<style type="text/css">
#main {
background-color: #000;
width: 400px;
height: 400px;
margin-left: auto;
margin: auto;
margin-top: 100px;
}
#small {
position: absolute;
width: 400px;
height: 400px;
left: 50%;
margin-left:-200px;
margin-top: 100px;
opacity: 0;
top: 0;
}
#fullScreen{
border-top:1px solid rgba(0,0,0,0);
background-color: #000000;
width: 100%;
height: 100%;
position: relative;
}
</style>
<body>
<div id="fullScreen" onclick="show()">
<div id="main">
<canvas id="myCanvas" width="400" height="400">
</canvas>
</div>
<div id="small">
<canvas id="smallMyCanvas" width="400" height="400">
</canvas>
</div>
</div>
</body>
<script type="text/javascript">
function show(){
window.$magic.init("myCanvas","smallMyCanvas");
}
</script>
</html>
</html>
2、JS 部分
(function(window){
var magic = {};
magic.center = null;
magic.r = 0;
magic.ctx = null;
magic.smallCtx = null,
magic.outsideAngle = 0;
magic.withinAngle = 270;
magic.circleDistance = 30;
magic.upTrianglePoints = [];
magic.downTrianglePoints = [];
magic.triangleDrawSidePercent = 0;
magic.drawTriangleDrawSideIndex = 0;
magic.xDeg = 0;
magic.smallCanvasPositionAddY = 0;
magic.smallCanvasScaleReduce = 1;
magic.smallCanvasId = ""
//初始化
magic.init = function(id,smallCanvasId){
this.getCanvas(id)
this.timingTask();
this.withinUpTrianglePoints();
this.withinDownTrianglePoints();
this.smallCanvasId = smallCanvasId;
this.getSmallCanvas(this.smallCanvasId);
}
//获取画布
magic.getCanvas = function(id){
var c= document.getElementById(id);
this.r = c.width / 2;
this.center = {x:this.r,y:this.r};
this.ctx = c.getContext("2d");
//锯齿修复
if (window.devicePixelRatio) {
c.style.width = c.width + "px";
c.style.height = c.height + "px";
c.height = c.height * window.devicePixelRatio;
c.width = c.width * window.devicePixelRatio;
this.ctx.scale(window.devicePixelRatio, window.devicePixelRatio);
}
};
//获取小画布
magic.getSmallCanvas = function(id){
var c = document.getElementById(id);
this.smallCtx = c.getContext("2d");
//锯齿修复
if (window.devicePixelRatio) {
c.style.width = c.width + "px";
c.style.height = c.height + "px";
c.height = c.height * window.devicePixelRatio;
c.width = c.width * window.devicePixelRatio;
this.smallCtx.scale(window.devicePixelRatio, window.devicePixelRatio);
}
var color = "FFFAE8";
var upPoint = this.upTrianglePoints[0];
var upLeftPoint = this.upTrianglePoints[1];
var upRightPoint = this.upTrianglePoints[2];
this.smallCtx.beginPath();
this.smallCtx.moveTo(upPoint.x, upPoint.y);
this.smallCtx.lineTo(upLeftPoint.x, upLeftPoint.y);
this.smallCtx.lineTo(upRightPoint.x, upRightPoint.y);
this.smallCtx.fillStyle = color;
this.smallCtx.closePath();
this.smallCtx.fill();
var downPoint = this.downTrianglePoints[0];
var downLeftPoint = this.downTrianglePoints[1];
var downRightPoint = this.downTrianglePoints[2];
this.smallCtx.beginPath();
this.smallCtx.moveTo(downPoint.x, downPoint.y);
this.smallCtx.lineTo(downLeftPoint.x, downLeftPoint.y);
this.smallCtx.lineTo(downRightPoint.x, downRightPoint.y);
this.smallCtx.fillStyle = color;
this.smallCtx.closePath();
this.smallCtx.fill();
}
//画圆
magic.drawCircle = function(point,r,startAngle,endAngle,counterclockwise){
this.ctx.strokeStyle = "#FFF";
this.ctx.lineWidth = 0.8;
this.ctx.beginPath();
this.ctx.arc(point.x,point.y,r,(2*Math.PI) * startAngle / 360,(2*Math.PI) * endAngle / 360,counterclockwise);
this.ctx.stroke();
};
//画线
magic.drawLine = function(fromPoint,toPoint,percent){
// 设置线条的颜色
this.ctx.strokeStyle = '#FFF';
// 设置线条的宽度
this.ctx.lineWidth = 1;
// 绘制直线
this.ctx.beginPath();
// 起点
this.ctx.moveTo(fromPoint.x, fromPoint.y);
// 终点
this.ctx.lineTo(fromPoint.x + (toPoint.x - fromPoint.x) * percent,fromPoint.y + (toPoint.y - fromPoint.y) * percent);
this.ctx.closePath();
this.ctx.stroke();
}
//计算小圆内正内接三角形各个坐标点
magic.withinUpTrianglePoints = function(){
var withinR = this.r - this.circleDistance;
var topPoint = {x:this.r,y:this.circleDistance};
var leftPoint = {x:this.r - withinR * Math.sin(Math.PI / 3),y:this.r + withinR * Math.cos(Math.PI / 3)};
var rightPoint = {x:this.r + withinR * Math.sin(Math.PI / 3),y:this.r + withinR * Math.cos(Math.PI / 3)};
this.upTrianglePoints = [topPoint,leftPoint,rightPoint];
}
//计算小圆内倒内接三角形各个坐标点
magic.withinDownTrianglePoints = function(){
var withinR = this.r - this.circleDistance;
var downPoint = {x:this.r,y:this.r * 2 - this.circleDistance};
var leftPoint = {x:this.r - withinR * Math.sin(Math.PI / 3),y:this.r - withinR * Math.cos(Math.PI / 3)};
var rightPoint = {x:this.r + withinR * Math.sin(Math.PI / 3),y:this.r - withinR * Math.cos(Math.PI / 3)};
this.downTrianglePoints = [leftPoint,rightPoint,downPoint];
}
//三角形变换任务队列
magic.drawTriangleQueue = function(time,queue){
if(this.xDeg == 70){
//小六边形升起
this.smallCanvasPositionAddY += 0.2;
this.smallCanvasScaleReduce -= 0.001;
var smallDiv = document.getElementById('small');
smallDiv.style['-webkit-transform'] = 'translateZ(50px) rotateX('+ this.xDeg +'deg) ' + 'scale('+ this.smallCanvasScaleReduce +') skew(0deg, 0deg) translate(0px, 0px)';
smallDiv.style['margin-top'] = (100 - this.smallCanvasPositionAddY) + 'px';
if(this.smallCanvasPositionAddY >= 80) {
window.clearInterval(time);
}
return;
}
if(this.drawTriangleDrawSideIndex == queue.length){
//绘制完成倾斜角度
var mainDiv = document.getElementById('main');
var smallDiv = document.getElementById('small');
//显示小六边形
smallDiv.style['opacity'] = '1';
this.xDeg += 1;
mainDiv.style['-webkit-transform'] = 'translateZ(50px) rotateX('+ this.xDeg + 'deg)';
smallDiv.style['-webkit-transform'] = 'translateZ(50px) rotateX('+ this.xDeg + 'deg)';
return;
}
//绘制三角形各个边
this.triangleDrawSidePercent += 0.01;
var callBack = queue[this.drawTriangleDrawSideIndex];
callBack();
if(this.triangleDrawSidePercent >= 1){
this.triangleDrawSidePercent = 0;
this.drawTriangleDrawSideIndex += 1;
}
}
//定时任务
magic.timingTask = function(){
var that = this;
var time = window.setInterval(function() {
//圆绘制
if(that.outsideAngle < 360){
that.outsideAngle += 0.2;
that.withinAngle -= 0.2;
}
that.drawCircle(that.center,that.r,0,that.outsideAngle,false);
that.drawCircle(that.center,that.r - that.circleDistance,270,that.withinAngle,true);
if(that.outsideAngle >= 360){
//三角形绘制任务队列
that.drawTriangleQueue(time,[
function(){
that.drawLine(that.downTrianglePoints[0],that.downTrianglePoints[1],that.triangleDrawSidePercent);
},
function(){
that.drawLine(that.downTrianglePoints[1],that.downTrianglePoints[2],that.triangleDrawSidePercent);
},
function(){
that.drawLine(that.downTrianglePoints[2],that.downTrianglePoints[0],that.triangleDrawSidePercent);
},
function(){
that.drawLine(that.upTrianglePoints[0],that.upTrianglePoints[1],that.triangleDrawSidePercent);
},
function(){
that.drawLine(that.upTrianglePoints[1],that.upTrianglePoints[2],that.triangleDrawSidePercent);
},
function(){
that.drawLine(that.upTrianglePoints[2],that.upTrianglePoints[0],that.triangleDrawSidePercent);
}
]);
}
},5);
}
window.$magic = magic;
})(window)
四、总结与思考
1、定时器全局只有一个,处理不同绘制阶段。
2、计算内圆的两个内接三角形的各个顶点,依次加到任务队列去执行,全部绘制完成,停止任务定时器。
3、绘制过程中加上抗锯齿逻辑,绘制更平滑。
仅为随笔交流,大神勿笑[抱拳][抱拳][抱拳]