弧度與sin及cos的關(guān)系
目的:
通過(guò)理解弧度與sin及cos的關(guān)系,可以根據(jù)弧度及半徑求出旋轉(zhuǎn)指定弧度后所到達(dá)的dx,dy坐標(biāo)
弧度(angle)與角度(degree)的關(guān)系:
- 360角度 = 2π
- 1角度 = π/180弧度
- 1弧度 = 180/π角度
即:30角度的弧度值 = 30 * (π/180) ,30弧度的角度值 = 30 * (180/π)
通過(guò)弧度與半徑求旋轉(zhuǎn)指定弧度后目標(biāo)點(diǎn)的坐標(biāo):
- sin(angle) = y/r:y為角的對(duì)邊長(zhǎng)度,即旋轉(zhuǎn)后坐標(biāo)點(diǎn)的y坐標(biāo);r為半徑,為斜邊長(zhǎng)
- cos(angle) = x/r:x為角的鄰邊長(zhǎng)度,即旋轉(zhuǎn)后坐標(biāo)點(diǎn)的x坐標(biāo);r為半徑,為斜邊長(zhǎng)
故圍繞中心點(diǎn)(0,0)旋轉(zhuǎn)求值:dx = cos(angle) * r,dy = sin(angle) * r
注:若中心點(diǎn)為(10,20),則dx = 10 + cos(angle) * r,dy = 20 + sin(angle) * r
五角星代碼示例1
<body>
<script>
window.onload = function() {
var canvas = document.getElementById("canvas");
if (canvas == null) {
return false;
}
var ctx = canvas.getContext("2d");
drawLine(ctx);
drawStar(ctx);
}
//畫(huà)橫豎線(田字格)
function drawLine(ctx) {
ctx.strokeStyle = "#ccc";
//劃?rùn)M線
for (var i = 0.5; i < 500; i++) {
ctx.beginPath();
ctx.moveTo(0, i * 10);
ctx.lineTo(500, i * 10);
ctx.stroke();
}
//劃豎線
for (var i = 0.5; i < 500; i++) {
ctx.beginPath();
ctx.moveTo(i * 10, 0);
ctx.lineTo(i * 10, 500);
ctx.stroke();
}
}
// 畫(huà)五角星、外邊圓,并繪畫(huà)出以圓心為圓點(diǎn)的坐標(biāo)軸及各角到圓心的直線
function drawStar(ctx) {
//五角星圓心的坐標(biāo)位置
var dx = 200;
var dy = 200;
//繪制出五角星外邊圓圓心
ctx.beginPath();
ctx.arc(dx, dy, 5, 0, 2 * Math.PI, true);
ctx.fillStyle = "#f00";
ctx.strokeStyle = "#f00";
//設(shè)置字號(hào),字體
ctx.font = "14px Verdana";
ctx.strokeText("圓心", dx, dy);
ctx.fill();
//五角星外邊圓的半徑,即圓心到各個(gè)角的距離
var size = 100;
ctx.beginPath();
/*定義一個(gè)起始弧度,從這個(gè)弧度開(kāi)始畫(huà)*/
var startAngle = -Math.PI * 0.5; //逆時(shí)針的一個(gè)直角弧度,位于y軸坐標(biāo)正上方位置
/*
*1.五角星劃線的角度:一個(gè)圓的弧度為2π,分為5個(gè)角即2π/5(任意兩個(gè)點(diǎn)到圓心形成的角度)
*2.2π/5為藍(lán)線圓心-0,圓心-3形成的角度,而五角星劃線是從0-1,所以圓心-0,圓心-1的角度是它的兩倍,故須*2
*3.圓心-0,圓心-3可以通過(guò)此代碼打開(kāi)網(wǎng)頁(yè)查看
*/
/*dig為圓心-0,圓心-1形成的弧度*/
var dig = (2 * Math.PI / 5) * 2;
/*開(kāi)始畫(huà)五角星圖*/
ctx.beginPath();
for (var i = 0; i < 5; i++) {
//正弧度順時(shí)針旋轉(zhuǎn),負(fù)弧度逆時(shí)針旋轉(zhuǎn)
var angle = startAngle + dig * i;
/*獲取當(dāng)前角度下一個(gè)點(diǎn)的x軸坐標(biāo):Math.cos(angle) * size*/
//cos(弧度) = x坐標(biāo)/r r為半徑 = 這里的size
var x = dx + Math.cos(angle) * size; //因弧度是以dx,dy為圓心旋轉(zhuǎn),所以需要加上dx,dy的坐標(biāo),以保持圖形的圓心仍為dx,dy
/*獲取當(dāng)前角度下一個(gè)點(diǎn)的y軸坐標(biāo):Math.sin(angle) * size*/
//sin(弧度) = y坐標(biāo)/r r為半徑 = 這里的size
var y = dy + Math.sin(angle) * size;
console.log("x:" + x);
console.log("y:" + y);
ctx.lineTo(x, y);
//給輸出文字設(shè)置顏色
ctx.strokeStyle = "#00f";
//輸出劃線先后順序
ctx.strokeText(i, x, y);
}
//這里必須寫(xiě),否則五角星會(huì)少stroke一條線(不影響fill)
//closePath,閉合圖形在非閉合狀態(tài)下,會(huì)通過(guò)此方法從當(dāng)前點(diǎn)至起始點(diǎn)畫(huà)一條直線
ctx.closePath();
ctx.fillStyle = "rgba(255,255,0,0.5)";
//填充
ctx.fill();
//輸出文字的時(shí)候設(shè)置過(guò),狀態(tài)已被ctx保存,無(wú)須再設(shè)置。
//ctx.strokeStyle = "#00f";
//劃線
ctx.stroke();
/*劃圓心到各角的線*/
ctx.beginPath();
var startAngle = -Math.PI * 0.5;
for (var i = 0; i < 5; i++) {
var angle = startAngle + dig * i;
var x = dx + Math.cos(angle) * size;
var y = dy + Math.sin(angle) * size;
console.log("x:" + x);
console.log("y:" + y);
ctx.moveTo(x, y);
ctx.lineTo(dx, dy);
}
//closePath這里可以不寫(xiě),因?yàn)檫@里劃的都是線,無(wú)需閉合
//ctx.closePath();
ctx.strokeStyle = "#f00";
ctx.stroke();
/*開(kāi)始畫(huà)五角星周邊圓*/
ctx.beginPath();
ctx.arc(dx, dy, size, 0, 2 * Math.PI, true);
ctx.strokeStyle = "#f00";
ctx.stroke();
/*以圓心為起點(diǎn)開(kāi)始畫(huà)坐標(biāo)軸*/
/*坐標(biāo)軸顏色*/
ctx.strokeStyle = "#000";
//橫坐標(biāo)
ctx.beginPath();
ctx.moveTo(0, dy);
ctx.lineTo(500, dy);
ctx.stroke();
//縱坐標(biāo)
ctx.beginPath();
ctx.moveTo(dx, 0);
ctx.lineTo(dx, 500);
ctx.stroke();
}
</script>
<canvas id="canvas" height="500" width="500"></canvas>
</body>
五角星代碼示例2
<script>
function strokeFiveStar() {
var canvas = document.getElementById("canvas");
if (canvas == null) {
return false;
}
var ctx = canvas.getContext("2d");
/*圓心坐標(biāo)*/
var cx = 200;
var cy = 200;
/*繪制圓心*/
ctx.arc(cx, cy, 5, 0, 2 * Math.PI, false);
ctx.fillStyle = "#f00";
ctx.fill();
/*定義起始繪制點(diǎn)弧度 -90角度,y軸正上方*/
var startAngle = -Math.PI / 2;
//定義半徑
var r = 100;
//繪制線條兩點(diǎn)(如第1個(gè)點(diǎn)與第2個(gè)點(diǎn))與圓心點(diǎn)構(gòu)成的弧度
var dig = (2 * Math.PI / 5) * 2;
ctx.beginPath();
/*根據(jù)角度連接5個(gè)點(diǎn)*/
for (var i = 0; i < 5; i++) {
var dx = cx + Math.cos(startAngle + dig * i) * r;
var dy = cy + Math.sin(startAngle + dig * i) * r;
/*i=0時(shí),因沒(méi)有子路徑,故lineTo的作用相當(dāng)于moveTo*/
ctx.lineTo(dx, dy);
ctx.strokeText("第" + (i + 1) + "個(gè)點(diǎn)", dx, dy);
}
/*將最后一個(gè)點(diǎn)連接到第一個(gè)點(diǎn)*/
ctx.closePath();
ctx.stroke();
}
</script>
Canvas圖形綜合操作globalCompositeOperation
使用方法:
ctx.globalCompositeOperation = type
12種type值的介紹:
- source-over:新圖形覆蓋原圖形,其他部分正常顯示
- destination-over:原圖形覆蓋新圖形,其他部分正常顯示
- source-in:只顯示在原圖形里面的新圖形,其他部分透明
- destination-in:只顯示在新圖形里面的原圖形,其他部分透明
- source-out:只顯示在原圖形之外的新圖形,其他部分透明
- destination-out:只顯示在新圖形之外的原圖形,其他部分透明
- source-atop:新圖形只繪制在原圖形之上,原圖形其他部分正常顯示
- destination-atop:原圖形只繪制在新圖形之上,原圖形其他部分正常顯示
- lighter:重疊部分變亮,其他部分正常顯示
- darker:重疊部分變暗,其他部分正常顯示
- xor:重疊部分透明,其他部分正常顯示
- copy:只保留新圖形,其他部分透明
以上類(lèi)型的比較可參考Mozilla開(kāi)發(fā)者文檔的globalCompositeOperation屬性
<!-- globalCompositeOperation demo-->
<head>
<meta charset="UTF-8">
<title>globalCompostionOperation</title>
<script>
function draw(id) {
var canvas = document.getElementById(id);
if(canvas == null) {
return false;
}
var ctx = canvas.getContext("2d");
var types = new Array(
/*0*/"source-over", /*覆蓋原圖形,其他部分正常顯示*/
/*1*/"destination-over",/*覆蓋新圖形,其他部分正常顯示*/
/*2 chrome不支持*/"source-in",/*原圖形之內(nèi)的新圖形,其他(原圖形&新圖形)都透明*/
/*3 chrome不支持*/"destination-in",/*新圖形之內(nèi)的原圖形,其他(原圖形&新圖形)都透明*/
/*4*/"source-out",/*原圖形之外的新圖形,其他(原圖形&新圖形)都透明*/
/*5 chrome不支持*/"destination-out",/*新圖形之外的原圖形,其他(原圖形&新圖形)都透明*/
/*6 chrome不支持*/"source-atop",/*原圖形之上,新圖形只繪制原圖形范圍內(nèi)部分,其他部分正常顯示*/
/*7*/"destination-atop",/*新圖形之上,原圖形只繪制新圖形范圍內(nèi)部分,其他部分正常顯示*/
/*8 chrome不支持*/"lighter",/*重疊部分加色,其他不變*/
/*9 chrome不支持*/"darker",/*重疊部分減色,其他不變*/
/*10*/"xor",/*重疊部分透明,其他不變*/
/*11*/"copy"/*只保留新圖形,其他清除*/
/*以上類(lèi)型,詳情可參考:https://developer.mozilla.org/zh-CN/docs/Web/API/Canvas_API/Tutorial/Compositing*/
);
/*設(shè)置圖形疊加組合模式*/
ctx.globalCompositeOperation = types[10];
ctx.fillStyle = "#f00";
ctx.fillRect(100,100,200,200);
ctx.fillStyle = "#ff0";
ctx.fillRect(150,150,200,200);
}
</script>
</head>
<body onload="draw('canvas')">
<canvas id="canvas" height="500" width="500"></canvas>
</body>
Canvas繪制陰影效果
功能:
為ctx設(shè)置陰影效果后,在當(dāng)前ctx狀態(tài)下,canvas中繪制的圖像都將出現(xiàn)陰影。
使用方法:
- shadowOffsetX:距離圖形當(dāng)前坐標(biāo)軸x軸的偏移量,默認(rèn)值為0
- shadowOffsetY:距離圖形當(dāng)前坐標(biāo)軸y軸的偏移量,默認(rèn)值為0
- shadowColor:陰影的顏色,默認(rèn)值為fully-transparent black,即透明
- shadowBlur:陰影的模糊程度,默認(rèn)值為0
代碼示例:
<body>
<script>
window.onload = function () {
var canvas = document.getElementById("canvas");
if (canvas == null) {
return false;
}
var ctx = canvas.getContext("2d");
/*設(shè)置x坐標(biāo)陰影偏移量*/
ctx.shadowOffsetX = -10;
/*設(shè)置y坐標(biāo)陰影偏移量*/
ctx.shadowOffsetY = 10;
/*設(shè)置陰影顏色*/
ctx.shadowColor = "#ccc";
/*設(shè)置陰影模糊程度,默認(rèn)是0*/
ctx.shadowBlur = 20;
/*繪制圖形*/
ctx.fillStyle = "#ff0";
ctx.fillRect(100,100,50,50);
/*這個(gè)圖形一樣會(huì)有陰影效果,ctx的狀態(tài)不斷被更新*/
ctx.fillStyle = "#ff0";
ctx.fillRect(200,100,50,50);
}
</script>
<canvas id="canvas" width="500" height="500">您的瀏覽器不支持</canvas>
</body>
Canvas的圖像繪制:drawImage
功能:
通過(guò)canvas的drawImage方法 ,將指定圖片繪制到canvas畫(huà)布上。
繪制流程:
- 創(chuàng)建一個(gè)圖片對(duì)象,用來(lái)承載圖像
var img = new Image();
- 設(shè)置圖像源
img.src = "xxx.jpg;"
- 監(jiān)聽(tīng)圖像對(duì)象的onload事件,圖像加載完成后會(huì)執(zhí)行該事件指定的函數(shù)
img.onload = draw
- 在onload制定的draw函數(shù)中通過(guò)drawImage方法將img對(duì)象中的圖像繪制到canvas畫(huà)布中
drawImage的3種方法:
drawImage(img,destX,destY):以畫(huà)布的destX、destY作為圖像顯示起始點(diǎn),將整個(gè)img圖像按圖像原始像素繪制到畫(huà)布中,超出畫(huà)布不繪制;
drawImage(img,destX,destY,destWidth,destHeight):將整個(gè)img圖像繪制到畫(huà)布中,以畫(huà)布的destX、destY作為顯示圖像的起始點(diǎn),destWidth、destHeight作為圖像的顯示大小;若destWidth、destHeight大于圖像原始像素,則圖像會(huì)放大(會(huì)模糊);反之則縮小。
drawImage(img,sourceX,sourceY,sourceWidth,sourceHeight,destX,destY,destWidth,destHeight):從img的sourceX、sourceY起始點(diǎn),獲取sourceWidth、sourceHeight大小的圖像,并將獲取到的圖像draw到畫(huà)布中,從畫(huà)布的destX、destY起始點(diǎn)開(kāi)始繪制,將獲取到的圖像繪制成destWidth、destHeight大小(destWidth、destHeight若大于sourceWidth、sourceHeight,圖像會(huì)放大即模糊;反之則縮小)
示例代碼:
<script>
window.onload = function () {
var canvas = document.getElementById("canvas");
if (canvas == null) {
return false;
}
var ctx = canvas.getContext("2d");
/*創(chuàng)建一個(gè)圖片對(duì)象*/
var img = new Image();
/*監(jiān)聽(tīng)圖片加載,加載成功結(jié)束后執(zhí)行*/
img.onload = function () {
/*將原圖draw到畫(huà)布上,超出畫(huà)布部分,不繪制*/
ctx.drawImage(img, 0, 0);
/*將整個(gè)img繪制到畫(huà)布上,畫(huà)布上的img起始點(diǎn)為100,100,寬高為300*300*/
ctx.drawImage(img, 100, 100, 200, 200);
/*以img的200,200為起始點(diǎn),在img上獲取寬高位150*150范圍的圖片,
并將獲取到的圖片粘貼到畫(huà)布坐標(biāo)300,300的位置上,圖片大小為200*200*/
/*圖片會(huì)變模糊,因?yàn)閟ource的大小是150*150,而dest的大小為200*200*/
ctx.drawImage(img, 200, 200, 150, 150, 300, 300, 200, 200);
}
img.src = "../raw/1.jpg";
};
</script>
CreateJs之EaselJs基礎(chǔ)應(yīng)用
EaselJs是什么?
EaselJs:一個(gè)javascript庫(kù),方便更快速的處理canvas。
EaselJs如何使用?
- 引入easeljs的js文件
<script src="https://code.createjs.com/easeljs-0.8.2.min.js"></script>
- 在body元素中創(chuàng)建一個(gè)canvas元素
<canvas id="demoCanvas" width="500" height="300"></canvas>
- 基于canvas元素創(chuàng)建一個(gè)createjs的舞臺(tái)
var stage = new createjs.Stage("demoCanvas");
- 創(chuàng)建需要被添加到舞臺(tái)的對(duì)象,如創(chuàng)建一個(gè)圖形對(duì)象
var circle = new createjs.Shape();
- 對(duì)圖形對(duì)象進(jìn)行處理,如畫(huà)一個(gè)圓
circle.graphics.beginFill("DeepSkyBlue").drawCircle(0, 0, 50);
- 將圖形對(duì)象添加到舞臺(tái)中去
stage.addChild(circle);
- 更新舞臺(tái)
stage.update();
如果需要根據(jù)指定的幀頻率變化舞臺(tái),繼續(xù)看下方:
8.設(shè)置幀頻率計(jì)時(shí)模式createjs.Ticker.timingMode = createjs.Ticker.RAF;
9.設(shè)置刷新頻率fsp值createjs.Ticker.framerate = 10;
即10fsp,1/10秒的速度刷新。
10.設(shè)置Ticker的tick事件監(jiān)聽(tīng)createjs.Ticker.addEventListener("tick", func);
11.定義func;通過(guò)tick事件,會(huì)根據(jù)指定的頻率執(zhí)行該func函數(shù);所有對(duì)舞臺(tái)的操作在這里處理即可,記得更新舞臺(tái)stage.update();
*注意點(diǎn):
1.默認(rèn)的計(jì)時(shí)模式為createjs.Ticker.TIMEOUT,
2.RAF計(jì)時(shí)模式下,framerate無(wú)效,
3.RAF模式下動(dòng)畫(huà)效果更流暢,
4.不需要按指定幀頻率時(shí),可使用RAF計(jì)時(shí)模式
基礎(chǔ)使用的示例代碼:
<head>
<meta charset="UTF-8">
<title>easeljs的使用流程</title>
<!--將js引入到文檔中-->
<script src="js/easeljs-0.8.2.min.js"></script>
<script>
function init() {
/*基于canvas創(chuàng)建一個(gè)Stage對(duì)象*/
var stage = new createjs.Stage("demoCanvas");
/*創(chuàng)建一個(gè)圖形對(duì)象*/
var shape = new createjs.Shape();
/*fill一個(gè)顏色為黃色,半徑為50,圓心在100,100坐標(biāo)的圓*/
shape.graphics.beginFill("#ff0").drawCircle(100, 100, 50);
/*設(shè)置圓的起始坐標(biāo)點(diǎn)x,y,故圓心位于200,200*/
shape.x = 100;
shape.y = 100;
/*將shape對(duì)象加入到stage中*/
stage.addChild(shape);
/*更新stage*/
stage.update();
/* 在shape對(duì)象中再畫(huà)一個(gè)圓,圓心100,100,原因與shape
* 的起始位置x,y相關(guān)
* f是beginFill的Tiny寫(xiě)法,dc是drawCircle的Tiny寫(xiě)法
* 更多Tiny寫(xiě)法可參考http://www.createjs.com/docs/easeljs/classes/Graphics.html*/
shape.graphics.f("#f00").dc(0, 0, 50);
/*shape發(fā)生變化后需要更新舞臺(tái)才能顯示最新的變化*/
stage.update();
/*設(shè)置Ticker的計(jì)時(shí)模式 RAF更流暢,缺點(diǎn)是
忽略幀速率(即忽略createjs.Ticker.framerate)*/
//createjs.Ticker.timingMode = createjs.Ticker.RAF;
/* 設(shè)置幀速率,默認(rèn)是30FSP,即1/30秒執(zhí)行一次update
* 如果Ticker計(jì)時(shí)模式設(shè)置為createjs.Ticker.RAF,那么此值無(wú)效;*/
createjs.Ticker.framerate = 5;
/* 添加一個(gè)tick監(jiān)聽(tīng)事件,tick事件會(huì)根據(jù)指定的幀速率執(zhí)行
* 對(duì)應(yīng)的函數(shù),如這里的update*/
createjs.Ticker.addEventListener("tick", update);
/* 計(jì)時(shí)模式為T(mén)IMEOUT的情況下,framerate=5,
* 故該函數(shù)會(huì)每隔1/5秒的頻率被調(diào)用*/
function update(event) {
shape.x += Math.random() * 300;
shape.y += Math.random() * 300;
/* 這個(gè)500是canvas的寬度,可以通過(guò)獲得canvas對(duì)象.width獲得
* 如果shape的起始點(diǎn)x坐標(biāo)大于canvas寬度,則初始化shape.x=0*/
if (shape.x > 500) {
shape.x = 0;
}
/*如果shape的起始點(diǎn)y坐標(biāo)大于canvas高度,則初始化shape.y=0*/
if (shape.y > 500) {
shape.y = 0;
}
/*每一次變化都需要通過(guò)update()來(lái)更新舞臺(tái)即stage*/
stage.update();
}
}
</script>
</head>
<body onload="init()">
<!--emment寫(xiě)法:canvas#demoCanvas[width=500,height=500]{您的瀏覽器不支持}-->
<canvas id="demoCanvas" width="500" height="500">您的瀏覽器不支持</canvas>
</body>