<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>粒子的时钟</title>
<style>
* {
margin:0;
outline:none;
padding:0;
}
body {
background:#000;
font-family:'Lucida Grande','Helvetica','Arial';
font-size:10px;
overflow:hidden;
}
canvas {
background:#222;
cursor:default;
z-index:1;
}
.nope {
color:#fff;
text-align:center;
margin-top:150px;
}
header {
position:relative;
text-shadow:1px 1px 0px rgba(0,0,0,0.5);
text-transform:uppercase;
width:100%;
z-index:10;
}
#about {
color:#fff;
color:rgba(255,255,255,0.5);
display:block;
float:right;
margin:20px;
text-align:right;
width:50%;
}
h1 {
color:rgba(255,255,255,0.75);
float:left;
font-size:10px;
font-weight:normal;
margin:20px;
}
a {
color:rgba(255,255,255,0.5);
display:inline-block;
text-decoration:none;
transition:0.5s ease color;
-moz-transition:0.5s ease color;
-o-transition:0.5s ease color;
-webkit-transition:0.5s ease color;
}
a:hover {
color:rgba(255,255,255,0.75);
}
ul#options {
list-style:none;
margin:10px 0 0;
position:relative;
right:0;
z-index:10;
}
ul#options li {
margin:5px 0;
min-width:200px;
opacity:0;
transition:0.25s ease-in opacity;
-moz-transition:0.25s ease-in opacity;
-o-transition:0.25s ease-in opacity;
-webkit-transition:0.25s ease-in opacity;
}
ul#options li.group {
margin-top:15px;
}
ul#options li * {
display:none;
}
ul#options li a {
box-shadow:1px 1px 3px rgba(0,0,0,0.25);
background-color:rgba(0,0,0,0.5);
border-radius:3px;
padding:3px 5px;
position:relative;
transition:0.5s ease all;
-moz-border-radius:3px;
-o-box-shadow:1px 1px 3px rgba(0,0,0,0.25);
-moz-box-shadow:1px 1px 3px rgba(0,0,0,0.25);
-webkit-box-shadow:1px 1px 3px rgba(0,0,0,0.25);
-moz-transition:0.5s ease all;
-o-transition:0.5s ease all;
-webkit-transition:0.5s ease all;
}
ul#options li a:hover {
color:rgba(255,255,255,0.75);
}
ul#options li a.on {
background-color:rgba(255,255,255,0.8);
color:rgba(0,0,0,0.9);
text-shadow:0px 0px 0px;
}
ul#options li a.on:after {
content:"\2713 ";
}
ul#options.on li {
opacity:1;
right:20px;
}
ul#options.on li * {
display:inline-block;
}
ul#borders {
}ul#borders li {
position:fixed;
list-style:none;
margin:0;
background-color:transparent;
background-color:rgba(0,0,0,0.05);
z-index:100;
}
li#top {
height:10px;
left:0;
right:0;
top:0;
}
li#right {
bottom:10px;
right:0;
top:10px;
width:10px;
}
li#bottom {
bottom:0;
height:10px;
left:0;
right:0;
}
li#left {
bottom:10px;
left:0;
top:10px;
width:10px;
}
</style>
</head>
<body>
<canvas width="800" height="400" id="canvas"><p class="nope">No canvas, no particles</p></canvas>
<header>
<h1>Particle Clock</h1>
<div id="about">
<a href="#" id="toggle-options"></a>
<ul id="options">
<li><a href="#" id="quivers" class="">Quiver</a></li>
<li><a href="#" id="gradient" class="on">Gradient</a></li>
<li><a href="#" id="color" class="on">Colorize</a></li>
<li><a href="#" id="valentineify" class="">Valentine-ify</a></li>
<li class="group"><span>Mouse down: explode and repel</span></li>
<li><span>Mouse down + shift: explode and attract</span></li>
<li><span>Arrow Up: increase particle size</span></li>
<li class="group"><span>Sorry about your CPU</span></li>
<li><span id="fps"></span></li>
</ul>
</div>
</header><script>
var Clock = (function() {
// private variables
var canvas, // canvas element
ctx, // canvas context
bgGrad = true, // background gradient flag
gradient, // gradient (background)
height = 400, // canvas height
key = {up: false, shift: false}, // key presses
particles = [], // particle array
particleColor = 'hsla(0, 0%, 100%, 0.3)', // particle color
mouse = {x: 0, y: 0}, // position of mouse / touch
press = false, // pressed flag
quiver = false, // quiver flag
text, // the text to copy pixels from
textSize = 140, // (initial) textsize
valentine = false, // valentine-ify it for a bit?
msgTime = 100, // time to show a message before returning to clock
updateColor = true, // update color of gradient / particles with time?
width = 800; // canvas width
// Constants
var FRAME_RATE = 20, // frames per second target
MIN_WIDTH = 800, // minimum width of canvas
MIN_HEIGHT = 400, // minimum height of canvas
PARTICLE_NUM = 600, // (max) number of particles to generate
RADIUS = Math.PI * 2; // radius of particle
var defaultStyles = function() {
textSize = 140;
// particle color
particleColor = 'hsla(0, 0%, 100%, 0.3)';
// color stops
var gradientStops = {
0: '#333333',
0.5: '#222222'
};
// create gradient
setGradient(gradientStops);
};
var draw = function(p) {
ctx.fillStyle = particleColor;
ctx.beginPath();
ctx.arc(p.x, p.y, p.size, 0, RADIUS, true);
ctx.closePath();
ctx.fill();
};
var explode = function() {
for(var i = 0, l = particles.length; i < l; i++) {
var p = particles[i];
if(p.inText) {
var ax = mouse.x - p.px,
ay = mouse.y - p.py,
angle = Math.atan2(ay, ax),
polarity,
C = Math.cos(angle),
S = Math.sin(angle);
// change polarity
// attract particles if mouse pressed, repel if shift + mousedown
polarity = (key.shift === true) ? -1 : 1;
p.x += polarity * (Math.pow((C-1), 2) -1) + p.velocityX * p.delta;
p.y += polarity * (Math.pow((S-1), 2) -1) + p.velocityY * p.delta;
// set previous positions
p.px = p.x;
p.py = p.y;
draw(p);
}
}
};
var getTime = function(amPM) {
var date = new Date(),
hours = date.getHours(),
timeOfDay = '';
if(amPM) {
hours = ( hours > 12 ) ? hours -= 12 : hours;
hours = ( hours == 0 ) ? 12 : hours;
} else {
hours = pad(hours);
}
var minutes = pad(date.getMinutes());
var seconds = pad(date.getSeconds());
return {
hours: hours,
minutes: minutes,
seconds: seconds,
timeString: hours + " : " + minutes + " : " + seconds
};
};
// animation loop
var loop = function() {
// clear out text
ctx.clearRect(0, 0, width, height);
var time = getTime(true);
textSize = 140;
// draw text on canvas
if(valentine === true) {
if(msgTime > 0) {
textSize = 180;
text = '?';
msgTime--;
} else {
text = time.timeString;
}
// valentine-ify it by setting hue to pink
setStyles(300);
} else if(updateColor === true && bgGrad === true) {
// changing color with time
// @TODO: come up with something better, this is a hacky implementation
var color = time.hours + time.minutes + time.seconds;
setStyles(color);
text = time.timeString;
} else {
defaultStyles();
text = time.timeString;
}
ctx.fillStyle = "rgb(255, 255, 255)";
ctx.textBaseline = "middle";
ctx.