Canvas學習-時鐘繪製
1. 繪製時鐘外邊框
- 創建畫布
<div class="container">
<canvas id="clock" height="200px" width="200px"></canvas>
</div>
備註:該容器就是繪製圖形的畫布。
- 繪製圓環
var dom = document.getElementById('clock'); //獲取元素
var ctx = dom.getContext('2d'); //上下文
var width = ctx.canvas.width; //上下文的寬度
var height = ctx.canvas.height; //上下文的高度
var r = width / 2; //半徑
// 繪製圓環
function drawBackground() {
ctx.translate(r, r); //確定座標遠點
ctx.beginPath(); //開始畫圖
ctx.lineWidth = 10; // 設置線條粗細
ctx.arc(0, 0, r-5, 0, 2 * Math.PI, false); //繪製圓形
ctx.stroke(); //繪製
}
drawBackground();
2.繪製時鐘內容
// 繪製小時數
var hourNumbers = [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2];
ctx.font = '18px Arial';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
hourNumbers.forEach(function (number, i) {
var rad = 2 * Math.PI / 12 * i;
var x = Math.cos(rad) * (r - 30);
var y = Math.sin(rad) * (r - 30);
ctx.fillText(number, x, y);
})
備註:在繪製小時數的時候,我們應該確定數字與對應弧度的關係,建立數組,填充數字。
3. 繪製小時數對應的圓點
// 繪製小時數對應的點
for (var i = 0; i < 60; i++) {
var rad = 2 * Math.PI / 60 * i;
var x = Math.cos(rad) * (r - 18);
var y = Math.sin(rad) * (r - 18);
ctx.beginPath();
if (i % 5 === 0) {
ctx.fillStyle = "#000";
ctx.arc(x, y, 2, 0, 2 * Math.PI, false);
} else {
ctx.fillStyle = "#ccc";
ctx.arc(x, y, 2, 0, 2 * Math.PI, false);
}
ctx.fill();
}
備註:繪製圓點的時候,我們需要區分整點數與非整點數之間的區別,填充不同的背景顏色。
4.繪製是真分針秒針
// 畫時針
function drawHour(hour, minute) {
ctx.save();
ctx.beginPath();
var rad = 2 * Math.PI / 12 * hour;
var mrad = 2 * Math.PI / 12 / 60 * minute;
ctx.rotate(rad + mrad);
ctx.lineWidth = 6;
ctx.lineCap = 'round';
ctx.moveTo(0, 10);
ctx.lineTo(0, -r / 2);
ctx.stroke();
ctx.restore();
}
// 畫分針
function drawMinute(minute, second) {
ctx.save();
ctx.beginPath();
var rad = 2 * Math.PI / 60 * minute;
var srad = 2 * Math.PI / 60 / 60 * second;
ctx.rotate(rad + srad);
ctx.lineWidth = 3;
ctx.lineCap = 'round';
ctx.moveTo(0, 10);
ctx.lineTo(0, -r + 30);
ctx.stroke();
ctx.restore();
}
// 畫秒針
function drawSecond(second) {
ctx.save();
ctx.beginPath();
ctx.fillStyle = '#c14543';
var rad = 2 * Math.PI / 60 * second;
ctx.rotate(rad);
ctx.moveTo(-2, 20);
ctx.lineTo(2, 20);
ctx.lineTo(1, -r + 18);
ctx.lineTo(-1, -r + 18);
ctx.lineTo(0, -r + 30);
ctx.fill();
ctx.restore();
}
備註:繪製分針的時候,我們需要考慮到分針對其的影響,所以需要計算分針數引起時針的弧度改變。在繪製分針的時候,同樣需要考慮秒針對分針的影響。
4. 畫中心點
// 畫中心點
function drawDot() {
ctx.beginPath();
ctx.fillStyle = '#FFFFFF';
ctx.arc(0, 0, 3, 2 * Math.PI, false)
ctx.fill();
}
5. 最終繪製方法
function draw() {
ctx.clearRect(0, 0, width, height);
var now = new Date();
var hour = now.getHours();
var minute = now.getMinutes();
var second = now.getSeconds();
drawBackground();
drawHour(hour, minute);
drawMinute(minute, second);
drawSecond(second);
drawDot();
ctx.restore();
}
draw();
setInterval(draw, 1000);
備註:在繪製圖形的時候,我們需要注意一下幾點:
- 繪製之前,我們需要清除畫布,避免圖形的疊加。
- 主要保存畫布之前的狀態,還原狀態,避免影響。
- 利用定時器,每隔一秒鐘,重新繪製圖片。
6. 效果圖
7. 代碼
var dom = document.getElementById('clock'); //獲取元素
var ctx = dom.getContext('2d'); //上下文
var width = ctx.canvas.width; //上下文的寬度
var height = ctx.canvas.height; //上下文的高度
var r = width / 2; //半徑
// 繪製圓環
function drawBackground() {
ctx.save();
ctx.translate(r, r); //確定座標遠點
ctx.beginPath(); //開始畫圖
ctx.lineWidth = 10; // 設置線條粗細
ctx.arc(0, 0, r - 5, 0, 2 * Math.PI, false); //繪製圓形
ctx.stroke(); //繪製
// 繪製小時數
var hourNumbers = [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2];
ctx.font = '18px Arial';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
hourNumbers.forEach(function (number, i) {
var rad = 2 * Math.PI / 12 * i;
var x = Math.cos(rad) * (r - 30);
var y = Math.sin(rad) * (r - 30);
ctx.fillText(number, x, y);
})
// 繪製小時數對應的點
for (var i = 0; i < 60; i++) {
var rad = 2 * Math.PI / 60 * i;
var x = Math.cos(rad) * (r - 18);
var y = Math.sin(rad) * (r - 18);
ctx.beginPath();
if (i % 5 === 0) {
ctx.fillStyle = "#000";
ctx.arc(x, y, 2, 0, 2 * Math.PI, false);
} else {
ctx.fillStyle = "#ccc";
ctx.arc(x, y, 2, 0, 2 * Math.PI, false);
}
ctx.fill();
}
}
// 畫時針
function drawHour(hour, minute) {
ctx.save();
ctx.beginPath();
var rad = 2 * Math.PI / 12 * hour;
var mrad = 2 * Math.PI / 12 / 60 * minute;
ctx.rotate(rad + mrad);
ctx.lineWidth = 6;
ctx.lineCap = 'round';
ctx.moveTo(0, 10);
ctx.lineTo(0, -r / 2);
ctx.stroke();
ctx.restore();
}
// 畫分針
function drawMinute(minute, second) {
ctx.save();
ctx.beginPath();
var rad = 2 * Math.PI / 60 * minute;
var srad = 2 * Math.PI / 60 / 60 * minute;
ctx.rotate(rad + srad);
ctx.lineWidth = 3;
ctx.lineCap = 'round';
ctx.moveTo(0, 10);
ctx.lineTo(0, -r + 30);
ctx.stroke();
ctx.restore();
}
// 畫秒針
function drawSecond(second) {
ctx.save();
ctx.beginPath();
ctx.fillStyle = '#c14543';
var rad = 2 * Math.PI / 60 * second;
ctx.rotate(rad);
ctx.moveTo(-2, 20);
ctx.lineTo(2, 20);
ctx.lineTo(1, -r + 18);
ctx.lineTo(-1, -r + 18);
ctx.lineTo(0, -r + 30);
ctx.fill();
ctx.restore();
}
// 畫中心點
function drawDot() {
ctx.beginPath();
ctx.fillStyle = '#FFFFFF';
ctx.arc(0, 0, 3, 2 * Math.PI, false)
ctx.fill();
}
function draw() {
ctx.clearRect(0, 0, width, height);
var now = new Date();
var hour = now.getHours();
var minute = now.getMinutes();
var second = now.getSeconds();
drawBackground();
drawHour(hour, minute);
drawMinute(minute, second);
drawSecond(second);
drawDot();
ctx.restore();
}
draw();
setInterval(draw, 1000);
8. 思考
如果畫布放大,那麼圖像會怎麼樣呢?顯然,因爲其中部分數據大小是固定寫死的,必然出現不協調的地方,此時我們必須考慮到,數據的比例問題。修改思路如下:在寬度、文字大小部分,我們需要採用相對大小。
9. 代碼優化
優化思路:首先確定比例,var rem = width/ 200; //比例(因爲初始樣式的數據是按照200爲基準的)
,然後在對應的數字大小部分乘上該比例即可。修改後的代碼如下:
var dom = document.getElementById('clock'); //獲取元素
var ctx = dom.getContext('2d'); //上下文
var width = ctx.canvas.width; //上下文的寬度
var height = ctx.canvas.height; //上下文的高度
var r = width / 2; //半徑
var rem = width/ 200; //比例(因爲初始樣式的數據是按照200爲基準的)
// 繪製圓環
function drawBackground() {
ctx.save();
ctx.translate(r, r); //確定座標遠點
ctx.beginPath(); //開始畫圖
ctx.lineWidth = 10 * rem; // 設置線條粗細
ctx.arc(0, 0, r - ctx.lineWidth/2, 0, 2 * Math.PI, false); //繪製圓形
ctx.stroke(); //繪製
// 繪製小時數
var hourNumbers = [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2];
ctx.font = 18* rem + 'px Arial';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
hourNumbers.forEach(function (number, i) {
var rad = 2 * Math.PI / 12 * i;
var x = Math.cos(rad) * (r - 30* rem);
var y = Math.sin(rad) * (r - 30* rem);
ctx.fillText(number, x, y);
})
// 繪製小時數對應的點
for (var i = 0; i < 60; i++) {
var rad = 2 * Math.PI / 60 * i;
var x = Math.cos(rad) * (r - 18* rem);
var y = Math.sin(rad) * (r - 18* rem);
ctx.beginPath();
if (i % 5 === 0) {
ctx.fillStyle = "#000";
ctx.arc(x, y, 2* rem, 0, 2 * Math.PI, false);
} else {
ctx.fillStyle = "#ccc";
ctx.arc(x, y, 2* rem, 0, 2 * Math.PI, false);
}
ctx.fill();
}
}
// 畫時針
function drawHour(hour, minute) {
ctx.save();
ctx.beginPath();
var rad = 2 * Math.PI / 12 * hour;
var mrad = 2 * Math.PI / 12 / 60 * minute;
ctx.rotate(rad + mrad);
ctx.lineWidth = 6* rem;
ctx.lineCap = 'round';
ctx.moveTo(0, 10* rem);
ctx.lineTo(0, -r / 2);
ctx.stroke();
ctx.restore();
}
// 畫分針
function drawMinute(minute, second) {
ctx.save();
ctx.beginPath();
var rad = 2 * Math.PI / 60 * minute;
var srad = 2 * Math.PI / 60 / 60 * second;
ctx.rotate(rad + srad);
ctx.lineWidth = 3* rem;
ctx.lineCap = 'round';
ctx.moveTo(0, 10* rem);
ctx.lineTo(0, -r + 30* rem);
ctx.stroke();
ctx.restore();
}
// 畫秒針
function drawSecond(second) {
ctx.save();
ctx.beginPath();
ctx.fillStyle = '#c14543';
var rad = 2 * Math.PI / 60 * second;
ctx.rotate(rad);
ctx.moveTo(-2* rem, 20* rem);
ctx.lineTo(2* rem, 20* rem);
ctx.lineTo(1, -r + 18* rem);
ctx.lineTo(-1, -r + 18* rem);
ctx.fill();
ctx.restore();
}
// 畫中心點
function drawDot() {
ctx.beginPath();
ctx.fillStyle = '#FFFFFF';
ctx.arc(0, 0, 3* rem, 2 * Math.PI, false)
ctx.fill();
}
function draw() {
ctx.clearRect(0, 0, width, height);
var now = new Date();
var hour = now.getHours();
var minute = now.getMinutes();
var second = now.getSeconds();
drawBackground();
drawHour(hour, minute);
drawMinute(minute, second);
drawSecond(second);
drawDot();
ctx.restore();
}
draw();
setInterval(draw, 1000);
10. 代碼下載
鏈接:canvas學習代碼下載