常见的数据可视化库

  • D3.js 目前 Web 端评价最高的 Javascript 可视化工具库(入手难)
  • ECharts.js 百度出品的一个开源 Javascript 数据可视化库
  • Highcharts.js 国外的前端数据可视化库,非商用免费,被许多国外大公司所使用
  • AntV 蚂蚁金服全新一代数据可视化解决方案 等等
  • Highcharts 和 Echarts 就像是 Office 和 WPS 的关系

自适应

https://mp.weixin.qq.com/s/iybivItaK5fAU2yPX1OrJQ

图形:canvas

https://www.w3school.com.cn/tags/html_ref_canvas.asp

canvas元素

<canvas>HTML5 新增的,一个可以使用脚本(通常为 JavaScript) 在其中绘制图像的 HTML 元素。它可以用来制作照片集或者制作简单(也不是那么简单)的动画,甚至可以进行实时视频处理和渲染。

<canvas> 看起来和 <img> 标签一样,只是 <canvas> 只有两个可选的属性 width、heigth 属性,而没有 src、alt 属性。

如果不给 <canvas> 设置 widht、height 属性时,则默认 width为300、height 为 150,单位都是 px。也可以使用 css 属性来设置宽高,但是如宽高属性和初始比例不一致,他会出现扭曲。所以,建议永远不要使用 css 属性来设置 <canvas> 的宽高。

渲染上下文(Thre Rending Context)

canvas元素创造了一个固定大小的画布,它公开了一个或多个渲染上下文,其可以用来绘制和处理要展示的内容。我们将会将注意力放在2D渲染上下文中。 元素有一个叫做 getContext() 的方法,这个方法是用来获得渲染上下文和它的绘画功能。

1
2
3
var canvas = document.getElementById('tutorial');
//获得 2d 上下文对象
var ctx = canvas.getContext('2d');

绘制矩形

不同于 SVG, 只支持两种形式的图形绘制:矩形和路径(由一系列点连成的线段)。所有其他类型的图形都是通过一条或者多条路径组合而成的。

canvas提供了三种方法绘制矩形:

  • fillRect(x, y, width, height)
    绘制一个填充的矩形,默认填充黑色
  • strokeRect(x, y, width, height)
    绘制一个矩形的边框
  • clearRect(x, y, width, height)
    清除指定矩形区域,让清除部分完全透明。

x与y指定了在canvas画布上所绘制的矩形的左上角(相对于原点)的坐标。width和height设置矩形的尺寸。

绘制路径

图形的基本元素是路径。路径是通过不同颜色和宽度的线段或曲线相连形成的不同形状的点的集合。一个路径,甚至一个子路径,都是闭合的。

  1. 首先,你需要创建路径起始点。
  2. 然后你使用画图命令去画出路径。
  3. 之后你把路径封闭。
  4. 一旦路径生成,你就能通过描边或填充路径区域来渲染图形。
  • beginPath()

    ·新建一条路径,生成之后,图形绘制命令被指向到路径上生成路径

  • closePath()

    闭合路径之后图形绘制命令又重新指向到上下文中。

  • moveTo(x,y)

    方法把路径移动到画布中的指定点,不创建线条。

  • stroke()

    通过线条来绘制图形轮廓

  • lineTo(x,y)

    绘制一条从当前位置到指定x以及y位置的直线。

  • fill()

    通过填充路径的内容区域生成实心的图形。

*注意:当你调用fill()函数时,所有没有闭合的形状都会自动闭合,所以你不需要调用closePath()函数。但是调用stroke()时不会自动闭合***。

绘制一个三角形

例如,绘制三角形的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
function draw() {
var canvas = document.getElementById('canvas');
if (canvas.getContext) {
var ctx = canvas.getContext('2d');

ctx.beginPath();
ctx.moveTo(75, 50);
ctx.lineTo(100, 75);
ctx.lineTo(100, 25);
ctx.fill();
}
}

样式和颜色

颜色绘制

  • fillStyle = color
    设置图形的填充颜色。
  • strokeStyle = color
    设置图形轮廓的颜色。

一旦您设置了 strokeStyle 或者 fillStyle 的值,那么这个新值就会成为新绘制的图形的默认值。如果你要给每个图形上不同的颜色,你需要重新设置 fillStylestrokeStyle 的值。

  • 透明度 Transparency

    除了可以绘制实色图形,我们还可以用 canvas 来绘制半透明的图形。通过设置 globalAlpha 属性或者使用一个半透明颜色作为轮廓或填充的样式。

    • globalAlpha = transparencyValue

      这个属性影响到 canvas 里所有图形的透明度,有效的值范围是 0.0 (完全透明)到 1.0(完全不透明),默认是 1.0。

线型 Line styles

  • lineWidth = value
    设置线条宽度。
  • lineCap = type
    设置线条末端样式。
  • lineJoin = type
    设定线条与线条间接合处的样式。
  • miterLimit = value
    限制当两条线相交时交接处最大长度;所谓交接处长度(斜接长度)是指线条交接处内角顶点到外角顶点的长度。
  • getLineDash()
    返回一个包含当前虚线样式,长度为非负偶数的数组。
  • setLineDash(segments)
    设置当前虚线样式。
  • lineDashOffset = value
    设置虚线样式的起始偏移量。

渐变 Gradients

就好像一般的绘图软件一样,我们可以用线性或者径向的渐变来填充或描边。我们用下面的方法新建一个 canvasGradient 对象,并且赋给图形的 fillStyle 或 strokeStyle 属性。

  • createLinearGradient(x1, y1, x2, y2)
    createLinearGradient 方法接受 4 个参数,表示渐变的起点 (x1,y1) 与终点 (x2,y2)。
  • createRadialGradient(x1, y1, r1, x2, y2, r2)
    createRadialGradient 方法接受 6 个参数,前三个定义一个以 (x1,y1) 为原点,半径为 r1 的圆,后三个参数则定义另一个以 (x2,y2) 为原点,半径为 r2 的圆。
1
2
var lineargradient = ctx.createLinearGradient(0,0,150,150);
var radialgradient = ctx.createRadialGradient(75,75,0,75,75,100);

Copy to Clipboard

