HTML5 -- Canvas

利用 HTML5 中的 Canvas,我们可以做很多很棒的事情,下面来看看我做的一个 Demo

mydemo.png

下面就针对这个例子介绍一下 Canvas 的基础使用。


HTML & CSS

当然 Canvas 的绘制需要借助 JavaScript, 首先让我们利用 HTMLCSS 将结构层和表现层搭建好,然后我们才可以大展身手。

你可以利用自己高超的 CSS 水平将页面写的十分炫酷,当然我只是简单的利用 CSS 对页面进行了布局,没有写其它用来表现的特性。

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <link rel="stylesheet" type="text/css" href="demo05.css">
    </head>
    <body>
        <article>
            <canvas width="680" height="320" id="myCanvas"></canvas>
            <form>
                <section>
                    <label for="backgroundColor">Select background :</label>
                    <select id="backgroundColor">
                        <option value="white" selected>White</option>
                        <option value="black">Black</option>
                    </select>
                </section>
                <section>
                    <label for="foregroundColor">Select ForegroundColor:</label>
                    <select id="foregroundColor">
                        <option value="white">White</option>
                        <option value="black" selected>Black</option>
                    </select>
                </section>
                <section>
                    <label for="shape">Select shape:</label>
                    <select id="shape">
                        <option value="circles" selected>Circles</option>
                        <option value="squares">Squares</option>
                    </select>
                </section>
                <section>
                    <label for="message">Input text:</label>
                    <input type="text" name="message" id="message" maxlength="48">
                </section>
                <input type="button" value="preview" id="previewButton">
            </form>
        </article>
        <script src="demo05.js"></script>
    </body>
</html>

其实大部分内容都是关于书写表单控件的,这些代码千篇一律,十分好懂,不过唯一值得注意的是,我在输入控件中加入了 maxlength, 对输入的长度进行了控制,如果输入的字符串太多,绘制文字的时候会出现文字溢出。

上述代码中最珍贵的一行是定义 canvas 元素的那一行,将画布定义为 680px 宽,320px 高。

下面利用 CSS 对页面进行稍微的修改。

*,
*::before,
*::after {
    -moz-box-sizing: border-box;
         box-sizing: border-box;
    margin: 0;
    padding: 0;
}

article {
    width: 680px;
    height: 320px;
    margin: 32px auto;

    text-align: center;
}

canvas {
    border: 1px solid #ccc;
}

form section {
    margin-bottom: 16px;
}

这里,为画布设置了一个边框,是为了更清楚的看到画布的位置。


Canvas 绘图

为了绘制图形,我们首先要得到画布元素,并要求得到它的 2d 绘制上下文。像下面这样。

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

有了这个 context, 我们就可以肆意的画图了,首先,让我们来画个矩形吧,需要哪些条件呢?事实上,我们只需要指定 x,y 坐标(矩形左上角的坐标)并且设置宽高就可以画出这个图形。

function drawSquare(canvas, context) {
    var width = Math.floor(Math.random() * 64);

    var x = Math.floor(Math.random() * canvas.width);
    var y = Math.floor(Math.random() * canvas.height);

    context.fillStyle = "lightblue";
    context.fillRect(x, y, width, width);
}

上面我们使用了随机值,这样我们就可以绘制出不同宽高分布在不同位置的矩形了。利用上面的代码,我们就可以看到下面这样的结果啦。

square.png

可以看到,有的矩形已经超出边界了,为什么呢?自己好好想想总会相处答案的吧!

既然已经知道怎么绘制矩形了,那么该怎么绘制圆形呢?我已经迫不及待的去画个圆了,因为我感觉圆比矩形好看,这也就是为什么我们在很多 app 中看到的是圆形头像。

不过,事情进展的不是很顺利,因为我们已经没有类似 fillCircle() 这样的函数可用了。所以我们不得不动笔去画一个,实际上利用 Canvas 你可以画出可以用笔画出的任何效果。在现实生活中,如果你想画画,那么你需要拿起一支笔,但是在画布上,你只需要调用 contextbeginPath() 方法就可以了,这相当于告诉画布:我要开始画些东西了,你准备好吧!

如果你想在指定的一个点开始你的笔迹,那么你可以使用 moveTo(x, y) 方法,如果你想从画笔的当前位置画线,可以使用 lineTo(x, y)方法。

好了,下面就让我们开始画圆吧!实际上,还有一个 arc() 方法,可以让我们去画圆,不过在这之前,我们需要调用 beginPath() 方法。

