H5和微信小游戏 Canvas API 整理

前言

微信小游戏推出后一度爆火,一个简单的跳一跳让大家玩的不亦乐乎,那么很多人就在想自己尝试学学微信小游戏,开发一个属于自己的微信小游戏。现在微信小游戏的开发都离不开游戏引擎,用原生小游戏开发工具开发的很少很少。但是毕竟我不是专业游戏开发,所有游戏引擎就不搞了,我们就单纯来看原生微信小游戏开发。

原生微信小游戏开发全是js,界面上所有的可见元素都是通过js canvas画出来的。所以这就是这篇博客的内容,我们要来整理下微信小游戏Canvas的绘图api。为什么要单独写篇博客整理呢,因为微信小游戏的官方文档并没有提供(反正我是没有找到)。因为微信小游戏的canvas绘制和H5的canvas绘制基本没有却别,这本身是属于H5的范畴,并不是微信小游戏的范畴,所以,废话说了这么多,下面开始正文。

(1)获取canvas

要使用canvas绘制,首先得获取到canvas实例,在H5中获取canvas和获取其它标签一样,通过document获取。

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");

但是微信小程序做了封装,它不允许用户直接操作dom,所以不能通过document获取canvas,而是提供了一个微信api。

let canvas =wx.createCanvas();
let ctx = canvas.getContext('2d');

(2)填充色和线条色

填充色:线条封闭区域内全部着色

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.fillStyle = "#0000ff";
ctx.fillRect(20, 20, 150, 100);

线条色:只给线条着色,着色宽度就是线条宽度

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.strokeStyle = "#0000ff";
ctx.strokeRect(20, 20, 150, 100);

(3)阴影

阴影颜色:阴影的本质就是光线被挡而形成的暗淡,所以建议不要给阴影设置很鲜艳的颜色

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.shadowColor = "black";
ctx.fillStyle = "blue";
ctx.fillRect(20, 20, 100, 80);

阴影大小:所谓阴影大小就是阴影扩散的范围

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.shadowBlur = 20;
ctx.shadowColor = "black";
ctx.fillStyle = "blue";
ctx.fillRect(20, 20, 100, 80);

阴影偏移:光源的方位决定的阴影投射的方向

var canvas = document.getElementById("myCanvas");
var ctx = canvas .getContext("2d");
ctx.shadowOffsetX = 20;
ctx.fillStyle = "blue";
ctx.fillRect(20, 20, 100, 80);
var canvas = document.getElementById("myCanvas");
var ctx = canvas .getContext("2d");
ctx.shadowOffsetY = 20;
ctx.fillStyle = "blue";
ctx.fillRect(20, 20, 100, 80);

(4)渐变

渐变就要涉及到渐变颜色和渐变方向,H5中渐变方向是通过起始点决定的,在createLinearGradient方法中传入两个点的坐标,这两个点的连线方向就是渐变的方向。设置渐变颜色是通过addColorStop方法添加。

var canvas = document.getElementById("myCanvas");
var ctx = canva.getContext("2d");
var my_gradient = ctx.createLinearGradient(0, 0, 0, 170);
my_gradient.addColorStop(0, "black");
my_gradient.addColorStop(1, "white");
ctx.fillStyle = my_gradient;
ctx.fillRect(20, 20, 150, 100);

我们尝试一下从做到右的渐变

var canvas = document.getElementById("myCanvas");
var ctx = canva.getContext("2d");
var my_gradient = ctx.createLinearGradient(0, 0, 170, 0);
my_gradient.addColorStop(0, "black");
my_gradient.addColorStop(1, "white");
ctx.fillStyle = my_gradient;
ctx.fillRect(20, 20, 150, 100);

渐变色可以添加多个,我们尝试添加三个渐变色:黑 -> 红 -> 白

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var my_gradient = ctx.createLinearGradient(0, 0, 170, 0);
my_gradient.addColorStop(0, "black");
my_gradient.addColorStop(0.5, "red");
my_gradient.addColorStop(1, "white");
ctx.fillStyle = my_gradient;
ctx.fillRect(20,20,150,100);

当然也可以给线条设置渐变

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var gradient = ctx.createLinearGradient(0, 0, 170, 0);
gradient.addColorStop("0", "magenta");
gradient.addColorStop("0.5", "blue");
gradient.addColorStop("1.0", "red");
ctx.strokeStyle = gradient;
ctx.lineWidth = 5;
ctx.strokeRect(20, 20, 150, 100);

