Web图形学与Web可视化

# Web图形学与Web可视化

# Canvas与webGL

Web图形学

  • 2D图形
    • html + css
    • Canvas: 使用js来绘制2D图像
    • svg:可缩放矢量图形使用直线,曲线,等几何图形来生成图像
  • 3D图形
    • WebGL:Web 3D/2D 图像API

Web图形学应用

# SVG

可缩放矢量图形(Scalable Vector Graphics,SVG), SVG 格式提供的是矢量图,这意味着它的图像能够被无限放大而不失真或降低质量。

<svg>SVG的根元素,用于定义SVG文档的开始和结束。
<rect>:绘制矩形的元素,可以通过指定位置、宽度和高度来定义矩形的形状。
<circle>:绘制圆形的元素,可以通过指定圆心坐标和半径来定义圆的形状。
<ellipse>:绘制椭圆的元素,可以通过指定中心点坐标、水平和垂直半径来定义椭圆的形状。
<line>:绘制直线的元素,可以通过指定起始点和结束点的坐标来定义直线的形状。
<polyline>:绘制折线的元素,可以通过指定一系列连接的点坐标来定义折线的形状。
<polygon>:绘制多边形的元素,可以通过指定一系列连接的点坐标来定义多边形的形状。
<path>:绘制路径的元素,可以通过指定一系列路径指令和参数来定义复杂的形状,如直线段、曲线、弧
<text>:用于在SVG中呈现文本的元素,可以指定文本内容、位置、字体样式等属性。
<g>:用于创建分组的元素,可以将多个元素组合在一起,并对整个组应用变换、样式等属性。

路径命令: 
M:移动到指定点(绝对坐标)
m:移动到指定点(相对坐标)
L:绘制直线到指定点(绝对坐标)
l:绘制直线到指定点(相对坐标)
H:绘制水平线(绝对坐标)
h:绘制水平线(相对坐标)
V:绘制垂直线(绝对坐标)
v:绘制垂直线(相对坐标)
C:绘制三次⻉塞尔曲线(绝对坐标)
c:绘制三次⻉塞尔曲线(相对坐标)
S:平滑的三次⻉塞尔曲线(绝对坐标)
s:平滑的三次⻉塞尔曲线(相对坐标)
Q:绘制二次⻉塞尔曲线(绝对坐标)
q:绘制二次⻉塞尔曲线(相对坐标)
T:平滑的二次⻉塞尔曲线(绝对坐标)
t:平滑的二次⻉塞尔曲线(相对坐标)
A:绘制椭圆弧(绝对坐标)
a:绘制椭圆弧(相对坐标)
Z:关闭路径

# Canvas

Canvas API 提供了一个通过JavaScript 和 HTML的 <canvas> 元素来绘制图形的方式。它可以用于动画、游戏画面、数据可视化、图片编辑以及实时视频处理等方面。

CanvasRenderingContext2D (opens new window)

fillStyle: 设置图形的填充颜色或样式。
strokeStyle: 设置图形的边框颜色或样式。
fillRect(x, y, width, height): 绘制一个填充的矩形。
strokeRect(x, y, width, height): 绘制一个矩形的边框。
clearRect(x, y, width, height): 清除指定矩形区域内的像素,使其变为透明。

beginPath(): 开始绘制路径。
moveTo(x, y): 将绘图游标移动到指定的坐标点。
lineTo(x, y): 绘制一条直线,从当前点到指定的坐标点。
closePath(): 封闭路径,连接起点和终点。

fill(): 填充当前路径的内部区域。
stroke(): 绘制当前路径的边框。
arc(x, y, radius, startAngle, endAngle, clockwise): 绘制弧或圆。
drawImage(image, x, y): 在指定位置绘制图像。
translate(x, y): 平移坐标系统的原点。
scale(scaleX, scaleY): 缩放坐标系统。
rotate(angle): 旋转坐标系统。
  • 绘制矩形

  • 绘制圆弧与圆形

  • 绘制路径曲线

  • 贝塞尔曲线

# Echarts

Q: Echarts是如何通过canvas绘制图表?

Echarts在canvas绘制库 ZRender的上层进行继续封装。

Echarts > Zrender > canvas

zrender (opens new window)

