学者玩玩Canvas-写个简单的模拟时钟
最近在看HTML5,随便玩玩Canvas,于是想着写个简单的模拟时钟,不过想象力不够丰富,没啥好创意,做的比较丑~~ 哈哈
代码:
/************************************************************************
*************************************************************************
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);
使用:
<!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>
超简单,所以思路就不多写了~~
每次刷新都是全幅重画的,本人比较懒~
有些固定位置的部位(如耳朵,嘴巴)为了避免每次重绘都要重新计算位置,用circular对象保存
//用于保存各个部位信息,不用每次重绘都重新计算
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对象,这样在每次画圆的时候就不用写那么一大串了~
//为CanvasRenderingContext2D添加方法arc2 使其支持circular对象
CanvasRenderingContext2D.prototype.arc2 = function (circular) {
this.arc(circular.x, circular.y, circular.r, circular.sAngle, circular.eAngle, circular.counterclockwise);
}
添加拖拽(耳朵,嘴巴)
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条渐变线条~~ 比较挫~
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();
}
求喷 求教育 求鄙视 就是无聊~