一、入門Canvas

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();
image-20200924151239693.png

總結(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編碼的字符串聘殖。目前,該方法支持度如下 :

image-20200925110637753.png

三行瑞、猜字母游戲

程序會(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()
}

下面為漸變漸出效果

GIF 2020-9-25 14-02-17.gif

下面為源代碼

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)然性能開銷是不容小覷的

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末昂验,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子艾扮,更是在濱河造成了極大的恐慌既琴,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,743評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件泡嘴,死亡現(xiàn)場(chǎng)離奇詭異甫恩,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)酌予,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門磺箕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人抛虫,你說我怎么就攤上這事松靡。” “怎么了建椰?”我有些...
    開封第一講書人閱讀 157,285評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵雕欺,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng)阅茶,這世上最難降的妖魔是什么蛛枚? 我笑而不...
    開封第一講書人閱讀 56,485評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮脸哀,結(jié)果婚禮上蹦浦,老公的妹妹穿的比我還像新娘。我一直安慰自己撞蜂,他們只是感情好盲镶,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,581評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蝌诡,像睡著了一般溉贿。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上浦旱,一...
    開封第一講書人閱讀 49,821評(píng)論 1 290
  • 那天宇色,我揣著相機(jī)與錄音,去河邊找鬼颁湖。 笑死宣蠕,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的甥捺。 我是一名探鬼主播抢蚀,決...
    沈念sama閱讀 38,960評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼镰禾!你這毒婦竟也來了皿曲?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,719評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤吴侦,失蹤者是張志新(化名)和其女友劉穎屋休,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體备韧,經(jīng)...
    沈念sama閱讀 44,186評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡劫樟,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,516評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了盯蝴。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,650評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡听怕,死狀恐怖捧挺,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情尿瞭,我是刑警寧澤闽烙,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響黑竞,放射性物質(zhì)發(fā)生泄漏捕发。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,936評(píng)論 3 313
  • 文/蒙蒙 一很魂、第九天 我趴在偏房一處隱蔽的房頂上張望扎酷。 院中可真熱鬧,春花似錦遏匆、人聲如沸法挨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽凡纳。三九已至,卻和暖如春帝蒿,著一層夾襖步出監(jiān)牢的瞬間荐糜,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工葛超, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留暴氏,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,370評(píng)論 2 360
  • 正文 我出身青樓巩掺,卻偏偏與公主長(zhǎng)得像偏序,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子胖替,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,527評(píng)論 2 349