图形基础篇01 # 浏览器中实现可视化的四种方式
Posted 凯小默
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了图形基础篇01 # 浏览器中实现可视化的四种方式相关的知识,希望对你有一定的参考价值。
说明
【跟月影学可视化】学习笔记。
方式一:html+CSS
优点:方便,不需要第三方依赖,甚至不需要 javascript 代码。
缺点:CSS 属性不能直观体现数据,绘制起来也相对麻烦,图形复杂会导致 HTML 元素多,而消耗性能。
方式二:SVG
SVG (Scalable Vector Graphics,可缩放矢量图)
是一种基于 XML 语法的图像格式,可以用图片(img 元素)的 src 属性加载。SVG 是对 HTML/CSS 的增强,弥补了 HTML 绘制不规则图形的能力。
优点:简单,直观,方便
缺点:图形复杂时需要的 SVG 元素太多,也非常消耗性能。
方式三:Canvas2D
HTML/CSS 还是 SVG,它们都属于声明式绘图系统,也就是我们根据数据创建各种不同的图形元素(或者 CSS 规则),然后利用浏览器渲染引擎解析它们并渲染出来。Canvas 调用绘图指令,然后引擎直接在页面上绘制图形。这是一种指令式的绘图系统。
优点:高性能绘制
缺点:直接操作图形元素不方便,如果要绘制的图形太多,或者处理大量的像素计算时,Canvas2D 依然会遇到性能瓶颈。
Canvas 能够直接操作绘图上下文,不需要经过 HTML、CSS 解析、构建渲染树、布局等一系列操作。因此单纯绘图的话,Canvas 比 HTML/CSS 和 SVG 要快得多。
另外可以使用 SVG 生成某些图形,然后用 Canvas 来渲染。这样,我们就既可以享受 SVG 的便利性,又可以享受 Canvas 的高性能。
现在浏览器的 canvas 一般有 webgl2、webgl 和 2d 三种上下文。它们并不是一个完整的 canvas api 规范,而是分成了 2d 规范和 webgl 规范。webgl 规范是 opengl es 规范在 web 端的实现,其中 webgl2 对应 opengl es 3.0,而 webgl 对应的是 opengl es 2.0。
方式四:WebGL
优点:功能强大、更适合绘制 3D 场景、大批量绘制、超高性能
缺点:使用繁琐,难度相对较高
使用 WebGL 的情景:
- 要绘制的图形数量非常多:比如有多达数万个几何图形需要绘制
- 对较大图像的细节做像素处理:比如,实现物体的光影、流体效果和一些复杂的像素滤镜,需要处理的像素点数量非常的多(一般是数十万甚至上百万数量级的)。
- 绘制 3D 物体:WebGL 内置了对 3D 物体的投影、深度检测等特性,不需要对坐标做底层的处理。
图形系统与浏览器渲染引擎工作对比
相比于 HTML 和 CSS,Canvas2D 和 WebGL 更适合去做可视化这一领域的绘图工作。它们的绘图 API 能够直接操作绘图上下文,一般不涉及引擎的其他部分,在重绘图像时,也不会发生重新解析文档和构建结构的过程,开销要小很多。
技术选型
几个不错的问题
Canvas 是不是有5M的大小限制?
Canvas画布大小有限制,不同的浏览器不同,一般的可视化大屏足够用了。检测设备的Canvas大小可以用这个项目:https://github.com/jhildenbiddle/canvas-size
Desktop:
Mobile:
canvas2d绘制出来的图形最终也是渲染到gpu中的吧,和webgl渲染到底区别在哪里,为啥webgl性能好
因为 canvas2d 渲染只能由浏览器底层控制,并不能自己控制gpu,而很多优化其实浏览器并不能代替开发者去做。比如说同时绘制几万个小圆形,因为图形都一样,自己写 webgl 的话,可以用 instanced drawing 的方式批量绘制,而 canvas2d 写浏览器不会帮你去这么做。可以说 webgl 在渲染大量元素的时候手段要更多得多,所以性能差别就明显了。
canvas2d 绘图是通过自身的 api,gpu 是浏览器底层调用的,不受开发者控制。webgl 不一样,将数据写入帧缓冲之后,最终通过WebGLProgram 来执行 shader 完成图形渲染,所以 webgl 能够自己控制 gpu 渲染。有很多图形计算,webgl 是可以放在 shader 里面去计算的,这样比用 js 计算快,这就是 gpu 和 cpu 计算的区别。
Canvas绘出圆形颜色渐变的倒计时图形有种朦胧感,怎么回事
这个牵扯到设备像素比dpr了。我们知道 mac 和 iphone 的 dpr 是 2,也就是说一个如果你在这样的设备上绘制 canvas,应当将它的画布坐标设置为样式坐标的 2 倍,才可以清晰地显示图像。浏览器的 window.devicePixelRatio 属性可以读取设备像素比。
实例:不同方式实现饼图
请参考:https://codepen.io/gltjk/pen/vYLmdvJ
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>kiamo pie</title>
<style>
.pie-graph
display: inline-block;
width: 250px;
height: 250px;
border-radius: 50%;
background-image: conic-gradient(
#37c 30deg,
#3c7 30deg,
#3c7 65deg,
orange 65deg,
orange 110deg,
#f73 110deg,
#f73 200deg,
#ccc 200deg
)
</style>
</head>
<body>
<h1>HTML+CSS、SVG、Canvas 三种方式实现饼图</h1>
<table>
<tr>
<th>HTML+CSS</th>
<th>SVG</th>
<th>Canvas</th>
</tr>
<tr>
<td>
<div class="pie-graph"></div>
</td>
<td>
<div id="svg"></div>
</td>
<td>
<div id="canvas"></div>
</td>
</tr>
</table>
<script>
// 数据处理
function prepare( values, colors )
const sum = values.reduce((x, y) => x + y)
return values.map((x, i) => [(x / sum) * 2 * Math.PI, colors[i]])
// svg 绘制饼图
function drawSvgPie(el, data, center, radius )
const paths = []
let start = x: center.x, y: center.y - radius
let deg = 0
for (const [value, color] of data)
deg += value
const end =
x: center.x + radius * Math.sin(deg),
y: center.y - radius * Math.cos(deg)
const largeArc = value >= Math.PI ? 1 : 0
const pathD =
`M $center.x $center.y` +
`L $start.x $start.y` +
`A $radius $radius 0 $largeArc 1 $end.x $end.y` +
'Z'
paths.push(`<path d="$pathD" fill="$color" />`)
start = end
const d = radius * 2
el.innerHTML =
'<svg xmlns="http://www.w3.org/2000/svg" ' +
`width="$dpx" height="$dpx" viewBox="0 0 $d $d">` +
paths.join('') +
'</svg>'
// canvas 绘制饼图
function drawCanvasPie(el, data, center, radius )
const canvas = document.createElement('canvas')
canvas.setAttribute('width', radius * 2)
canvas.setAttribute('height', radius * 2)
const ctx = canvas.getContext('2d')
let start = -Math.PI / 2
for (const [value, color] of data)
const end = start + value
ctx.beginPath()
ctx.arc(center.x, center.y, radius, start, end, false)
ctx.lineTo(center.x, center.y)
ctx.fillStyle = color
ctx.fill()
ctx.closePath()
start = end
el.append(canvas)
// 页面加载完成
window.onload = function ()
const values = [30, 35, 45, 90, 160]
const colors = ['#37c', '#3c7', 'orange', '#f73', '#ccc']
const commonData =
data: prepare( values, colors ),
center: x: 125, y: 125 ,
radius: 125
console.log(commonData)
drawCanvasPie(document.querySelector('#canvas'), commonData)
drawSvgPie(document.querySelector('#svg'), commonData)
</script>
</body>
</html>
以上是关于图形基础篇01 # 浏览器中实现可视化的四种方式的主要内容,如果未能解决你的问题,请参考以下文章
设置 matplotlib 正确显示中文的四种方式 看这一篇就够啦!