【图形基础篇】01 # 浏览器中实现可视化的四种方式

简介: 【图形基础篇】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 能够直接操作绘图上下文,一般不涉及引擎的其他部分,在重绘图像时,也不会发生重新解析文档和构建结构的过程,开销要小很多。


2e8a2eb5c5a844ee9ee2dd65ec336281.png



技术选型

054eabe121ad41ec9b1ad8b658891c82.png



几个不错的问题

Canvas 是不是有5M的大小限制?


Canvas画布大小有限制,不同的浏览器不同,一般的可视化大屏足够用了。检测设备的Canvas大小可以用这个项目:https://github.com/jhildenbiddle/canvas-size

Desktop

5d92b5dda5bd490a87b1dd0108d89d99.png


Mobile

0188c5b781004a5b913e8846b01d576d.png



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="${d}px" height="${d}px" 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>



1dc7dccadfdf44d897cea1222910c49f.png




相关实践学习
基于阿里云DeepGPU实例,用AI画唯美国风少女
本实验基于阿里云DeepGPU实例,使用aiacctorch加速stable-diffusion-webui,用AI画唯美国风少女,可提升性能至高至原性能的2.6倍。
目录
相关文章
|
Web App开发 JSON 前端开发
前端必备的谷歌浏览器JSON可视化插件:JSON-Handle
前端必备的谷歌浏览器JSON可视化插件:JSON-Handle
前端必备的谷歌浏览器JSON可视化插件:JSON-Handle
|
Web App开发 JavaScript 前端开发
Vis.js – 基于浏览器的动态 JavaScript 可视化库
  Vis.js 是一个动态的,基于浏览器的可视化库。该库被设计为易于使用,能处理大量的动态数据。该库由以下几部分组成:一是数据集和数据视图,基于灵活的键/值数据集,可以添加,更新和删除项目,订阅数据集变化;二是时间轴,用于显示不同类型的时间轴数据,在时间轴上项目可以交互移动,缩放和操纵;三是图形,使用节点和边显示一个交互式图形或网络。
1777 0
|
机器学习/深度学习 Web App开发 数据可视化
远程连接服务器jupyter notebook、浏览器以及深度学习可视化方法
h1 { counter-reset: h2counter; } h2 { counter-reset: h3counter; } h3 { counter-reset: h4counter; } h4 { counter-reset: h5counter; } ...
2336 0
|
机器学习/深度学习 数据可视化 算法框架/工具
Fabrik – 在浏览器中协作构建,可视化,设计神经网络
Fabrik是一个在线协作平台,通过简单的拖放界面来构建,可视化和训练深度学习模型。 它允许研究人员使用Web GUI协同开发和调试模型,该GUI支持导入,编辑和导出广泛流行的框架(如Caffe,Keras和TensorFlow)编写和导出的网络。
1075 0
|
1月前
|
JavaScript 前端开发 UED
JS:如何获取浏览器窗口尺寸?
JS:如何获取浏览器窗口尺寸?
118 1
|
1月前
|
JavaScript
浏览器插件crx文件--JS混淆与解密
浏览器插件crx文件--JS混淆与解密
57 0
|
1月前
|
JavaScript 前端开发 算法
Node.js中的process.nextTick与浏览器环境中的nextTick有何不同?
Node.js中的process.nextTick与浏览器环境中的nextTick有何不同?
|
1月前
|
JavaScript 前端开发 小程序
js 实现浏览器下载视频2种方法
js 实现浏览器下载视频2种方法
568 0
|
1月前
|
Web App开发 JavaScript
Vue 项目中使用 debugger 在 chrome 谷歌浏览器中失效以及 console.log 指向去了 vue.js 代码
Vue 项目中使用 debugger 在 chrome 谷歌浏览器中失效以及 console.log 指向去了 vue.js 代码
427 0
|
1月前
|
Web App开发 JavaScript 前端开发
浏览器与Node.js事件循环:异同点及工作原理
浏览器与Node.js事件循环:异同点及工作原理