canvas.uvue 4.2 KB
Newer Older
X
xty 已提交
1 2 3 4 5 6
<template>
    <view class="page-body">
        <canvas canvas-id="canvas" id="canvas" class="canvas"></canvas>
    </view>
</template>

雪洛's avatar
雪洛 已提交
7
<script setup>
X
xty 已提交
8 9 10 11 12 13 14 15 16
    class Ball {
		private canvasWidth : number
        private canvasHeight : number
        private ctx : CanvasRenderingContext2D
        private x : number
        private y : number
        private vx : number
        private vy : number
        private radius : number = 5
X
xty 已提交
17
		private devicePixelRatio: Number
X
xty 已提交
18

X
xty 已提交
19
		constructor(x: number, y: number, vx: number, vy: number, ctx: CanvasRenderingContext2D, devicePixelRatio: number){
X
xty 已提交
20 21 22 23 24 25 26
			this.ctx = ctx
			this.canvasWidth = ctx.canvas.width
			this.canvasHeight = ctx.canvas.height
			this.x = x
			this.y = y
			this.vx = vx
			this.vy = vy
X
xty 已提交
27 28
			this.devicePixelRatio = devicePixelRatio
			this.radius *= this.devicePixelRatio
X
xty 已提交
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
		}

		draw() {
		    this.ctx.fillStyle = '#007AFF'
		    this.ctx.beginPath()
		    this.ctx.arc(this.x, this.y, this.radius, 0, 2 * Math.PI)
		    this.ctx.closePath()
		    this.ctx.fill()
		}

		move() {
		    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)
		    }
		}
    }

	class BallAnimation {
		private ctx : CanvasRenderingContext2D
		private ballList : Array<Ball> = []
		private speed = 3
		private layer = 3
		private ballInlayer = 20
		private interval : number = 0
X
xty 已提交
74
		constructor(ctx : CanvasRenderingContext2D, devicePixelRatio: Number){
X
xty 已提交
75
			this.ctx = ctx
X
xty 已提交
76 77
			this.speed *= devicePixelRatio
			this.initBall(devicePixelRatio)
X
xty 已提交
78 79 80 81 82 83
		}

		private getDistance(x: number, y: number) : number{
		    return Math.pow((Math.pow(x, 2) + Math.pow(y, 2)), 0.5)
		}

X
xty 已提交
84
		private initBall(devicePixelRatio: Number) {
X
xty 已提交
85 86 87
			let canvasWidth = this.ctx.canvas.width,
			    canvasHeight = this.ctx.canvas.height
			for (let i = 0; i < this.layer; i++) {
X
xty 已提交
88
			    let radius = this.getDistance(canvasWidth / 2, canvasHeight / 2) / this.layer * i
X
xty 已提交
89
			    for (let j = 0; j < this.ballInlayer; j++) {
X
xty 已提交
90
			        let deg = j * 2 * Math.PI / this.ballInlayer,
X
xty 已提交
91 92 93 94 95 96
			            sin = Math.sin(deg),
			            cos = Math.cos(deg),
			            x = radius * cos + canvasWidth / 2,
			            y = radius * sin + canvasHeight / 2,
			            vx = this.speed * cos,
			            vy = this.speed * sin
X
xty 已提交
97
			        this.ballList.push(new Ball(x, y, vx, vy, this.ctx, devicePixelRatio))
X
xty 已提交
98 99 100 101 102 103
			    }
			}
		}

		private animate(ballList: Array<Ball>) {
		    this.ctx.clearRect(0, 0, this.ctx.canvas.width,  this.ctx.canvas.height )
X
xty 已提交
104
		    this.ballList.forEach(function(item) {
X
xty 已提交
105 106 107
		        item.move()
		        item.draw()
		    })
X
xty 已提交
108
		    this.ctx.draw()
X
xty 已提交
109 110 111 112 113
		}

		start(){
			//Todo.. requestAnimationFrame
			clearInterval(this.interval)
X
xty 已提交
114 115
			this.interval = setInterval(()=> {
			    this.animate(this.ballList)
X
xty 已提交
116 117 118 119 120 121 122 123 124
			}, 17)
		}
		stop(){
			clearInterval(this.interval)
		}
	}

	var animation : BallAnimation|null = null
	onReady(() => {
X
xty 已提交
125 126
		const res = uni.getDeviceInfo();
		const devicePixelRatio = res.devicePixelRatio !== null ? res.devicePixelRatio! : 1
X
xty 已提交
127 128 129
		let canvas = uni.getElementById("canvas") as UniCanvasElementImpl
	    let canvasContext = canvas.getContext("2d");
		if(canvasContext != null) {
X
xty 已提交
130
			animation = new BallAnimation(canvasContext, devicePixelRatio)
X
xty 已提交
131 132 133 134 135 136 137 138 139 140
			animation?.start()
		} else {
			console.log("canvas.getContext error!!")
		}
	})

	onUnload(()=> {
	    animation?.stop()
		animation = null
	})
X
xty 已提交
141
	onPageShow(()=>{
X
xty 已提交
142 143 144
		animation?.start()
	})

145
	onPageHide(()=>{
X
xty 已提交
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
		animation?.stop()
	})

</script>

<style>
    .page-body-wrapper {
        text-align: center;
    }

    .canvas {
        width: 610rpx;
        height: 610rpx;
        margin: auto;
        background-color: #fff;
    }
</style>