Canvas
本章学习Canvas以下内容 :
- 上下文
- 公共方法
- 实现一个渐变的淡入淡出效果
一、创建一个canvas标签
<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");
// 浏览器检测
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
总结 :
- Canvas对象可以通过
getContext()
方法获得HTML52D环境上下文对象,所有操作都需要该对象- 上下文对象采用画布左下角为原点(0,0)的笛卡尔坐标系,坐标轴向右,向下为正方向
- Canvas使用即时模式绘制图像,即每次发生变化后,都会重新绘制,而Flash、Silverlight使用保留模式
二、Canvas公共方法
目前canvas有两个公共方法,一是getContext()
、第二个是toDataURL()
,这个方法返回当前Canvas对象产生位图的字符串,他就是屏幕的一个快照,通过提供一个不同的MIME类型作为参数,可以返回不同的数据格式,基本的格式是image/png
另外,还有一个公共方法toBlob()
,将返回一个引用图像的文件,而不是一个base64编码的字符串。目前,该方法支持度如下 :
三、猜字母游戏
程序会随机从a-z
抽取一个字母,让玩家按下对应的按键去猜出是哪一个字母。代码如下 :
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 = "开始进行猜字母游戏,从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网址,所以下面这种方式不能用了
// 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 = "这不是一个字母";
} 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);
// 猜测的次数
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);
// 显示猜测过的字母
context.fillStyle = "#66ccff";
context.font = "16px Sans-Serif";
context.fillText(
"你已猜测过的字母: " + this.letterToGuessed.toString(),
10,
260
);
if (this.gameOver) {
context.fillStyle = "#66ccff";
context.font = "40px sans-serif";
context.fillText("你猜对了,答案是 : " + this.letterToGuess, 50, 180);
}
}
}
new CanvasApp().setup();
三、使用Canvas制造淡入淡出效果
其实上述游戏都可以直接使用HTML来完成,因为静态的图像和文字就是HTML的领域,但是画布具有强大的绘图、着色和基本二维形状变换。
A. 必要属性了解
为了完成这个程序,需要设置一些必要的属性
- context.globalAlpha : 对透明度进行设置,当为0时,文字完全不可见
B. 动画循环
传统的动画实现就是通过不断调用函数不断重新绘制页面出现的,我们需要创建一个函数,每隔一段时间去重复调用它。用于清除画布内容,然后对画布进行重新绘制
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
什么是无障碍访问 : 无障碍访问即能被残障人士使用的网站,例如语音浏览器、移动电话、手持设备、更多工作在困难环境的用户
Canvas是一个采用即时模式进行位图映射的屏幕区域,因此并不适合实现无障碍访问,在Canvas中,我们并不能通过任何接口访问Canvas里面的元素。所以我们需要创建一些DOM元素放进Canvas标签中,它的作用跟以前所说的JS支持平稳退化是一样的。例如,在单页应用你常看见以下代码,这是为了给不支持Javascript的浏览器一个提示。
<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>
当然,我们可以触发Canvas某些方法时改变这个DOM元素,这就称为更新后备DOM,当然性能开销是不容小觑的
网友评论