function drawCircle(canvas, context) {
    var radius = Math.floor(Math.random() * 48);

    var x = Math.floor(Math.random() * canvas.width);
    var y = Math.floor(Math.random() * canvas.height);

    context.beginPath();
    context.arc(x, y, radius, 0, Math.PI * 2, true);
    context.fillStyle = "lightblue";
    context.fill();
}

值得一提的是,arc() 方法中第四和第五个参数使用的都是弧度值,不过我们一般喜欢使用角度,比如 360 度,而不是 2 PI,所以我们可以写一个转换函数,然后你就可以尽情的使用熟悉的角度值了。

function degreesToRadians(degrees) {
    return (degrees * Math.PI) / 180;
}

下面,你就可以画出下面这样的效果。

circle.png

图形已经绘制完毕了,我们就去看看如何绘制文字,首先我们的获取输入控件中输入的文字,然后我们需要使用 contextmeasureText() 测量文字的宽度,因为我们想让文字居中。

function drawText(canvas, context) {
    var selectObj = document.getElementById("foregroundColor");
    var index = selectObj.selectedIndex;
    var fgColor = selectObj[index].value;
    var fontSize = "24";

    context.fillStyle = fgColor;
    context.font = "bold " + fontSize + "px sans-serif";
    context.textAlign = "left";

    var message = document.getElementById("message").value;
    var messageWidth = context.measureText(message).width;
    var x = Math.floor(canvas.width / 2 - messageWidth / 2);
    var y = Math.floor(canvas.height / 2 - fontSize / 2);
    context.fillText(message, x, y);
}

可以使用 context.font 设置文字相关的信息,第一个参数是 font style, 可以设置为 bold 或者 italic,第二个参数是文字的大小,第三个参数是 font family,这里我指定为 sans-serif

你可能还有疑问的是,context.textAlign 是什么玩意?这个就是设置 fillText() 中 x 坐标指定的是文本哪个部位的坐标,如果你设置为 center,那么这个 x 就是文本中间的 x 坐标。当然我们这里设置为 left 就是文本最左边的 x 坐标。

那么问题来了,我们为什么还要使用 measureText() 这么费劲的测试文本的宽度使文本居中呢?的确如此,我们可以使用 textAlign 轻易的实现文本居中,下面是对上述函数的改写。

function drawText(canvas, context) {
    var selectObj = document.getElementById("foregroundColor");
    var index = selectObj.selectedIndex;
    var fgColor = selectObj[index].value;
    var fontSize = "24";

    context.fillStyle = fgColor;
    context.font = "bold " + fontSize + "px sans-serif";
    context.textAlign = "center"; // change

    var x = Math.floor(canvas.width / 2); // change
    var y = Math.floor(canvas.height / 2 - fontSize / 2);

    var message = document.getElementById("message").value;
    context.fillText(message, x, y);
}

文字也绘制完毕了,下面就绘制图形右下角的笑脸图片,当然这是个图片,不是一笔一笔画出来的。

function drawImage(canvas, context) {
    var smileImage = new Image();
    smileImage.src = "smile.png";

    smileImage.onload = function() {
        context.drawImage(smileImage, 632, 272, 24, 24);
    }
}

drawImage() 的第二个参数是图形的左上角的 x 坐标,第三个参数是左上角的 y 坐标,第四个参数是图形的宽度,第五个参数是图形的高度。

这里为什么还是用一个 onload 呢?因为图片总是需要加载的,如果图片还没有加载完毕,就开始去绘制图片,肯定会绘制失败,所以我们利用一个回调,当图片加载完毕,再去绘制图片。

最后再来介绍一个目前浏览器支持不是很好的属性,我们可以将这个 Canvas 转化为一个图片,怎么样?听上去是不是很心动,其实写起来很容易。

function makeImage() {
    var canvas = document.getElementById("myCanvas");
    canvas.onclick = function() {
        window.location = canvas.toDataURL("image/png");
    }
}

这个时候,如果你的浏览器支持的话,只要你点击一些画布,那么就会有一个图片版本弹出来,供你保存到本地。

我在我的电脑上做了测试,只有 Firefox 支持这个功能,我喜欢的 Google Chrome, Opera, Yandex 在这方面的支持还不尽如人意。


如果你想要项目的源码,你可以到 我的 Github 下载源码。

Ending...

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,108评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,699评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,812评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,236评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,583评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,739评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,957评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,704评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,447评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,643评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,133评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,486评论 3 256
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,151评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,889评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,782评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,681评论 2 272

推荐阅读更多精彩内容