一、入門(mén)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>

說(shuō)明 :

  • id : dom元素名稱(chēng)
  • width : 畫(huà)布寬度
  • height : 畫(huà)布高度

加載如下的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ì)象可以通過(guò)getContext()方法獲得HTML52D環(huán)境上下文對(duì)象,所有操作都需要該對(duì)象
  • 上下文對(duì)象采用畫(huà)布左下角為原點(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è)快照,通過(guò)提供一個(gè)不同的MIME類(lèi)型作為參數(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 = "開(kāi)始進(jìn)行猜字母游戲,從a-z開(kāi)始";
    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攻擊,禁止打開(kāi)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è)過(guò)的字母
    context.fillStyle = "#66ccff";
    context.font = "16px Sans-Serif";
    context.fillText(
      "你已猜測(cè)過(guò)的字母: " + 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來(lái)完成,因?yàn)殪o態(tài)的圖像和文字就是HTML的領(lǐng)域,但是畫(huà)布具有強(qiáng)大的繪圖、著色和基本二維形狀變換。

A. 必要屬性了解

為了完成這個(gè)程序,需要設(shè)置一些必要的屬性

  • context.globalAlpha : 對(duì)透明度進(jìn)行設(shè)置,當(dāng)為0時(shí),文字完全不可見(jiàn)

B. 動(dòng)畫(huà)循環(huán)

傳統(tǒng)的動(dòng)畫(huà)實(shí)現(xiàn)就是通過(guò)不斷調(diào)用函數(shù)不斷重新繪制頁(yè)面出現(xiàn)的,我們需要?jiǎng)?chuàng)建一個(gè)函數(shù),每隔一段時(shí)間去重復(fù)調(diào)用它。用于清除畫(huà)布內(nèi)容,然后對(duì)畫(huà)布進(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無(wú)障礙訪問(wèn) : 子DOM

什么是無(wú)障礙訪問(wèn) : 無(wú)障礙訪問(wèn)即能被殘障人士使用的網(wǎng)站,例如語(yǔ)音瀏覽器、移動(dòng)電話、手持設(shè)備、更多工作在困難環(huán)境的用戶(hù)

Canvas是一個(gè)采用即時(shí)模式進(jìn)行位圖映射的屏幕區(qū)域,因此并不適合實(shí)現(xiàn)無(wú)障礙訪問(wèn),在Canvas中,我們并不能通過(guò)任何接口訪問(wèn)Canvas里面的元素。所以我們需要?jiǎng)?chuàng)建一些DOM元素放進(jìn)Canvas標(biāo)簽中,它的作用跟以前所說(shuō)的JS支持平穩(wěn)退化是一樣的。例如,在單頁(yè)應(yīng)用你??匆?jiàn)以下代碼,這是為了給不支持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元素,這就稱(chēng)為更新后備DOM,當(dāng)然性能開(kāi)銷(xiāo)是不容小覷的

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容