制圓形和圓弧都使用arc()方法:
Arc(x, y, r, startAngle, endAngle, antiClockwise)
Arc()方法是從(x,y)位置畫出半徑為r的圓形;
startAngle及endAngle決定圓弧的起點角度與終點角度; startAngle: 起點是X軸方向, 即3點鐘方向。
antiClockwise參數決定是否已逆時針方向繪圖,逆時針為true,順時針為false。
在canvas中所有涉及角度的坐標系有兩點注意的:
0弧度的方向是正右方向。
弧度的順時針和逆時針:
角度與弧度轉公式
角度轉弧度 π/180×角度
弧度變角度 180/π×弧度
將角度轉換為弧度,計算公式可以參考下面的公式:
radians = degrees * Math.PI/180
degrees 角度
radians 弧度
圓的弧度(360):360 * Math.PI/180 = Math.PI * 2 = 6.28
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>繪制圓</title>
<script type="text/javascript">
function drawCircle(){
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
//開始繪圖--圓
ctx.strokeStyle="#336600"; //設定邊框顏色
ctx.lineWidth=10; //設定線條寬度 10px
ctx.fillStyle="#FF0000"; //設定填充顏色
ctx.beginPath(); //路徑開始
ctx.arc(100,100,50,0,Math.PI*2,true); //起始點(100,100)半徑50的圓
ctx.closePath(); //關閉路徑
ctx.fill(); //繪出填滿圖形
ctx.stroke(); //繪出邊框
}
</script>
<!--style標記內是CSS語法-->
<style type="text/css">
Canvas { border: 1px solid black; } //將框線設為1px
</style>
</head>
<body>
<input type="button" value=" 畫 圓 " onclick="drawCircle();"><br />
<canvas id="myCanvas" width="400" height="200"></canvas>
</body>
</html>
繪制圓弧
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>繪制圓弧</title>
<style type="text/css">
canvas{
border: 1px solid #000;
}
</style>
</head>
<body>
<canvas width="600" height="400"></canvas>
</body>
<script type="text/javascript">
var canvas = document.querySelector("canvas")
var ctx = canvas.getContext("2d");
ctx.beginPath(); //開始繪制路徑
// ctx.arc(100, 100, 60, 0, 6.28, false);
// ctx.arc(100, 100, 60, 0, -6.28, true);
ctx.arc(100, 100, 60, 0, Math.PI * 2, false);
ctx.stroke(); //顯示路徑線
ctx.fillStyle = "pink"; //設置填充顏色
ctx.fill(); //填充顏色
</script>
</html>
繪制笑臉
<canvas> 是HTML中的一個元素,它可被用來通過 JavaScript(Canvas API 或 WebGL API)繪制圖形及圖形動畫。
Canvas API 提供了一個通過 JavaScript 和 HTML 的 <canvas> 元素來繪制圖形的方式。它可以用于動畫、游戲畫面、數據可視化、圖片編輯以及實時視頻處理等方面。
<canvas>標簽本身沒有繪圖能力,它僅僅是圖形的容器。在HTML,一般通過Javascript語言來完成實際的操作。
本文通過Javascript操作Canvas制作一個簡單的顯示當前時間的動畫時鐘,了解和學習簡單的canvas用法,僅以拋磚引玉。
首先創建一個HTML文件,為了方便管理,使用一個div標簽包裹兩個canvas標簽,并加上一些簡單的css樣式。
<!doctype html>
<html lang="zh-cn">
<head><title>Canvas繪制動畫時鐘</title>
<style>
html,body{margin:0;padding:0}
#clockWrap {
position: relative;
}
canvas {
position: absolute;
}
#clock-ui {
z-index: 2;
}
#clock-plate {
z-index: 1;
}
</style>
</head>
<body>
<div id="clockWrap">
<canvas id="clock-plate"></canvas>
<canvas id="clock-ui"></canvas>
</div>
<script></script>
</body></html>
本示例中使用了兩個canvas標簽(為什么使用兩個,一個不是更簡單嗎?),一個用于繪制鐘面,一個根據當前時間實時顯示和更新時針、分針和秒針的動態指向。好了,話不多說,開干。
一個簡單的時鐘,可以分為鐘面上的刻度和指針。其中刻度和12個數字是固定的,我們可以將它們繪制在當作背景的canvas上(示例中id為clock-plate的canvas)。
(1)要使用canvas,首先必須通過容器獲取渲染上下文:
var $=function(id){return document.querySelector(id);}//這個函數只是為了方便獲取dom元素
const canvasbg=$("#clock-plate"),
canvas=$("#clock-ui"),
ctx = canvasbg.getContext("2d"),//背景容器上下文
ctxUI = canvas.getContext("2d");//指針容器上下文,后面代碼要用
//定義畫布寬度和高度,時鐘圓直徑,并設置畫布大小
const oW=1000,oH=800,cW=400,r=cW/2,oX=oW/2,oY=oH/2;
canvas.width=oW;
canvas.height=oH;
canvasbg.width=oW;
canvasbg.height=oH;
(2)畫鐘的邊框,為了好看,這里畫兩個圈:
//畫出時鐘外圓框
ctx.lineWidth = 12;
ctx.beginPath();
ctx.arc(oX, oY, r+14, 0, 2 * Math.PI);
ctx.stroke();
ctx.closePath();
ctx.lineWidth = 8;
//畫出時鐘內圓框(刻度圈)
ctx.beginPath();
ctx.arc(oX, oY, r, 0, 2 * Math.PI);
ctx.stroke();
ctx.closePath();
ctx.beginPath();
邊框效果圖
(3)繪制刻度線和數字,可以利用三角函數計算出每個刻度的坐標:
利用三角函數計算刻度線的坐標位置
鐘面上有12個大格,從正上方12開始,它們的度數分別是270,300,330,0,30,60,90,120,150,180,210,240。然后利用JS的Math.sin和Math.cos分別計算出各大格的坐標。注意:js中Math.sin()和Math.cos()的參數不是角度數是弧度。可以使用Math.PI/180*角度來轉化,比如將30度轉換成弧度=Math.PI/180*30
//繪制鐘表中心點
ctx.beginPath();
ctx.arc(oX, oY, 8, 0, 2 * Math.PI);//圓心
ctx.fill();
ctx.closePath();
//設置刻度線粗細度
ctx.lineWidth = 3;
//設置鐘面12個數字的字體、大小和對齊方式
ctx.font = "30px serif";
ctx.textAlign="center";
ctx.textBaseline="middle";
var kdx,kdy;
//繪制12個大刻度和12個數字
//為方便計算,先定義了0-11這12個刻度對應的度數,也可以直接定義對應的弧度。
const hd=Math.PI/180,degr=[270,300,330,0,30,60,90,120,150,180,210,240];
for(var i=0;i<12;i++){
kdx=oX+Math.cos(hd*degr[i])*(r-3);
kdy=oY+Math.sin(hd*degr[i])*(r-3);
ctx.beginPath();
ctx.arc(kdx, kdy, 6, 0, 2 * Math.PI);//畫圓形大刻度
ctx.fill();
//繪制刻度對應的數字
ctx.strokeText(i==0? 12 : i,oX+Math.cos(hd*degr[i])*(r-24),oY+Math.sin(hd*degr[i])*(r-24));
ctx.closePath();
}
//繪制小刻度
ctx.lineWidth = 2;
for(var i=0;i<60;i++){
if(i % 5 == 0) continue;//跳過與刻度重疊的刻度
x0=Math.cos(hd*i*6);
y0=Math.sin(hd*i*6);
ctx.beginPath();
ctx.moveTo(oX+x0*(r-10), oY+y0*(r-10));
ctx.lineTo(oX+x0*r, oY+y0*r); //畫短刻度線
ctx.stroke();
ctx.closePath();
}
效果如圖:
鐘面效果圖
(4)根據當前時間繪制指針
習慣上,時針粗短,分針略粗而長,秒針細長。為加大區別,示例中秒針細長并且繪制成紅色。
function drawHp(i){//繪制時針
const x0=Math.cos(hd*i*30),y0=Math.sin(hd*i*30);
drawPointer(oX,oY,oX+x0*(r-90),oY+y0*(r-90),10,"#000000");
}
function drawMp(i){//繪制分針
const x0=Math.cos(hd*i*6),y0=Math.sin(hd*i*6);
drawPointer(oX,oY,oX+x0*(r-60),oY+y0*(r-60),5,"#000000");
}
function drawSp(i){//繪制秒針
const x0=Math.cos(hd*i*6),y0=Math.sin(hd*i*6);
drawPointer(oX,oY,oX+x0*(r-20),oY+y0*(r-20),2,"#FF0000");
}
//抽取出繪制三種指針時共同的部分,注意指針繪制在渲染上下文ctxUI中
function drawPointer(ox,oy,tx,ty,width,color){
ctxUI.strokeStyle = color;
ctxUI.lineCap = "round";
ctxUI.lineWidth = width;
ctxUI.beginPath();
ctxUI.moveTo(ox, oy);
ctxUI.lineTo(tx,ty);
ctxUI.stroke();
ctxUI.closePath();
}
現在已經有了繪制三種指針的方法,參數是當前時間的時、分和秒,將根據它們的值確定指針的坐標。不過,因為使用的是默認的convas坐標體系,0值實際指向3的位置,需要小小的修正一下。
window.requestAnimationFrame(function fn(){
var d = new Date();
ctxUI.clearRect(0,0,oW,oH);
//度數從0開始,而0在3刻度(15分/秒位置),修正為全值減15,如果小于0則修正回來
var hour=d.getHours(),minute=d.getMinutes()-15,second=d.getSeconds()-15;
hour=hour>11? hour-15 : hour-3;
drawHp(hour>=0? hour : 12+hour);
drawMp(minute>=0? minute : 60+minute);
drawSp(second>=0? second : 60+second);
window.requestAnimationFrame(fn);
});
接下來,調用window.requestAnimationFrame,在其中繪制并更新指標的位置。看看效果如何:
指針繪制情況與實際時間相符
貌似效果有了,截圖時電腦上的時間是10時17分,指針繪制上,時針指向10時,分針指向17。嗯,感覺有點別扭?對了,時針和分針怎么是端端正正地指向它們的整時整分刻度上呢?實際鐘表上時針和分針是展示動態進度的,此時時針應該越過10時的位置才對。沒關系,我們在繪制時針和分針時別點東西,讓它的角度值加上分針和秒針的值試試。
//修改后的繪制三種指針的方法
function drawHp(i,f,m){//繪制時針,參數:時,分,秒
const x0=Math.cos(hd*(i+(f/60)+(m/600))*30),y0=Math.sin(hd*(i+(f/60)+(m/600))*30);
drawPointer(oX,oY,oX+x0*(r-90),oY+y0*(r-90),10,"#000000");
}
function drawMp(i,f){//繪制分針,參數,分,秒
const x0=Math.cos(hd*(i+(f/60))*6),y0=Math.sin(hd*(i+(f/60))*6);
drawPointer(oX,oY,oX+x0*(r-60),oY+y0*(r-60),5,"#000000");
}
function drawSp(i){//繪制秒針
const x0=Math.cos(hd*i*6),y0=Math.sin(hd*i*6);
drawPointer(oX,oY,oX+x0*(r-20),oY+y0*(r-20),2,"#FF0000");
}
再來看看效果,嗯,立竿見影呀:
指針指向更合理了
到此為止,canvas繪制一個簡易時鐘就完成了。下面繼續優化一下。剛才使用requestAnimationFrame方法即時更新繪制情況。這個方法與刷新率有關,看看mdn上面怎么說的:
window.requestAnimationFrame() 方法會告訴瀏覽器你希望執行一個動畫。它要求瀏覽器在下一次重繪之前,調用用戶提供的回調函數。
對回調函數的調用頻率通常與顯示器的刷新率相匹配。雖然 75hz、120hz 和 144hz 也被廣泛使用,但是最常見的刷新率還是 60hz(每秒 60 個周期/幀)。為了提高性能和電池壽命,大多數瀏覽器都會暫停在后臺選項卡或者隱藏的 <iframe> 中運行的 requestAnimationFrame()。
本示例中,更新指針的位置并不需要很高的刷新頻率,可以通過節流進行一下優化:
var fps = 5, fpsInterval = 1000 / fps,lastTime = new Date().getTime(); //記錄上次執行的時間
function runStep() {
requestAnimationFrame(runStep);
var d=new Date(),now = d.getTime()
var elapsed = now - lastTime;
if (elapsed > fpsInterval) {
ctxUI.clearRect(0,0,oW,oH);
lastTime = now - (elapsed % fpsInterval);
//度數從0開始,而0在3刻度(15分/秒位置),修正為全值-15,如果小于0則用60減回
var hour=d.getHours(),minute=d.getMinutes()-15,second=d.getSeconds()-15;//console.log(d.getSeconds(),second);
hour=hour>11? hour-15 : hour-3;
drawHp(hour>=0? hour : 12+hour,minute+15,second+15);
drawMp(minute>=0? minute : 60+minute,second+15);
drawSp(second>=0? second : 60+second);
}
}
runStep();
當然,實現時鐘的方法是很多,比如可以使用畫布的旋轉(rotate方法)來實現指針的動態轉動等等。
完整HTML+JS源碼:
.說明:
推薦指數:★★★★
通俗易懂,小白一看就會,高手請飄過。
學python也是需要懂一點Html、Css、JavaScript的基礎知識的。
建議使用vscode編輯器。
2.效果圖1
3.代碼:保存為html,用瀏覽器打開即可。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>圓形百分比進度條效果</title>
<style type="text/css">
*{
margin: 0;
padding: 0;
}
.bg{
width: 200px;
height: 200px;
border-radius: 100%;
background: #ccc;
position: relative;
margin: 20px auto;
}
.circle-right, .circle-left, .mask-right, .mask-left{
width: 200px;
height: 200px;
border-radius: 100%;
position: absolute;
top: 0;
left: 0;
}
.circle-right, .circle-left{
background: skyblue;
}
.mask-right, .mask-left{
background: #ccc;
}
.circle-right, .mask-right{
clip: rect(0,200px,200px,100px);
}
.circle-left, .mask-left{
clip: rect(0,100px,200px,0);
}
.text{
width: 160px;
height: 160px;
line-height: 160px;
text-align: center;
font-size: 34px;
color: deepskyblue;
border-radius: 100%;
background: #fff;
position: absolute;
top: 20px;
left: 20px;
}
</style>
</head>
<body>
<div class="bg">
<div class="circle-right"></div>
<!--100%是顯示百分數,動態顯示由0~100-->
<div class="text">100%</div>
</div>
<script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script>
<script type="text/javascript">
$(function(){
//獲取百分比值
var num = parseInt($('.text').html());
//通過計時器來顯示過渡的百分比進度
var temp = 0;
var timer = setInterval(function(){
calculate(temp);
//清除計時器結束該方法調用
if(temp == num){
clearInterval(timer);
}
temp++;
},30)
//改變頁面顯示百分比
function calculate(value){
//改變頁面顯示的值
$('.text').html(value + '%');
//清除上次調用該方法殘留的效果
$('.circle-left').remove();
$('.mask-right').remove();
//當百分比小于等于50
if(value <= 50){
var html = '';
html += '<div class="mask-right" style="transform:rotate('+ (value * 3.6) +'deg)"></div>';
//元素里添加子元素
$('.circle-right').append(html);
}else{
value -= 50;
var html = '';
html += '<div class="circle-left">';
html += '<div class="mask-left" style="transform:rotate('+ (value * 3.6) +'deg)"></div>';
html += '</div>';
//元素后添加元素
$('.circle-right').after(html);
}
}
})
</script>
</body>
</html>
4.拆分法:把一個含有css和js(JavaScript)的html,拆掉三個文件,一個叫cirbar1.html,另外的叫:cirbar1.css和cirbar1.js文件,放在同一個文件夾內。這是./的意思,也可以指定文件夾。
4.1 cirbar1.html的代碼:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>圓形百分比進度條效果v2</title>
<!--如果是style type="text/css"這種直接在html中設置css,注意起始是*,不是點-->
<!--style type="text/css"-->
<link href="./cirbar1.css" rel="stylesheet" />
</head>
<body>
<div class="bg">
<div class="circle-right"></div>
<div class="text">100%</div>
</div>
<!--這個外部js文件=jquery.min.js,不能少,否則不能動了-->
<script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"--></script>
<!--同樣的,把寫在html的js,新建一個cirbar1.js,復制下去,保存,這樣子簡潔很多-->
<!--script type="text/javascript"-->
<script src="./cirbar1.js"></script>
</body>
</html>
4.2 cirbar1.css的代碼:
*{
margin: 0;
padding: 0;
}
.bg{
width: 200px;
height: 200px;
border-radius: 100%;
background: #ccc;
position: relative;
margin: 20px auto;
}
.circle-right, .circle-left, .mask-right, .mask-left{
width: 200px;
height: 200px;
border-radius: 100%;
position: absolute;
top: 0;
left: 0;
}
.circle-right, .circle-left{
background: skyblue;
}
.mask-right, .mask-left{
background: #ccc;
}
.circle-right, .mask-right{
clip: rect(0,200px,200px,100px);
}
.circle-left, .mask-left{
clip: rect(0,100px,200px,0);
}
.text{
width: 160px;
height: 160px;
line-height: 160px;
text-align: center;
font-size: 34px;
color: deepskyblue;
border-radius: 100%;
background: #fff;
position: absolute;
top: 20px;
left: 20px;
}
4.3 cirbar1.js的代碼:
$(function(){
//獲取百分比值
var num = parseInt($('.text').html());
//通過計時器來顯示過渡的百分比進度
var temp = 0;
var timer = setInterval(function(){
calculate(temp);
//清除計時器結束該方法調用
if(temp == num){
clearInterval(timer);
}
temp++;
},30)
//改變頁面顯示百分比
function calculate(value){
//改變頁面顯示的值
$('.text').html(value + '%');
//清除上次調用該方法殘留的效果
$('.circle-left').remove();
$('.mask-right').remove();
//當百分比小于等于50
if(value <= 50){
var html = '';
html += '<div class="mask-right" style="transform:rotate('+ (value * 3.6) +'deg)"></div>';
//元素里添加子元素
$('.circle-right').append(html);
}else{
value -= 50;
var html = '';
html += '<div class="circle-left">';
html += '<div class="mask-left" style="transform:rotate('+ (value * 3.6) +'deg)"></div>';
html += '</div>';
//元素后添加元素
$('.circle-right').after(html);
}
}
})
==============================
再來一個,不用外部js文件的圓形進度條
順帶回顧一下相關知識。
==============================
5.效果圖
6.三個文件,放在同一個文件夾中
6.1 cirbar.html代碼:
<!--第1步---聲明html5-->
<!DOCTYPE html>
<!--第2步---html大框架-->
<html lang="en">
<!--第2-1步---head部分-->
<head>
<!--第2-1-1步---meta部分:聲明字符編碼格式:utf-8-->
<!--注意與python的第一行聲明一樣:# -*- coding: utf-8 -*-->
<meta charset="utf-8" />
<!--第2-1-2步---標題名稱-->
<title>圓形進度條v1</title>
<!--注意:./代表同一個文件夾下,也就是css和js文件與本html文件放在同一個文件夾下-->
<!--第2-1-3步---導入css文件-->
<link href="./cirbar.css" rel="stylesheet" />
</head>
<!--第2-2步---body部分-->
<body>
<!--第2-2-1步---定義畫布部分,注意沒有逗號隔開,大小設置-->
<canvas class="canvas" id="canvas" width="400" height="400"></canvas>
<!--第2-2-2步---導入js文件部分-->
<script src="./cirbar.js"></script>
<!--注意收尾-->
</body>
<!--注意收尾-->
</html>
6.2 cirbar.css代碼:
.canvas {
/*畫布的背景顏色設置為:黑色*/
background:#303030;
}
6.3 cirbar.js代碼:
window.onload = function () {
var canvas = document.getElementById('canvas'), //獲取canvas元素
context = canvas.getContext('2d'), //獲取畫圖環境,指明為2d
centerX = canvas.width / 2, //Canvas中心點x軸坐標
centerY = canvas.height / 2, //Canvas中心點y軸坐標
rad = Math.PI * 2 / 100, //將360度分成100份,那么每一份就是rad度
speed = 0.1; //加載的快慢就靠它了
//繪制紅色外圈
function blueCircle(n) {
context.save();
context.strokeStyle = " #1E90FF"; //隨百分數轉動的外圈的顏色為藍色
context.lineWidth = 3; //設置線寬
context.beginPath(); //路徑開始
//注意-為順時針,+為逆時針
//用于繪制圓弧context.arc(x坐標,y坐標,半徑,起始角度,終止角度,順時針/逆時針)
//context.arc(centerX, centerY, 50, Math.PI / 2, Math.PI / 2 - n * rad, false);
context.arc(centerX, centerY, 50, -Math.PI / 2, -(Math.PI / 2 - n * rad), false);
context.stroke(); //繪制
context.closePath(); //路徑結束
context.restore();
}
//繪制白色外圈,初始的白色外圈
function whiteCircle() {
context.save();
context.beginPath();
// 下面百分數的字體顏色設置后上面的外圈的顏色竟然保持一樣
//context.strokeStyle = "#F8F8FF";
context.arc(centerX, centerY, 50, 0, Math.PI * 2, false);
context.stroke();
context.closePath();
context.restore();
}
//百分比文字繪制
function text(n) {
context.save(); //save和restore可以保證樣式屬性只運用于該段canvas元素
context.strokeStyle = "#7FFF00";//設置中間動態百分數的顏色
context.font = "25px Arial"; //設置字體大小和字體
context.textAlign = 'center';//字體水平居中
context.textBaseline = 'middle';//字體垂直居中
//繪制字體,并且指定位置
context.strokeText(n.toFixed(0) + "%", centerX, centerY);
context.stroke(); //執行繪制
context.restore();
}
//循環獲取
(function drawFrame() {
window.requestAnimationFrame(drawFrame, canvas);
context.clearRect(0, 0, canvas.width, canvas.height);
whiteCircle();
text(speed);
blueCircle(speed);
if (speed < 100) {
//1可從后臺獲取值,也是從0~100,step為1,代表速度
speed += 1;
}
}());
}
注意到6.3js文件與4.3js文件的區別了么?一個有:window.onload =,一個沒有,且只有$和小括號,因為外部的就是文件定義了一部分功能。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。