浏览器中实现可视化的方式有哪几种?带你盘点一下

前言

 📫 大家好,我是南木元元,热衷分享有趣实用的文章,希望大家多多支持,一起进步!

 🍅 个人主页:南木元元


目录

可视化的含义

浏览器中实现可视化的4种方式

1. HTML+CSS

2. SVG

3. Canvas2D

4. WebGL

技术选型

总结


可视化的含义

说到数据可视化,在很多人的印象里,可视化就等同于制作下面这些美丽的图表。

但其实数据可视化远不止于此。让我们来问问ChatGPT,看看它怎么说。

总结一下,可视化就是:借助于图形化手段,将数据信息组织起来,清晰有效的传达与沟通信息。像我们熟知的图形、图表以及地图等都属于数据可视化的范畴。 在Web上,图形通常是通过浏览器绘制的,本文就来盘点一下在浏览器中渲染绘制图形的几种方式。

浏览器中实现可视化的4种方式

在现代浏览器中实现可视化的绘制技术主要有4种:HTML+CSS、Canvas2D、SVG、WebGL。

1. HTML+CSS

HTML+CSS这种方式通常用来呈现普通的 Web 网页,在可视化中使用的相对较少,但也可以用来实现常见的柱状图、饼图等图表。比如,要实现一个柱状图,其实也很简单,代码如下:

  • HTML代码

<div class="bar" style="height: 50px;"></div>
<div class="bar" style="height: 80px;"></div>
<div class="bar" style="height: 120px;"></div>
<div class="bar" style="height: 60px;"></div>
  •  CSS代码
.bar {width: 30px;background-color: red;display: inline-block;margin-right: 20px;
}

实现的柱状图效果:

再来看看如何实现一个饼图,代码如下:

.pie {width: 250px;height: 250px;border-radius: 50%;background: conic-gradient(red 6deg, orange 6deg 18deg, yellow 18deg 45deg, green 45deg 110deg, blue 110deg 200deg, purple 200deg);
}

直接使用conic-gradient方法创建一个锥形渐变即可实现。

通过上面的例子可以发现,一些常见的可视化图表都可以使用HTML和CSS来实现,并且不需要引入额外的第三方库,但为什么在可视化领域很少直接用HTML和CSS来绘制图表呢?这是因为,Web开发以呈现块状内容为主,而可视化开发因为需要呈现各种各样的形状结构,所以,形状更丰富的SVG以及更底层的Canvas2D和WebGL就是更合适的技术了。

此外,使用HTML+CSS实现可视化有2个缺点:

  1. 在绘制复杂图形时,使用HTML+CSS的能力有限
  2. 图形发生变化时重绘的性能开销比较大

第一点其实很好理解,HTML和CSS主要还是为网页布局而创造的,使用它们虽然能绘制可视化图表,但是绘制的方式并不简洁。上面实现的柱状图和折线图都是最基础版,如果要实现稍微复杂一点的效果其实就没那么容易了。