创建出 canvasGradient 对象后,我们就可以用 addColorStop 方法给它上色了。

  • gradient.addColorStop(position, color)

    addColorStop 方法接受 2 个参数,position 参数必须是一个 0.0 与 1.0 之间的数值,表示渐变中颜色所在的相对位置。例如,0.5 表示颜色会出现在正中间。color 参数必须是一个有效的 CSS 颜色值(如 #FFF, rgba(0,0,0,1),等等)。

图案样式 Patterns

上一节的一个例子里面,我用了循环来实现图案的效果。其实,有一个更加简单的方法:createPattern。

createPattern(image, type)
该方法接受两个参数。Image 可以是一个 Image 对象的引用,或者另一个 canvas 对象。Type 必须是下面的字符串值之一:repeat,repeat-x,repeat-y 和 no-repeat。
注意: 用 canvas 对象作为 Image 参数在 Firefox 1.5 (Gecko 1.8) 中是无效的。
图案的应用跟渐变很类似的,创建出一个 pattern 之后,赋给 fillStyle 或 strokeStyle 属性即可。

var img = new Image();
img.src = ‘someimage.png’;
var ptrn = ctx.createPattern(img,’repeat’);

阴影 Shadows

  • shadowOffsetX = float
    shadowOffsetX 和 shadowOffsetY 用来设定阴影在 X 和 Y 轴的延伸距离,它们是不受变换矩阵所影响的。负值表示阴影会往上或左延伸,正值则表示会往下或右延伸,它们默认都为 0。

  • shadowOffsetY = float
    shadowOffsetX 和 shadowOffsetY 用来设定阴影在 X 和 Y 轴的延伸距离,它们是不受变换矩阵所影响的。负值表示阴影会往上或左延伸,正值则表示会往下或右延伸,它们默认都为 0。

  • shadowBlur = float
    shadowBlur 用于设定阴影的模糊程度,其数值并不跟像素数量挂钩,也不受变换矩阵的影响,默认为 0。

  • shadowColor = color
    shadowColor 是标准的 CSS 颜色值,用于设定阴影颜色效果,默认是全透明的黑色。

图像

上传图像

1
<input type="file"></input>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function getObjectURL(file) {
var url = null;
if (window.createObjcectURL != undefined) {
url = window.createOjcectURL(file);
} else if (window.URL != undefined) {
url = window.URL.createObjectURL(file);
} else if (window.webkitURL != undefined) {
url = window.webkitURL.createObjectURL(file);
}
return url;
}
var objURL = getObjectURL(imgFile);//imgFile文件对象
//objURL -->blob:http://127.0.0.1:5500/d17cdcc3-b698-4011-a6d2-f63360cdd22b
// 你可以像使用普通 URL 那样使用它,比如用在 img.src 上。
$("#img").attr("src", objURL);

通过window.URL.createObjectURL方法可以把一个blob转化为一个Blob URL,并且用做文件下载或者图片显示的链接。File对象是一种特殊的Blob对象

每次你调用window.URL.createObjectURL(),就会产生一个唯一的对象URL,即使是你对一个已创建了对象URL的文件再次创建一个对象URL。每个创建了的对象URL必须要释放。当文档关闭时,它们会自动被释放。如果你的网页要动态使用它们,你需要显式调用 window.URL.revokeObjectURL() 来释放它们

绘制图片

获取图片的方式

  • HTMLImageElement
    图片由Image()函数构造出来,或者任何的元素

    • 用脚本创建一个新的 HTMLImageElement 对象,使用Image()构造函数

      1
      2
      var img = new Image();   // 创建一个<img>元素
      img.src = objURL; // 设置图片源地址

      若调用 drawImage 时,图片没装载完,那什么都不会发生(在一些旧的浏览器中可能会抛出异常)。因此你应该用load事件来保证不会在加载完毕之前使用这个图片:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      //已知图像路径
      var img = new Image(); // 创建img元素
      img.src = 'myImage.png'; // 设置图片源地址
      img.onload = function(){
      // 执行drawImage语句
      //1.创建的img对象
      ctx.drawImage(this,offsetX,0,imgW,imgH);
      //2.文中的img标签
      ctx.drawImage(document.getElementById("img"), 0, 0, imgW, imgH);
      }
  • HTMLVideoElement
    用一个HTML的

  • HTMLCanvasElement
    可以使用另一个 元素作为你的图片源。

    • HTMLCanvasElement.toDataURL()获取canvas对应的data-URL (一串 Base64 编码的字符串)。

      1
      2
      3
      4
      5
      6
      canvas.toDataURL(type, encoderOptions);
      type 可选的
      默认格式类型为 image/png.
      encoderOptions 可选的
      表示所述图像质量对于使用的图像格式即使用有损压缩,如 image/jpeg和image/webp。
      如果此参数是其他任何参数,则使用图像质量的默认值。默认值为0.92
      1
      2
      3
      4
      5
      var canvas = document.getElementById("canvas");
      var dataURL = canvas.toDataURL();
      //dataURL,相当于就是src
      img.src = dataURL
      //src-> //'data:image/gif;base64,R0lGODlhCwALAIAAAAAA3pn/ZiH5BAEAAAEALAAAAAALAAsAAAIUhA+hkcuO4lmNVindo7qyrIXiGBYAOw==';

      设置jpegs图片的质量

      1
      2
      3
      4
      var fullQuality = canvas.toDataURL("image/jpeg", 1.0);
      // data:image/jpeg;base64,/9j/4AAQSkZJRgABAQ...9oADAMBAAIRAxEAPwD/AD/6AP/Z"
      var mediumQuality = canvas.toDataURL("image/jpeg", 0.5);
      var lowQuality = canvas.toDataURL("image/jpeg", 0.1);
  • ImageBitmap
    这是一个高性能的位图,可以低延迟地绘制,它可以从上述的所有源以及其它几种源中生成。

ImageData 对象

ImageData对象中存储着canvas对象真实的像素数据

getImageData(left, top, width, height)

获得一个包含画布场景像素数据的ImageData对像

  • **width**图片宽度,单位是像素

  • height图片高度,单位是像素

  • data

    Uint8ClampedArray类型的一维数组,包含着RGBA格式的整型数据,范围在0至255之间(包括255)。

**putImageData()**对场景进行像素数据的写入

图像模糊

https://developer.mozilla.org/zh-CN/docs/Web/API/Window/devicePixelRatio

https://zhuanlan.zhihu.com/p/31426945

https://juejin.cn/post/6844903759995207693

设备像素比

设备像素比(window.devicePixelRatio)当前显示设备的物理像素分辨率与CSS像素分辨率之比,此值也可以解释为像素大小的比率:一个CSS像素的大小与一个物理像素的大小。 简单来说,它告诉浏览器应使用多少屏幕实际像素来绘制单个CSS像素。

在很早以前还没高分屏的时候,开发写的的1像素也就是实际的1像素(如果不考虑缩放的情况),你根本不需要做什么特殊的处理。如果css中设置100px那他就是100px。

后来出现了高分屏的手机,并且在window对象下面出现了devicePixelRatio 这个神秘的属性,并且还可以用devicePixelRatio在媒体查询中进行判断。这个属性的意思就是:渲染时,css中的像素(逻辑像素)候和实际像素(物理像素)的比值。比如说:iPhone 4S它的devicePixelRatio 属性的值是2,那就是100px逻辑像素等于200px的设备实际像素。原先需要一个像素绘制的点,现在会用两个像素来绘制。

canvas 的 css 宽高与画布宽高

1
<canvas id="canvas" width="200" height="200"></canvas>

canvas 标签中的 widthheight 属性并不是 css 中的宽高,而是 canvas 画布宽高(绘图区域),当不设置 canvas 的 css 宽高时,canvas 会将 widthheight的值作为 css 宽高,而 css 宽高是元素在页面上的可见尺寸

但是 canvas 的上下文宽高略奇怪,它可不管像素比是 1 是 2 还是 3,它就是会将整个 canvas 绘图区域塞进 css 宽高中并且填满,绘图的时候会将绘制的图形的宽高按照塞进 css 时宽与高的缩放比率分别进行缩放(所以如果缩放比率不同,就会导致绘制的图形变形

但是上面这些都不是导致模糊的真正原因,下面这个才是捣乱的元凶:

canvas 绘图时,会从两个物理像素的中间位置开始绘制并向两边扩散 0.5 个物理像素。当设备像素比为 1 时,一个 1px 的线条实际上占据了两个物理像素(每个像素实际上只占一半),由于不存在 0.5 个像素,所以这两个像素本来不应该被绘制的部分也被绘制了,于是 1 物理像素的线条变成了 2 物理像素,视觉上就造成了模糊

解决绘图模糊

创建的图片的时候根据devicePixelRatio 放大数倍(比原照片更大的新的一张图片)然后再用css再把它缩小到原来的样子。因此缩小后的图片不会超过自己原来的尺寸并且不会再模糊。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var getPixelRatio = function (context) {
var backingStore = context.backingStorePixelRatio ||
context.webkitBackingStorePixelRatio ||
context.mozBackingStorePixelRatio ||
context.msBackingStorePixelRatio ||
context.oBackingStorePixelRatio ||
context.backingStorePixelRatio || 1;
return (window.devicePixelRatio || 1) / backingStore;
};
var pixelRatio = getPixelRatio(canvas);
console.log(pixelRatio)
//设置宽高
function setCanvasArea(canvas, ctx) {
canvas.width = Math.floor(cw * pixelRatio);
canvas.height = Math.floor(ch * pixelRatio);
// 设置canvas的真实宽高
canvas.style.width = cw + 'px';
canvas.style.height = ch + 'px';
ctx.scale(pixelRatio, pixelRatio);
}

反锯齿

CanvasRenderingContext2D.imageSmoothingEnabled 是 Canvas 2D API 用来设置图片是否平滑的属性,true表示图片平滑(默认值),false表示图片不平滑。

反锯齿默认是启用的,我们可能想要关闭它以看到清楚的像素。你可以通过切换勾选框来看到imageSmoothingEnabled属性的效果

zoomctx.imageSmoothingEnabled = false;
zoomctx.mozImageSmoothingEnabled = false;
zoomctx.webkitImageSmoothingEnabled = false;
zoomctx.msImageSmoothingEnabled = false;

img

第一个图像以其自然大小绘制,第二个图像缩放为3倍并启用了图像平滑,而第三个图像缩放为3倍但禁用了图像平滑。

imageSmoothingQuality

使用imageSmoothingQuality属性来调整平滑质量

1
2
3
4
ctx.imageSmoothingQuality = value
value = ctx.imageSmoothingQuality
//value
//"low","medium","high"

image-rendering

https://developer.mozilla.org/zh-CN/docs/Web/CSS/image-rendering

CSS 属性 image-rendering 用于设置图像缩放算法。

1
2
3
4
5
6
7
8
9
/* 专有属性值 */
image-rendering: auto;
image-rendering: crisp-edges;
image-rendering: pixelated;

/* 全局属性值 */
image-rendering: inherit;
image-rendering: initial;
image-rendering: unset;

保存图片

https://juejin.cn/post/6844904019605848072

性能

  • 避免浮点数的坐标点,用整数取而代之
  • 在离屏canvas中缓存图片的不同尺寸,而不要用drawImage()去缩放它们。

变形

translate(x, y)

rotate(angle)

scale(x, y)

如果比1小,会缩小图形, 如果比1大会放大图形

如果参数为负实数, 相当于以x 或 y轴作为对称轴镜像反转(例如, 使用translate(0,canvas.height); scale(1,-1); 以y轴作为对称轴镜像反转

transform(a, b, c, d, e, f)

a (m11)
水平方向的缩放
b(m12)
竖直方向的倾斜偏移
c(m21)
水平方向的倾斜偏移
d(m22)
竖直方向的缩放
e(dx)
水平方向的移动
f(dy)
竖直方向的移动

组合

绘制顺序:globalCompositeOperation,这个属性设定了在画新图形时采用的遮盖策略

save&&restore

  • save()
    保存画布(canvas)的所有状态
  • restore()
    save 和 restore 方法是用来保存和恢复 canvas 状态的,都没有参数。Canvas 的状态就是当前画面应用的所有样式和变形的一个快照。

Canvas状态存储在栈中,每当save()方法被调用后,当前的状态就被推送到栈中保存。每一次调用 restore 方法,上一个保存的状态就从栈中弹出,所有设定都恢复。

图形:Konva

工作原理

Konva 的对象是以一颗树的形式保存的,Konva.Stage 是树的根节点,Stage 子节点是用户创建的图层 (Konva.Layer)。

每一个 layer 有两个 <canvas> 渲染器: 场景渲染器 和 图像命中检测渲染器。场景渲染器输出你所看见的内容,图像命中渲染器在隐藏的 canvas 里用于高性能的检测事件。

图层可以包含图形、嵌套图形的组、嵌套组的组。Stage(舞台),layers(图层),groups(组),和 shapes(图形) 都是虚拟节点,类似于 HTML 的 DOM 节点。

节点结构图:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
              Stage
|
+------+------+
| |
Layer Layer
| |
+-----+-----+ Shape
| |
Group Group
| |
+ +---+---+
| | |
Shape Group Shape
|
+
|
Shape

示例

  1. 引入 Konva.js 文件

    1
    <script src="konva.js"></script>
  2. 然后页面中放置一个容器作为 Konva 处理的对象. Konva 会在该容器中添加 canvas 标签. 值得说明的是, 需要为这个标签添加 id 属性.

    1
    <div id="dv"></div>
  3. 然后编写 js 代码,Konva 是一个完全面向对象的库.

  4. 创建舞台

    1
    2
    3
    4
    5
    var stage = new Konva.Stage({
    container: 'dv',
    width: window.innerWidth,
    height: window.innerHeight
    });
  • 首先, 在 Konva 中所有的图形都是在 Konva 中的一个构造函数. Konva 是全局的命名空间.
  • 创建舞台使用的是 Stage 构造函数,该函数需要提供参数.
  • Konva 中所有图形的参数都是使用 json 对象的方式进行提供.
  • 舞台需要设置容器的 id, 即 container 属性. 以及宽( width ), 高( height ).
  1. 舞台中可以放置一个到多个层( Layer ), 所有的图形应该放在在层中

    • 首先创建层对象. 层对象不需要传递参数.
    1
    var layer = new Konva.Layer();
    • 将层添加到舞台中. Konva 中凡是添加, 都是使用 add 方法.

      1
      stage.add( layer );
  2. 在层中放置一个矩形, 就创建一个 矩形对象

    1
    2
    3
    4
    5
    6
    7
    var rect = new Konva.Rect({
    x: 100,
    y: 50,
    width: 200,
    height: 100,
    fill: 'red'
    });

    将矩形添加到 层中

    1
    layer.add( rect );
  3. 最后绘图使用 draw 方法

    1
    layer.draw();

stage

layer 的概念类似于 ps 中的图层,或者 DOM 中的 z-index,当我们向 stage 中添加一个 layer 时,DOM 中会再加入一个 canvas 元素来对应这个 layer。

当我们往 layer 中添加了多个 shape 时,调用 layer.draw 时,layer 会按照形状添加的先后顺序依次进行绘制。后面添加的在上面,最先添加的在最下面。

图表:Antv

G2

https://blog.csdn.net/u011262253/article/details/107370549

G2 的数据处理流程

https://g2.antv.vision/zh/docs/manual/tutorial/data-flow

图形组件

1
2
3
4
5
6
7
8
9
10
const data = [
{ year: '1951 年', sales|value: 38 },
{ year: '1952 年', sales|value: 52 },
{ year: '1956 年', sales|value: 61 },
{ year: '1957 年', sales|value: 145 },
{ year: '1958 年', sales|value: 48 },
{ year: '1959 年', sales|value: 38 },
{ year: '1960 年', sales|value: 38 },
{ year: '1962 年', sales|value: 38 },
];

度量 scale和坐标轴Axis

每个图表通常包含两个坐标轴,在直角坐标系(笛卡尔坐标系)下,分别为 x 轴和 y 轴,在极坐标轴下,则分别由角度和半径 2 个维度构成。

image.png

每个坐标轴由坐标轴线(line)、刻度线(tickLine)、刻度文本(label)、标题(title)以及网格线(grid)组成。

image.png
度量类型

https://g2.antv.vision/zh/docs/manual/tutorial/scale

  1. 分类(非连续)数据,又分为有序分类和无序分类。
  2. 连续数据,时间也是一种连续数据类型。
  3. 常量度量,数据是一种常量,只有单个值。

度量的类型有:

数据类型 度量类型
连续 linear、log、pow、time、quantize、quantile
分类(非连续) cat、timeCat
常量 identity
  • 分类度量:
    • cat: 分类度量,[‘男’, ‘女’]。
    • timeCat: 时间分类度量,比如股票的时间不包括周末或者未开盘的日期。
  • 连续度量:
    • linear: 线性度量,连续的数字 [1, 2, 3, 4, 5]。
    • time:连续的时间度量。
    • log: log 度量连,续非线性的 Log 数据 将 [1, 10, 100, 1000] 转换成 [0, 1, 2, 3]。
    • pow: pow 度量,连续非线性的 pow 数据 将 [2, 4, 8, 16, 32] 转换成 [1, 2, 3, 4, 5]。
    • quantize:分段度量,用户可以指定不均匀的分段,例如 [0-100, 100-200, 200-300] 在一个区间内映射到一个值上。
    • quantile: 等分度量,根据数据的分布自动计算分段。
  • 常量度量
    • identity: 常量度量,也就是说数据的某个字段是不变的常量。
坐标轴配置

坐标轴的内容是由 scale 度量控制的,所以 scale 度量的名字控制着坐标轴的标题内容。 chart.axis() 只用于控制坐标轴的外观配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
 //度量(Scale)用于定义坐标轴内容的类型和展示方式
chart.scale({
year: {
alias: "时间",
range: [0.05, 0.75], //设置坐标系两端留白
},
value: {
alias: "数量",
// ticks: [0, 100, 200, 300, 400, 500, 600], //设置坐标轴数值范围
//设置坐标轴数值范围
min: 0,
max: 1000,
tickCount: 10, //设置坐标轴刻度线个数
tickInterval: 200, //设置坐标轴刻度线间距
formatter: (val) => `¥${val}`, //格式化
},
Value: {
sync: true,
nice: true,
},
});
//scale 度量的名字控制着坐标轴的标题内容
// chart.scale("year", {

// });
// chart.scale("value", {

// });
//只用于控制坐标轴的外观配置
chart.axis("year", {
// tickLine: null, //刻度线
title: {
style: {
fill: "#1890ff",
},
},
});
chart.axis("value", {
// tickLine: null, //刻度线
title: {
style: {
fill: "#1890ff",
},
},
});

图例legend

图例配置

图例作为图表的辅助元素,用于标定不同的数据类型以及数据的范围,辅助阅读图表,帮助用户在图表中进行数据的筛选过滤。

在 G2 中,根据数据的类型,目前提供了以下两种图例:

  1. 分类图例

    img
  2. 连续图例

    img
分类图例

图例配置:通过 chart.legend() 接口对图例进行配置,具体的配置详见 API

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
chart.legend("year", {
show: true,
position: "top-left",
marker: (name: any, index: any, item: any) => {
return {
symbol: "circle",
style: {
fill: index === 0 ? "purple" : "green",
stroke: "#363636",
lineWidth: 1,
},
};
},
style: {
fontWeight: "normal",
fontSize: 12,
fill: "#303133",
},
}); // 只更改 x 维度对应的图例的显示位置
连续图例

提示信息Tooltip

https://g2.antv.vision/zh/docs/manual/tutorial/tooltip

1
2
3
chart.tooltip({
showCrosshairs: true, // 展示 Tooltip 辅助线
});

文本标签

https://g2.antv.vision/zh/docs/api/general/label

文本标签对应每一条数据记录,G2 除了提供文本标签的显示功能外,用户还可以指定显示的内容、配置文本样式等。使用如下接口配置:

1
chart.line().position("date*blockchain").label("nlp");

文本标签类型

针对不同的图表类型有不同的文本标签类型。G2 默认提供了 4 种类型:

  • ‘base’,默认类型,用于直角坐标系下的图表
  • ‘interval’,用于 Interval 几何标记下所有图形的文本标注,比如柱状图等
  • ‘pie’,专用于饼图的文本标注,带有文本连接线
  • ‘polar’,用于极坐标系下图表的文本标注
1
2
3
chart.interval().position('x*y').label('z', {
type: 'polar',
});

图形标注

图形标注,Annotation,作为 G2 图表的辅助元素,主要用于在图表上标识额外的标记注解。

image.png

滑块

https://g2.antv.vision/zh/docs/manual/concepts/component/slider

滚动条

https://g2.antv.vision/zh/docs/manual/concepts/component/scrollbar

color

  • 如果班级等于 ‘1’或者人数大于 40 则映射成红色
  • 其他则映射成绿色
1
2
3
4
5
6
7
8
9
chart
.interval()
.position('班级*人数')
.color('班级*人数', (grade, count) => {
if (grade == '1' || count > 40) {
return 'red';
}
return 'green';
});

img

主题

自定义主题 - Theme

缩略轴

几何图形

点图 point

1
2
x、y 映射到位置的单个图形
chart.point()
  • 单个的数值字段,分类字段或者连续字段,数据以及语法如下:
1
2
3
const data = [{ carat: 10 }];
// ...
chart.point().position('carat');
  • 两个数值字段,分类字段连续字段,语法如下:
1
2
const data = [{ month: '一月', temperature: 10 }];
chart.point().position('month*temperature');
  • 两个数据字段,y 轴对应的数据字段是数组,如:
1
2
const data = [{ month: '一月', temperature: [-5, 10] }];
chart.point().position('month*temperature');

路径和线 path && line

1
2
多个点连接成线
chart.line()
color

color 可以区分不同的线,增加 color 视觉通道,可以将数据进行分组,绘制出多条直线

1
2
3
4
5
const data = [
{ month: '一月', temperature: 10, city: '北京' },
{ month: '一月', temperature: 15, city: '南京' },
];
chart.line().position('month*temperature').color('city');
img
size

size 的视觉通道跟图形的自由度相关,自由度 = 空间维度 - 图形维度,线是一维的,所以线图的自由度是 1。在 G2 中我们将 size 视觉通道映射的线的宽度,由于人对宽度的识别度不高,这个映射慎用。

img
shape

线图支持的图形:

  • line 常见的实线
  • dot 点线
  • smooth 平滑的曲线
img
  • 信号相关的折线图:vh hv hvh vhv
img
线图和坐标系

线图在直角坐标系和极坐标系下有所差别,在极坐标下线图需要进行闭合。

img

区域图 area

1
2
线和 x 轴包围而成的面积使用颜色或者纹理填充
chart.area()

区间图 interval

1
2
分类字段映射到 x 轴的位置, y 是个区间值,默认最小值是 0
chart.interval()

多边形 polygon

1
chart.polygon()

自定义图 schema

图形元素

Element 即一条/一组数据对应的图形元素,它代表一条数据或者一个数据集

职责:绘制、更新、销毁 Shape & 状态管理

element element

Element 主要职责如下:

  • 绘制 Shape
  • 更新 Shape,当对应的 Element 数据发生更新时,更新对应的 shape(而不是销毁再创建)
  • 销毁 Shape
  • Shape 状态管理

G2 默认提供了三种图形状态:active、selected 以及 inactive,对于 Element 来说这三种状态都是相互独立的,即用户开启了 active 状态之后又开启了 selected 状态,element 就会在 active 的状态上叠加 selected 状态,交互状态之间的关联全部交由具体的交互行为负责,所以我们除了提供 setState() 方法外,还会提供 clearState() hasState() 方法。

1
element.setState('active', true); // 开启 active 状态

Element 相关操作

  1. 如何获取 Element 实例
1
2
3
4
5
6
7
8
9
10
11
12
13
// 创建 Interval
const interval = chart.interval().position('x*y');

chart.render();

// 获取 Interval 下的 Element 实例
const elements = interval.elements;

// 根据特定的条件查找 Element 实例
const someElements = interval.getElementsBy((element) => {
const data = element.getData();
return data.x === 'a';
});
  1. 通过 Element 操纵图形状态
1
2
3
4
const interval = chart.interval().position('x*y');

// 将 Interval 的第一个 Element 实例设置为 active 状态
interval.elements[0].setState('active', false);
  1. 修改 Element 图形元素的状态样式
1
2
3
4
5
6
7
8
9
10
11
chart
.interval()
.position('x*y')
.state({
active: {
style: {
lineWidth: 2,
stroke: '#000',
},
},
});

View 视图

G2 的 View 是图层容器的概念,每一个 View 拥有自己独立的数据源、坐标系、几何标记、Tooltip 以及图例,可以理解 View 是整个 G2 体系中,用来组装数据,Component,Geometry 的容器。 一个 View 可以包含有多个子 View,通过这种嵌套关系,可以将一个画布按照不同的布局划分多个不同区域(分面),也可以将不同数据源的多个 View 叠加到一起,形成一个多数据源,多图层的图表。

如何创建视图

直接通过调用 chart.createview() 即可创建 View 对象,此时会默认创建一个绘图区域于 Chart 相同的视图,当然你可以通过 region 属性指定 view 的绘图区域。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { Chart } from '@antv/g2';

// step 1: 需要创建 chart 对象
const chart = new Chart({
container: 'container',
autoFit: false,
width: 1000,
height: 500,
});

// step 2: 然后创建一个视图
const view = chart.createView({
region: {
start: { x: 0.2, y: 0.2 }, // 指定该视图绘制的起始位置,x y 为 [0 - 1] 范围的数据
end: { x: 1, y: 1 }, // 指定该视图绘制的结束位置,x y 为 [0 - 1] 范围的数据
},
padding: [20, 40], // 指定视图的留白
});

多 View 划分画布

在看股票涨跌情况的时候

  1. 一方面会使用专业的 k 线图去展示股票涨跌信息;
  2. 另一方面,我们也可以使用一个简单的柱形图,显示绝对的涨跌情况,并根据柱子的红绿颜色标记涨跌。

这种情况,就使用两个 View 并排显示,去显示不同的图形,具体如下 demo:

img

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import DataSet from '@antv/data-set';
import { Chart } from '@antv/g2';

fetch('https://gw.alipayobjects.com/os/antvdemo/assets/data/candle-sticks.json')
.then(res => res.json())
.then(data => {
// 设置状态量,时间格式建议转换为时间戳,转换为时间戳时请注意区间
const ds = new DataSet();
const dv = ds.createView();
dv.source(data)
.transform({
type: 'map',
callback: obj => {
obj.trend = (obj.start <= obj.end) ? '上涨' : '下跌';
obj.range = [obj.start, obj.end, obj.max, obj.min];
return obj;
}
});
const chart = new Chart({
container: 'container',
autoFit: true,
height: 400,
padding: [10, 40, 40, 40]
});
chart.scale({
time: {
type: 'timeCat',
range: [0, 1],
tickCount: 4,
},
trend: {
values: ['上涨', '下跌']
},
volumn: { alias: '成交量' },
start: { alias: '开盘价' },
end: { alias: '收盘价' },
max: { alias: '最高价' },
min: { alias: '最低价' },
range: { alias: '股票价格' }
});
chart.tooltip({
showTitle: false,
showMarkers: false,
itemTpl: '<li class="g2-tooltip-list-item" data-index={index}>'
+ '<span style="background-color:{color};" class="g2-tooltip-marker"></span>'
+ '{name}{value}</li>'
});

const kView = chart.createView({
region: {
start: { x: 0, y: 0 },
end: { x: 1, y: 0.7 },
}
});
kView.data(dv.rows);
kView.schema()
.position('time*range')
.color('trend', val => {
if (val === '上涨') {
return '#f04864';
}

if (val === '下跌') {
return '#2fc25b';
}
})
.shape('candle')
.tooltip('time*start*end*max*min', (time, start, end, max, min) => {
return {
name: time,
value: '<br><span style="padding-left: 16px">开盘价:' + start + '</span><br/>'
+ '<span style="padding-left: 16px">收盘价:' + end + '</span><br/>'
+ '<span style="padding-left: 16px">最高价:' + max + '</span><br/>'
+ '<span style="padding-left: 16px">最低价:' + min + '</span>'
};
});

const barView = chart.createView({
region: {
start: { x: 0, y: 0.7 },
end: { x: 1, y: 1 },
}
});
barView.data(dv.rows);
barView.scale('volumn', {
tickCount: 2,
})
barView.axis('time', {
tickLine: null,
label: null
});
barView.axis('volumn', {
label: {
formatter: val => {
return +val / 1000 + 'k';
}
}
});
barView.interval()
.position('time*volumn')
.color('trend', val => {
if (val === '上涨') {
return '#f04864';
}

if (val === '下跌') {
return '#2fc25b';
}
})
.tooltip('time*volumn', (time, volumn) => {
return {
name: time,
value: '<br/><span style="padding-left: 16px">成交量:' + volumn + '</span><br/>'
};
});

chart.render();
});

API

https://g2.antv.vision/zh/docs/api/general/chart#chart-api

1
2
3
chart.clear(); // 清理所有
chart.source(newData); // 重新加载数据

图表:echarts

背景

ECharts,一个使用 JavaScript 实现的开源可视化库,可以流畅的运行在 PC 和移动设备上,兼容当前绝大部分浏览器(IE8/9/10/11,Chrome,Firefox,Safari等),底层依赖矢量图形库 ZRender,提供直观,交互丰富,可高度个性化定制的数据可视化图表。

特性

  • 千万数据的前端展现:对流加载(4.0+)的支持,使用 WebSocket 或者对数据分块后加载,加载多少渲染多少
  • 移动端优化:移动端小屏上适于用手指在坐标系中进行缩放、平移。细粒度的模块化和打包机制可以让 ECharts 在移动端也拥有很小的体积,可选的 SVG 渲染模块让移动端的内存占用不再捉襟见肘。
  • 多渲染方案,跨平台使用!:ECharts 支持以 Canvas、SVG(4.0+)、VML 的形式渲染图表。VML 可以兼容低版本 IE,SVG 使得移动端不再为内存担忧,Canvas 可以轻松应对大数据量和特效的展现。不同的渲染方式提供了更多选择,使得 ECharts 在各种场景下都有更好的表现。

搭建

引入 ECharts

npm install echarts –save

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import * as echarts from 'echarts';

// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('main'));
// 绘制图表
myChart.setOption({
title: {
text: 'ECharts 入门示例'
},
tooltip: {},
xAxis: {
data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
},
yAxis: {},
series: [
{
name: '销量',
type: 'bar',
data: [5, 20, 36, 10, 10, 20]
}
]
});

按需引入 ECharts 图表和组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// 引入 echarts 核心模块,核心模块提供了 echarts 使用必须要的接口。
import * as echarts from 'echarts/core';
// 引入柱状图图表,图表后缀都为 Chart
import { BarChart } from 'echarts/charts';
// 引入提示框,标题,直角坐标系,数据集,内置数据转换器组件,组件后缀都为 Component
import {
TitleComponent,
TooltipComponent,
GridComponent,
DatasetComponent,
TransformComponent
} from 'echarts/components';
// 标签自动布局、全局过渡动画等特性
import { LabelLayout, UniversalTransition } from 'echarts/features';
// 引入 Canvas 渲染器,注意引入 CanvasRenderer 或者 SVGRenderer 是必须的一步
import { CanvasRenderer } from 'echarts/renderers';

// 注册必须的组件
echarts.use([
TitleComponent,
TooltipComponent,
GridComponent,
DatasetComponent,
TransformComponent,
BarChart,
LabelLayout,
UniversalTransition,
CanvasRenderer
]);

// 导出
export default echarts;

需要注意的是为了保证打包的体积是最小的,ECharts 按需引入的时候不再提供任何渲染器,所以需要选择引入 CanvasRenderer 或者 SVGRenderer 作为渲染器。这样的好处是假如你只需要使用 svg 渲染模式,打包的结果中就不会再包含无需使用的 CanvasRenderer 模块。

基本概念

图表容器及大小

初始化

echarts.init

高度

  • 在 HTML 中定义有宽度和高度的父容器(推荐)

    1
    2
    3
    4
    <div id="main" style="width: 600px;height:400px;"></div>
    <script type="text/javascript">
    var myChart = echarts.init(document.getElementById('main'));
    </script>
  • 指定图表的大小

    1
    2
    3
    4
    5
    6
    7
    <div id="main"></div>
    <script type="text/javascript">
    var myChart = echarts.init(document.getElementById('main'), null, {
    width: 600,
    height: 400
    });
    </script>

自适应容器大小

1
2
3
4
5
6
7
8
9
10
var myChart = echarts.init(document.getElementById('main'));
window.onresize = function() {
myChart.resize();
};

//除了直接调用 resize() 不含参数的形式之外,还可以指定宽度和高度,实现图表大小不等于容器大小的效果。
myChart.resize({
width: 800,
height: 400
});

容器节点被销毁以及被重建时

在图表容器被销毁之后,调用 echartsInstance.dispose 销毁实例,在图表容器重新被添加后再次调用 echarts.init 初始化。

样式

颜色主题(Theme)

最简单的更改全局样式的方式,是直接采用颜色主题(theme)。例如,在 示例集合 中,可以通过切换深色模式,直接看到采用主题的效果。

ECharts5 除了一贯的默认主题外,还内置了'dark'主题。可以像这样切换成深色模式:

1
var chart = echarts.init(dom, 'dark');

其他的主题,没有内置在 ECharts 中,需要自己加载。这些主题可以在 主题编辑器 里访问到。也可以使用这个主题编辑器,自己编辑主题。下载下来的主题可以这样使用:

如果主题保存为 JSON 文件,则需要自行加载和注册,例如:

1
2
3
4
5
// 假设主题名称是 "vintage"
$.getJSON('xxx/xxx/vintage.json', function(themeJSON) {
echarts.registerTheme('vintage', JSON.parse(themeJSON));
var chart = echarts.init(dom, 'vintage');
});

如果保存为 UMD 格式的 JS 文件,文件内部已经做了自注册,直接引入 JS 即可:

1
2
3
// HTML 引入 vintage.js 文件后(假设主题名称是 "vintage")
var chart = echarts.init(dom, 'vintage');
// ...

高亮的样式:emphasis

在鼠标悬浮到图形元素上时,一般会出现高亮的样式。默认情况下,高亮的样式是根据普通样式自动生成的。但是高亮的样式也可以自己定义,主要是通过 emphasis 属性来定制。emphasis 中的结构,和普通样式的结构相同,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
option = {
series: {
type: 'scatter',

// 普通样式。
itemStyle: {
// 点的颜色。
color: 'red'
},
label: {
show: true,
// 标签的文字。
formatter: 'This is a normal label.'
},

// 高亮样式。
emphasis: {
itemStyle: {
// 高亮时点的颜色。
color: 'blue'
},
label: {
show: true,
// 高亮时标签的文字。
formatter: 'This is a emphasis label.'
}
}
}
};

坐标轴

x 轴、y 轴

x 轴和 y 轴都由轴线、刻度、刻度标签、轴标题四个部分组成。

img

普通的二维数据坐标系都有 x 轴和 y 轴,通常情况下,x 轴显示在图表的底部,y 轴显示在左侧,一般配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
option = {
xAxis: {
type: 'time',
name: '销售时间'
// ...
},
yAxis: {
type: 'value',
name: '销售数量'
// ...
}
// ...
};

当 x 轴(水平坐标轴)跨度很大,可以采用区域缩放方式灵活显示数据内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
option = {
xAxis: {
type: 'time',
name: '销售时间'
// ...
},
yAxis: {
type: 'value',
name: '销售数量'
// ...
},
dataZoom: [
// ...
]
// ...
};

轴线

ECharts 提供了轴线 axisLine 相关的配置

刻度

ECharts 提供了轴线 axisTick 相关的配置

刻度标签

ECharts 提供了轴线 axisLabel 相关的配置

图例

图例是图表中对内容区元素的注释、用不同形状、颜色、文字等来标示不同数据列,通过点击对应数据列的标记,可以显示或隐藏该数据列。

图例要注意视情况使用,有些双轴图包含了多种图表类型,不同类型的图例样式要有所区分。

布局

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
option = {
legend: {
// Try 'horizontal'
orient: 'vertical',
right: 10,
top: 'center'
},
dataset: {
source: [
['product', '2015', '2016', '2017'],
['Matcha Latte', 43.3, 85.8, 93.7],
['Milk Tea', 83.1, 73.4, 55.1],
['Cheese Cocoa', 86.4, 65.2, 82.5],
['Walnut Brownie', 72.4, 53.9, 39.1]
]
},
xAxis: { type: 'category' },
yAxis: {},
series: [{ type: 'bar' }, { type: 'bar' }, { type: 'bar' }]
};

img

对于图例较多时,可以使用可滚动翻页的图例

1
2
3
4
5
6
7
8
9
10
11
12
option = {
legend: {
type: 'scroll',
orient: 'vertical',
right: 10,
top: 20,
bottom: 20,
data: ['图例一', '图例二', '图例三' /* ... */, , '图例n']
// ...
}
// ...
};

样式

1
2
3
4
5
6
7
8
9
10
11
12
option = {
legend: {
data: ['图例一', '图例二', '图例三'],
backgroundColor: '#ccc',
textStyle: {
color: '#ccc'
// ...
}
// ...
}
// ...
};

交互

根据场景需要,图例可支持交互操作,点击控制显示或隐藏对应的数据列;

1
2
3
4
5
6
7
8
9
10
11
12
option = {
legend: {
data: ['图例一', '图例二', '图例三'],
selected: {
图例一: true,
图例二: true,
图例三: false
}
// ...
}
// ...
};

视觉映射

数据可视化是数据到视觉元素的映射过程(这个过程也可称为视觉编码,视觉元素也可称为视觉通道)。

ECharts 的每种图表本身就内置了这种映射过程,比如折线图把数据映射到“线”,柱状图把数据映射到“长度”。

此外,ECharts 还提供了 visualMap 组件 来提供通用的视觉映射。visualMap 组件中可以使用的视觉元素有:

  • 图形类别(symbol)、图形大小(symbolSize)
  • 颜色(color)、透明度(opacity)、颜色透明度(colorAlpha)、
  • 颜色明暗度(colorLightness)、颜色饱和度(colorSaturation)、色调(colorHue)

数据和维度

ECharts 中的数据,一般存放于 series.data 中。

不同的图表类型,数据格式有所不一样,但是他们的共同特点就都是数据项(dataItem) 的集合。每个数据项含有 数据值(value) 和其他信息(可选)。每个数据值,可以是单一的数值(一维)或者一个数组(多维)。

1
2
3
4
5
6
7
8
9
10
11
12
13
//线性表
series: {
data: [
{ // 这里每一个项就是数据项(dataItem)
value: 2323, // 这是数据项的数据值(value)
itemStyle: {...}
},
1212, // 也可以直接是 dataItem 的 value,这更常见。
2323, // 每个 value 都是『一维』的。
4343,
3434
]
}

在图表中,往往默认把 value 的前一两个维度进行映射,比如取第一个维度映射到 x 轴,取第二个维度映射到 y 轴。如果想要把更多的维度展现出来,可以借助 visualMap。最常见的情况,散点图(scatter) 使用半径展现了第三个维度。

visualMap 组件

visualMap 组件定义了把数据的指定维度映射到对应的视觉元素上。

visualMap 组件可以定义多个,从而可以同时对数据中的多个维度进行视觉映射。

ECharts 的视觉映射组件分为连续型(visualMapContinuous)与分段型(visualMapPiecewise)。

连续型的意思是,进行视觉映射的数据维度是连续的数值;而分段型则是数据被分成了多段或者是离散型的数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
option = {
visualMap: [
{ // 第一个 visualMap 组件
type: 'continuous', // 定义为连续型 visualMap
...
},
{ // 第二个 visualMap 组件
type: 'piecewise', // 定义为分段型 visualMap
...
}
],
...
};
连续型视觉映射

连续型视觉映射通过指定最大值、最小值,就可以确定视觉映射的范围。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
option = {
visualMap: [
{
type: 'continuous',
min: 0,
max: 5000,
dimension: 3, // series.data 的第四个维度(即 value[3])被映射
seriesIndex: 4, // 对第四个系列进行映射。
inRange: {
// 选中范围中的视觉配置
color: ['blue', '#121122', 'red'], // 定义了图形颜色映射的颜色列表,
// 数据最小值映射到'blue'上,
// 最大值映射到'red'上,
// 其余自动线性计算。
symbolSize: [30, 100] // 定义了图形尺寸的映射范围,
// 数据最小值映射到30上,
// 最大值映射到100上,
// 其余自动线性计算。
},
outOfRange: {
// 选中范围外的视觉配置
symbolSize: [30, 100]
}
}
// ...
]
};

其中,visualMap.inRange 表示在数据映射范围内的数据采用的样式;而 visualMap.outOfRange 则指定了超出映射范围外的数据的样式。

visualMap.dimension 则指定了将数据的哪个维度做视觉映射。

分段型视觉映射

分段型视觉映射组件有三种模式:

使用分段型视觉映射时,需要将 type 设为 'piecewise',并且将上面的三个配置项选其一配置即可,其他配置项类似连续型视觉映射。

数据集

https://juejin.cn/post/6844903552108724238#heading-0

https://www.runoob.com/echarts/echarts-dataset.html

数据集dataset)来单独声明数据。虽然每个系列都可以在 series.data 中设置数据,但是从 ECharts4 支持 数据集 开始,更推荐使用 数据集 来管理数据。

数据集带来的好处是:

  • 能够贴近数据可视化常见思维方式:

    • (I)提供数据,
    • (II)指定数据到视觉的映射,从而形成图表。
  • 数据和其他配置可以被分离开来。数据常变,其他配置常不变。分开易于分别管理。

  • 数据可以被多个系列或者组件复用,对于大数据量的场景,不必为每个系列创建一份数据。

  • 支持更多的数据的常用格式,例如二维数组、对象数组等,一定程度上避免使用者为了数据格式而进行转换。

设置数据

在系列中设置数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
option = {
xAxis: {
type: 'category',
data: ['Matcha Latte', 'Milk Tea', 'Cheese Cocoa', 'Walnut Brownie']
},
yAxis: {},
series: [
{
type: 'bar',
name: '2015',
data: [89.3, 92.1, 94.4, 85.4]
},
{
type: 'bar',
name: '2016',
data: [95.8, 89.4, 91.2, 76.9]
},
{
type: 'bar',
name: '2017',
data: [97.7, 83.1, 92.5, 78.1]
}
]
};

这种方式的优点是,适于对一些特殊的数据结构(如“树”、“图”、超大数据)进行一定的数据类型定制。 但是缺点是,常需要用户先处理数据,把数据分割设置到各个系列(和类目轴)中。此外,不利于多个系列共享一份数据,也不利于基于原始数据进行图表类型、系列的映射安排。

在数据集中设置数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
//dataset
option = {
legend: {},
tooltip: {},
dataset: {
// 提供一份数据。
source: [
['product', '2015', '2016', '2017'],
['Matcha Latte', 43.3, 85.8, 93.7],
['Milk Tea', 83.1, 73.4, 55.1],
['Cheese Cocoa', 86.4, 65.2, 82.5],
['Walnut Brownie', 72.4, 53.9, 39.1]
]
},
// 声明一个 X 轴,类目轴(category)。默认情况下,类目轴对应到 dataset 第一列。
xAxis: { type: 'category' },
// 声明一个 Y 轴,数值轴。
yAxis: {},
// 声明多个 bar 系列,默认情况下,每个系列会自动对应到 dataset 的每一列。
series: [{ type: 'bar' }, { type: 'bar' }, { type: 'bar' }]
};

//第二种或者也可以使用常见的“对象数组”的格式:
option = {
legend: {},
tooltip: {},
dataset: {
// 用 dimensions 指定了维度的顺序。直角坐标系中,如果 X 轴 type 为 category,
// 默认把第一个维度映射到 X 轴上,后面维度映射到 Y 轴上。
// 如果不指定 dimensions,也可以通过指定 series.encode
// 完成映射,参见后文。
dimensions: ['product', '2015', '2016', '2017'],
source: [
{ product: 'Matcha Latte', '2015': 43.3, '2016': 85.8, '2017': 93.7 },
{ product: 'Milk Tea', '2015': 83.1, '2016': 73.4, '2017': 55.1 },
{ product: 'Cheese Cocoa', '2015': 86.4, '2016': 65.2, '2017': 82.5 },
{ product: 'Walnut Brownie', '2015': 72.4, '2016': 53.9, '2017': 39.1 }
]
},
xAxis: { type: 'category' },
yAxis: {},
series: [{ type: 'bar' }, { type: 'bar' }, { type: 'bar' }]
};

img

数据到图形的映射

https://echarts.apache.org/zh/tutorial.html#%E4%BD%BF%E7%94%A8%20dataset%20%E7%AE%A1%E7%90%86%E6%95%B0%E6%8D%AE

series.seriesLayoutBy

把数据集( dataset )的行或列映射为系列(series)

series.seriesLayoutBy

  • ‘column’: 默认值。系列被安放到 dataset 的列上面。

    系列( series )对应到“列”的时候,那么每一列就称为一个“维度( dimension )”,而每一行称为数据项( item )。

  • ‘row’: 系列被安放到 dataset 的行上面。

    系列( series )对应到表行,那么每一行就是“维度( dimension )”,每一列就是数据项( item )。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
option = {
legend: {},
tooltip: {},
dataset: {
source: [
['product', '2012', '2013', '2014', '2015'],
['Matcha Latte', 41.1, 30.4, 65.1, 53.3],
['Milk Tea', 86.5, 92.1, 85.7, 83.1],
['Cheese Cocoa', 24.1, 67.2, 79.5, 86.4]
]
},
xAxis: [
{type: 'category', gridIndex: 0},
{type: 'category', gridIndex: 1}
],
yAxis: [
{gridIndex: 0},
{gridIndex: 1}
],
grid: [
{bottom: '55%'},
{top: '55%'}
],
series: [
// 这几个系列会在第一个直角坐标系中,每个系列对应到 dataset 的每一行。
{type: 'bar', seriesLayoutBy: 'row'},
{type: 'bar', seriesLayoutBy: 'row'},
{type: 'bar', seriesLayoutBy: 'row'},
// 这几个系列会在第二个直角坐标系中,每个系列对应到 dataset 的每一列。
{type: 'bar', xAxisIndex: 1, yAxisIndex: 1},
{type: 'bar', xAxisIndex: 1, yAxisIndex: 1},
{type: 'bar', xAxisIndex: 1, yAxisIndex: 1},
{type: 'bar', xAxisIndex: 1, yAxisIndex: 1}
]
}

img

series.dimension

维度名( dimension name ,便于在图表中显示)可以在定义在 dataset 的第一行(或者第一列)。例如上面的例子中,'score''amount''product' 就是维度名。从第二行开始,才是正式的数据。当然也可以设置 dataset.sourceHeader: true 显示声明第一行(列)就是维度,或者 dataset.sourceHeader: false 表明第一行(列)开始就直接是数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//维度的定义,也可以使用单独的 dataset.dimensions 或者 series.dimensions 来定义,这样可以同时指定维度名,和维度的类型( dimension type )
var option1 = {
dataset: {
dimensions: [
{ name: 'score' },
// 可以简写为 string ,表示 dimension name 。
'amount',
// 可以在 type 中指定维度类型。
{ name: 'product', type: 'ordinal' }
],
source: [
//...
]
}
// ...
};

var option2 = {
dataset: {
source: [
// ...
]
},
series: {
type: 'line',
// series.dimensions 会更优先于 dataset.dimension 采纳。
dimensions: [
null, // 可以设置为 null 表示不想设置维度名
'amount',
{ name: 'product', type: 'ordinal' }
]
}
// ...
};

series.encode

可以定义 data 的哪个维度被编码成什么

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
option = {
dataset: {
source: [
// 每一列称为一个『维度』。
// 这里分别是维度 0、1、2、3、4。
[12, 44, 55, 66, 2],
[23, 6, 16, 23, 1],
...
]
},
series: {
type: 'xxx',
encode: {
x: [3, 1, 5], // 表示维度 3、1、5 映射到 x 轴。
y: 2, // 表示维度 2 映射到 y 轴。
tooltip: [3, 2, 4] // 表示维度 3、2、4 会在 tooltip 中显示。
}
}
}

当使用 dimensions 给维度定义名称后,encode 中可直接引用名称,例如:

series: {
type: 'xxx',
dimensions: ['date', 'open', 'close', 'highest', 'lowest'],
encode: {
x: 'date',
y: ['open', 'close', 'highest', 'lowest']
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// 在任何坐标系和系列中,都支持:
encode: {
// 使用 “名为 product 的维度” 和 “名为 score 的维度” 的值在 tooltip 中显示
tooltip: ['product', 'score']
// 使用 “维度 1” 和 “维度 3” 的维度名连起来作为系列名。(有时候名字比较长,这可以避免在 series.name 重复输入这些名字)
seriesName: [1, 3],
// 表示使用 “维度2” 中的值作为 id。这在使用 setOption 动态更新数据时有用处,可以使新老数据用 id 对应起来,从而能够产生合适的数据更新动画。
itemId: 2,
// 指定数据项的名称使用 “维度3” 在饼图等图表中有用,可以使这个名字显示在图例(legend)中。
itemName: 3
}

// 直角坐标系(grid/cartesian)特有的属性:
encode: {
// 把 “维度1”、“维度5”、“名为 score 的维度” 映射到 X 轴:
x: [1, 5, 'score'],
// 把“维度0”映射到 Y 轴。
y: 0
}

// 单轴(singleAxis)特有的属性:
encode: {
single: 3
}

// 极坐标系(polar)特有的属性:
encode: {
radius: 3,
angle: 2
}

// 地理坐标系(geo)特有的属性:
encode: {
lng: 3,
lat: 2
}

// 对于一些没有坐标系的图表,例如饼图、漏斗图等,可以是:
encode: {
value: 3
}

数据转换transform

filter

sort

API

datasetIndex

可以同时定义多个 dataset。系列可以通过 series.datasetIndex 来指定引用哪个 dataset

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var option = {
dataset: [
{
// 序号为 0 的 dataset。
source: []
},
{
// 序号为 1 的 dataset。
source: []
},
{
// 序号为 2 的 dataset。
source: []
}
],
series: [
{
// 使用序号为 2 的 dataset。
datasetIndex: 2
},
{
// 使用序号为 1 的 dataset。
datasetIndex: 1
}
]
};

示例

坐标轴

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
var option = {
dataset: {
source: [
['score', 'amount', 'product'],
[89.3, 58212, 'Matcha Latte'],
[57.1, 78254, 'Milk Tea'],
[74.4, 41032, 'Cheese Cocoa'],
[50.1, 12755, 'Cheese Brownie'],
[89.7, 20145, 'Matcha Cocoa'],
[68.1, 79146, 'Tea'],
[19.6, 91852, 'Orange Juice'],
[10.6, 101852, 'Lemon Juice'],
[32.7, 20112, 'Walnut Brownie']
]
},
xAxis: {},
yAxis: { type: 'category' },
series: [
{
type: 'bar',
encode: {
// 将 "amount" 列映射到 X 轴。
x: 'amount',
// 将 "product" 列映射到 Y 轴。
y: 'product'
}
}
]
};


img

地图+散点图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
dataset: {
dimensions: ['name', 'lng', 'lat'],
source: [
['北京', 116.46, 39.92]
]
},
series: [
{
name: 'pm2.5',
type: 'scatter',
coordinateSystem: 'bmap',
symbolSize: function (val) {
return val[2] / 10;
},
// datasetIndex:0,
encode: {
lng: 1,
lat: 2
},
}
]

配置项

title

标题组件,包含主标题和副标题。

legend

grid

https://echarts.apache.org/examples/zh/editor.html?c=scatter-anscombe-quartet&edit=1&reset=1

容器中的图表位置,单个 grid 内最多可以放置上下两个 X 轴,左右两个 Y 轴。

  • Axis. gridIndex
    • x 轴所在的 grid 的索引,默认位于第一个 grid。

xAxis

  • type
    • category(默认),数据在x轴展示
    • value,数据在y轴展示

series

  • name(有的话,legend可以不用配置)
  • showSymbol,开始不显示拐点,鼠标经过显示
  • itemStyle:设置拐点颜色以及边框
  • radius:设置饼状图大小 ,[内圆,外圆]

echart实例方法

setoption

切换数据

事件

事件

在 Apache ECharts 的图表中用户的操作将会触发相应的事件。开发者可以监听这些事件,然后通过回调函数做相应的处理,比如跳转到一个地址,或者弹出对话框,或者做数据下钻等等。

ECharts 中的事件名称对应 DOM 事件名称,均为小写的字符串,如下是一个绑定点击操作的示例。

1
2
3
4
myChart.on('click', function(params) {
// 控制台打印数据的名称
console.log(params.name);
});

在 ECharts 中事件分为两种类型,一种是用户鼠标操作点击,或者 hover 图表的图形时触发的事件,还有一种是用户在使用可以交互的组件后触发的行为事件,例如在切换图例开关时触发的 ‘legendselectchanged’ 事件(这里需要注意切换图例开关是不会触发 'legendselected' 事件的),数据区域缩放时触发的 ‘datazoom’ 事件等等。

鼠标事件的处理

ECharts 支持常规的鼠标事件类型,包括 'click''dblclick''mousedown''mousemove''mouseup''mouseover''mouseout''globalout''contextmenu' 事件。下面先来看一个简单的点击柱状图后打开相应的百度搜索页面的示例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 基于准备好的dom,初始化ECharts实例
// var myChart = echarts.init(document.getElementById('main'));

// 指定图表的配置项和数据
var option = {
xAxis: {
data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
},
yAxis: {},
series: [
{
name: '销量',
type: 'bar',
data: [5, 20, 36, 10, 10, 20]
}
]
};
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
// 处理点击事件并且跳转到相应的百度搜索页面
myChart.on('click', function(params) {
window.open('https://www.baidu.com/s?wd=' + encodeURIComponent(params.name));
});

LIVE

所有的鼠标事件包含参数 params,这是一个包含点击图形的数据信息的对象,如下格式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
type EventParams = {
// 当前点击的图形元素所属的组件名称,
// 其值如 'series'、'markLine'、'markPoint'、'timeLine' 等。
componentType: string;
// 系列类型。值可能为:'line'、'bar'、'pie' 等。当 componentType 为 'series' 时有意义。
seriesType: string;
// 系列在传入的 option.series 中的 index。当 componentType 为 'series' 时有意义。
seriesIndex: number;
// 系列名称。当 componentType 为 'series' 时有意义。
seriesName: string;
// 数据名,类目名
name: string;
// 数据在传入的 data 数组中的 index
dataIndex: number;
// 传入的原始数据项
data: Object;
// sankey、graph 等图表同时含有 nodeData 和 edgeData 两种 data,
// dataType 的值会是 'node' 或者 'edge',表示当前点击在 node 还是 edge 上。
// 其他大部分图表中只有一种 data,dataType 无意义。
dataType: string;
// 传入的数据值
value: number | Array;
// 数据图形的颜色。当 componentType 为 'series' 时有意义。
color: string;
};

如何区分鼠标点击到了哪里:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
myChart.on('click', function(params) {
if (params.componentType === 'markPoint') {
// 点击到了 markPoint 上
if (params.seriesIndex === 5) {
// 点击到了 index 为 5 的 series 的 markPoint 上。
}
} else if (params.componentType === 'series') {
if (params.seriesType === 'graph') {
if (params.dataType === 'edge') {
// 点击到了 graph 的 edge(边)上。
} else {
// 点击到了 graph 的 node(节点)上。
}
}
}
});

使用 query 只对指定的组件的图形元素的触发回调:

1
chart.on(eventName, query, handler);

query 可为 string 或者 Object

如果为 string 表示组件类型。格式可以是 ‘mainType’ 或者 ‘mainType.subType’。例如:

1
2
3
4
chart.on('click', 'series', function() {});
chart.on('click', 'series.line', function() {});
chart.on('click', 'dataZoom', function() {});
chart.on('click', 'xAxis.category', function() {});

如果为 Object,可以包含以下一个或多个属性,每个属性都是可选的:

1
2
3
4
5
6
7
8
9
{
${mainType}Index: number // 组件 index
${mainType}Name: string // 组件 name
${mainType}Id: string // 组件 id
dataIndex: number // 数据项 index
name: string // 数据项 name
dataType: string // 数据项 type,如关系图中的 'node', 'edge'
element: string // 自定义系列中的 el 的 name
}

例如:

1
2
3
4
5
6
7
8
9
10
11
12
chart.setOption({
// ...
series: [
{
name: 'uuu'
// ...
}
]
});
chart.on('mouseover', { seriesName: 'uuu' }, function() {
// series name 为 'uuu' 的系列中的图形元素被 'mouseover' 时,此方法被回调。
});

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
chart.setOption({
// ...
series: [
{
// ...
},
{
// ...
data: [
{ name: 'xx', value: 121 },
{ name: 'yy', value: 33 }
]
}
]
});
chart.on('mouseover', { seriesIndex: 1, name: 'xx' }, function() {
// series index 1 的系列中的 name 为 'xx' 的元素被 'mouseover' 时,此方法被回调。
});

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
chart.setOption({
// ...
series: [
{
type: 'graph',
nodes: [
{ name: 'a', value: 10 },
{ name: 'b', value: 20 }
],
edges: [{ source: 0, target: 1 }]
}
]
});
chart.on('click', { dataType: 'node' }, function() {
// 关系图的节点被点击时此方法被回调。
});
chart.on('click', { dataType: 'edge' }, function() {
// 关系图的边被点击时此方法被回调。
});

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
chart.setOption({
// ...
series: {
// ...
type: 'custom',
renderItem: function(params, api) {
return {
type: 'group',
children: [
{
type: 'circle',
name: 'my_el'
// ...
},
{
// ...
}
]
};
},
data: [[12, 33]]
}
});
chart.on('mouseup', { element: 'my_el' }, function() {
// name 为 'my_el' 的元素被 'mouseup' 时,此方法被回调。
});

你可以在回调函数中获得这个对象中的数据名、系列名称后在自己的数据仓库中索引得到其它的信息后更新图表,显示浮层等等,如下示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
myChart.on('click', function(parmas) {
$.get('detail?q=' + params.name, function(detail) {
myChart.setOption({
series: [
{
name: 'pie',
// 通过饼图表现单个柱子中的数据分布
data: [detail.data]
}
]
});
});
});

组件交互的行为事件

在 ECharts 中基本上所有的组件交互行为都会触发相应的事件,常用的事件和事件对应参数在 events 文档中有列出。

下面是监听一个图例开关的示例:

1
2
3
4
5
6
7
8
9
// 图例开关的行为只会触发 legendselectchanged 事件
myChart.on('legendselectchanged', function(params) {
// 获取点击图例的选中状态
var isSelected = params.selected[params.name];
// 在控制台中打印
console.log((isSelected ? '选中了' : '取消选中了') + '图例' + params.name);
// 打印所有图例的状态
console.log(params.selected);
});

代码触发 ECharts 中组件的行为

上面提到诸如 'legendselectchanged' 事件会由组件交互的行为触发,那除了用户的交互操作,有时候也会有需要在程序里调用方法触发图表的行为,诸如显示 tooltip,选中图例。

在 ECharts 通过调用 myChart.dispatchAction({ type: '' }) 触发图表行为,统一管理了所有动作,也可以方便地根据需要去记录用户的行为路径。

常用的动作和动作对应参数在 action 文档中有列出。

下面示例演示了如何通过 dispatchAction 去轮流高亮饼图的每个扇形。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
option = {
title: {
text: '饼图程序调用高亮示例',
left: 'center'
},
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b} : {c} ({d}%)'
},
legend: {
orient: 'vertical',
left: 'left',
data: ['直接访问', '邮件营销', '联盟广告', '视频广告', '搜索引擎']
},
series: [
{
name: '访问来源',
type: 'pie',
radius: '55%',
center: ['50%', '60%'],
data: [
{ value: 335, name: '直接访问' },
{ value: 310, name: '邮件营销' },
{ value: 234, name: '联盟广告' },
{ value: 135, name: '视频广告' },
{ value: 1548, name: '搜索引擎' }
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
};

let currentIndex = -1;

setInterval(function() {
var dataLen = option.series[0].data.length;
// 取消之前高亮的图形
myChart.dispatchAction({
type: 'downplay',
seriesIndex: 0,
dataIndex: currentIndex
});
currentIndex = (currentIndex + 1) % dataLen;
// 高亮当前图形
myChart.dispatchAction({
type: 'highlight',
seriesIndex: 0,
dataIndex: currentIndex
});
// 显示 tooltip
myChart.dispatchAction({
type: 'showTip',
seriesIndex: 0,
dataIndex: currentIndex
});
}, 1000);

LIVE

访问来源
直接访问 : 335 (13.08%)

监听“空白处”的事件

有时候,开发者需要监听画布的“空白处”所触发的事件。比如,当需要在用户点击“空白处”的时候重置图表时。

在讨论这个功能之前,我们需要先明确两种事件。zrender 事件和 echarts 事件。

1
2
3
4
5
6
myChart.getZr().on('click', function(event) {
// 该监听器正在监听一个`zrender 事件`。
});
myChart.on('click', function(event) {
// 该监听器正在监听一个`echarts 事件`。
});

zrender 事件与 echarts 事件不同。前者是当鼠标在任何地方都会被触发,而后者是只有当鼠标在图形元素上时才能被触发。事实上,echarts 事件是在 zrender 事件的基础上实现的,也就是说,当一个 zrender 事件在图形元素上被触发时,echarts 将触发一个 echarts 事件给开发者。

有了 zrender 事件,我们就可以实现监听空白处的事件,具体如下:

1
2
3
4
5
6
myChart.getZr().on('click', function(event) {
// 没有 target 意味着鼠标/指针不在任何一个图形元素上,它是从“空白处”触发的。
if (!event.target) {
// 点击在了空白处,做些什么。
}
});

交互

过渡动画

https://echarts.apache.org/handbook/zh/how-to/animation/transition

拖拽的实现

https://echarts.apache.org/handbook/zh/how-to/interaction/drag

销毁

假设页面中存在多个标签页,每个标签页都包含一些图表。当选中一个标签页的时候,其他标签页的内容在 DOM 中被移除了。这样,当用户再选中这些标签页的时候,就会发现图表“不见”了。

本质上,这是由于图表的容器节点被移除导致的。即使之后该节点被重新添加,图表所在的节点也已经不存在了。

正确的做法是,在图表容器被销毁之后,调用 echartsInstance.dispose 销毁实例,在图表容器重新被添加后再次调用 echarts.init 初始化。

小贴士:在容器节点被销毁时,总是应调用 echartsInstance.dispose 以销毁实例释放资源,避免内存泄漏。

问题

https://mp.weixin.qq.com/s/h6mJY0tuaw_Pr6mdRmWu5Q

异步数据的加载

https://echarts.apache.org/handbook/zh/how-to/data/dynamic-data

Echarts 资源 🔫

目前整个数据大屏的 Echarts 图表资源都是在社区中寻找的资源。推荐几个 Echarts 社区地址:

D3.js和echarts.js不同

D3.js和echarts.js都是用来生成各类图表的,区别的话可以从使用方法和实现方式上,echart.js是通过canvas来绘制图形具体使用方法是通过echarts.init 方法初始化一个 echarts 实例并通过 setOption 方法生成一个简单的柱状图很轻松搞定。D3.js通过svg来绘制图形,使用时需要先创建画布(svg元素),然后进行各种绘制图形。

从兼容方面对比两者的话,echart.js兼容到IE6及以上的所有主流浏览器,而D3.js兼容IE9及以上以及所有的主流浏览器,如果项目考虑兼容IE6,建议使用echart.js

从学习成本上来说,echart.js是封装好的方法可以直接调用,学习起来更加快速上手,而相对来说D3.js的学习偏底层学习起来成本较大,也正因为如此D3.js也有更大的灵活性,当你需要的图表中echart中找不到时可以来D3中自己搞定

前端地图框架

地图:https://blog.csdn.net/weixin_43216105/article/details/109715995

  1. Leaflet
    Leaflet 是最著名的前端地图可视化库,它开源、体积小、结构清晰、简单易用。
  2. Mapbox GL JS
    Mapbox GL JS 是目前最新潮的前端地图库,它的矢量压缩、动态样式和三维性能令人印象深刻。它本身是开源的,但一般依赖于Mapbox公司提供的底图服务。
  3. ArcGIS API for JS
    ArcGIS API for JS 是较为学院派的前端地图库,它是ArcGIS开发套件中的一部分,和桌面端和服务器端ArcGIS软件有较好的协作。它不开源且收费不低,在学术场景下较为常用。
  4. Openlayers
    Openlayers 也是常用的前端地图库,它开源,相比于Leaflet更加复杂和完备。
  5. Cesium
    Cesium 是三维地理可视化的常用库,在大尺度的可视化(地形、建筑、地球)中十分常用。
  6. 百度地图 JS API /百度地图 API GL
    百度地图 JS API 是传统的二维地图,百度地图 API GL 是三维地图,它们依赖百度地图提供的后台服务。除了地图服务外还有检索、导航、实时交通等关联服务。开发者有免费的限额。
  7. 高德地图 JS API
    高德地图 JS API 与百度类似。
  8. Google Maps JS API
    谷歌地图 JS API 在境外有更好的数据。
  9. AntV L7
    AntV L7 是空间数据可视化库,它可以使用高德地图等协作构建地图可视化。
  10. Mapbox.js
    Mapbox.js 是 Leaflet 的一个扩展插件(与 Mapbox GL JS 不同)。

vue

引入百度地图

js

在vue项目里面引入百度地图api有两种方式,一个是官方文档提供

1
2
//注意版本
<script type="text/javascript" src="http://api.map.baidu.com/api?v=3.0&ak=你的密钥"></script>

然后在webpack里面需要配置externals选项,设置外部扩展

1
2
3
externals: {
'BaiduMap': 'BMap'
}

在使用的时候,组件里面需要引入

1
import BaiduMap from 'BaiduMap'
1
2
3
mounted() {
var map = new BaiduMap.Map(xxx)
}

vue-baidu-map

api

参数

方法 返回值 描述
enableDragging() none 启用地图拖拽,默认启用
disableDragging() none 禁用地图拖拽
enableInertialDragging() none 启用地图惯性拖拽,默认禁用
disableInertialDragging() none 禁用地图惯性拖拽
enableScrollWheelZoom() none 允许地图可被鼠标滚轮缩放,默认禁用
disableScrollWheelZoom() none 禁止地图被鼠标滚轮缩放
enableContinuousZoom() none 开启双击平滑缩放效果
disableContinuousZoom() none 关闭双击平滑缩放效果
enableResizeOnCenter() none 开启图区resize中心点不变
disableResizeOnCenter() none 关闭图区resize中心点不变
enableDoubleClickZoom() none 启用地图双击缩放,左键双击放大、右键双击缩小
disableDoubleClickZoom() none 取消地图双击缩放
enableKeyboard() none 启用键盘操作,默认禁用。键盘的上、下、左、右键可连续移动地图。同时按下其中两个键可使地图进行对角移动。PgUp、PgDn、Home和End键会使地图平移其1/2的大小。+、-键会使地图放大或缩小一级
disableKeyboard() none 禁用键盘操作
enablePinchToZoom() none 启用双指缩放地图。
disablePinchToZoom() none 禁用双指缩放地图。
enableRotateGestures() none 是否允许通过手势旋转地图。
enableTiltGestures() none 是否允许通过手势倾斜地图。
enableAutoResize() none 启用自动适应容器尺寸变化,默认启用
disableAutoResize() none 禁用自动适应容器尺寸变化
checkResize() none 地图容器变化后调用此方法用来重新铺图
resize() none 强制地图调整尺寸,此时会以当前容器尺寸为基准重新计算视野所需图像数据并重新绘制。当关闭自动调整视野时(enableAutoResize 配置),需要调用此方法来强制地图刷新。
getSize() Size 返回地图当前尺寸,以像素表示
getContainerSize() Size 获取地图容器尺寸
getZoomUnits() Number 返回当前地图级别,一个像素对应多少单位的平面墨卡托坐标
getContainer() HTMLElement 返回地图的DOM容器元素。当创建用户自定义控件时,需要自行实现Control.initialize()方法,并将控件的容器元素添加到地图上,通过此方法可获得地图容器
pixelToPoint(pixel: Pixel ) Point 像素坐标转换为经纬度坐标
pointToPixel(point: Point ) Pixel 经纬度坐标转换为像素坐标
lnglatToMercator(lng: Number, lat: Number) [McLng, McLat] 经纬度球体坐标转换为墨卡托平面坐标
mercatorToLnglat(McLng: Number, lat: McLat) [lng, lat] 墨卡托平面坐标转换为经纬度球体坐标
isLoaded() boolean 返回地图是否经过centerAndZoom进行初始化
addSpots(spots: Array, options: Object) number 添加地点区域,作为地图上的虚拟可点击区域。其中参数spots为热区点数组,options为可选配置参数;返回区域id。
getSpots(id: string) Array 根据id返回地点区域数组
removeSpots(id: number) none 根据id移除区域数组
clearSpots() none 清除地点区域,此操作将清空所有虚拟可点数据
clearLabels() none 清空当前map所有的自定义底图标注
addLabelsToMapTile(labels:Array) none 在底图上添加文字,这些文字会和底图文字一同参与避让。
removeLabelsFromMapTile(labelUids:Array) none 从底图上移除文字标注,参数为uid数组,根据数组里的uid进行移除
getIconByClickPosition(clickPosition: Pixel) Object null 通过点击坐标获取当前点中的底图icon,如果获取到返回其{name, uid, position},否则返回null
setBounds(bounds:Bounds) none 设置地图可拖动区域,参数为地图拖拽的区域范围
getBounds() Bounds 获取地图当前视野范围的矩形区域,以地理坐标表示。如果地图尚未初始化则返回一个空的 Bounds 实例。
getCoordType() string 获取地图坐标类型,为CoordType常量
getMapStyleId() string 获取当前地图样式id,对于内置样式则返回样式名称;对于自定义样式,则返回内部自动生成的样式id
getPanes() MapPanes 获取覆盖物容器元素,返回地图覆盖物容器对象
getInfoWindow() InfoWindow null 获取当前打开的信息窗口实例,如果当前地图没有处于打开状态信息窗口,则返回 null
setDefaultCursor(cursor: String) none 设置地图默认的鼠标指针样式。参数cursor应符合CSS的cursor属性规范
getDefaultCursor() String 获取地图默认的鼠标指针样式,返回cursor值
setDraggingCursor(cursor: String) none 设置拖拽地图时的鼠标指针样式。参数cursor应符合CSS的cursor属性规范
getDraggingCursor() String 返回拖拽地图时的鼠标指针样式
setMinZoom(zoom: Number) none 设置地图允许的最小级别。取值不得小于地图类型所允许的最小级别
setMaxZoom(zoom: Number) none 设置地图允许的最大级别。取值不得大于地图类型所允许的最大级别
getDistance(start: Point , end: Point ) Number 返回两点之间的距离,单位是米
getMapType() MapTypeId 返回地图类型
setViewport(view: Array Viewport , viewportOptions: ViewportOptions ) none 根据提供的地理区域或坐标设置地图视野,调整后的视野会保证包含提供的地理区域或坐标
getViewport(view: Array< Point >, viewportOptions: ViewportOptions ) Viewport 根据提供的地理区域或坐标获得最佳的地图视野,返回的对象中包含center和zoom属性,分别表示地图的中心点和级别。此方法仅返回视野信息,不会将新的中心点和级别做用到当前地图上
centerAndZoom(center: Point , zoom: Number) none 设初始化地图。 如果center类型为Point时,zoom必须赋值,范围3-19级,若调用高清底图(针对移动端开发)时,zoom可赋值范围为3-18级。如果center类型为字符串时,比如“北京”,zoom可以忽略,地图将自动根据center适配最佳zoom级别
panTo(center: Point ) none 将地图的中心点更改为给定的点,跳转到指定中心点进行渲染。如果该点在当前的地图视图中已经可见,则会以平滑动画的方式移动到中心点位置。可以通过配置强制移动过程不使用动画效果
panBy(x: Number, y: Number) none 将地图在水平位置上移动x像素,垂直位置上移动y像素。如果指定的像素大于可视区域范围或者在配置中指定没有动画效果,则不执行滑动效果
flyTo(center: Point , zoom: Number) none 飞到指定的中心点和级别,提供给定位缩放地图使用
reset() none 重新设置地图,恢复地图初始化时的中心点和级别
setCenter(center: Point String[, options: Object]) none 设置地图中心点。center除了可以为坐标点以外,还支持城市名。可选配置参数包括’noAnimation: boolean’是否禁用动画效果;’callback: function’动画结束后调用此方法,如果没有动画则立即调用
getCenter() Point 返回地图当前中心点
setMapType(mapTypeId: MapTypeId ) none 设置地图类型
setZoom(zoom: Number[,options]) none 将视图切换到指定的缩放等级,中心点坐标不变。注意:当有信息窗口在地图上打开时,地图缩放将保证信息窗口所在的坐标位置不动。可选配置参数包括’noAnimation:boolean’是否禁用动画效果;’callback:function’动画结束后会调用此方法,如果没有动画则立即调用;’zoomCenter:Point’缩放中心点,默认以地图中心点为基准缩放
getZoom() Number 返回地图当前缩放级别
zoomIn() none 放大一级视图
zoomOut() none 缩小一级视图
addControl(control: Control ) none 将控件添加到地图,一个控件实例只能向地图中添加一次
removeControl(control: Control ) none 从地图中移除控件。如果控件从未被添加到地图中,则该移除不起任何作用
addContextMenu()(menu: ContextMenu ) none 添加右键菜单
removeContextMenu()(menu: ContextMenu ) none 移除右键菜单
addOverlay(overlay: Overlay ) none 将覆盖物添加到地图中,一个覆盖物实例只能向地图中添加一次
removeOverlay(overlay: Overlay ) none 从地图中移除覆盖物。如果覆盖物从未被添加到地图中,则该移除不起任何作用
clearOverlays() none 清除地图上所有覆盖物
pointToOverlayPixel(point: Point ) Pixel 根据地理坐标获取对应的覆盖物容器的坐标,此方法用于自定义覆盖物
overlayPixelToPoint(pixel: Pixel ) Point 根据覆盖物容器的坐标获取对应的地理坐标
getOverlays() Array< Overlay > 获取当前地图上的所有覆盖物,返回覆盖物对象的集合
getPanes() MapPanes 返回地图覆盖物容器列表
getCurrentMaxTilt() number 获取当前地图允许的最大倾斜角度
hightlightSpotByUid(uid: string, tilePosStr: string) none 根据 uid 将底图上的 poi 高亮显示,其中参数tilePosStr为label的位置字符串
resetSpotStatus() none 重置热区状态,即将高亮的热区点取消
addAreaSpot() none 重置热区状态,即将高亮的热区点取消
getAreaSpot(id: string) Array 返回地点区域数组
removeAreaSpot(id: string) none 移除区域数组
clearAreaSpots() none 清除地点区域,此操作将清空所有虚拟可点数据
setTrafficOn() none 开启路况图层
setTrafficOff() none 关闭路况图层
showOverlayContainer() none 显示覆盖物
hideOverlayContainer() none 不显示覆盖物
setMapStyleV2(config: Object) none 设置个性化地图,参数为个性化配置对象
startViewAnimation(viewAnimation: ViewAnimation) Number 启动视角动画
cancelViewAnimation(viewAnimation: ViewAnimation) none 停止视角动画
getMapScreenshot() url 获取地图截图,地球模式不支持。需要初始化地图配置preserveDrawingBuffer:true,否则是黑屏
loadMapStyleFiles(callback: Function) none 加载地图当前样式所需要的样式文件,callback为加载成功后的回调函数
setCopyrightOffset(logo: Object, cpy: Object) none 设置版权信息位置,其中logo为logo位置,copyright为文字位置
destroy() none 销毁地图,当使用 WebGL 渲染地图时,如果确认不再使用该地图实例,则需要调用本方法销毁 WebGL 上下文,否则频繁创建新地图实例会导致浏览器报:too many WebGL context 的警告
isSupportEarth() boolean 判断浏览器是否支持地球,支持返回true,否则返回false