使用h5 canvas实现时钟的动态效果
难点在于:
秒钟刻度和时钟刻度的绘制
整点文字沿着内边圆形环绕
其中刻度的环绕并不难计算,文字的环绕就比较坑爹了,canvas绘制的文字是在绘制坐标之上的(文字基线和对齐方式影响),需要进行偏移的计算,使之文字中点正好落在圆上。
这一步相当淡疼,由于api中并没有测量字高的办法,而使用fontSize,其实也并不是字的准确高度,因此,y坐标+二分之一行高向下偏移,使之垂直居中,却总是不够准确的。而x坐标+二分之一行宽向左偏移,使之水平居中,则没有这个问题,因为api提供了测量行宽的方法。
一切都是因为 ctx.measureText(text).width 存在,但 ctx.measureText(numText).height 不存在。打印测量结果,也只有一个宽度属性。文档中说canvas对于绘制文字的支持比较弱,从这一点上看 何止是弱。
直接设置基线和对齐方式为居中,似乎也存在一定误差,看起来总不是那么赏心悦目。下面的代码中两种方式都写了。
会走的时钟预览:
时间显示可能略有误差。
知识点和求解参考图
主要知识点为圆的坐标公式,和三角函数sin,cos计算。实际上,圆的坐标公式使用的并不多,引入求值反而可能复杂化。
下图是计算刻度线坐标和整点文字绘制坐标的参考图:
canvas画时钟效果的代码编写
下面是全部代码:
!DOCTYPE htML>
html lang="en">
head>
meta charset="UTF-8">
meta name="viewport" content="width=1024, height=768,inITial-scale=1.0,maximum-scale=1.0,user-scalable=0">
title>
时钟/title>
/head>
body>
p style="margin: 50px">
canvas width="300" height="300">
/canvas>
canvas width="200" height="200" style="background-color: #bbbbbb">
/canvas>
canvas width="200" height="200">
/canvas>
canvas width="200" height="200">
/canvas>
/p>
script>
VAR clockHelper = function (canvas, config) {
if (!config) {
config = {
}
}
var ctx = canvas.getContext('2d');
var deColor = config.deColor ? config.deColor : '#333333';
var deConfig = {
ringWidth: config.ringWidth ? config.ringWidth : 6,//圆环宽度 ringColor: config.ringColor ? config.ringColor : deColor,//圆环颜色 hSaleL: config.hSaleL ? config.hSaleL : 8,//时刻度线长 hScaleWidth: config.hScaleWidth ? config.hScaleWidth : 4,//时刻度线宽 hScaleColor: config.hScaleColor ? config.hScaleColor : deColor,//时刻度颜色 msSaleL: config.msSaleL ? config.msSaleL : 4,//分秒刻度线长 msScaleWidth: config.msScaleWidth ? config.msScaleWidth : 2,//分秒刻度线宽 msScaleColor: deColor,//分秒刻度颜色 hFontSize: config.hFontSize ? config.hFontSize : 18,//整点文字大小 hHandWidth: config.hHandWidth ? config.hHandWidth : 10,//时针宽度 mHandWidth: config.mHandWidth ? config.mHandWidth : 5,//分针宽度 sHandWidth: config.sHandWidth ? config.sHandWidth : 2,//秒针宽度 hHandColor: config.hHandColor ? config.hHandColor : deColor,//时针颜色 mHandColor: config.mHandColor ? config.mHandColor : deColor,//分针颜色 sHandColor: config.sHandColor ? config.sHandColor : '#bb3333',//秒针颜色 handMode: ['ms', 's'].indexOf("" + config.handMode) !== -1 ? config.handMode : 's',//指针读秒模式,ms:毫秒,s:秒。 clockFaceColor: config.clockFaceColor ? config.clockFaceColor : '', }
;
var ox = canvas.width / 2;
var oy = canvas.height / 2;
var width = canvas.width;
var height = canvas.height;
ctx.font = deConfig.hFontSize + "px 黑体";
//中线圆环半径 var ringR = (width height) ? (width / 2 - deConfig.ringWidth / 2) : (height / 2 - deConfig.ringWidth / 2);
//内圆环半径 var ringinnerR = (width height) ? (width / 2 - deConfig.ringWidth) : (height / 2 - deConfig.ringWidth);
var timer;
var timeSleep = 100;
var isStart = false;
function start() {
if (isStart) {
return;
}
isStart = true;
if (deConfig.handMode == 'ms') {
timeSleep = 100;
}
else {
timeSleep = 1000;
}
ctx.clearRect(0, 0, width, height);
draw();
timer = setInterval(function () {
if (isStart) {
ctx.clearRect(0, 0, width, height);
draw();
}
}
, timeSleep);
}
function stop() {
isStart = false;
clearInterval(timer) }
function draw() {
beforedraw();
drawCircleFace();
drawHands();
afterDraw();
}
function drawCircleFace() {
ctx.fillStyle = deConfig.ringColor;
ctx.strokeStyle = deConfig.ringColor;
ctx.lineWidth = deConfig.ringWidth;
ctx.beginPath();
ctx.arc(ox, oy, ringR, 0, Math.PI * 2);
ctx.stroke();
if (deConfig.clockFaceColor) {
ctx.fillStyle = deConfig.clockFaceColor;
ctx.fill();
}
var x1 = ox;
var y1 = oy;
var x2 = ox;
var y2 = oy;
var radin = 0;
ctx.lineWidth = deConfig.hScaleWidth;
// ctx.beginPath();
for (var i = 1;
i = 60;
i++) {
radin = i * 6 * Math.PI / 180;
x1 = ox + ringInnerR * Math.sin(radin);
y1 = oy - ringInnerR * Math.cos(radin);
if (i % 5 === 0) {
ctx.lineWidth = deConfig.hScaleWidth;
x2 = ox + (ringInnerR - deConfig.hSaleL) * Math.sin(radin);
y2 = oy - (ringInnerR - deConfig.hSaleL) * Math.cos(radin);
ctx.fillStyle = deConfig.hScaleColor;
var numText = i / 5 + "";
var textWidth = ctx.measureText(numText).width;
var x3 = ox + (ringInnerR - deConfig.hSaleL - deConfig.hFontSize) * Math.sin(radin);
var y3 = oy - (ringInnerR - deConfig.hSaleL - deConfig.hFontSize) * Math.cos(radin);
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
//不设置文字居中,基线居中,自己计算。貌似都有误差。因为旋转过程中,角度变化,且文字宽高不尽相同 // var x3 = ox + (ringInnerR - deConfig.hSaleL - deConfig.hFontSize) * Math.sin(radin) - textWidth / 2;
// var y3 = oy - (ringInnerR - deConfig.hSaleL - deConfig.hFontSize) * Math.cos(radin) + deConfig.hFontSize/ 2;
//x2,y2已经求过,化简为: // var x3 = x2 - deConfig.hFontSize * Math.sin(radin) - textWidth / 2;
// var y3 = y2 + deConfig.hFontSize * Math.cos(radin) + textWidth / 2;
//文字x轴向左偏移一半文字宽,使之水平居中;
向下偏移一半高度,使之垂直居中。 // 实际中发现,字高没法测(api无),而使用fontSize不准。但y轴加上字宽,位置倒是更对齐一些。 // var x3 = x2 + textWidth / 2;
// var y3 = y2 - deConfig.hFontSize / 2;
ctx.fillText(numText, x3, y3);
}
else {
ctx.lineWidth = deConfig.msScaleWidth;
x2 = ox + (ringInnerR - deConfig.msSaleL) * Math.sin(radin);
y2 = oy - (ringInnerR - deConfig.msSaleL) * Math.cos(radin);
}
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.l@R_360_1850@o(x2, y2);
ctx.stroke();
}
}
//改变坐标中点,并旋转画布也许是更好的选择。 function drawHands() {
var date = new Date();
var h = date.getHours() % 12;
var m = date.getMinutes();
var s = date.getSeconds();
var ms = date.getMilliseconds();
// console.LOG(h + ":" + m + ":" + s);
// 时针 var hradin = (h + m / 60 + s / 3600) * Math.PI * 2 / 12;
var mRadin = (m + s / 60) * Math.PI * 2 / 60;
var sRadin;
if (deConfig.handMode == 'ms') {
sRadin = (s + ms / 1000) * Math.PI * 2 / 60;
}
else {
sRadin = s * Math.PI * 2 / 60;
}
var x = 0;
var y = 0;
var hDotR = deConfig.hHandWidth + 2;
var mDotR = 0.6 * hDotR var sDotR = 0.5 * hDotR //秒针半径 var sHandR = ringInnerR - deConfig.hSaleL * 2 //分针半径 var mHandR = 0.8 * sHandR;
//时针半径 var hHandR = 0.7 * mHandR;
//时针 ctx.beginPath();
ctx.lineWidth = deConfig.hHandWidth;
ctx.strokeStyle = deConfig.hHandColor;
ctx.strokeStyle = deConfig.hHandColor;
ctx.moveTo(ox, oy);
x = ox + hHandR * Math.cos(hRadin - Math.PI / 2);
y = oy + hHandR * Math.sin(hRadin - Math.PI / 2);
ctx.lineTo(x, y);
ctx.stroke();
//针尖。直接圆型了(矩形指针来绘制针尖,计算复杂。。。) ctx.beginPath();
ctx.lineWidth = 0;
ctx.arc(x, y, deConfig.hHandWidth / 2, 0, 2 * Math.PI);
ctx.fill();
//中心 ctx.beginPath();
// ctx.lineWidth = hDotR;
ctx.arc(ox, oy, hDotR / 2, 0, Math.PI * 2);
ctx.fill();
ctx.stroke();
//分针 ctx.beginPath();
ctx.lineWidth = deConfig.mHandWidth;
ctx.strokeStyle = deConfig.mHandColor;
ctx.fillStyle = deConfig.mHandColor;
ctx.moveTo(ox, oy);
x = ox + mHandR * Math.cos(mRadin - Math.PI / 2);
y = oy + mHandR * Math.sin(mRadin - Math.PI / 2);
ctx.lineTo(x, y);
ctx.stroke();
//针尖。直接圆型了(矩形指针来绘制针尖,计算复杂。。。) ctx.beginPath();
ctx.lineWidth = 0;
ctx.arc(x, y, deConfig.mHandWidth / 2, 0, 2 * Math.PI);
ctx.fill();
//中心 ctx.beginPath();
ctx.arc(ox, oy, mDotR / 2, 0, Math.PI * 2);
ctx.stroke();
//秒针 ctx.beginPath();
ctx.strokeStyle = deConfig.sHandColor;
ctx.fillStyle = deConfig.sHandColor;
ctx.lineWidth = deConfig.sHandWidth;
//秒针有长短两线 x = ox - sHandR / 4 * Math.cos(sRadin - Math.PI / 2);
y = oy - sHandR / 4 * Math.sin(sRadin - Math.PI / 2);
ctx.moveTo(x, y);
x = ox + sHandR * Math.cos(sRadin - Math.PI / 2);
y = oy + sHandR * Math.sin(sRadin - Math.PI / 2);
ctx.lineTo(x, y);
ctx.stroke();
//针尖。直接圆型了(矩形指针来绘制针尖,计算复杂。。。) ctx.beginPath();
ctx.lineWidth = 0;
ctx.arc(x, y, deConfig.sHandWidth / 2, 0, 2 * Math.PI);
ctx.fill();
//中心 ctx.beginPath();
ctx.fillStyle = deColor;
ctx.arc(ox, oy, sDotR, 0, Math.PI * 2);
ctx.fill();
ctx.stroke();
}
function beforeDraw() {
if (typeof exp.beforeDraw === 'function') {
exp.beforeDraw(ctx, deConfig);
}
}
function afterDraw() {
if (typeof exp.afterDraw === 'function') {
exp.afterDraw(ctx, deConfig);
}
}
var exp = {
start: start, stop: stop, beforeDraw: null, afterDraw: null, }
return exp;
}
var clockCanvas1 = document.getelementsbytagname('canvas')[0];
var clockCanvas2 = document.getElementsByTagName('canvas')[1];
var clockCanvas3 = document.getElementsByTagName('canvas')[2];
var clockCanvas4 = document.getElementsByTagName('canvas')[3];
var clock = clockHelper(clockCanvas1, {
mHandColor: '#3333bb', sHandColor: '#bb3333'}
);
clock.start();
setTimeout(function () {
clock.stop() }
, 5000) setTimeout(function () {
clock.start();
}
, 8000) clockHelper(clockCanvas2, {
mHandColor: 'green', hHandWidth: 6, mHandWidth: 4, hFontSize: 14, hScaleWidth: 2, handMode: 'ms' }
).start();
clockHelper(clockCanvas2, {
mHandColor: 'green', hHandWidth: 6, mHandWidth: 4, hFontSize: 14, hScaleWidth: 2, handMode: 'ms' }
).start();
clockHelper(clockCanvas3, {
deColor: '#bbbbbb', sHandColor: '#bbbbbb', clockFaceColor: '#112233',//钟面 hHandWidth: 6, mHandWidth: 4, hFontSize: 14, hScaleWidth: 2, handMode: 's' }
).start();
var clock4 = clockHelper(clockCanvas4, {
deColor: '#bbbbbb', sHandColor: '#bbbbbb', // clockFaceColor: '#112233', hHandWidth: 6, mHandWidth: 4, hFontSize: 14, hScaleWidth: 2, handMode: 's' }
);
clock4.afterDraw = function (ctx, deConfig) {
var grd = ctx.createLinearGradient(0, 0, clockCanvas4.width, clockCanvas4.height);
grd.addColorStop(0, "rgba(255,0,0,0.3)");
grd.addColorStop(1, "rgba(0,0,255,0.5)");
ctx.fillStyle = grd;
ctx.arc(clockCanvas4.width/2,clockCanvas4.height/2,clockCanvas4.width/2,0,Math.PI*2);
// ctx.fillRect(0, 0, clockCanvas4.width, clockCanvas4.height);
ctx.fill();
ctx.fillText('时钟绘制完成后,自定义其他绘制',clockCanvas4.width/2,clockCanvas4.height - deConfig.hFontSize);
}
;
clock4.start();
/script>
/body>
/html>
说明:
1、clockHelper第一个参数传入画布。第二个参数传入时钟界面的配置对象,包括指针、刻度的颜色、大小等,配置项和clockHelper中的deConfig默认对象是相对的,参考deConfig的属性传入参数即可。
2、clockHelper的封装性略差,仅是基本能用型。但属性不多,改造应该并不困难。
3、提供了时钟界面绘制之前和之后的方法,可以在beforeDraw和afterDraw这两个方法中执行自己的逻辑。但是由于事先设计没有留出足够的空白像素,用处不大。只能进行一些简单的再绘制。比如给钟面添加色彩、渐变。
相关推荐:
H5+C3实现时钟效果
使用Canvas制作时钟动画的方法
以上就是使用h5 canvas实现时钟的动态效果的详细内容,更多请关注其它相关文章!
声明:本文内容由网友自发贡献,本站不承担相应法律责任。对本内容有异议或投诉,请联系2913721942#qq.com核实处理,我们将尽快回复您,谢谢合作!
若转载请注明出处: 使用h5 canvas实现时钟的动态效果
本文地址: https://pptw.com/jishu/584304.html