第二点,HTML和CSS作为浏览器渲染引擎的一部分,为了完成页面渲染的工作,除了绘制图形外,还要做很多额外的工作。如下是浏览器的渲染过程:

  1. 解析HTML,生成DOM树,解析CSS,生成CSSOM树
  2. 将DOM树和CSSOM树结合,生成渲染树(Render Tree)
  3. Layout(回流):根据生成的渲染树,进行回流(Layout),得到节点的几何信息(位置,大小
  4. Painting(重绘):根据渲染树以及回流得到的几何信息,得到节点的绝对像素
  5. Display:将像素发送给GPU,展示在页面上。

上述过程中,当图形发生变化时,会触发回流和重绘,渲染树中或大或小的部分需要重新计算,这样其实性能开销是很大的。而Canvas2D和WebGL相比而言,它们的绘图API能够直接操作绘图上下文,在重绘图像时,不会发生重新解析文档和构建结构的过程,开销要小很多。

2. SVG

现代浏览器支持SVG(Scalable Vector Graphics,可缩放矢量图),SVG是一种基于XML语法的图像格式,可以用图片(img元素)的src属性加载。而且,浏览器还可以内嵌SVG标签,并且像操作普通的HTML元素一样,利用DOM API 操作SVG元素。下面是使用SVG实现与前面相同的柱状图效果的代码:

<svg width="200" height="200"><rect x="0" y="80" width="30" height="50" fill="red" /><rect x="50" y="50" width="30" height="80" fill="red" /><rect x="100" y="10" width="30" height="120" fill="red" /><rect x="150" y="70" width="30" height="60" fill="red" />
</svg>

 

在上述SVG代码中,rect表示绘制一个矩形元素。除了rect外,SVG还提供了丰富的图形元素,可以绘制矩形、圆弧、椭圆、多边形和贝塞尔曲线等等。现在,想要绘制一个饼图,只需使用SVG内置的circle标签,通过stroke-dasharray属性(定义轮廓为虚线)来调整stroke-width(轮廓宽度)就可以实现饼图,代码如下:

<svg viewBox="0 0 32 32" width="100" height="100" style="border-radius: 50%;"><circle cx="16" cy="16" r="16" stroke-width="32" stroke-dasharray="20 100" fill="yellow" stroke="red"></circle><circle cx="16" cy="16" r="16" stroke-width="32" stroke-dasharray="40 100" stroke-dashoffset="-20" fill="transparent" stroke="blue"></circle>
</svg>

 实现的饼图效果:

SVG和传统的HTML+CSS的绘图方式差别不大,只不过,HTML元素在绘制矢量图形方面的能力有些不足,而SVG运用了一些SVG支持的特殊属性,恰好弥补了这方面的缺陷。因此,用SVG绘图比用HTML和CSS要方便很多。

但是,SVG图表也有缺点,它HTML元素一样,在输出图形前都需要经过引擎的解析、布局计算和渲染树生成。如果要绘制的图形很复杂,需要大量的SVG元素,就会大大增加DOM树渲染和重绘所需要的时间,对性能开销非常大,所以SVG只适合应用于元素较少的简单可视化场景。

3. Canvas2D

Canvas2D上下文来绘制可视化图表也很方便,它是一种指令式的绘图系统,我们调用一些绘图指令,就可以在画布上绘制图形。而上面的HTML+CSS、SVG其实都属于声明式绘图系统,也就是我们根据数据创建各种不同的图形元素(或者CSS规则),然后利用浏览器渲染引擎解析它们并渲染出来。

我们接下来就继续通过绘制一个上述的柱状图来看看Canvas2D的使用方式,代码如下:

<canvas id="myCanvas" width="200" height="200"></canvas>
<script>// 获取canvas元素const canvas = document.getElementById("myCanvas");// 获取二维渲染上下文const ctx = canvas.getContext("2d");// 设置填充颜色ctx.fillStyle = "red";// 使用fillRect()绘制填充的矩形ctx.fillRect(0, 80, 30, 50);ctx.fillRect(50, 50, 30, 80);ctx.fillRect(100, 10, 30, 120);ctx.fillRect(150, 70, 30, 60);
</script>

其实很简单,就是创建一个画布,获取渲染上下文,然后设置填充颜色,最后使用fillRect()绘制相应的填充矩形即可实现简单柱状图( 想要更进一步学习的话,也可以去看我的这篇文章 )。

Canvas的优点是能够直接操作绘图上下文,不需要经过HTML、CSS解析、构建渲染树、布局等一系列操作。因此单纯绘图的话,Canvas比HTML+CSS、SVG要快得多,绘制性能较优。

Canvas的缺点是处理事件交互的时候没有HTML和SVG方便, 在HTML和SVG中,一个元素对应一个基本图形,所以我们可以很方便地操作它们,比如在柱状图的某个柱子上注册点击事件,相比来说,Canvas实现交互就比较麻烦,需要手动去计算图形的坐标位置来获取图形。并且如果要绘制的图形太多,或者处理大量的像素计算时,Canvas2D依然会遇到性能瓶颈。

所以可以总结一下SVG和Canvas2D分别的使用场景:当数据量不大且侧重交互的情况,用SVG比较合适;当数据量较大的时候用Canvas比较合适。

4. WebGL

WebGL是浏览器提供的功能强大的绘图系统,它是基于OpenGL ES 规范的浏览器实现的,API相对更底层,让我们来看看使用WebGL绘制上述的柱状图的代码:

const canvas = document.getElementById("canvas");
//获取WebGL绘图上下文
const gl = canvas.getContext("webgl");
//顶点着色器
const vertexShaderSource = `attribute vec2 a_position;void main() {gl_Position = vec4(a_position, 0.0, 1.0);}`;//片元着色器
const fragmentShaderSource = `precision mediump float;void main() {gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);}`;//创建着色器
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexShaderSource);
gl.compileShader(vertexShader);
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentShaderSource);
gl.compileShader(fragmentShader);
//创建程序对象
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
gl.useProgram(program);//获取attribute变量位置
const a_Position = gl.getAttribLocation(program, "a_position");
//向缓冲区对象写入的数据
const vertices = new Float32Array([-1, -1,-0.7, -1,-0.7, -0.5,-0.7, -0.5,-1, -0.5,-1, -1,-0.5, -1,-0.2, -1,-0.2, -0.2,-0.2, -0.2,-0.5, -0.2,-0.5, -1,0, -1,0.3, -1,0.3, 0.2,0.3, 0.2,0, 0.2,0, -1,0.5, -1,0.8, -1,0.8, -0.4,0.8, -0.4,0.5, -0.4,0.5, -1,
])
const vertexBuffer = gl.createBuffer();//创建缓冲区对象
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);// 绑定缓冲区对象
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);// 将数据写入缓冲区对象
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0); // 调用顶点缓冲
gl.enableVertexAttribArray(a_Position);// 激活a_Position使用缓冲数组
//绘制三角形
gl.drawArrays(gl.TRIANGLES, 0, vertices.length / 2);