# 3D图形:WebGL

OpenGL是一种跨平台的图形编程接口,用于渲染2D和3D图形。它提供了一系列函数和命令,用于操作图形硬件以进行高性能的图形渲染。

WebGL(Web 图形库)是一个 JavaScript API,可在任何兼容的 Web 浏览器中渲染高性能的交互式3D 和 2D 图形,而无需使用插件。WebGL 通过引入一个与 OpenGL ES 2.0 非常一致的 API 来做到这一点,该 API 可以在 HTML5 <canvas> 元素中使用。这种一致性使 API 可以利用用戶设备提供的硬件图形加速。

Q: openGL和WebGL是什么关系?

WebGL(Web Graphics Library)则是一种基于OpenGL的Web标准,用于在Web浏览器中进行图形渲染。WebGL是HTML5的一部分,使用JavaScript API与浏览器的图形引擎进行交互,将OpenGL的功能暴露给Web开发者。

WebGL使用OpenGL ES 2.0着色器语言来编写顶点着色器和片段着色器。

WebGL核心概念

  1. 顶点缓冲区(VertexBuffer):顶点缓冲区是存储顶点数据的内存缓冲区,用于描述3D模型的几何形状。开发者将顶点数据加载到顶点缓冲区中,然后通过WebGL绘制指令使用这些顶点进行渲染。
  2. 着色器(Shader):着色器是一段在GPU上执行的程序,用于控制WebGL渲染管线中的不同阶段。WebGL使用顶点着色器(VertexShader)和片元着色器(FragmentShader)来处理顶点和像素的计算和渲染。
  3. 纹理(Texture):纹理是应用到3D模型表面的图像或图案。WebGL支持加载和使用纹理,可以将纹理映射到几何形状的表面,实现真实感和细节。

WebGL 核心API:

  • gl.POINTS
  • gl.LINES -gl.T.TRIANGLES

只能会点、线、三⻆形,所有的图形都是通过 这三种基础图形构成。

# ThreeJS

ThreeJS提供了更简单、高级的方式来创建和渲染3D场景。提供了许多有用的功能和工具,如相机、灯光、几何体、纹理映射、动画等,使开发者能够更轻松地构建复杂的3D场景。

https://threejs.org/docs/index.html (opens new window)

ThreeJS: 对WebGL的封装 > WebGL: OpenGL在web场景下的封装 > OpenGL

在react下方便快速地使用封装的ThreeJS

# Web可视化

Web可视化

  • 数据大屏
  • 数据平台
  • 地图
  • 更多..

可视化(Visualization)是利用计算机图形学和图像处理技术,将数据转换成图形或图像在屏幕上显示出来,并进行交互处理的理论、方法和技术。

主流web可视化库:

  • Echarts55kstars
  • D3.js106kstars
  • HighCharts11kstarts
  • Chartjs5kstars
  • AntV2kstars

# Echarts应用及原理

  • 手写Echart折线图:
<!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>canvas手写chart折线图</title>
    <style>
        #myCanvas {
  border: 1px solid red;
}
    </style>
</head>
<body>
    <canvas id="myCanvas"></canvas>
</body>
<script>
    const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');

// 设置画布尺寸
canvas.width = 500;
canvas.height = 300;

const option = {
  xAxis: {
    type: 'category',
    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
  },
  yAxis: {
    type: 'value'
  },
  series: [
    {
      data: [150, 230, 224, 218, 135, 147, 260],
      type: 'line'
    }
  ]
};

const xAxisData = option.xAxis.data;
const yAxisData = option.series[0].data;
const maxValue = Math.max(...yAxisData);
const minValue = 0;
const dataLength = xAxisData.length;

// 绘制坐标轴
const padding = 40; // 坐标轴与画布边界的距离
const xAxisHeight = canvas.height - padding; // x 轴的高度
const yAxisWidth = canvas.width - padding; // y 轴的宽度

// 绘制 x 轴
ctx.beginPath();
ctx.moveTo(padding, xAxisHeight);
ctx.lineTo(yAxisWidth, xAxisHeight);
ctx.strokeStyle = 'black';
ctx.stroke();

