跟月影学可视化
月影
前奇虎 360 奇舞团团长,可视化 UI 框架 SpriteJS 核心开发者,《JavaScript 王者归来》作者
30206 人已学习
新⼈⾸单¥68
登录后,你可以任选4讲全文学习
课程目录
已完结/共 54 讲
跟月影学可视化
15
15
1.0x
00:00/00:00
登录|注册

02 | 指令式绘图系统:如何用Canvas绘制层次关系图?

增加鼠标交互
修改绘制不同类型几何图形
不能方便地控制内部图形元素
高效渲染
简单易用
小试牛刀
绘制静态图形
缺点
优点
绘制层次关系图
使用d3-hierarchy转换数据
获取JSON数据
利用Canvas绘制几何图形
Canvas的坐标系
Canvas元素和2D上下文
要点总结
Canvas的优缺点
如何用Canvas绘制层次关系图
Canvas基本用法
Canvas绘制层次关系图

该思维导图由 AI 生成,仅供参考

你好,我是月影。
Canvas 是可视化领域里非常重要且常用的图形系统,在可视化项目中,它能够帮助我们将数据内容以几何图形的形式,非常方便地呈现出来。
今天,我们就在上一节课的基础上对 Canvas 进行稍微深入一些的介绍,来学习一下 Canvas 绘制基本几何图形的方法。
我主要会讲解如何用它的 2D 上下文来完成绘图,不过,我不会去讲和它有关的所有 Api,重点只是希望通过调用一些常用的 API 能给你讲清楚,Canvas2D 能做什么、要怎么使用,以及它的局限性是什么。最后,我还会带你用 Canvas 绘制一个表示省市关系的层次关系图(Hierarchy Graph)。希望通过这个可视化的例子,能帮你实践并掌握 Canvas 的用法。
在我们后面的课程中,基本上 70~80% 的图都可以用 Canvas 来绘制,所以其重要性不言而喻。话不多说,让我们正式开始今天的内容吧!

如何用 Canvas 绘制几何图形?

首先,我们通过一个绘制红色正方形的简单例子,来讲一讲 Canvas 的基本用法。

1. Canvas 元素和 2D 上下文

对浏览器来说,Canvas 也是 HTML 元素,我们可以用 canvas 标签将它插入到 HTML 内容中。比如,我们可以在 body 里插入一个宽、高分别为 512 的 canvas 元素。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

Canvas是可视化领域中重要且常用的图形系统,能够帮助将数据内容以几何图形的形式呈现出来。本文介绍了Canvas的基本用法和绘制层次关系图的方法。首先,文章介绍了Canvas元素和2D上下文的基本概念,包括Canvas元素的属性和样式的区别,以及Canvas的坐标系。其次,详细讲解了如何用Canvas绘制几何图形,包括绘制红色正方形的简单例子和Canvas的坐标系。文章通过简单易懂的例子和图示,帮助读者快速了解Canvas的基本用法和绘制层次关系图的方法。在绘制图形过程中,文章提到了获取Canvas上下文和利用Canvas上下文绘制图形的步骤,以及绘制图形的具体操作和注意事项。此外,还介绍了两种将图形放置在画布中心的方法,并对它们的优缺点进行了比较。最后,总结了绘制矩形的完整方法和Canvas上下文提供的更多丰富的API。 Canvas的优点在于其简单易用的图形系统和高效的渲染能力,能够快速绘制各种复杂的几何图形,并且在渲染大量轮廓复杂的图形时表现出色。然而,Canvas的缺点在于绘制出的图形对于浏览器来说只是像素点,难以直接操作图形对象,限制了对内部图形元素的控制。 总之,本文通过清晰的步骤和实例,为读者提供了快速了解Canvas基本用法和绘制层次关系图的方法的指南,同时也指出了Canvas的优缺点,为读者全面了解Canvas提供了参考。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《跟月影学可视化》
新⼈⾸单¥68
立即购买
登录 后留言

