console
window.onload = function () {
var fpsEle = document.getElementById('fps')
var inputWord = document.getElementById('input-word')
var btnGenerate = document.getElementById('btn-generate')
var fontSize = 180
var canvas = document.getElementById('particle_canvas')
var CANVAS_WIDTH = 600
var CANVAS_HEIGHT = 300
canvas.width = CANVAS_WIDTH
canvas.height = CANVAS_HEIGHT
var ctx = canvas.getContext('2d')
ctx.font = 'bold ' + fontSize + 'px Microsoft YaHei'
ctx.fillStyle = 'blue'
ctx.textAlign = 'left'
ctx.textBaseline = 'top'
var circleList
var colors = [
'#a09d1d',
'#84b826',
'#168a30',
'#155fbf',
'#40148c',
'#5f168b',
'#93148c',
'#970c0d',
'#af2e15',
'#ab4913',
'#a45a12',
'#514e0e',
]
var Circle = function (targetX, targetY, curX, curY) {
this.targetX = targetX
this.targetY = targetY
this.x = curX || targetX
this.y = curY || targetY
this.color = colors[Math.floor(Math.random() * colors.length)]
var _speed = 0.1
this.done = false
this.update = function () {
if (Math.abs(this.targetX - this.x) >= 0.05 || Math.abs(this.targetY - this.y) >= 0.05) {
this.x += (this.targetX - this.x) * _speed
this.y += (this.targetY - this.y) * _speed
}
else {
this.done = true
}
this.render()
}
this.render = function () {
Circle.ctx.save()
Circle.ctx.fillStyle = this.color
Circle.ctx.beginPath()
Circle.ctx.arc(this.x, this.y, Circle.radius, 0, 2 * Math.PI, false)
Circle.ctx.fill()
Circle.ctx.restore()
}
}
Circle.ctx = ctx
Circle.diameter = 6
Circle.radius = Circle.diameter / 2
Circle.space = 2
function generate (word) {
var wordWidth = ctx.measureText(word).width
var wordPosition = {
x: (CANVAS_WIDTH - wordWidth) / 2,
y: 0
}
ctx.clearRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT)
ctx.fillText(word, wordPosition.x, wordPosition.y)
var imageData = new Uint32Array(ctx.getImageData(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT).data.buffer)
var i, j
!circleList && (circleList = [])
var totalCount = 0
var circle
for (i = 0; i < CANVAS_HEIGHT; i += Circle.diameter + Circle.space) {
for (j = 0; j < CANVAS_WIDTH; j += Circle.diameter + Circle.space) {
if (!!imageData[i * CANVAS_WIDTH + j]) {
if (totalCount < circleList.length) {
circle = circleList[totalCount]
circle.targetX = j
circle.targetY = i
circle.done = false
}
else {
circleList.push(new Circle(j, i, wordPosition.x + Math.random() * wordWidth, Math.random() * 200))
}
totalCount++
}
}
}
circleList = circleList.slice(0, totalCount - 1)
tick(true)
}
var doneCount = 0
function updateAll () {
ctx.clearRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT)
doneCount = 0
for (var i = 0; i < circleList.length; i++) {
circleList[i].update()
circleList[i].done && doneCount++
}
doneCount === circleList.length && (rendering = false)
}
var rendering = true
var last = Date.now()
var now
var delta
var fps
var tick = function (forceRender) {
forceRender === true && (rendering = true)
if (!rendering) return false
now = Date.now()
delta = now - last
last = now
updateAll()
fps = Math.floor((1000 / delta))
fpsEle.innerHTML = fps
requestAnimationFrame(tick)
}
generate('start!')
btnGenerate.onclick = function (e) {
generate(inputWord.value)
}
}
<p id="fps"></p>
<canvas id="particle_canvas"></canvas>
<input type="text" placeholder="输入文字" id="input-word"/>
<button id="btn-generate">生成</button>
* {
padding: 0;
margin: 0;
}
html, body {
width: 100%;
height: 100%;
}
body {
background-color: #eee;
}
canvas {
display: block;
border: 1px solid #ccc;
box-sizing: border-box;
}