实现的效果:

可以看到,使用WebGL绘制一个简单的柱状图,它的代码相比上面三种方式,就已经复杂了很多,需要手写大量的GLSL代码,学习成本较高,上手比较困难(想要了解更多的可以去看我的这两篇文章:WebGL简介和快速上手WebGL)。

那什么时候需要用到WebGL呢?

  • 要绘制的图形数量非常多或要计算的像素点数量非常的多(一般是数十万甚至上百万数量级的)的时候,即使Canvas2D也会达到性能瓶颈,这时就需要用WebGL来绘制,充分利用GPU并行计算的能力,来快速、精准地操作图像的像素,实现超高性能绘制。
  • 绘制3D物体。WebGL内置了对 3D 物体的投影、深度检测等处理,所以用它来渲染 3D 物体就不需要我们自己对坐标做底层的处理了。

技术选型

上述四种方式都有各自的优缺点,实际应用中的技术选型可以参考下图:

总结

本文主要介绍了在浏览器中实现可视化的4种方式,不同的方式有各自的优缺点,实际应用中,也应该根据具体的场景来选择合适的方案实现可视化,以达到最佳效果。

🔥如果此文对你有帮助的话,欢迎💗关注、👍点赞、⭐收藏、✍️评论支持一下博主~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/173220.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

springboot 自动配置

1. O(∩_∩)O 对应功能的starter --autoconfigure --寻找autoconfigure的META-INF/spring/org.springframework.boot.autoconfigure.Autoconfiguration.imports–加载所有自动配置类 自动配置类的作用&#xff1a;提供后续所需要的功能组件 在自动配置类中找到注解EnableConf…

A100 A800 H100 H800 模块

老美对A100、A800、H100和H800在内的多款AI芯片实施了出口限制&#xff0c; 目前&#xff0c;具体限制的时长并没有明确的公开信息。 科研人员在面对此类限制 &#xff0c;可能需要寻找替代的供应渠道&#xff0c;加强国内外合作&#xff0c; 或者加大在本土技术研发的投入&a…

如何查看电脑版Office的有效期

有时候点击Office账户看不到有效期信息&#xff0c;那么如何查看呢&#xff0c;其实用一条命令就可以查看。 首选WinR运行&#xff0c;输入cmd回车&#xff0c;然后输入下面的命令&#xff1a; cscript “C:\Program Files\Microsoft Office\Office16\ospp.vbs” /dstatus当然…

Java游戏制作——王者荣耀

一.准备工作 首先创建一个新的Java项目命名为“王者荣耀”&#xff0c;并在src下创建两个包分别命名为“com.sxt"、”com.stx.beast",在相应的包中创建所需的类。 创建一个名为“img”的文件夹来储存所需的图片素材。 二.代码呈现 package com.sxt;import javax.sw…

物联网AI 无线连接学习之蓝牙基础篇 协议概述

学物联网&#xff0c;来万物简单IoT物联网&#xff01;&#xff01; 1 蓝牙协议总体架构 1.1 Application层 应用属性层&#xff0c;通过API函数与协议栈交互&#xff1b; 1.2 Host层 Host层&#xff0c;逻辑链路控制及自适应协议层、安全管理层、属性协议层、通用访问配置…

Java8实战-总结49

Java8实战-总结49 CompletableFuture&#xff1a;组合式异步编程对多个异步任务进行流水线操作构造同步和异步操作将两个 CompletableFuture 对象整合起来&#xff0c;无论它们是否存在依赖 CompletableFuture&#xff1a;组合式异步编程 对多个异步任务进行流水线操作 构造同…

【开源】基于Vue+SpringBoot的企业项目合同信息系统

项目编号&#xff1a; S 046 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S046&#xff0c;文末获取源码。} 项目编号&#xff1a;S046&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 合同审批模块2.3 合…

深入理解 Docker 核心原理:Namespace、Cgroups 和 Rootfs