全部留言(42)

  • 最新
  • 精选
  • Spring
    老师,有点不太理解translate的平移操作,平移后画布的坐标系是怎么发生变化的呢? 平移的是画布还是坐标系。

    作者回复: 平移的是坐标系,你可以理解为将坐标原点移动了,例如本来画布左上角坐标是0,0,现在translate(100,100),那么也就是距离画布左上角(100,100)处的坐标是0,0,相应左上角坐标就是-100,-100了。相当于此时开始再绘制任何图形,每个顶点的坐标和原来相比都偏移了100,100

    2020-06-24
    35
  • 特异型大光头
    原理大致听懂了,学着做个打砖块练习 https://codepen.io/ysosu/pen/MWKorYj 问题: function draw(ctx, node, {fillStyle = 'rgba(0, 0, 0, 0.2)', textColor = 'white'} = {}) {}; 里面这个{fillStyle = 'rgba(0, 0, 0, 0.2)', textColor = 'white'} = {}没看懂 跟这样写的差别是啥function draw(ctx, node, fillStyle = 'rgba(0, 0, 0, 0.2)', textColor = 'white' ) {};

    作者回复: 这两种写法是参数签名不同,我上面这种写法调用起来虽然麻烦一点,但是能让代码可读性更好。 因为同样调用: draw(context, el, {fillStyle: 'red', textColor: 'black'}) 比 draw(context, el, 'red', 'black') 可读性要好 假设你是代码维护者,前者你一看就知道后面两个颜色参数哪个是fillStyle,哪个是textColor;后者你不看函数定义,不知道red和black分别哪个是fillStyle,哪个是textColor。 代码是给人阅读的,所以设计API的时候需要考虑这样的细节。 打砖块很赞~~

    2020-06-25
    2
    24
  • 宁康
    借鉴了之前留言的朋友的部分逻辑重新开发了一个五子棋程序,主要修改了几个地方: - 使用二维数组记录落子情况,方便后续判断胜负 - 重新获取光标后不进行整个棋盘的渲染,而是将上一个光标处局部修复 - 根据当前落子周围八个方向4个单位距离的棋盘中是否赢了 遇到的问题: - 光标是用1个单位线宽绘制出来的,我用同样一个单位线宽去覆盖,发现覆盖不全,还会残留线段,最后只能加大线宽去覆盖,请问老师这个是什么问题? 五子棋在线预览:https://codesandbox.io/s/chess-demo-d2qgt

    作者回复: 赞~这个五子棋不错。同样宽度覆盖,因为Canvas有反锯齿等处理,另外还有光栅化的精度问题,所以边缘的像素会覆盖不了的,一般来说是需要增加线宽,这个是正常的。

    2020-06-26
    2
    18
  • Geek_3469f6
    老师现在讲的还可以完全听懂,学习了之后立刻实践了以下。并且,学练结合,把以前的想法实现了下。这次没有偷懒。画了个五子棋盘+棋子,输赢判定逻辑还没写。 https://codepen.io/maslke/pen/MWKoKKp

    作者回复: 赞👍

    2020-06-25
    2
    10
  • 随遇而安
    我尝试了用canvas绘制不规则多边形,如果想要添加鼠标交互事件,获取到鼠标的坐标之后,可以利用凸包算法判断点是否在不规则多边形内。

    作者回复: 棒~

    2020-06-24
    4
    9
  • 春饼sama
    老师,获取json的都挂了

    作者回复: 把代码里的qhres全都替换成qhres2就可以了

    2021-07-05
    3
  • 筑梦师刘渊
    作业2: 1. 先封装一个清除圆形方法: CanvasRenderingContext2D.prototype.clearCircle = function (x, y,r) { context.save(); context.fillStyle = "rgba(255,255,255,255)"; context.beginPath(); context.arc(x, y, r, 0, TAU); context.fill(); context.restore(); }; 2. 检测鼠标是否在圆内(在圆内就先清除圆再绘制名称和新颜色): // 鼠标检测移动到小圆就变色 function isInCircle(ctx, mx, my, node) { const children = node.children; if (children) { for (let i = 0; i < children.length; i++) { isInCircle(ctx, mx, my, children[i]); } } else { const { x, y, r } = node; if ((my - y) * (my - y) + (mx - x) * (mx - x) < r * r) { console.log(x, y); ctx.clearCircle(x, y, r); ctx.fillStyle = "rgba(255,0,0,0.2)"; ctx.beginPath(); ctx.arc(x, y, r, 0, TAU); ctx.fill(); const name = node.data.name; ctx.fillStyle = "white"; ctx.font = "1.5rem Arial"; ctx.textAlign = "center"; ctx.fillText(name, x, y); } } } 3. 监听鼠标mousemove事件(变换页面鼠标位置与canvas内坐标的关系): canvas.addEventListener("mousemove", (e) => { const x = e.clientX * 2; const y = e.clientY * 2; isInCircle(context, x, y, root); });

    作者回复: 很棒~

    2020-06-26
    6
    3
  • gltjk
    提交一下第二个作业。之前纠结了一下怎么在鼠标移出城市时恢复小圆的颜色,最后决定专门做一个新的 canvas 叠在上面。另外鼠标移动的事件是不是要做个节流比较好?我试了一下感觉又不够流畅,就去掉了…… https://codepen.io/gltjk/pen/GRomzQE

    作者回复: 可以,这个思路挺好的,当然这个问题也可以只用一个canvas,不过用两个的好处也是有的,这样只需要更新局部的图形了。

    2020-06-24
    2
    3
  • 1830
    老师,JSON数据不能用了可以解决一下不,或者把数据结构要求贴一下我们模拟一下

    作者回复: 因为之前用了360的CDN服务,那个域名过期了,把代码里面的qhres全都换成qhres2就可以了

    2021-07-07
    2
  • sheeeeep
    交作业:https://output.jsbin.com/rirahom,思路基本和大家一致。 看完评论有两个主要的优化方法: 1. 减少重绘次数:判断是否在「圆」内 或 判断结果和上次不同,才进行重绘 2. 缩小重绘区域:进行局部清除和局部重绘

    作者回复: 棒~

    2020-07-08
    2
    2
收起评论
显示
设置
留言
42
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部