Canvas
本章學(xué)習(xí)Canvas以下內(nèi)容 :
- 上下文
- 公共方法
- 實(shí)現(xiàn)一個(gè)漸變的淡入淡出效果
一雹姊、創(chuàng)建一個(gè)canvas標(biāo)簽
<canvas id="canvasOne" width="500" height="300" >
你的瀏覽器不支持HTML5
</canvas>
說明 :
- id : dom元素名稱
- width : 畫布寬度
- height : 畫布高度
加載如下的js
import "@s/assets/style/normalize.scss";
import helloworld from '@s/assets/images/helloworld.jpg'
function canvasApp() {
const theCanvas = document.getElementById("canvasOne");
// 瀏覽器檢測(cè)
if (!theCanvas || !theCanvas.getContext) {
return;
}
function drawScreen() {
const context = theCanvas.getContext("2d");
// 背景
context.fillStyle = "#000000";
context.font = "20px Sans-Serif";
// 文字
context.textBaseline = "top";
context.fillText("Hello World!", 195, 80);
// 圖片
const helloWorldImage = new Image()
helloWorldImage.onload = function() {
context.drawImage(helloWorldImage,160,130)
}
helloWorldImage.src = helloworld
// 邊框
context.strokeStyle = "#000000"
context.strokeRect(5,5,490,290)
}
drawScreen()
}
canvasApp();
總結(jié) :
- Canvas對(duì)象可以通過
getContext()
方法獲得HTML52D環(huán)境上下文對(duì)象股缸,所有操作都需要該對(duì)象- 上下文對(duì)象采用畫布左下角為原點(diǎn)(0,0)的笛卡爾坐標(biāo)系,坐標(biāo)軸向右吱雏,向下為正方向
- Canvas使用即時(shí)模式繪制圖像敦姻,即每次發(fā)生變化后,都會(huì)重新繪制歧杏,而Flash镰惦、Silverlight使用保留模式
二、Canvas公共方法
目前canvas有兩個(gè)公共方法犬绒,一是getContext()
旺入、第二個(gè)是toDataURL()
,這個(gè)方法返回當(dāng)前Canvas對(duì)象產(chǎn)生位圖的字符串凯力,他就是屏幕的一個(gè)快照茵瘾,通過提供一個(gè)不同的MIME類型作為參數(shù),可以返回不同的數(shù)據(jù)格式咐鹤,基本的格式是image/png
另外拗秘,還有一個(gè)公共方法toBlob()
,將返回一個(gè)引用圖像的文件祈惶,而不是一個(gè)base64編碼的字符串聘殖。目前,該方法支持度如下 :
三行瑞、猜字母游戲
程序會(huì)隨機(jī)從a-z
抽取一個(gè)字母,讓玩家按下對(duì)應(yīng)的按鍵去猜出是哪一個(gè)字母餐禁。代碼如下 :
import "@s/assets/style/normalize.scss";
import helloworld from "@s/assets/images/helloworld.jpg";
class CanvasApp {
constructor() {
this.letters = "a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,s,y,z".split(
","
);
this.message = "開始進(jìn)行猜字母游戲血久,從a-z開始";
this.today = new Date();
this.lettersGuess = "";
this.letterToGuessed = null;
this.guesses = null;
this.higherOrLower = "";
this.gameOver = false;
this.theCanvas = document.getElementById("canvasOne");
this.context = this.theCanvas.getContext("2d");
}
setup() {
const letterIndex = Math.floor(Math.random() * this.letters.length);
this.letterToGuess = this.letters[letterIndex];
this.guesses = 0;
this.letterToGuessed = [];
this.gameOver = false;
window.addEventListener("keydown", this._eventKeyPressed.bind(this), true);
document.getElementById('createImageData').addEventListener('click',this._createImageDataPressed.bind(this))
this.drawScreen();
}
_createImageDataPressed() {
console.log(this.theCanvas.toDataURL())
let pdfWindow = window.open()
pdfWindow.document.write(`<img src=${ this.theCanvas.toDataURL()} />`)
// chrome為了防止CSRF攻擊,禁止打開dataURL網(wǎng)址帮非,所以下面這種方式不能用了
// window.open(
// this.theCanvas.toDataURL(),
// "canvasImage",
// `let=0,top=0,width=${this.theCanvas.width},heigth=${this.theCanvas.height},toolbar=0,resizable=0`
// );
}
_eventKeyPressed(e) {
if (this.gameOver) return;
const letterPressed = String.fromCharCode(e.keyCode).toLowerCase();
this.guesses++;
this.letterToGuessed.push(letterPressed);
if (letterPressed == this.letterToGuess) {
this.gameOver = true;
} else {
const letterIndex = this.letters.indexOf(this.letterToGuess);
const guessIndex = this.letters.indexOf(letterPressed);
if (guessIndex < 0) {
this.higherOrLower = "這不是一個(gè)字母";
} else if (guessIndex > letterIndex) {
this.higherOrLower = "更小";
} else {
this.higherOrLower = "更大";
}
}
this.drawScreen();
console.log(letterPressed);
}
drawScreen() {
const context = this.theCanvas.getContext("2d");
// 背景
context.fillStyle = "#ffffaa";
context.fillRect(0, 0, 500, 300);
// 邊框
context.strokeStyle = "#000000";
context.strokeRect(5, 5, 490, 290);
context.textBaseline = "top";
// 日期
context.fillStyle = "#000000";
context.font = "10px Sans-Serif";
context.fillText(this.today, 150, 10);
// 消息
context.fillStyle = "#ff0000";
context.font = "14px Sans-Serif";
context.fillText(this.message, 125, 30);
// 猜測(cè)的次數(shù)
context.fillStyle = "#109910";
context.font = "16px Sans-Serif";
context.fillText("Guesses :" + this.guesses, 215, 50);
// 顯示Higher或者Lowere
context.fillStyle = "#000000";
context.font = "16px Sans-Serif";
context.fillText("答案提示: " + this.higherOrLower, 150, 125);
// 顯示猜測(cè)過的字母
context.fillStyle = "#66ccff";
context.font = "16px Sans-Serif";
context.fillText(
"你已猜測(cè)過的字母: " + this.letterToGuessed.toString(),
10,
260
);
if (this.gameOver) {
context.fillStyle = "#66ccff";
context.font = "40px sans-serif";
context.fillText("你猜對(duì)了氧吐,答案是 : " + this.letterToGuess, 50, 180);
}
}
}
new CanvasApp().setup();
三、使用Canvas制造淡入淡出效果
其實(shí)上述游戲都可以直接使用HTML來完成末盔,因?yàn)殪o態(tài)的圖像和文字就是HTML的領(lǐng)域筑舅,但是畫布具有強(qiáng)大的繪圖、著色和基本二維形狀變換陨舱。
A. 必要屬性了解
為了完成這個(gè)程序翠拣,需要設(shè)置一些必要的屬性
- context.globalAlpha : 對(duì)透明度進(jìn)行設(shè)置,當(dāng)為0時(shí)游盲,文字完全不可見
B. 動(dòng)畫循環(huán)
傳統(tǒng)的動(dòng)畫實(shí)現(xiàn)就是通過不斷調(diào)用函數(shù)不斷重新繪制頁面出現(xiàn)的误墓,我們需要?jiǎng)?chuàng)建一個(gè)函數(shù)蛮粮,每隔一段時(shí)間去重復(fù)調(diào)用它。用于清除畫布內(nèi)容谜慌,然后對(duì)畫布進(jìn)行重新繪制
function gameLoop(callback) {
window.requestAnimation(callback.call(this))
this.gameLoop()
}
下面為漸變漸出效果
下面為源代碼
import "@s/assets/style/normalize.scss";
import helloworld from "@s/assets/images/helloworld.jpg";
class CanvasApp {
constructor() {
this.theCanvas = document.getElementById("canvasOne");
this.context = this.theCanvas.getContext("2d");
this.fadeIn = true;
this.text = "Hello World";
this.alpha = 0;
}
setup() {
const helloWorldImage = new Image();
helloWorldImage.onload = ()=> {
this.context.drawImage(helloWorldImage,0,0, 720, 300);
};
helloWorldImage.src = helloworld;
this.gameLoop(this.drawScreen);
}
gameLoop(callback) {
window.requestAnimationFrame(this.gameLoop.bind(this, callback));
callback.call(this);
}
drawScreen() {
this.context.globalAlpha = 1;
this.context.fillStyle = "#000000";
this.context.fillRect(0, 0, 720, 300);
this.context.globalAlpha = 0.25;
if (this.fadeIn) {
this.alpha += 0.01;
if (this.alpha >= 1) {
this.alpha = 1;
this.fadeIn = false;
}
} else {
this.alpha -= 0.01;
if (this.alpha < 0) {
this.alpha = 0;
this.fadeIn = true;
}
}
this.context.font = "72px Sans-Serif";
this.context.textBaseline = "top";
this.context.globalAlpha = this.alpha;
this.context.fillStyle = "#ffffff";
this.context.fillText(this.text, 150, 120);
}
}
new CanvasApp().setup();
四然想、Canvas無障礙訪問 : 子DOM
什么是無障礙訪問 : 無障礙訪問即能被殘障人士使用的網(wǎng)站,例如語音瀏覽器欣范、移動(dòng)電話变泄、手持設(shè)備、更多工作在困難環(huán)境的用戶
Canvas是一個(gè)采用即時(shí)模式進(jìn)行位圖映射的屏幕區(qū)域恼琼,因此并不適合實(shí)現(xiàn)無障礙訪問妨蛹,在Canvas中,我們并不能通過任何接口訪問Canvas里面的元素驳癌。所以我們需要?jiǎng)?chuàng)建一些DOM元素放進(jìn)Canvas標(biāo)簽中滑燃,它的作用跟以前所說的JS支持平穩(wěn)退化是一樣的。例如颓鲜,在單頁應(yīng)用你潮砭剑看見以下代碼,這是為了給不支持Javascript的瀏覽器一個(gè)提示甜滨。
<noscript>
<strong>We're sorry but mobile-mall doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
同理
<canvas id="canvasOne" width="720" height="300">
<div id="backup-dom">
你的瀏覽器不支持HTML5
</div>
</canvas>
當(dāng)然乐严,我們可以觸發(fā)Canvas某些方法時(shí)改變這個(gè)DOM元素,這就稱為更新后備DOM衣摩,當(dāng)然性能開銷是不容小覷的