甚至可以给文字设置渐变

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var gradient = ctx.createLinearGradient(0, 0, 170, 0);
gradient.addColorStop("0", "magenta");
gradient.addColorStop("0.5", "blue");
gradient.addColorStop("1.0", "red");
ctx.strokeStyle = gradient;
ctx.strokeText("Big smile!", 10, 50);

(5)元素重复

createPattern() 方法在指定的方向内重复指定的元素。元素可以是图片、视频,或者其他 <canvas> 元素。被重复的元素可用于绘制/填充矩形、圆形或线条等等。

重复模式:repeat、repeat-x、repeat-y、no-repeat

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, 300, 150); 
var img = document.getElementById("img")
var pat = ctx.createPattern(img, "repeat");
ctx.rect(0, 0, 260, 130);
ctx.fillStyle = pat;
ctx.fill();

(6)放射渐变

没有和渐变放在一起,主要是函数不一样

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var grd = ctx.createRadialGradient(75, 50, 5, 90, 60, 100);
grd.addColorStop(0, "red");
grd.addColorStop(1, "white");
ctx.fillStyle = grd;
ctx.fillRect(10, 10, 150, 100);
参数 描述
x0 渐变的开始圆的 x 坐标
y0 渐变的开始圆的 y 坐标
r0 开始圆的半径
x1 渐变的结束圆的 x 坐标
y1 渐变的结束圆的 y 坐标
r1 结束圆的半径

这个参数理解起来有点麻烦,我们改下代码再看效果就明显多了。

var canvas = document.getElementById("myCanvas");
var ctx =canvas.getContext("2d");
var grd = ctx.createRadialGradient(75, 50, 50, 150, 50, 50);
grd.addColorStop(0, "red");
grd.addColorStop(1, "blue");
ctx.fillStyle = grd;
ctx.fillRect(10, 10, 150, 100);

从上图我们可以看出,渐变区域是由两个圆决定的,超出两个圆的区域,渐变停止,用外围像素填充。

(7)添加渐变色

前面讲了这么多渐变,最重要的一个函数却没有说,所有的渐变色都通过addColorStop()方法添加的。
addColorStop()这个函数是可以添加很多颜色,按照顺序, 一次均匀渐变。

var canvas =document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var grd = ctx.createLinearGradient(0, 0, 170, 0);
grd.addColorStop(0, "black");
grd.addColorStop("0.3", "magenta");
grd.addColorStop("0.5", "blue");
grd.addColorStop("0.6", "green");
grd.addColorStop("0.8", "yellow");
grd.addColorStop(1, "red");
ctx.fillStyle = grd;
ctx.fillRect(20, 20, 150, 100);

(8)线端样式

H5中支持三种线端样式:

描述
butt 默认,向线条的每个末端添加平直的边缘
round 向线条的每个末端添加圆形线帽
square 向线条的每个末端添加正方形线帽
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.lineCap = "round";
ctx.moveTo(20, 20);
ctx.lineTo(20, 200);
ctx.stroke();

(9)线交样式

H5中支持三种线端样式:

描述
bevel 创建斜角
round 创建圆角
miter 默认,创建尖角
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.lineJoin = "round";
ctx.moveTo(20, 20);
ctx.lineTo(100, 50);
ctx.lineTo(20, 100);
ctx.stroke();

斜接长度
这里不得不提一个很冷门的属性叫斜接长度,它是只两条线段相交时,并且lineJoin="miter",内角和外交的距离。


...
ctx.lineJoin = "miter";
ctx.miterLimit = 5;
...

为了避免斜接长度过长,我们可以使用 miterLimit 属性。如果斜接长度超过 miterLimit 的值,边角会以 lineJoin 的 "bevel" 类型来显示


(10)设置线宽

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.lineWidth = 10;
ctx.strokeRect(30, 30, 200, 80);

(11)绘制矩形

我们可以直接调用fillRect绘制矩形

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.fillStyle = "#00bcd4";
ctx.fillRect(20, 20, 150, 100);

也可以先调用rect,再调用fill

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.fillStyle = "#00bcd4";
ctx.rect(20, 20, 150, 100);
ctx.fill();

