Files
sociology_app/pages/component/canvas/canvas.vue
2025-03-12 11:39:31 +08:00

275 lines
6.8 KiB
Vue

<template>
<view>
<page-head :title="title"></page-head>
<view class="page-body">
<view class="page-body-wrapper">
<!-- #ifdef APP-PLUS || H5 -->
<canvas
canvas-id="canvas"
class="canvas"
:start="startStatus"
:change:start="animate.start"
:data-width="canvasWidth"
:data-height="canvasWidth"
></canvas>
<!-- #endif -->
<!-- #ifndef APP-PLUS || H5 -->
<canvas canvas-id="canvas" id="canvas" class="canvas"></canvas>
<!-- #endif -->
</view>
</view>
</view>
</template>
<script module="animate" lang="renderjs">
function Ball({
x,
y,
vx,
vy,
canvasWidth,
canvasHeight,
ctx
}) {
this.canvasWidth = canvasWidth
this.canvasHeight = canvasHeight
this.ctx = ctx
this.x = x
this.y = y
this.vx = vx
this.vy = vy
this.radius = 5
}
Ball.prototype.draw = function() {
this.ctx.beginPath()
this.ctx.fillStyle = '#007AFF'
this.ctx.arc(this.x, this.y, this.radius, 0, 2 * Math.PI)
this.ctx.closePath()
this.ctx.fill()
}
Ball.prototype.move = function() {
this.x += this.vx
this.y += this.vy
// 回到中心
// if (getDistance(this.x - this.canvasWidth / 2, this.y - this.canvasHeight / 2) >
// getDistance(this.canvasWidth / 2, this.canvasHeight / 2) + this.radius) {
// this.x = this.canvasWidth / 2
// this.y = this.canvasHeight / 2
// }
// 边框反弹
if (this.x < this.radius) {
this.vx = Math.abs(this.vx)
return
}
if (this.x > this.canvasWidth - this.radius) {
this.vx = -Math.abs(this.vx)
}
if (this.y < this.radius) {
this.vy = Math.abs(this.vy)
return
}
if (this.y > this.canvasWidth - this.radius) {
this.vy = -Math.abs(this.vy)
}
}
function getDistance(x, y) {
return Math.pow(Math.pow(x, 2) + Math.pow(y, 2), 0.5)
}
export default {
methods: {
start(newVal, oldVal, owner, ins) {
let canvasWidth = ins.getDataset().width,
canvasHeight = ins.getDataset().height,
canvasEle = document.querySelectorAll('.canvas>canvas')[0],
ctx = canvasEle.getContext('2d'),
speed = 3,
ballList = [],
layer = 3,
ballInlayer = 20
for (let i = 0; i < layer; i++) {
let radius = getDistance(canvasWidth / 2, canvasHeight / 2) / layer * i
for (let j = 0; j < ballInlayer; j++) {
let deg = j * 2 * Math.PI / ballInlayer,
sin = Math.sin(deg),
cos = Math.cos(deg),
x = radius * cos + canvasWidth / 2,
y = radius * sin + canvasHeight / 2,
vx = speed * cos,
vy = speed * sin
ballList.push(new Ball({
x,
y,
vx,
vy,
canvasWidth,
canvasHeight,
ctx,
radius: 5
}))
}
}
function animate(ballList) {
ctx.clearRect(0, 0, canvasEle.width, canvasEle.height)
ballList.forEach(function(item) {
item.move()
item.draw()
})
requestAnimationFrame(function() {
animate(ballList)
})
}
animate(ballList)
}
}
}
</script>
<script>
// #ifndef APP-PLUS || H5
let ctx = null,
interval = null;
function Ball(x, y, vx, vy, canvasWidth, canvasHeight, ctx) {
this.canvasWidth = canvasWidth;
this.canvasHeight = canvasHeight;
this.ctx = ctx;
this.x = x;
this.y = y;
this.vx = vx;
this.vy = vy;
this.radius = 5;
}
Ball.prototype.draw = function () {
this.ctx.setFillStyle("#007AFF");
this.ctx.beginPath();
this.ctx.arc(this.x, this.y, this.radius, 0, 2 * Math.PI);
this.ctx.closePath();
this.ctx.fill();
};
Ball.prototype.move = function () {
this.x += this.vx;
this.y += this.vy;
// 回到中心
// if (getDistance(this.x - this.canvasWidth / 2, this.y - this.canvasHeight / 2) >
// getDistance(this.canvasWidth / 2, this.canvasHeight / 2) + this.radius) {
// this.x = this.canvasWidth / 2
// this.y = this.canvasHeight / 2
// }
// 边框反弹
if (this.x < this.radius) {
this.vx = Math.abs(this.vx);
return;
}
if (this.x > this.canvasWidth - this.radius) {
this.vx = -Math.abs(this.vx);
}
if (this.y < this.radius) {
this.vy = Math.abs(this.vy);
return;
}
if (this.y > this.canvasWidth - this.radius) {
this.vy = -Math.abs(this.vy);
}
};
function getDistance(x, y) {
return Math.pow(Math.pow(x, 2) + Math.pow(y, 2), 0.5);
}
// #endif
export default {
data() {
return {
title: "canvas",
canvasWidth: 0,
startStatus: false,
ballList: [],
};
},
onReady: function () {
this.$nextTick(() => {
uni
.createSelectorQuery()
.select(".canvas")
.boundingClientRect((data) => {
this.canvasWidth = data.width;
// #ifdef APP-PLUS || H5
this.startStatus = true;
// #endif
// #ifndef APP-PLUS || H5
ctx = uni.createCanvasContext("canvas");
this.drawBall();
// #endif
})
.exec();
});
},
// #ifndef APP-PLUS || H5
onUnload: function () {
clearInterval(interval);
},
methods: {
drawBall: function () {
let canvasWidth = this.canvasWidth,
canvasHeight = this.canvasWidth,
speed = 3,
ballList = [],
layer = 3,
ballInlayer = 20;
for (let i = 0; i < layer; i++) {
let radius =
(getDistance(canvasWidth / 2, canvasHeight / 2) / layer) * i;
for (let j = 0; j < ballInlayer; j++) {
let deg = (j * 2 * Math.PI) / ballInlayer,
sin = Math.sin(deg),
cos = Math.cos(deg),
x = radius * cos + canvasWidth / 2,
y = radius * sin + canvasHeight / 2,
vx = speed * cos,
vy = speed * sin;
ballList.push(new Ball(x, y, vx, vy, canvasWidth, canvasHeight, ctx));
}
}
function animate(ballList) {
// ctx.clearRect(0, 0, canvasWidth, canvasHeight)
ballList.forEach(function (item) {
item.move();
item.draw();
});
ctx.draw();
}
interval = setInterval(function () {
animate(ballList);
}, 17);
},
},
// #endif
};
</script>
<style>
.page-body-wrapper {
text-align: center;
}
.canvas {
width: 610rpx;
height: 610rpx;
margin: auto;
background-color: #fff;
}
</style>