效果图:
<template>
<div class="home-box">
<canvas id="canvas" />
<div class="lightCircle" ref="circleRef" v-for="(item,index) in 5" :key="index"></div>
<div class="lightCircle" ref="circleRef2" v-for="(item,index) in 5" :key="index + '1'"></div>
<div :class="'lightCircle2 lightCircle2'+index" ref="circleRef3" v-for="(item,index) in 5" :key="index + '2'"></div>
<div ref="circle0" class="circle circle0">
<span class="chi">一级菜单</span>
</div>
<div ref="circle1" class="circle circle1">
<span class="chi">二级菜单1</span>
</div>
<div ref="circle2" class="circle circle2">
<span class="chi">二级菜单2</span>
</div>
<div ref="circle3" class="circle circle3">
<span class="chi">二级菜单3</span>
</div>
<div ref="circle4" class="circle circle4">
<span class="chi">二级菜单4</span>
</div>
<div ref="circle5" class="circle circle5">
<span class="chi">二级菜单5</span>
</div>
</div>
</template>
<script>
export default {
name: "homePage",
data () {
return {
resizeTimer: null,
}
},
mounted () {
this.initCanvas();
},
methods: {
initCanvas () {
let that = this;
let canvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d");
this.canvasResize(canvas, ctx);
window.onresize = function () {
setTimeout(() => {
that.canvasResize(canvas, ctx, 1);
}, 500)
}
},
canvasResize (canvas, ctx, flag) {
canvas.width = canvas.offsetWidth;
canvas.height = canvas.offsetHeight;
this.createLine(canvas, ctx, flag);//画线
},
createLine (canvas, ctx, flag) {
let that = this;
let { circle0, circle1, circle2, circle3, circle4, circle5 } = this.$refs,//offsetLeft依次对应 圆心,左上角
r0 = circle0.offsetWidth / 2,
r1 = circle1.offsetWidth / 2,
dig0 = Math.PI / 9,//20度
dig1 = Math.PI / 6,//30度
dig3 = Math.PI / 3,//60度
dig4 = Math.PI / 18,//10度
dig5 = Math.PI * 11 / 36,//55度
// console.log(Math.sin(Math.PI/2));//等于1,Math.PI代表180度
//五环上的坐标
valueArr1 = [
{//value1
x: circle1.offsetLeft + r1 + r1 * Math.cos(dig1),
y: circle1.offsetTop + r1 + r1 * Math.sin(dig1),
},
{//value2
x: circle2.offsetLeft + r1 - r1 * Math.sin(dig3),
y: circle2.offsetTop + r1 + r1 * Math.cos(dig3),
},
{//value3
x: circle3.offsetLeft,
y: circle3.offsetTop + r1,
},
{//value4
x: circle4.offsetLeft + r1 - r1 * Math.sin(dig1),
y: circle4.offsetTop + r1 - r1 * Math.cos(dig1),
},
{//value5
x: circle5.offsetLeft + r1 + r1 * Math.cos(dig0),
y: circle5.offsetTop + r1 - r1 * Math.sin(dig0),
},
],
//圆心上的坐标
valueArr0 = [
{//对应value1
x: circle0.offsetLeft - r0 * Math.cos(dig0),
y: circle0.offsetTop - r0 * Math.sin(dig0),
},
{//对应value2
x: circle0.offsetLeft + r0 * Math.cos(dig1),
y: circle0.offsetTop - r0 * Math.sin(dig1),
},
{//对应value3
x: circle0.offsetLeft + r0 * Math.cos(dig4),
y: circle0.offsetTop + r0 * Math.sin(dig4),
},
{//对应value4
x: circle0.offsetLeft + r0 * Math.cos(dig5),
y: circle0.offsetTop + r0 * Math.sin(dig5),
},
{//对应value5
x: circle0.offsetLeft - r0 * Math.cos(dig0),
y: circle0.offsetTop + r0 * Math.sin(dig0),
},
];
clear();
createCircle(flag);
for (let i = 0; i < valueArr1.length; i++) {
drawDynamicLine(valueArr1[i].x, valueArr1[i].y, valueArr0[i].x, valueArr0[i].y);
}
/*清除画布*/
function clear () {
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
/*画点*/
function createCircle (flag) {
ctx.fillStyle = "#01abf9";
let style = document.styleSheets[0];//keyframes
if (flag == 1) {
//自适应拖动屏幕时,删除keyframes样式
for (let j = 0; j < valueArr1.length; j++) {
style.deleteRule("Mylight" + j);
}
}
for (let i = 0; i < valueArr1.length; i++) {
that.$nextTick(() => {
if (that.$refs.circleRef[i]) {
that.$refs.circleRef[i].style.left = valueArr1[i].x - 1 + 'px';
that.$refs.circleRef[i].style.top = valueArr1[i].y - 1 + 'px';
}
if (that.$refs.circleRef2[i]) {
that.$refs.circleRef2[i].style.left = valueArr0[i].x - 1 + 'px';
that.$refs.circleRef2[i].style.top = valueArr0[i].y - 1 + 'px';
}
// 写入keyframes样式
style.insertRule(`@keyframes Mylight${i}{
0% { left:${that.$refs.circleRef[i].style.left};top:${that.$refs.circleRef[i].style.top}}
90%{ opacity:1}
100%{left:${that.$refs.circleRef2[i].style.left};opacity:0;top:${that.$refs.circleRef2[i].style.top};}
}`, 1);
})
}
ctx.shadowBlur = 2;//Reseting the blur
}
/*
绘制两点直线
画动态直线
@(x1,y1) 起点
@(x2,y2) 终点
*/
function drawDynamicLine (x1, y1, x2, y2) {
const x22 = x2;
const y22 = y2;
if (x1 == x2) {
drawVerticalLine(x1, y1, x2, y2); /*斜率不存在的情况*/
} else {
drawCommonLine(x1, y1, x2, y2); /*斜率为正或者负或者0*/
}
/*k存在的情况*/
function drawCommonLine (x1, y1, x2, y2) {
let timer1 = null;
clearInterval(timer1);
//y=kx+b
let k = (y2 - y1) / (x2 - x1) //斜率k 正 负 0
let b = y1 - k * x1 //常数b
let i = 0;
let flag = compare(x1, x2);
function draw () {
let xi = x1 + i;
let yi = k * xi + b;
let xj = x1 + i + 20; //控制步长决定绘制的是虚线还是实线
let yj = k * xj + b;
//最后一段 线段的步长缝合
if (xj + 20 > x22 || yj + 20 > y22) {
let a = x22 + 20 - xj;
xj = x1 + i + a;
yj = k * xj + b;
// console.log(1,xj,yj,x22,y22);
drawLine(xi, yi, xj, yj);
return
}
drawLine(xi, yi, xj, yj);
i += 20 * flag;
if (Math.abs(i) <= Math.abs(x1 - x2)) {
timer1 = window.setTimeout(function () {
draw();
}, 50);
}
}
draw();
}
/*k不存在,也就是垂直的情况*/
function drawVerticalLine (x1, y1, x2, y2) {
let timer2 = null;
clearInterval(timer2);
let i = 0;
let flag = compare(y1, y2);
function draw () {
let yi = y1 + i;
let yj = y1 + i + 5 * flag;
drawLine(x1, yi, x2, yj);
i += 20 * flag;
if (Math.abs(i) <= Math.abs(y1 - y2)) {
timer2 = window.setTimeout(function () {
draw();
}, 50);
}
}
draw();
}
/*比较函数*/
function compare (a, b) {
if (a < b) {
return 1;
} else {
return -1;
}
}
/*线条片段*/
function drawLine (x1, y1, x2, y2) {
//线条发光
ctx.shadowColor = "#fff";
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
ctx.shadowBlur = 15;
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.lineWidth = 2;
ctx.strokeStyle = "#01bbf3";//线条颜色
ctx.stroke();
ctx.closePath();
ctx.fill();
}
}
}
}
}
</script>
<style scoped lang="less">
.home-box {
width: 100%;
height: 100%;
color: #ffffff;
font-size: 32px;
font-weight: 600;
line-height: 38px;
position: relative;
background: #f2f2f2;
canvas {
width: 100%;
height: 100%;
position: absolute;
}
span.chi {
width: 90px;
text-align: center;
height: auto;
animation: none;
}
.circle {
width: 250px;
height: 250px;
display: flex;
justify-content: center;
align-items: center;
position: absolute;
cursor: pointer;
&.circle0 {
width: 360px;
height: 360px;
left: 50%;
top: 45%;
transform: translateX(-50%) translateY(-50%);
.chi {
width: 130px;
text-align: center;
height: 92px;
font-size: 30px;
font-family: PingFangSC-Semibold, PingFang SC;
font-weight: 600;
color: rgba(181, 232, 255, 1);
line-height: 46px;
text-shadow: 0px 0px 2px rgba(137, 218, 255, 1);
}
}
&.circle1 {
left: 22%;
top: 8%;
}
&.circle2 {
left: 63%;
top: 5%;
}
&.circle3 {
left: 77%;
top: 35%;
}
&.circle4 {
overflow: hidden;
left: 55%;
top: 69%;
}
&.circle5 {
left: 10%;
top: 55%;
}
}
}
.lightCircle {
position: absolute;
width: 5px;
height: 5px;
border-radius: 200%;
background-color: #01abf9;
box-shadow: 0 0 10px 8px #01abf9;
}
.lightCircle2 {
display: none\0;
position: absolute;
width: 5px;
height: 5px;
border-radius: 50%;
background-color: #01abf9;
box-shadow: 0 0 20px 10px #01abf9;
&.lightCircle20 {
animation: Mylight0 5s infinite forwards;
}
&.lightCircle21 {
animation: Mylight1 5s infinite forwards;
}
&.lightCircle22 {
animation: Mylight2 5s infinite forwards;
}
&.lightCircle23 {
animation: Mylight3 5s infinite forwards;
}
&.lightCircle24 {
animation: Mylight4 5s infinite forwards;
}
}
</style>