HTML5的绝活:巧用Canvas制作会动的时钟
這次我們的目標是畫一個會和時間同步的時鐘,不過沒有美學感覺,樣子丑的厲害。
HTML5支持canvas了,我們可以直接在頁面上繪圖了,我看了下canvas和GDI+的接口差不多,所以我們先了解些基本的概念和方式,然后來做一個應用吧。
我們做所有的畫之情需要一個畫布,html的canvas標簽就是幫我們聲明了一個畫布。
<canvas id="mycanvas">?
</canvas>
?????? 這個默認的畫布的大小是300*150,接下來的工作大多就是javaScript來做了。
首先要實例化這個畫布
[javascript] view plaincopy
$(?
function() {?
??? var canvas = document.getElementById("mycanvas");?
??? $.log(canvas.width);?
??? $.log(canvas.height);?
??? var context = canvas.getContext("2d");?
??? $.log(context.canvas);?
??? $.log(context.fillStyle); //要填充的區域的顏色?
??? $.log(context.strokeStyle); //要繪制的線條的顏色?
??? $.log(context.lineCap); //筆帽樣式?
??? $.log(context.lineJoin); //兩條連續線段的連接樣式?
??? $.log(context.lineWidth); //線段的寬度?
??? $.log(context.miterLimit); //斜聯接?
??? $.log(context.shadowColor); //陰影的顏色,默認為#000000,?
??? $.log(context.shadowOffsetX); //陰影在x方向上的偏移量,默認為0,不受坐標轉換的影響。?
??? $.log(context.shadowOffsetY); //陰影在y方向上的偏移量,默認為0,不受坐標轉換的影響。?
??? $.log(context.shadowBlur); //陰影的模糊度,默認為0,負數值將會被忽略?
}?
);
?
上面的結果你可以得到一個大致的想法,就是content可以認為是我們將來作畫用的畫筆(估計有專業人士對強烈抗議,我直接忽略),canvas就是我們的畫布。我們現在的畫筆是2D的畫筆,換句話說就是畫平面幾何的畫筆。
接下來,就是我們利用這個畫筆來學習怎么畫了
各種線
[javascript] view plaincopy
$(
function() {
var canvas = document.getElementById("mycanvas");
var context = canvas.getContext("2d");
context.strokeStyle = "rgb(255, 0, 0)";
context.beginPath();
context.lineCap = "butt"; //默認
context.lineWidth = 10;
context.moveTo(10, 10);
context.lineTo(100, 10); //簡單的一條線
context.stroke(); //該方法真正在畫布上繪制該線段
context.beginPath();
context.lineCap = "round"; //圓形線頭
context.moveTo(10, 30);
context.lineTo(100, 30);
context.stroke(); //該方法真正在畫布上繪制該線段
context.beginPath();
context.lineCap = "square"; //方形線頭
context.moveTo(10, 50);
context.lineTo(100, 50);
context.stroke(); //該方法真正在畫布上繪制該線段
}
);
?
各種陰影
[javascript] view plaincopy
$(
function() {
var canvas = document.getElementById("mycanvas");
var context = canvas.getContext("2d");
context.strokeStyle = "rgb(255, 0, 0)";
context.lineWidth = 10;
context.shadowColor = "#0000FF";
context.beginPath();
context.lineCap = "round";
context.moveTo(10, 10);
context.lineTo(100, 10);
context.shadowOffsetX = 10;
context.shadowBlur = 10;
context.stroke();
context.beginPath();
context.lineCap = "round";
context.moveTo(10, 30);
context.lineTo(100, 30);
context.shadowOffsetY = 10;
context.shadowBlur = 10;
context.stroke();
}
);
各種線∠連接
[javascript] view plaincopy
$(
function() {
var canvas = document.getElementById("mycanvas");
var context = canvas.getContext("2d");
context.strokeStyle = "rgb(255, 0, 0)";
context.lineWidth = 10;
context.shadowColor = "#0000FF";
context.beginPath();
context.lineJoin = "miter"; //兩條線段的外邊緣一直擴展到它們相交
context.moveTo(10, 70);
context.lineTo(50, 10);
context.lineTo(80, 70);
context.stroke();
context.lineJoin = "bevel"; //以一個斜邊進行連接
context.moveTo(100, 70);
context.lineTo(140, 10);
context.lineTo(180, 70);
context.stroke();
context.lineJoin = "round"; //:以一個圓弧邊進行連接
context.beginPath();
context.moveTo(200, 70);
context.lineTo(240, 10);
context.lineTo(280, 70);
context.stroke();
context.closePath(); //關閉path
}
);
mitre的限定
[javascript] view plaincopy
$(
function() {
var canvas = document.getElementById("mycanvas");
var context = canvas.getContext("2d");
context.strokeStyle = "rgb(255, 0, 0)";
context.lineWidth = 10;
context.shadowColor = "#0000FF";
context.beginPath();
context.miterLimit = 1; //miterLimit 屬性為斜面的長度設置一個上限。
//只對線條使用設置為 "miter" 的 lineJoin 屬性繪制并且兩條線段以銳角相交的時候有效
context.lineJoin = "miter"; //兩條線段的外邊緣一直擴展到它們相交
context.moveTo(10, 70);
context.lineTo(50, 10);
context.lineTo(80, 70);
context.stroke();
}
);
各種幾何圖形
[javascript] view plaincopy
$(
function() {
var canvas = document.getElementById("mycanvas");
canvas.height = 500; //改變默認高度
canvas.width = 500;
var context = canvas.getContext("2d");
context.strokeStyle = "rgb(255, 0, 0)";
context.fillStyle = "#AABBCC";
context.lineWidth = 2;
context.shadowColor = "#0000FF";
//矩形
context.beginPath();
context.fillRect(10, 10, 50, 50); //實體矩形:x,y,width,height
context.strokeRect(70, 10, 50, 50)//空心矩形:x,y,width,height
//context.move(10,100);
//圓弧:x, y, radius, startAngle, endAngle, anticlockwise
context.beginPath();
context.arc(35, 110, 25, (Math.PI / 180) * 0, (Math.PI / 180) * 360, false);
context.stroke();
//context.closePath();
context.beginPath();
context.arc(85, 110, 25, (Math.PI / 180) * 0, (Math.PI / 180) * 180, false);
context.stroke();
//context.closePath();
context.beginPath();
context.arc(135, 110, 25, (Math.PI / 180) * 0, (Math.PI / 180) * 180, true);
context.stroke();
//context.closePath();
context.beginPath();
context.arc(185, 110, 25, (Math.PI / 180) * 180, (Math.PI / 180) * 360, true);
context.stroke();
//context.closePath();
context.beginPath();
context.arc(235, 110, 25, (Math.PI / 180) * 90, (Math.PI / 180) * 0, false);
context.fillStyle = "blue";
context.fill();
//context.stroke();
//context.closePath();
context.beginPath();
context.arc(285, 110, 25, (Math.PI / 180) * 180, (Math.PI / 180) * 45, false);
context.closePath();
context.stroke();
context.beginPath();
context.arc(335, 110, 25, (Math.PI / 180) * 180, (Math.PI / 180) * 45, false);
context.closePath();
context.fillStyle = "blue";
context.fill();
context.stroke();
//曲線
context.beginPath();
context.moveTo(10, 160); //二次貝塞爾曲線的起始點
//controlX, controlY, endX, endY
context.quadraticCurveTo(70, 280, 235, 140);
context.stroke();
context.closePath();
context.beginPath();
context.moveTo(10, 300); //三次貝塞爾曲線的起始點
//controlX1, controlY1, controlX2, controlY2, endX, endY
context.bezierCurveTo(70, 280, 50, 400, 235, 190);
context.stroke();
context.closePath();
}
);
各種變換
記得CSS3中的transform不?canvas肯定也有啊
平移
[javascript] view plaincopy
$(
function() {
var canvas = document.getElementById("mycanvas");
canvas.height = 500; //改變默認高度
canvas.width = 500;
var context = canvas.getContext("2d");
context.strokeStyle = "rgb(255, 0, 0)";
context.fillStyle = "#AABBCC";
context.lineWidth = 2;
context.shadowColor = "#0000FF";
context.moveTo(10, 10);
//context.beginPath();
//context.beginPath();
context.fillRect(10, 10, 50, 50); //實體矩形:x,y,width,height
//context.stroke();
$(canvas).on(
"click",
{ "context": context },
function(e) {
$.log(e.data.context);
var ctx = e.data.context;
ctx.translate(10, 10); //再最后的路徑點上偏移10*10的位置
context.fillRect(10, 10, 50, 50);
context.stroke();
}
);
}
);
縮放
[javascript] view plaincopy
$(
function() {
var canvas = document.getElementById("mycanvas");
canvas.height = 500; //改變默認高度
canvas.width = 500;
var context = canvas.getContext("2d");
context.strokeStyle = "rgb(255, 0, 0)";
context.fillStyle = "#AABBCC";
context.lineWidth = 2;
context.shadowColor = "#0000FF";
context.moveTo(10, 10);
//context.beginPath();
//context.beginPath();
context.fillRect(10, 10, 50, 50); //實體矩形:x,y,width,height
//context.stroke();
$(canvas).on(
"click",
{ "context": context },
function(e) {
$.log(e.data.context);
var ctx = e.data.context;
ctx.scale(1.1, 1.1); //在最后的大小基礎上縮放倍數 必須是正數
context.fillRect(10, 10, 50, 50);
context.stroke();
}
);
}
);
?
旋轉
[javascript] view plaincopy
$(
function() {
var canvas = document.getElementById("mycanvas");
canvas.height = 500; //改變默認高度
canvas.width = 500;
var context = canvas.getContext("2d");
context.strokeStyle = "rgb(255, 0, 0)";
context.fillStyle = "#AABBCC";
context.lineWidth = 2;
context.shadowColor = "#0000FF";
context.moveTo(10, 10);
//context.beginPath();
//context.beginPath();
context.fillRect(10, 10, 50, 50); //實體矩形:x,y,width,height
//context.stroke();
$(canvas).on(
"click",
{ "context": context },
function(e) {
$.log(e.data.context);
var ctx = e.data.context;
ctx.rotate((Math.PI / 180) * 10); //旋轉的角度,旋轉的中心是canvas坐標原點
context.fillRect(10, 10, 50, 50);
context.stroke();
}
);
}
);
?
?
transform,transform的參數比較多,也比較難理解,簡單的說transform是最自由的變形方式,下面給出些參考
[javascript] view plaincopy
//以下兩段代碼結果一致
context.transform(1, 0, 0, 1, 10, 10)
context.translate(10, 10);
//以下兩段代碼結果一致
context.transform(10, 0, 0, 10, 0, 0);
context.scale(10, 10);
//以下三段代碼結果一致
context.transform(Math.cos((Math.PI / 180) * 10), Math.sin((Math.PI / 180) * 10), -Math.sin((Math.PI / 180) * 10), Math.cos((Math.PI / 180)) * 10, 0, 0);
context.transform(-Math.sin((Math.PI/180)*10),Math.cos((Math.PI/180)*10),Math.cos((Math.PI/180)*10),Math.sin((Math.PI/180)*10), 0,0);
context.rotate(10);
?
組合
[javascript] view plaincopy
$(
function() {
var canvas = document.getElementById("mycanvas");
canvas.height = 100;
canvas.width = 100;
var context = canvas.getContext("2d");
context.fillStyle = "#AABBCC";
context.fillRect(10, 10, 50, 50);
//默認 新圖形會覆蓋在原有內容之上
context.globalCompositeOperation = "source-over";
context.fillStyle = "blue";
context.arc(70, 30, 25, (Math.PI / 180) * 0, (Math.PI / 180) * 360, false);
context.fill();
$("span").html(context.globalCompositeOperation);
$(canvas).toggle(
function() {
canvas.width = 100;
// 原有內容之下繪制新圖形
context.clearRect(0, 0, 500, 500);
context.beginPath();
context = canvas.getContext("2d");
context.fillStyle = "#AABBCC";
context.fillRect(10, 10, 50, 50);
context.globalCompositeOperation = "destination-over";
context.fillStyle = "blue";
context.arc(70, 30, 25, (Math.PI / 180) * 0, (Math.PI / 180) * 360, false);
context.fill();
$("span").html(context.globalCompositeOperation);
},
function() {
canvas.width = 100;
//新圖形會僅僅出現與原有內容重疊的部分。其它區域都變成透明的
context.clearRect(0, 0, 500, 500);
context.beginPath();
context.fillStyle = "#AABBCC";
context.fillRect(10, 10, 50, 50);
context.globalCompositeOperation = "source-in";
context.fillStyle = "blue";
context.arc(70, 30, 25, (Math.PI / 180) * 0, (Math.PI / 180) * 360, false);
context.fill();
$("span").html(context.globalCompositeOperation);
},
function() {
canvas.width = 100;
//原有內容中與新圖形重疊的部分會被保留,其它區域都變成透明的destination-in
context.clearRect(0, 0, 500, 500);
context.beginPath();
context = canvas.getContext("2d");
context.fillStyle = "#AABBCC";
context.fillRect(10, 10, 50, 50);
context.globalCompositeOperation = "destination-in";
context.fillStyle = "blue";
context.arc(70, 30, 25, (Math.PI / 180) * 0, (Math.PI / 180) * 360, false);
context.fill();
$("span").html(context.globalCompositeOperation);
},
function() {
canvas.width = 100;
//只有新圖形中與原有內容不重疊的部分會被繪制出來source-out
context.clearRect(0, 0, 500, 500);
context.beginPath();
context = canvas.getContext("2d");
context.fillStyle = "#AABBCC";
context.fillRect(10, 10, 50, 50);
context.globalCompositeOperation = "source-out";
context.fillStyle = "blue";
context.arc(70, 30, 25, (Math.PI / 180) * 0, (Math.PI / 180) * 360, false);
context.fill();
$("span").html(context.globalCompositeOperation);
},
function() {
canvas.width = 100;
//原有內容中與新圖形不重疊的部分會被保留
context.clearRect(0, 0, 500, 500);
context.beginPath();
context = canvas.getContext("2d");
context.fillStyle = "#AABBCC";
context.fillRect(10, 10, 50, 50);
context.globalCompositeOperation = "destination-out";
context.fillStyle = "blue";
context.arc(70, 30, 25, (Math.PI / 180) * 0, (Math.PI / 180) * 360, false);
context.fill();
$("span").html(context.globalCompositeOperation);
},
function() {
canvas.width = 100;
//新圖形中與原有內容重疊的部分會被繪制,并覆蓋于原有內容之上
context.clearRect(0, 0, 500, 500);
context.beginPath();
context = canvas.getContext("2d");
context.fillStyle = "#AABBCC";
context.fillRect(10, 10, 50, 50);
context.globalCompositeOperation = "source-atop";
context.fillStyle = "blue";
context.arc(70, 30, 25, (Math.PI / 180) * 0, (Math.PI / 180) * 360, false);
context.fill();
$("span").html(context.globalCompositeOperation);
},
function() {
canvas.width = 100;
//原有內容中與新內容重疊的部分會被保留,并會在原有內容之下繪制新圖形
context.clearRect(0, 0, 500, 500);
context.beginPath();
context = canvas.getContext("2d");
context.fillStyle = "#AABBCC";
context.fillRect(10, 10, 50, 50);
context.globalCompositeOperation = "destination-atop";
context.fillStyle = "blue";
context.arc(70, 30, 25, (Math.PI / 180) * 0, (Math.PI / 180) * 360, false);
context.fill();
$("span").html(context.globalCompositeOperation);
},
function() {
canvas.width = 100;
//兩圖形中重疊部分作加色處理
context.clearRect(0, 0, 500, 500);
context.beginPath();
context = canvas.getContext("2d");
context.fillStyle = "#AABBCC";
context.fillRect(10, 10, 50, 50);
context.globalCompositeOperation = "lighter";
context.fillStyle = "blue";
context.arc(70, 30, 25, (Math.PI / 180) * 0, (Math.PI / 180) * 360, false);
context.fill();
$("span").html(context.globalCompositeOperation);
},
function() {
canvas.width = 100;
//兩圖形中重疊的部分作減色處理darker
context.clearRect(0, 0, 500, 500);
context.beginPath();
context = canvas.getContext("2d");
context.fillStyle = "#AABBCC";
context.fillRect(10, 10, 50, 50);
context.globalCompositeOperation = "darker";
context.fillStyle = "blue";
context.arc(70, 30, 25, (Math.PI / 180) * 0, (Math.PI / 180) * 360, false);
context.fill();
$("span").html(context.globalCompositeOperation);
},
function() {
canvas.width = 100;
//重疊的部分會變成透明
context.clearRect(0, 0, 500, 500);
context.beginPath();
context = canvas.getContext("2d");
context.fillStyle = "#AABBCC";
context.fillRect(10, 10, 50, 50);
context.globalCompositeOperation = "xor";
context.fillStyle = "blue";
context.arc(70, 30, 25, (Math.PI / 180) * 0, (Math.PI / 180) * 360, false);
context.fill();
$("span").html(context.globalCompositeOperation);
},
function() {
canvas.width = 100;
//只有新圖形會被保留,其它都被清除掉
context.clearRect(0, 0, 500, 500);
context.beginPath();
context = canvas.getContext("2d");
context.fillStyle = "#AABBCC";
context.fillRect(10, 10, 50, 50);
context.globalCompositeOperation = "copy";
context.fillStyle = "blue";
context.arc(70, 30, 25, (Math.PI / 180) * 0, (Math.PI / 180) * 360, false);
context.fill();
$("span").html(context.globalCompositeOperation);
alert("演示結束");
}
);
}
);
?
字體(看文檔說canvas的字體支持CSS樣式的描寫,但是,我不知道怎么樣讓canvas的font支持CSS3的在線字體)
[javascript] view plaincopy
我們嘗試寫一圈旋轉的文字,吧上面的知識點合起來看看效果
[javascript] view plaincopy
$(
function() {
var canvas = document.getElementById("mycanvas");
canvas.height = 500;
canvas.width = 500;
var context = canvas.getContext("2d");
context.translate(150, 150);
context.scale(0.7, 0.7);
context.font = "12px Tahoma";
for (var i = 0; i < 12; i++) {
context.fillText((i + 3) % 12 == 0 ? 12 : (i + 3) % 12, 150, 10);
context.rotate((Math.PI / 6));
}
}
);
?
在具體繪制的時候,定位總是讓我這樣沒有空間感的人感覺痛苦,所以我現在canvas上畫上很多格子,幫助我進行布局
[javascript] view plaincopy
$(
function() {
var canvas = document.getElementById("mycanvas");
canvas.height = 500;
canvas.width = 500;
var context = canvas.getContext("2d");
context.lineWidth = 1;
context.strokeStyle = "rgb(211,211,211)";
for (var i = 0; i < 50; i++) {
$.log(i);
context.moveTo(i * 10, 0);
context.lineTo(i * 10, 500);
context.stroke();
}
for (var i = 0; i < 50; i++) {
$.log(i);
context.moveTo(0, i * 10);
context.lineTo(500, i * 10);
context.stroke();
}
}
);
?
前面的準備工作都完成了,現在我們來綜合下,完成一個具有時分秒的會動的鐘
[javascript] view plaincopy
$(
function() {
clock();
setInterval(clock, 1000);
}
);
function clock() {
var canvas = document.getElementById("mycanvas");
canvas.height = 500;
canvas.width = 500;
var context = canvas.getContext("2d");
context.beginPath();
context.lineWidth = 1;
context.strokeStyle = "rgb(211,211,211)";
for (var i = 0; i < 50; i++) {
$.log(i);
context.moveTo(i * 10, 0);
context.lineTo(i * 10, 500);
context.stroke();
}
for (var i = 0; i < 50; i++) {
$.log(i);
context.moveTo(0, i * 10);
context.lineTo(500, i * 10);
context.stroke();
}
context.beginPath();
context.strokeStyle = "rgb(255,0,0)";
context.arc(250, 250, 200, (Math.PI / 180) * 0, (Math.PI / 180) * 360, false);
context.stroke();
context.save(); //存儲當前畫布坐標系狀態
context.beginPath();
context.font = "14px Tahoma"
context.translate(255, 255); //將坐標系坐標原點移至圖中間
context.strokeStyle = "#FFFFFF";
for (var i = 0; i < 12; i++) {
context.fillText((i + 3) % 12 == 0 ? 12 : (i + 3) % 12, 180, 0);
context.rotate((Math.PI / 6));
}
context.restore();
context.save();
context.beginPath();
context.lineWidth = 5;
context.translate(255, 255); //將坐標系坐標原點移至圖中間
for (i = 0; i < 60; i++) {
if (i % 5 != 0) {
context.beginPath();
context.moveTo(180, 0);
context.lineTo(190, 0);
context.stroke();
}
context.rotate(Math.PI / 30);
}
context.restore();
var now = new Date();
var sec = now.getSeconds();
var min = now.getMinutes();
var hr = now.getHours() >= 12 ? now.getHours() - 12 : now.getHours();
context.save();
context.translate(255, 255); //將坐標系坐標原點移至圖中間
// - (Math.PI / 6) * 3 是因為0度在3點這里
context.rotate(hr * (Math.PI / 6) + (Math.PI / 360) * min + (Math.PI / 21600) * sec - (Math.PI / 6) * 3);
context.lineWidth = 14;
context.beginPath();
context.moveTo(-20, 0);
context.lineTo(150, 0);
context.stroke();
context.restore();
context.save();
context.translate(255, 255); //將坐標系坐標原點移至圖中間
context.rotate(min * (Math.PI / 30) + (Math.PI / 1800) * sec - (Math.PI / 6) * 3)
context.lineWidth = 10;
context.beginPath();
context.moveTo(-28, 0);
context.lineTo(160, 0);
context.stroke();
context.restore();
context.save();
context.translate(255, 255); //將坐標系坐標原點移至圖中間
context.lineWidth = 1;
context.rotate(sec * (Math.PI / 30) + (Math.PI / 1800) * sec - (Math.PI / 6) * 3)
context.lineWidth = 10;
context.beginPath();
context.moveTo(-28, 0);
context.lineTo(160, 0);
context.stroke();
context.restore();
}
?
?
轉載于:https://blog.51cto.com/wws5201985/812705
總結
以上是生活随笔為你收集整理的HTML5的绝活:巧用Canvas制作会动的时钟的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关于测试行业的零星思考
- 下一篇: UImageview加边框 加阴影