把fill换成stroke也是一样,效果一个是填充,一个是描边。

(12)清除像素

clearRect()方法可以清除一块区域的所有像素

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.fillStyle = "red";
ctx.fillRect(0, 0, 300, 150);
ctx.clearRect(20, 20, 100, 50);

(13)贝塞尔曲线

这是一个大头,和Android一样,贝塞尔曲线是构建平面图形很重要的一个知识点。H5中提供的贝塞尔曲线api还没有Android中丰富,但是也足够用了。

函数 释义
beginPath() 开始一段路径
moveTo() 移动至一个新的起点,注意区分和beginPath的差异
closePath() 关闭一段路径
lineTo() 连接到指定点
clip() 从画布中裁剪出一个可视区域,只有被剪切区域内的像素才可见
quadraticCurveTo() 二次贝塞尔曲线
bezierCurveTo() 三阶贝塞尔曲线
arc() 创建圆弧
arcTo() 创建介于两个切线之间的弧
isPointInPath() 判断一个点是不是在封闭路径内

先画个最简单的路径

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(300, 150);
ctx.stroke();

再画个三次贝塞尔曲线

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.moveTo(20, 20);
ctx.bezierCurveTo(20, 100, 200, 100, 200, 20);
ctx.stroke();

画弧线

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.arc(100, 75, 50, 0, Math.PI + Math.PI / 2);
ctx.stroke();

连接切线弧
抱歉,这个api的参数我看了半天,还是没懂,和我预期效果不一样。

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.beginPath();
ctx.moveTo(20, 20);           // 创建开始点
ctx.lineTo(100, 20);          // 创建水平线
ctx.arcTo(150, 20, 150, 70, 50); // 创建弧
ctx.lineTo(150, 120);         // 创建垂直线
ctx.stroke();                // 进行绘制

(14)画布操作

在任何绘图语言中,都少不了操作画布,js也一样,canvas也支持几种操作。

缩放

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.strokeRect(5, 5, 25, 15);
ctx.scale(2, 2);
ctx.strokeRect(5, 5, 25, 15);
ctx.scale(2, 2);
ctx.strokeRect(5, 5, 25, 15);
ctx.scale(2, 2);
ctx.strokeRect(5, 5, 25, 15);

旋转

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.rotate(20 * Math.PI / 180);
ctx.fillRect(50, 20, 100, 50);

位移

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.fillRect(10, 10, 100, 50);
ctx.translate(70, 70);
ctx.fillRect(10, 10, 100, 50);

变换
绘制一个矩形;通过 transform() 添加一个新的变换矩阵,再次绘制矩形;添加一个新的变换矩阵,然后再次绘制矩形。请注意,每当您调用 transform() 时,它都会在前一个变换矩阵上构建

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");

ctx.fillStyle="yellow";
ctx.fillRect(0, 0, 250, 100)

ctx.transform(1, 0.5, -0.5, 1, 30, 10);
ctx.fillStyle="red";
ctx.fillRect(0, 0, 250, 100);

ctx.transform(1, 0.5, -0.5, 1, 30, 10);
ctx.fillStyle="blue";
ctx.fillRect(0, 0, 250, 100);

transform() 方法替换当前的变换矩阵。它以下面描述的矩阵来操作当前的变换矩阵:

a  c  e
b  d  f
0  0  1
参数 描述
a 水平缩放绘图
b 水平倾斜绘图
c 垂直倾斜绘图
d 垂直缩放绘图
e 水平移动绘图
f 垂直移动绘图

重置变换矩阵
不管之前的变换矩阵是什么,setTransform()都会重置掉,然后构建新的变换矩阵。所以在下面的例子中,不会显示红色矩形,因为它在蓝色矩形下面。

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");

ctx.fillStyle = "yellow";
ctx.fillRect(0, 0, 250, 100)

ctx.setTransform(1, 0.5, -0.5, 1, 30, 10);
ctx.fillStyle = "red";
ctx.fillRect(0, 0, 250, 100);

ctx.setTransform(1, 0.5, -0.5, 1, 30, 10);
ctx.fillStyle = "blue";
ctx.fillRect(0, 0, 250, 100);

