数据可视化系列之 ZRender 创建图表

384 阅读6分钟

pexels-lee81-8558941.jpg

引言

  • 在数据可视化的世界里,ZRender 以其轻量级和高性能的特点,成为了一个冉冉升起的明星。
  • 它是一个基于Canvas的渲染器,被 ECharts 等流行图表库广泛使用。
  • 带领你从零开始,一步步探索 ZRender 的奥秘。

ZRender 简介

什么是 ZRender?

ZRender 的特点

  • 轻量级:体积小,加载快速。
  • 高性能:优化了 Canvas 的渲染性能,适合大规模数据。
  • 易于集成:可以轻松集成到任何 Web 项目中。
  • 丰富的图形:支持多种基础图形,如矩形、圆形、线条等。

ZRender 基础

引入 ZRender

CDN

<!DOCTYPE html>
<html>
  <head>
    <title>ZRender Tutorial</title>
  </head>
  <body>
    <div id="main" style="width: 600px; height: 400px;"></div>
    <script src="https://cdn.bootcdn.net/ajax/libs/zrender/5.3.1/zrender.min.js"></script>
    <script src="main.js"></script>
  </body>
</html>

NPM

npm install zrender

初始化 ZRender 实例(画布创建)

在 JavaScript 文件中初始化 ZRender 实例。

// main.js
let dom = document.getElementById("main");
var zr = zrender.init(dom);

绘制简单图形

使用 ZRender 绘制一个简单的矩形,并设置矩形样式,然后添加到画布中。

var rect = new zrender.Rect({
  shape: {
    x: 0,
    y: 0,
    width: 200,
    height: 200,
  },
  style: {
    fill: "red",
  },
});
zr.add(rect);

修改现有图形属性

rect.attr("shape", {
  width: 50, // 只更新 width。其余将保持不变。对于组或者整个zrender对象重绘调用dirty()方法触发
});

常用图形合集

类型描述使用场景
圆形(Circle)基本的圆形图形。表示数据点,如科学图表中的温度读数。
扇形(Sector)圆形的一部分,常用于饼图。数据可视化,如市场份额或用户满意度分布。
矩形(Rectangle)基本的矩形或正方形图形。构建图表的框架,如柱状图中的柱子。
直线(Line)直线段,可用于连接两点。流程图、图表的坐标轴或数据点之间的连接。
曲线(Polyline)由多个点定义的折线。折线图、路径规划或时间序列数据的可视化。
多边形(Polygon)由多个顶点定义的封闭多边形。地理区域划分、图表中的特定区域高亮。
椭圆(Ellipse)类似圆形,但长轴和短轴不同。表示椭圆形状的数据区域,如医学成像或天体轨迹。
圆环(Ring)圆形的圆环,内圆和外圆之间形成环。仪表盘、进度条或表示相对大小的图表。
文本(Text)用于显示文本的图形。标签、图例或图表中的文字说明。
图片(Image)可以显示图片的图形。展示产品图片、地图上的标志或用户头像。
心形(Heart)特殊形状的心形图形。用于情感分析、社交媒体数据可视化。
路径(Path)通过路径指令绘制的复杂图形。自定义形状的图表元素,如自定义的图标或装饰图案。
水滴(Droplet)表示水滴形状的图形。表示液体数据,如降雨量或水位。
扩展图形通过 zrender.Path.extend 可以自定义和扩展新的图形类型。满足特定需求的定制图形,如特殊的图表元素或动画效果。

样式和动画示例

绘制圆形

使用zrender.Circle类绘制一个圆形。

var circle = new zrender.Circle({
  shape: {
    cx: 100,
    cy: 100,
    r: 50,
  },
  style: {
    fill: "blue",
  },
});
zr.add(circle);

设置样式

为图形设置样式,包括填充色、边框等。

style: {
    fill: '#2fc25b',
    stroke: '#80d4c1',
    lineWidth: 2
}

变换和动画

  • animate(path, loop): 创建一个动画对象。动画不会立即开始,如需立即开始,需调用 zrender.Animator.start

    • path 对该对象的哪个元素执行动画,如 xxx.animate('a.b', true) 表示对 xxx.a.b 执行动画。
    • loop 是否循环动画。
  • when(time, props)

    • time 关键帧时刻,单位毫秒。
    • props 关键帧的属性,应为 Animatable 对象的属性。
shape
  .animate("scale", true)
  .when(1000, {
    scale: [2, 2, 100, 100],
  })
  .start();

ZRender 事件处理

鼠标事件

为图形添加鼠标事件监听。

shape.on("mouseover", function () {
  console.log("Mouse over");
});

事件冒泡

处理图形事件的冒泡。

zr.on("click", function (param) {
  if (param.target) {
    console.log("Click on shape", param.target.dataModel);
  }
});

交互式图形

var rect = new zrender.Rect({
  shape: {
    x: 100,
    y: 100,
    width: 100,
    height: 100,
  },
  style: {
    fill: "#fff",
    stroke: "#555",
  },
  draggable: true,
});
zr.add(rect);