// 绘制 y 轴
ctx.beginPath();
ctx.moveTo(padding, xAxisHeight);
ctx.lineTo(padding, padding);
ctx.strokeStyle = 'black';
ctx.stroke();

// 绘制 x 轴刻度线和刻度标签
const xLabelInterval = (yAxisWidth - padding) / (dataLength - 1); // x 轴刻度标签间隔

for (let i = 0; i < dataLength; i++) {
  const x = padding + i * xLabelInterval;
  const y = xAxisHeight + 15; // 将刻度标签下移

  // 绘制刻度线
  ctx.beginPath();
  ctx.moveTo(x, xAxisHeight);
  ctx.lineTo(x, xAxisHeight - 5);
  ctx.strokeStyle = 'black';
  ctx.stroke();

  // 绘制刻度标签
  ctx.fillStyle = 'black';
  ctx.textAlign = 'center';
  ctx.fillText(xAxisData[i], x, y);
}

// 绘制 y 轴刻度线和刻度标签
const yLabelCount = 5; // y 轴刻度标签数量
const yLabelInterval = (xAxisHeight - padding) / yLabelCount; // y 轴刻度标签间隔
const yValueInterval = maxValue / yLabelCount; // y 轴刻度值间隔

for (let i = 0; i <= yLabelCount; i++) {
  const x = padding - 5;
  const y = xAxisHeight - i * yLabelInterval;

  // 绘制刻度线
  ctx.beginPath();
  ctx.moveTo(padding, y);
  ctx.lineTo(padding + 5, y);
  ctx.strokeStyle = 'black';
  ctx.stroke();

  // 绘制刻度标签
  ctx.fillStyle = 'black';
  ctx.textAlign = 'right';
  ctx.fillText((i * yValueInterval).toString(), x, y + 5);
}

// 绘制折线图
const xInterval = (yAxisWidth - padding) / (dataLength - 1); // x 轴坐标间隔
const yRatio = (xAxisHeight - padding) / maxValue; // y 轴数值比例

ctx.beginPath();
ctx.moveTo(padding, xAxisHeight - (yAxisData[0] - minValue) * yRatio);

for (let i = 0; i < dataLength; i++) {
  const x = padding + i * xInterval;
  const y = xAxisHeight - (yAxisData[i] - minValue) * yRatio;

  // 绘制折线
  ctx.lineTo(x, y);
  ctx.strokeStyle = 'blue';
  ctx.lineWidth = 2;
}
ctx.stroke();


</script>
</html>

百度地图插件 (opens new window)

# 备注

  • svg 与 canvas 有什么区别?
  1. 标签上的widthheight:
    • svg: css上的宽高会覆盖写svg标签上的宽高;
    • canvas: css上的宽高也覆盖写标签上的宽高,一旦canvas标签的width和height确定了,再通过css修改宽高,图像会被拉伸

    canvas是标量图,绘制最小的点位是一个像素点;svg绘制的最小单位是svg内部的元素;

  • 问题:canvas的width和height与css中的width、height是什么关系?会冲突么?

  • Canvas和SVG的区别是什么?如何技术选型?

操作对象 渲染方式 适用场景
canvas 像素 像素 性能优先,自由度优先SVG
SVG XML矢量描述标签 DOM 缩放还原度优先
  • 如何优化Echarts性能?

思考:

  1. 开源:
    • Web worker => 纯逻辑计算,并且字符串 => 放弃
    • 切换渲染引擎 => svg or canvas => svg元素 or canvas像素点
    • 内存泄漏 => 及时销毁echarts实例
  2. 节流:
    • 采样 Samping:采样率为10%,即每10个数据里面选择一个数据进行展示
    • 数据懒加载:

渲染性能

  • 降低渲染压力
    • 降低渲染数据量
      • 数据懒加载: 懒加载、异步加载
      • 采样率控制
      • 数据项处理:过滤,缓存
      • 引入缩放、视图切换
    • 降低渲染动画
    • 组件懒加载
    • Canvas Or Svg
  • 提供渲染性能
    • WebWorker
    • 切换页面销毁echarts实例

# 参考

上次更新: 11/6/2023, 11:12:18 PM
最近更新
01
taro开发实操笔记
09-29
02
前端跨端技术调研报告
07-28
03
Flutter学习笔记
07-15
更多文章>