(15)字体

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.font = "italic small-caps bold 40px Arial";
ctx.fillStyle = "red";
ctx.fillText("Hello World", 10, 50);
描述
font-style 规定字体样式。可能的值:normal italic oblique
font-variant 规定字体变体。可能的值:normal small-caps
font-weight 规定字体的粗细。可能的值:normal bold bolder lighter 100 200 300 400 500 600 700 800 900
font-size / line-height 规定字号和行高,以像素计。
font-family 规定字体系列。
caption 使用标题控件的字体(比如按钮、下拉列表等)。
icon 使用用于标记图标的字体。
menu 使用用于菜单中的字体(下拉列表和菜单列表)。
message-box 使用用于对话框中的字体。
small-caption 使用用于标记小型控件的字体。
status-bar 使用用于窗口状态栏中的字体。

(16)文字对齐基线

水平基线

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");

// 在位置 150 创建蓝线
ctx.strokeStyle = "blue";
ctx.moveTo(150, 20);
ctx.lineTo(150, 170);
ctx.stroke();

ctx.font = "15px Arial";
// 显示不同的 textAlign 值
ctx.textAlign = "start";
ctx.fillText("textAlign = start", 150, 60);
ctx.textAlign = "end";
ctx.fillText("textAlign = end", 150, 80);
ctx.textAlign = "left";
ctx.fillText("textAlign = left", 150, 100);
ctx.textAlign = "center";
ctx.fillText("textAlign = center", 150, 120);
ctx.textAlign = "right";
ctx.fillText("textAlign = right", 150, 140);
描述
start 默认,文本在指定的位置开始。
end 文本在指定的位置结束。
center 文本的中心被放置在指定的位置。
left 文本左对齐。
right 文本右对齐。

垂直基线

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");

//在位置 y=100 绘制蓝色线条
ctx.strokeStyle="blue";
ctx.moveTo(5,100);
ctx.lineTo(395,100);
ctx.stroke();

ctx.font = "20px Arial"
//在 y = 200 以不同的 textBaseline 值放置每个单词
ctx.textBaseline = "top";
ctx.fillText("Top", 5, 100);
ctx.textBaseline = "bottom";
ctx.fillText("Bottom", 50, 100);
ctx.textBaseline = "middle";
ctx.fillText("Middle", 120, 100);
ctx.textBaseline = "alphabetic";
ctx.fillText("Alphabetic", 190, 100);
ctx.textBaseline = "hanging";
ctx.fillText("Hanging", 290, 100);
描述
alphabetic 默认。文本基线是普通的字母基线。
top 文本基线是 em 方框的顶端。
hanging 文本基线是悬挂基线。
middle 文本基线是 em 方框的正中。
ideographic 文本基线是表意基线。
bottom 文本基线是 em 方框的底端。

(17)文字测量

注意:这个测量只能拿到宽度,不要想当然地取高度。

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.font = "25px Arial";
var txt = "Hello World"
ctx.fillText("width:" + ctx.measureText(txt).width, 10, 50);
ctx.fillText(txt, 10, 100);

(18)绘制图片

绘制图片提供了三个层级的api:简单绘制、可控大小、可控裁剪

在看代码之前有必要说一下,和获取canvas对象一样,微信小游戏和H5获取image对象也不一样,H5中是通过document.getElementById()获取的,而微信小游戏是通过wx.createImage()函数获取的。

简单绘制

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var img = document.getElementById("image");
ctx.drawImage(img, 10, 10);

可控大小

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var img = document.getElementById("image");
ctx.drawImage(img, 10, 10, 240, 160);

可控裁剪

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var img = document.getElementById("image");
ctx.drawImage(img, 90, 130, 90, 80, 20, 20, 90, 80);

(19)ImageData

这是一个比较好玩的类,它定义一个Image的数据,我们可以自己创建一个空的ImageData,然后手动给每一个像素设置RGBA。

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var imageData = ctx.createImageData(100, 100);
for (var i = 0;i < imageData.data.length; i+=4)
{
  imageData.data[i + 0] = 255;
  imageData.data[i + 1] = 0;
  imageData.data[i + 2] = 0;
  imageData.data[i + 3] = 255;
}
ctx.putImageData(imageData, 10, 10);

createImageData方法会创建一个空的ImageData,它是一个数组,数组长度是width * height * 4。每连续的4位代表一个像素,分别是R、G、B、A,默认都是0。所以懂点色彩基础的都知道,默认就是全透明黑色。

