最近在看HTML5,隨便玩玩Canvas,因而想着寫個簡單的模擬時鐘,不過想象力不夠豐富,沒啥好創意,作的比較醜~~ 哈哈javascript
Demon點這兒你懂得 哈哈html
代碼:java
/************************************************************************
*************************************************************************
case Name : clock - jQuery Plugin
case Revison : 1.0
case Date : 2014-4-02
case Author: zy_ding@ctrip.com
case Support: FF, IE9, IE10, Chrome, Others(unknown)
case License : N/A
*************************************************************************/
(function ($) {
$.fn.clock = function (opt) {
var defaults = {
radius: 200,
ctX: 500,
ctY: 300,
speed: 1000 / 60,
plummetLength: 160
}
var options = $.extend(defaults, opt);
var colors = ['#000', '#104070', '#184F73', '#285F83', '#306090', '#386F93', '#4070A0', '#487FA3', '#5080B0', '#588FB3', '#6090C0', '#689FC3', '#70A0D0', '#78AFD3'];
var $this = this;
var time = new Date();
var milSeconds = time.getMilliseconds();
var second = time.getSeconds();
var minute = time.getMinutes();
var hour = time.getHours() % 12;
var increase = 1;
var lastPosition = 30;
var lastAngle = 155;
var c = $this[0];
var cxt = c.getContext("2d");
var initDraw = function () {
setInterval(beginDraw, options.speed);
}
var beginDraw = function () {
time = new Date();
milSeconds = time.getMilliseconds();
second = time.getSeconds();
minute = time.getMinutes();
hour = time.getHours() % 12;
//清理畫布
cxt.clearRect(0, 0, $this.attr("width"), $this.attr("height"));
//畫表盤
drawPanel();
drawMonth();
//畫耳朵
drawEars();
//畫秒針
drawSecondPoint();
//畫分針
drawMinutePoint();
//畫時針
drawHourPoint();
//畫眼睛
drawEyes(cxt);
//畫鐘擺
drawPlummet();
}
var drawPanel = function () {
//外盤面
cxt.beginPath();
cxt.strokeStyleStyle = colors[3];
cxt.fillStyle = "#fff";
cxt.lineWidth = 10;
cxt.arc(options.ctX, options.ctY, options.radius, 0, Math.PI * 2, true);
cxt.fill();
cxt.stroke();
//中間盤面
cxt.beginPath();
cxt.lineWidth = 1;
cxt.arc(options.ctX, options.ctY, options.radius - 20, 0, Math.PI * 2, true);
cxt.fillStyle = colors[13];
cxt.fill();
cxt.stroke();
//圓點
cxt.beginPath();
cxt.arc(options.ctX, options.ctY, 20, 0, Math.PI * 2, true);
cxt.fillStyle = colors[3];
cxt.fill();
cxt.stroke();
//刻度
cxt.beginPath();
cxt.strokeStyle = colors[3];
cxt.stroke();
for (var i = 0; i < 60; i++) {
cxt.beginPath();
var x1 = options.ctX + (options.radius * Math.sin((i * 6 / 180) * Math.PI));
var y1 = options.ctY - (options.radius * Math.cos((i * 6 / 180) * Math.PI));
var x2;
var y2;
if (i % 5 != 0) {
x2 = options.ctX + ((options.radius - 10) * Math.sin((i * 6 / 180) * Math.PI));
y2 = options.ctY - ((options.radius - 10) * Math.cos((i * 6 / 180) * Math.PI));
}
else {
x2 = options.ctX + ((options.radius - 30) * Math.sin((i * 6 / 180) * Math.PI));
y2 = options.ctY - ((options.radius - 30) * Math.cos((i * 6 / 180) * Math.PI));
}
if (i % 15 == 0) {
cxt.beginPath();
cxt.fillStyle = colors[11];
cxt.arc(x1, y1, 8, 0, Math.PI * 2, true);
cxt.fill();
}
else {
cxt.moveTo(x1, y1);
cxt.lineTo(x2, y2);
cxt.stroke();
}
}
}
var drawEars = function () {
cxt.strokeStyle = colors[11];
cxt.fillStyle = colors[11];
var r = 30;
cxt.beginPath();
cxt.arc(options.ctX + options.radius * (Math.sin(45 / 180 * Math.PI)) + r, options.ctY - options.radius * (Math.cos(45 / 180 * Math.PI)) - r, r, 0, Math.PI * 2, true);
cxt.fill();
cxt.stroke();
cxt.beginPath();
cxt.arc(options.ctX - options.radius * (Math.sin(45 / 180 * Math.PI)) - r, options.ctY - options.radius * (Math.cos(45 / 180 * Math.PI)) - r, r, 0, Math.PI * 2, true);
cxt.fill();
cxt.stroke();
}
var drawMonth = function () {
cxt.strokeStyle = colors[3];
cxt.fillStyle = colors[6];
var r = 80;
cxt.beginPath();
cxt.arc(options.ctX, options.ctY + r / 2, r, Math.PI / 4, Math.PI * 3 / 4, false);
cxt.fill();
cxt.stroke();
}
var drawSecondPoint = function () {
for (var i = 0; i < 14; i++) {
cxt.beginPath();
cxt.strokeStyle = colors[i];
var x = options.ctX + ((options.radius - 40) * Math.sin((second * 6 / 180 - i / 360 + milSeconds * 6 / 180000) * Math.PI));
var y = options.ctY - ((options.radius - 40) * Math.cos((second * 6 / 180 - i / 360 + milSeconds * 6 / 180000) * Math.PI));
cxt.moveTo(options.ctX, options.ctY);
cxt.lineTo(x, y);
cxt.stroke();
}
}
var drawMinutePoint = function () {
for (var i = 0; i < 10; i++) {
cxt.beginPath();
cxt.strokeStyle = colors[i];
var x = options.ctX + ((options.radius - 80) * Math.sin((minute * 6 / 180 - i / 360 + (second / 1800)) * Math.PI));
var y = options.ctY - ((options.radius - 80) * Math.cos((minute * 6 / 180 - i / 360 + (second / 1800)) * Math.PI));
cxt.moveTo(options.ctX, options.ctY);
cxt.lineTo(x, y);
cxt.stroke();
}
}
var drawHourPoint = function () {
for (var i = 0; i < 6; i++) {
cxt.beginPath();
cxt.strokeStyle = colors[i];
var x = options.ctX + ((options.radius - 120) * Math.sin((hour * 30 / 180 - i / 360 + minute / 360) * Math.PI));
var y = options.ctY - ((options.radius - 120) * Math.cos((hour * 30 / 180 - i / 360 + minute / 360) * Math.PI));
cxt.moveTo(options.ctX, options.ctY);
cxt.lineTo(x, y);
cxt.stroke();
}
}
var drawEyes = function () {
cxt.beginPath();
if (lastPosition + increase > 80) {
increase = -1;
} else if (lastPosition + increase < 30) {
increase = 1;
}
lastPosition += increase;
cxt.arc(options.ctX - lastPosition, options.ctY - 80, 20, 0, Math.PI * 2, true);
cxt.arc(options.ctX + lastPosition, options.ctY - 80, 20, 0, Math.PI * 2, true);
cxt.fillStyle = colors[11];
cxt.fill();
}
var drawPlummet = function () {
if (lastAngle + increase > 205) {
increase = -1;
} else if (lastAngle + increase < 155) {
increase = 1;
}
lastAngle += increase;
cxt.beginPath();
cxt.strokeStyle = colors[11];
cxt.fillStyle = colors[11];
cxt.moveTo(options.ctX, options.ctY + options.radius);
cxt.lineTo(options.ctX + Math.sin(lastAngle / 180 * Math.PI) * options.plummetLength, options.ctY + options.radius - Math.cos(lastAngle / 180 * Math.PI) * options.plummetLength);
cxt.stroke();
cxt.beginPath();
cxt.arc(options.ctX + Math.sin(lastAngle / 180 * Math.PI) * options.plummetLength, options.ctY + options.radius - Math.cos(lastAngle / 180 * Math.PI) * options.plummetLength, 30, 0, Math.PI * 2, true);
cxt.fill();
cxt.stroke();
}
return this.each(function () {
initDraw();
});
};
}
)(jQuery);
使用:jquery
<!DOCTYPE html">
<html>
<head>
<title></title>
<style> #myCanvas { border: 1px solid #c3c3c3; background-color:#ddd;
}
</style>
</head>
<body>
<canvas width="1400" height="800" id="myCanvas">
Your browser does not support the canvas element.
</canvas>
<script src="http://code.jquery.com/jquery-latest.js" type="text/javascript"></script>
<script src="jquery.clock.js" type="text/javascript"></script>
<script type="text/javascript"> $(document).ready(function() { $('#myCanvas').clock(); }); </script>
</body>
</html>
超簡單,因此思路就很少寫了~~canvas
每次刷新都是全幅重畫的,本人比較懶~app
有些固定位置的部位(如耳朵,嘴巴)爲了不每次重繪都要從新計算位置,用circular對象保存ide
//用於保存各個部位信息,不用每次重繪都從新計算
var circular = function (x, y, r, sAngle, eAngle, counterclockwise) {
this.x = x;
this.y = y;
this.r = r;
this.sAngle = sAngle;
this.eAngle = eAngle;
this.counterclockwise = counterclockwise;
}
爲CanvasRenderingContext2D添加方法arc2 使其支持本身建的circular對象,這樣在每次畫圓的時候就不用寫那麼一大串了~this
//爲CanvasRenderingContext2D添加方法arc2 使其支持circular對象
CanvasRenderingContext2D.prototype.arc2 = function (circular) {
this.arc(circular.x, circular.y, circular.r, circular.sAngle, circular.eAngle, circular.counterclockwise);
}
添加拖拽(耳朵,嘴巴)spa
var circulars = []; var activePart; var isActive = false; var xDistance; var yDistance; //鼠標按下位置 $this.mousedown(function (e) { var x = e.clientX; var y = e.clientY; cxt.beginPath(); $.each(circulars, function (index, circular) { if (circular) { cxt.arc2(circular) if (cxt.isPointInPath(x, y)) { activePart = circular; xDistance = x - circular.x; yDistance = y - circular.y; isActive = true; return false; } } }) }); //鼠標彈起位置 $this.mouseup(function (e) { var x = e.clientX; var y = e.clientY; if (activePart && isActive) { activePart.x = x - xDistance; activePart.y = y - yDistance; isActive = false; } });
應該有許多不合理的地方,好比指針想實現那種「幻影」的效果,可是沒找到好的方法,就一個循環畫了14條漸變線條~~ 比較挫~prototype
for (var i = 0; i < 14; i++) {
cxt.beginPath();
cxt.strokeStyle = colors[i];
var x = options.ctX + ((options.radius - 40) * Math.sin((second * 6 / 180 - i / 360 + milSeconds * 6 / 180000) * Math.PI));
var y = options.ctY - ((options.radius - 40) * Math.cos((second * 6 / 180 - i / 360 + milSeconds * 6 / 180000) * Math.PI));
cxt.moveTo(options.ctX, options.ctY);
cxt.lineTo(x, y);
cxt.stroke();
}
嘴巴就是一個小半圓~~
var drawMonth = function () {
cxt.strokeStyle = colors[3];
cxt.fillStyle = colors[6];
var r = 80;
cxt.beginPath();
if (!circulars[2]) {
circulars[2] = new circular(options.ctX, options.ctY + r / 2, r, Math.PI / 4, Math.PI * 3 / 4, false);
}
cxt.arc2(circulars[2]);
cxt.fill();
cxt.stroke();
}
耳朵,鼻子,鐘擺。。。都是圓形 o(╯□╰)o~
var drawEars = function () {
cxt.strokeStyle = colors[11];
cxt.fillStyle = colors[11];
var r = 30;
cxt.beginPath();
if (!circulars[1]) {
circulars[1] = new circular(options.ctX + options.radius * (Math.sin(45 / 180 * Math.PI)) + r, options.ctY - options.radius * (Math.cos(45 / 180 * Math.PI)) - r, r, 0, Math.PI * 2, true);
}
cxt.arc2(circulars[1]);
cxt.fill();
cxt.stroke();
cxt.beginPath();
if (!circulars[0]) {
circulars[0] = new circular(options.ctX - options.radius * (Math.sin(45 / 180 * Math.PI)) - r, options.ctY - options.radius * (Math.cos(45 / 180 * Math.PI)) - r, r, 0, Math.PI * 2, true);
}
cxt.arc2(circulars[0]);
cxt.fill();
cxt.stroke();
}
鐘擺和眼睛是隨刷新平率作往返運動的,位置和時間無關~~ 這個大概不合適 不過懶得改~
var drawPlummet = function () {
if (lastAngle + increase > 205) {
increase = -1;
} else if (lastAngle + increase < 155) {
increase = 1;
}
lastAngle += increase;
cxt.beginPath();
cxt.strokeStyle = colors[11];
cxt.fillStyle = colors[11];
cxt.moveTo(options.ctX, options.ctY + options.radius);
cxt.lineTo(options.ctX + Math.sin(lastAngle / 180 * Math.PI) * options.plummetLength, options.ctY + options.radius - Math.cos(lastAngle / 180 * Math.PI) * options.plummetLength);
cxt.stroke();
cxt.beginPath();
cxt.arc(options.ctX + Math.sin(lastAngle / 180 * Math.PI) * options.plummetLength, options.ctY + options.radius - Math.cos(lastAngle / 180 * Math.PI) * options.plummetLength, 30, 0, Math.PI * 2, true);
cxt.fill();
cxt.stroke();
}
求噴 求教育 求鄙視 就是無聊~