来自&#xff1a;探索云原生 https://www.lixueduan.com 原文&#xff1a;https://www.lixueduan.com/posts/docker/03-container-core/ 通过这篇文章你可以了解到 Docker 容器的核心实现原理&#xff0c;包括 Namespace、Cgroups、Rootfs 等三个核心功能。 后续文章会演示如…

install pnpm : 无法加载文件的解决办法

问题描述 我在使用pnpm的时候报错 PS D:\emss\pure-admin-backend> pnpm install pnpm : 无法加载文件 C:\Users\RD-16\AppData\Roaming\npm\pnpm.ps1。未对文件 C:\Users\RD-16\AppData\Roaming\npm\pnpm.ps1 进行数字签名。无法在当前系统上运 行该脚本。有关运行脚本和设…

网络篇---第二篇

系列文章目录 文章目录 系列文章目录前言一、说说 TCP 与 UDP 的区别,以及各自的优缺点二、说一下 HTTP 和 HTTPS 的区别三、说说HTTP、TCP、Socket 的关系是什么?前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,…

【腾讯云云上实验室】用向量数据库—实践相亲社交应用

快速入口 &#x1f449;向量数据库_大模型知识库_向量数据存储_向量数据检索- 腾讯云 (tencent.com) 文章目录 前言1. 向量数据库概念及原理1.1 向量数据库概念1.2 向量数据库核心原理1.3 向量数据库优缺点1.4 向量数据库与传统数据库的区别 2. 腾讯云向量数据库的基本特性及优…

Couchdb 权限绕过漏洞复现(CVE-2017-12635)

Couchdb 权限绕过漏洞复现&#xff08;CVE-2017-12635&#xff09; ​​ 开启环境给了三个端口号&#xff0c;不知道哪个是正常的&#xff0c;最后试出来52226端口正常。 登录URL&#xff1a;http://192.168.91.129/_utils/# 来到了登录页面 ​​ 用postman发送PUT方法的…

线性分组码的奇偶校验矩阵均匀性分析

回顾信道编解码知识&#xff0c;我们知道信道编码要求编码具有检纠错能力&#xff0c;作为FEC&#xff08;forward error correction&#xff09;前向纠错编码的一类&#xff0c;线性分组码表示校验位与信息位的关系能够线性表示。 在这篇文章中&#xff0c;并不是要讨论信道编…

lua的gc原理

lua垃圾回收(Garbage Collect)是lua中一个比较重要的部分。由于lua源码版本变迁&#xff0c;目前大多数有关这个方面的文章都还是基于lua5.1版本&#xff0c;有一定的滞后性。因此本文通过参考当前的5.3.4版本的Lua源码&#xff0c;希望对Lua的GC算法有一个较为详尽的探讨。 L…

API风格比较

SOAP、REST、GraphQL、RPC 下图展示了 API 时间线和 API 风格比较。 随着时间的推移&#xff0c;不同的 API 架构风格被发布。它们每个都有自己的标准化数据交换模式。 您可以在图中查看每种样式的用例。 代码优先与 API 优先 下图显示了代码优先开发和 API 优先开发之间的…

C语言公交车之谜(ZZULIOJ1232:公交车之谜)

题目描述 听说郑州紫荆山公园有英语口语角&#xff0c;还有很多外国人呢。为了和老外对上几句&#xff0c;这周六早晨birdfly拉上同伴早早的就坐上了72路公交从学校向紫荆山进发。一路上没事干&#xff0c;birdfly开始思考一个问题。 从学校到紫荆山公园共有n(1<n<20)站路…

UI彩虹外链网盘系统整站源码/PHP网盘与外链分享程序/整站+模版文件

源码简介&#xff1a; 全新UI彩虹外链网盘系统源码&#xff0c;它是PHP网盘与外链分享程序&#xff0c;提供了整站模版文件&#xff0c;前后端美化模板。 彩虹外链网盘美化模板是一款专为PHP网盘和外链分享程序设计的模板。它具备多种功能&#xff0c;包括支持所有格式文件的…

在NAS上部署.NET版本的WOL远程开机服务

在本文中&#xff0c;我们将以部署基于.NET的WOL远程开机服务为例&#xff0c;详细介绍如何利用Docker技术在群辉部署ASP.NET服务。同时&#xff0c;我们还将展示如何对原有的控制台WOL进行改造&#xff0c;以及如何使用SignAuthorization简易URL验签类库。文章相关的代码开源地…

基于ssm的网上订餐系统

一、系统架构 前端&#xff1a;jsp | js | css | jquery 后端&#xff1a;spring | springmvc | mybatis 环境&#xff1a;jdk1.7 | mysql | maven | tomcat 二、代码与数据库 三、功能介绍 01. web端-首页 02. web端-我的餐车 03. web端-我的订单 04. web端-用户中心 05. web…