[JavaScript] (Day-21) - Canvas 画布

Kind hearts are more than coronets. 善良的心灵胜于显贵的地位。

Canvas是HTML5新增的组件,它就像一块幕布,可以用JavaScript在上面绘制各种图表、动画等

一个Canvas定义了一个指定尺寸的矩形框,在这个范围内我们可以随意绘制:

<canvas id="test-canvas" width="200" height="200"></canvas>

通常在 <canvas>内部添加一些说明性 HTML 代码,如果浏览器支持 Canvas,它将忽略<canvas>内部的 HTML,如果浏览器不支持 Canvas,它将显示<canvas>内部的HTML


检测浏览器是否支持 Canvas

方法一:
<!-- HTML代码 -->
<canvas id="test-canvas" width="200" heigth="100">
    <p>你的浏览器不支持Canvas</p>
</canvas>

如果显示<p>便签内部的内容,说明改浏览器不支持 Canvas

方法二:

利用 canvas.getContext

var canvas = document.getElementById('test-canvas');
if (canvas.getContext) {
    alert('你的浏览器支持Canvas!');
} else {
    alert('你的浏览器不支持Canvas!');
}

Canvas 核心方法介绍 getContext()

getContext('2d')方法让我们拿到一个CanvasRenderingContext2D对象,所有的绘图操作都需要通过这个对象完成

var ctx = canvas.getContext('2d');

如果需要绘制3D,HTML5还有一个 WebGL 规范,允许在 Canvas 中绘制 3D 图形:

gl = canvas.getContext("webgl");

绘制形状

Canvas 的坐标系统:

Canvas 的坐标以左上角为原点,水平向右为X轴,垂直向下为Y轴,以像素为单位,所以每个点都是非负整数。

绘制笑脸
<script>
    var canvas = document.getElementById('test-canvas'),
    ctx = canvas.getContext('2d');
    ctx.clearRect(0, 0, 200, 200); // 擦除(0,0)位置大小为200x200的矩形,擦除的意思是把该区域变为透明
    ctx.fillStyle = '#00ff00'; // 设置颜色
    ctx.fillRect(10, 10, 130, 130); // 把(10,10)位置大小为130x130的矩形涂色
    // 利用Path绘制复杂路径:
    var path = new Path2D();
    path.arc(75, 75, 50, 0, Math.PI*2, true);
    path.moveTo(110,75);
    path.arc(75, 75, 35, 0, Math.PI, false);
    path.moveTo(65, 65);
    path.arc(60, 65, 5, 0, Math.PI*2, true);
    path.moveTo(95, 65);
    path.arc(90, 65, 5, 0, Math.PI*2, true);
    ctx.strokeStyle = '#ff0000';
    ctx.stroke(path);
</script>

绘制文本

绘制文本就是在指定的位置输出文本,可以设置文本的字体、样式、阴影等,与CSS完全一致

<script>
    var canvas = document.getElementById('test-canvas'),
    ctx = canvas.getContext('2d');
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.shadowOffsetX = 2;
    ctx.shadowOffsetY = 2;
    ctx.shadowBlur = 2;
    ctx.shadowColor = '#666666';
    ctx.font = '21px Arial';
    ctx.fillStyle = '#333333';
    ctx.fillText("[JavaScript] - Canvas 画布", 20, 40);
</script>

综合实例

绘制K线图

<body>
    <canvas id="stock-canvas" width="300" height="200"></canvas>
</body>
    
<script>
    window.loadStockData = function (r) {
        var NUMS = 30,
        data = r.data;
        if (data.length > NUMS) {
            data = data.slice(data.length - NUMS);
        }
        data = data.map(function (x) {
            return {
                date: x[0],
                open: x[1],
                close: x[2],
                high: x[3],
                low: x[4],
                vol: x[5],
                change: x[6]
            };
        });
        window.drawStock(data);
    }

    window.drawStock = function (data) {
        var canvas = document.getElementById('stock-canvas'),
        width = canvas.width,
        height = canvas.height,
        ctx = canvas.getContext('2d');
        ctx.clearRect(0, 0, width, height);
        ctx.fillText('Create k线图 by Canvas', 10, 10);
        var max=data.reduce((x,y)=>(x.high>y.high?x:y)).high;
        var min=data.reduce((x,y)=>(x.low<y.low?x:y)).low;
        var step=width/data.length;
        //alert(max+','+min+','+step);
        data.forEach(function(element,index){
            //alert(element.high+','+element.low);
            var majHeight=0,start=0,minHeight=element.high - element.low;
            if(element.open < element.close) {
                ctx.fillStyle='red';
                start=element.close;
                majHeight=element.close - element.open;             
            } else {
                ctx.fillStyle='green';
                start=element.open;
                majHeight=element.open - element.close;
            }
            var x1=index*step,y1=(max-start)/(max-min)*height;
            var x2=x1+step/2,y2=(max-element.high)/(max-min)*height;
            var h1=majHeight/(max-min)*height,h2=minHeight/(max-min)*height;
            ctx.fillRect(x1,y1,step,h1);//rect
            ctx.beginPath();//line
            ctx.strokeStyle=ctx.fillStyle;
            ctx.moveTo(x2,y2);
            ctx.lineTo(x2,y2+h2);
            ctx.stroke(); 
        });
    };

    // 加载最近30个交易日的K线图数据:
    var js = document.createElement('script');
    js.src = 'http://img1.money.126.net/data/hs/kline/day/history/2015/0000001.json?callback=loadStockData&t=' + Date.now();
    document.getElementsByTagName('head')[0].appendChild(js);

</script>

Canvas 除了能绘制基本的形状和文本,还可以实现动画、缩放、各种滤镜和像素转换等高级操作

如果要实现非常复杂的操作,考虑以下优化方案:

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

推荐阅读更多精彩内容

  • 一:canvas简介 1.1什么是canvas? ①:canvas是HTML5提供的一种新标签 ②:HTML5 ...
    GreenHand1阅读 4,661评论 2 32
  • 书中代码示例效果展示:Core HTML5 Canvas Examples 基础知识 canvas元素 canva...
    szu_bee阅读 2,798评论 2 28
  • 一、canvas简介 1.1 什么是canvas?(了解) 是HTML5提供的一种新标签 Canvas是一个矩形区...
    Looog阅读 3,934评论 3 40
  • 一、canvas简介 1.1 什么是canvas?(了解) 是HTML5提供的一种新标签 Canvas是一个矩形区...
    J_L_L阅读 1,490评论 0 4
  • 优点: 1.文件结构划分清晰2.代码注释详细 缺点: 1.ViewController应该有一个公共父类 不太合理...
    tianlei阅读 418评论 0 0