1.效果预览
动画.gif2.实现思路
1.绘制一颗星星,让这颗星星在画布中运动
2.在画布中绘制一组星星,每颗星星都在画布中运动
3.当星星之间的距离小于某个数值时进行连线
4.当鼠标点击画布时,新增5颗星星到画布中
5.鼠标移入画布时,在鼠标处新建一颗星星,跟随鼠标移动
3.实现代码
1.画布设置
- 新建画布
<div class="star_content">
<canvas id="star_canvas" ref="star_canvas"></canvas>
</div>
- 给画布设置背景,也可以选择图片背景
#star_canvas {
background-color: #333333;
}
- 设置画布大小,获取上下文对象
const star_canvas = ref<HTMLCanvasElement>();
star_canvas.value!.width = 1000;
star_canvas.value!.height = 800;
let ctx: CanvasRenderingContext2D;
ctx = star_canvas.value!.getContext("2d") as CanvasRenderingContext2D;
- 清空画布
ctx.clearRect(0, 0, 1000, 800);
- 设置画笔的边缘和填充颜色
ctx.fillStyle = "white";
ctx.strokeStyle = "white";
2.绘制单个移动的星星
- 每个星星的结构包含坐标、星星半径和移动速度
interface Star {
x: number;
y: number;
r: number;
speedX: number;
speedY: number;
}
- 星星的坐标、半径和移动速度都随机生成
const randomSpeed = () => {
return Math.random() * 3 * Math.pow(-1, Math.round(Math.random()));
};
- 生成一颗星星
const generateStar = () => {
const star: Star = {
x: 0,
y: 0,
r: 0,
speedX: 0,
speedY: 0,
};
star.x = Math.random() * 1000;
star.y = Math.random() * 800;
star.r = Math.random() * 5;
star.speedX = randomSpeed();
star.speedY = randomSpeed();
return star;
};
let star = generateStar();
- 将星星绘制在画布上
const Draw = (ctx: CanvasRenderingContext2D, star: Star) => {
ctx.beginPath();
ctx.arc(star.x, star.y, star.r, 0, Math.PI * 2);
ctx.fill();
ctx.closePath();
};
Draw(ctx, star);
- 使星星移动,碰到画布边缘时,改变星星的移动方向
const Move = (star: Star) => {
star.x -= star.speedX;
star.y -= star.speedY;
if (star.x < 0 || star.x > 1000) {
star.speedX *= -1;
}
if (star.y < 0 || star.y > 800) {
star.speedY *= -1;
}
};
let timer;
timer = setInterval(() => {
ctx.clearRect(0, 0, 1000, 800);
Draw(ctx, star);
Move(star);
}, 50);
3.绘制一组星星,在画布中移动
let starArr: Star[] = [];
for (let i = 0; i < 20; i++) {
let star = generateStar();
starArr.push(star);
}
timer = setInterval(() => {
ctx.clearRect(0, 0, 1000, 800);
starArr.forEach((star: Star) => {
Draw(ctx, star);
Move(star);
});
}, 50);
4.判断星星之间的距离,进行连线
- 两颗星星进行连线
const DrawLine = (startX: number, startY: number, endX: number, endY: number, ctx: CanvasRenderingContext2D) => {
ctx.beginPath();
ctx.moveTo(startX, startY);
ctx.lineTo(endX, endY);
ctx.stroke();
ctx.closePath();
};
- 判断距离
starArr.forEach((star: Star, index: number) => {
for (let i = index + 1; i < starArr.length; i++) {
if (Math.abs(star.x - starArr[i].x) < 50 && Math.abs(star.y - starArr[i].y) < 50) {
DrawLine(star.x, star.y, starArr[i].x, starArr[i].y, ctx);
}
}
});
5.点击添加星星和鼠标星星跟随
- 点击添加星星
star_canvas.value!.onclick = e => {
for (let i = 0; i < 5; i++) {
let star = generateStar();
star.x = e.offsetX;
star.y = e.offsetY;
starArr.push(star);
}
};
- 鼠标跟随
const mouse_star = generateStar();
mouse_star.speedX = 0;
mouse_star.speedY = 0;
star_canvas.value!.onmousemove = e => {
mouse_star.x = e.offsetX;
mouse_star.y = e.offsetY;
};
timer = setInterval(() => {
ctx.clearRect(0, 0, 1000, 800);
// 鼠标star移动
Draw(ctx, mouse_star);
// star移动
starArr.forEach((star: Star) => {
Draw(ctx, star);
Move(star);
});
// 比较star和所有其他star的距离,小于50连线
starArr.forEach((star: Star, index: number) => {
for (let i = index + 1; i < starArr.length; i++) {
if (Math.abs(star.x - starArr[i].x) < 50 && Math.abs(star.y - starArr[i].y) < 50) {
DrawLine(star.x, star.y, starArr[i].x, starArr[i].y, ctx);
}
}
});
// 比较鼠标star和所有star的距离
for (let i = 0; i < starArr.length; i++) {
if (Math.abs(mouse_star.x - starArr[i].x) < 50 &&
Math.abs(mouse_star.y - starArr[i].y) < 50) {
DrawLine(mouse_star.x, mouse_star.y, starArr[i].x,
starArr[i].y, ctx);
}
}
}, 50);
- 离开页面前清除定时器
onBeforeUnmount(() => {
clearInterval(timer);
});
3.全部代码
- index.vue
<template>
<div class="star_content">
<canvas id="star_canvas" ref="star_canvas"></canvas>
</div>
</template>
<script setup lang="ts">
import { onBeforeUnmount, onMounted, ref } from "vue";
import { Star, Move, Draw, DrawLine, generateStar } from "./index";
const star_canvas = ref<HTMLCanvasElement>();
let ctx: CanvasRenderingContext2D;
let timer: any;
const initStar = () => {
ctx = star_canvas.value!.getContext("2d") as CanvasRenderingContext2D;
ctx.fillStyle = "white";
ctx.strokeStyle = "white";
let starArr: Star[] = [];
for (let i = 0; i < 20; i++) {
let star = generateStar();
starArr.push(star);
}
// 鼠标star
const mouse_star = generateStar();
mouse_star.speedX = 0;
mouse_star.speedY = 0;
// 鼠标star跟随移动
star_canvas.value!.onmousemove = e => {
mouse_star.x = e.offsetX;
mouse_star.y = e.offsetY;
};
timer = setInterval(() => {
ctx.clearRect(0, 0, 1000, 800);
// 鼠标star移动
Draw(ctx, mouse_star);
// star移动
starArr.forEach((star: Star) => {
Draw(ctx, star);
Move(star);
});
// 比较star和所有其他star的距离,小于50连线
starArr.forEach((star: Star, index: number) => {
for (let i = index + 1; i < starArr.length; i++) {
if (Math.abs(star.x - starArr[i].x) < 50 && Math.abs(star.y - starArr[i].y) < 50) {
DrawLine(star.x, star.y, starArr[i].x, starArr[i].y, ctx);
}
}
});
// 比较鼠标star和所有star的距离
for (let i = 0; i < starArr.length; i++) {
if (Math.abs(mouse_star.x - starArr[i].x) < 50 && Math.abs(mouse_star.y - starArr[i].y) < 50) {
DrawLine(mouse_star.x, mouse_star.y, starArr[i].x, starArr[i].y, ctx);
}
}
}, 50);
// 点击添加star
star_canvas.value!.onclick = e => {
for (let i = 0; i < 5; i++) {
let star = generateStar();
star.x = e.offsetX;
star.y = e.offsetY;
starArr.push(star);
}
};
};
const initCanvas = () => {
ctx = star_canvas.value?.getContext("2d") as CanvasRenderingContext2D;
star_canvas.value!.width = 1000;
star_canvas.value!.height = 800;
initStar();
};
onMounted(() => {
initCanvas();
});
onBeforeUnmount(() => {
clearInterval(timer);
});
</script>
<style lang="less" scoped>
#star_canvas {
background-color: #333333;
}
</style>
- index.ts
export interface Star {
x: number;
y: number;
r: number;
speedX: number;
speedY: number;
}
export const generateStar = () => {
const star: Star = {
x: 0,
y: 0,
r: 0,
speedX: 0,
speedY: 0,
};
star.x = Math.random() * 1000;
star.y = Math.random() * 800;
star.r = Math.random() * 5;
star.speedX = randomSpeed();
star.speedY = randomSpeed();
return star;
};
export const randomSpeed = () => {
return Math.random() * 3 * Math.pow(-1, Math.round(Math.random()));
};
export const Draw = (ctx: CanvasRenderingContext2D, star: Star) => {
ctx.beginPath();
ctx.arc(star.x, star.y, star.r, 0, Math.PI * 2);
ctx.fill();
ctx.closePath();
};
export const Move = (star: Star) => {
star.x -= star.speedX;
star.y -= star.speedY;
if (star.x < 0 || star.x > 1000) {
star.speedX *= -1;
}
if (star.y < 0 || star.y > 800) {
star.speedY *= -1;
}
};
export const DrawLine = (startX: number, startY: number, endX: number, endY: number, ctx: CanvasRenderingContext2D) => {
ctx.beginPath();
ctx.moveTo(startX, startY);
ctx.lineTo(endX, endY);
ctx.stroke();
ctx.closePath();
};
网友评论