rect.on("dragend", function (param) {
  console.log("Rectangle position:", param.target.position);
});

绘制折线图表(示例)

image.png

在线访问地址

html 准备

首先,确保您有一个 HTML 文件和可以编辑 JavaScript 代码的环境。在 HTML 文件中引入 ZRender 库:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>ZRender 折线图示例</title>
  </head>
  <body>
    <div id="main" style="width: 600px; height: 400px;"></div>
    <script src="https://cdn.bootcdn.net/ajax/libs/zrender/5.3.1/zrender.min.js"></script>
  </body>
</html>

创建 ZRender 实例

let zr = zrender.init(document.getElementById("main"), {
  renderer: "canvas", // 指定使用Canvas渲染器
});

准备数据和参数配置

我们将创建一个简单的数据集,表示折线图的各个数据点。

// 数据和参数配置
let padding = { left: 40 };
let data = [1, 3, 2, 5, 4];

绘制坐标轴

// X轴
let xAxis = new zrender.Line({
  shape: {
    x1: padding.left,
    y1: 300,
    x2: 600,
    y2: 300,
  },
  style: {
    stroke: "#666",
    lineWidth: 2,
  },
});
zr.add(xAxis);

// Y轴
let yAxis = new zrender.Line({
  shape: {
    x1: padding.left,
    y1: 0,
    x2: padding.left,
    y2: 300,
  },
  style: {
    stroke: "#666",
    lineWidth: 2,
  },
});
zr.add(yAxis);
// X轴刻度
let xAxisTicks = data.map(function (value, index) {
  return index;
});

// Y轴刻度
let yAxisTicks = data.map(function (value) {
  return value * 50; // 假设数据点数值乘以50为Y轴坐标
});
// X轴text
xAxisTicks.forEach(function (tick, index) {
  let line = new zrender.Line({
    shape: {
      x1: tick * 60 + padding.left, // 假设每个刻度间隔60px
      y1: 300, // X轴在Y=300位置
      x2: tick * 60 + padding.left,
      y2: 310, // 刻度线偏移量
    },
    style: {
      stroke: "#999",
      lineWidth: 1,
    },
  });
  zr.add(line);

  let text = new zrender.Text({
    position: [tick * 60 + padding.left, 320], // 文本位置在刻度线上方
    style: {
      text: index + 1, // 刻度值为数据点索引 + 1
      fill: "#666",
      textBaseline: "top",
      textAlign: "center",
    },
  });
  zr.add(text);
});
// Y轴text
yAxisTicks.forEach(function (tick, index) {
  let line = new zrender.Line({
    shape: {
      x1: padding.left,
      y1: 300 - tick, // 从Y轴底部向上绘制
      x2: padding.left - 10, // 刻度线偏移量
      y2: 300 - tick,
    },
    style: {
      stroke: "#999",
      lineWidth: 1,
    },
  });
  zr.add(line);

  let text = new zrender.Text({
    position: [padding.left - 40, 300 - tick], // 文本位置在刻度线右侧
    style: {
      text: tick, // 刻度值为数据点数值
      fill: "#666",
      textBaseline: "middle",
      textAlign: "right",
    },
  });
  zr.add(text);
});

计算坐标

我们需要将数据转换为图表上的点坐标。

let dataPoints = data.map(function (value, index) {
  return [padding.left + index * 60, value * 50]; // 将数据映射到坐标系
});

设置标题

// 设置标题
let title = new zrender.Text({
  position: [200, 20], // 标题位置在画布上方中间
  style: {
    text: "ZRender 折线图示例",
    fill: "#333",
    fontSize: 20,
    textBaseline: "bottom",
    textAlign: "center",
  },
});
zr.add(title);

绘制折线

使用 ZRender 的Polyline类绘制折线。

// 绘制折线
let line = new zrender.Polyline({
  shape: {
    points: dataPoints,
  },
  style: {
    stroke: "#1890ff", // 线的颜色
    lineWidth: 2, // 线宽
  },
});
zr.add(line);

添加数据点

最后,我们在折线图上绘制每个数据点。

dataPoints.forEach(function (point) {
  let circle = new zrender.Circle({
    shape: {
      cx: point[0],
      cy: point[1],
      r: 4,
    },
    style: {
      fill: "#1890ff",
    },
  });
  zr.add(circle);
});

添加网格

为图表添加网格线,使数据点更易于阅读。

// 网格
let grid = new zrender.Rect({
  shape: {
    x: padding.left,
    y: 0,
    width: 600,
    height: 300,
  },
  style: {
    fill: "rgba(0,0,0,0.05)", // 网格背景色
  },
  silent: true, // 静默模式,不响应鼠标事件
});
zr.add(grid);

结语

通过本教程的学习,我们不仅掌握了 ZRender 的基本使用方法,还学习了如何将数据点转换为可视化图形,以及如何为图形添加交互功能。ZRender 的强大功能,结合 ECharts 的丰富图表类型,为数据可视化提供了无限可能。随着实践的深入,你将能够发掘 ZRender 更多的潜力,创造出令人惊叹的视觉效果。