上面例子中,我们给每个像素都赋值绿色,最后调用ctx.putImageData把像素绘制到屏幕上。

另外,还提供了一个方法可以根据一个ImageData创建一个同样大小的ImageData,但是不会复制数据。

var imageData = context.createImageData(imageData);

另外,还有一个更神奇的方法:getImageData,这个方法可以获取屏幕上任意区域的像素信息。

var imgData = ctx.getImageData(10, 10, 100, 100);

利用这个可以实现一些很好玩的效果,比如对屏幕图像做色彩反向。

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var img = document.getElementById("image");
ctx.drawImage(img, 0, 0);
var imgData = ctx.getImageData(0, 0, c.width, c.height);
// 反转颜色
for (var i = 0; i < imgData.data.length; i += 4)
{
  imgData.data[i] = 255 - imgData.data[i];
  imgData.data[i + 1] = 255 - imgData.data[i + 1];
  imgData.data[i + 2] = 255 - imgData.data[i + 2];
  imgData.data[i + 3] = 255;
}
ctx.putImageData(imgData, 0, 0);

稍微有点色彩理论基础的都知道,255 - color就等于color的反响色。当然这是最简单的,你还可以做很多其它的效果,比如老照片,浮雕等等。

(20)全局透明度

globalAlpha可以设置全局透明度,不同颜色会叠加显示。

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.fillStyle = "red";
ctx.fillRect(20, 20, 75, 50);
// 调节透明度
ctx.globalAlpha = 0.2;
ctx.fillStyle = "blue";
ctx.fillRect(50, 50, 75, 50);
ctx.fillStyle = "green";
ctx.fillRect(80, 80, 75, 50);

(21)图层混合模式

这个和Android中的XFermode差不多。

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");

ctx.fillStyle = "red";
ctx.fillRect(20, 20, 75, 50);
ctx.globalCompositeOperation = "source-over";
ctx.fillStyle = "blue";
ctx.fillRect(50, 50, 75, 50);

ctx.fillStyle = "red";
ctx.fillRect(150, 20, 75, 50);
ctx.globalCompositeOperation = "destination-over";
ctx.fillStyle = "blue";
ctx.fillRect(180, 50, 75, 50);
描述
source-over 默认。在目标图像上显示源图像。
source-atop 在目标图像顶部显示源图像。源图像位于目标图像之外的部分是不可见的。
source-in 在目标图像中显示源图像。只有目标图像内的源图像部分会显示,目标图像是透明的。
source-out 在目标图像之外显示源图像。只会显示目标图像之外源图像部分,目标图像是透明的。
destination-over 在源图像上方显示目标图像。
destination-atop 在源图像顶部显示目标图像。源图像之外的目标图像部分不会被显示。
destination-in 在源图像中显示目标图像。只有源图像内的目标图像部分会被显示,源图像是透明的。
destination-out 在源图像外显示目标图像。只有源图像外的目标图像部分会被显示,源图像是透明的。
lighter 显示源图像 + 目标图像。
copy 显示源图像。忽略目标图像。
xor 使用异或操作对源图像与目标图像进行组合。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,406评论 5 475
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,976评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,302评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,366评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,372评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,457评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,872评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,521评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,717评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,523评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,590评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,299评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,859评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,883评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,127评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,760评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,290评论 2 342

推荐阅读更多精彩内容

  • canvas元素的基础知识 在页面上放置一个canvas元素,就相当于在页面上放置了一块画布,可以在其中进行图形的...
    oWSQo阅读 10,268评论 0 19
  •   HTML5 添加的最受欢迎的功能就是 元素。这个元素负责在页面中设定一个区域,然后就可以通过 JavaScri...
    霜天晓阅读 2,984评论 0 2
  • 1 Canvas接口元素定义 1.1 getContext()方法 为了在canvas上绘制,你必须先得到一个画布...
    Kevin_Junbaozi阅读 1,281评论 1 2
  • 一、简介 HTML5 中的定义:“它是依赖分辨率的位图画布,你可以在 canvas 上面绘制任何图形,甚至加载照片...
    destiny0904阅读 10,513评论 1 4
  • 一:canvas简介 1.1什么是canvas? ①:canvas是HTML5提供的一种新标签 ②:HTML5 ...
    GreenHand1阅读 4,657评论 2 32