前端进阶五

前端进阶五

  前端进阶四:渲染引擎

数据可视化库概述

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

D3–可视化库的jquery

安装

1
npm install d3

全局导入或者部分导入

1
2
3
4
//全局导入
import * as d3 from "d3";
//部分导入
import {scaleLinear} from "d3-scale";

D3 API,共八种:

第一章:核心函数:选择、过渡、数组、数学、请求、格式化、本地化

第二章:比例尺:线性比例尺、恒等比例尺、乘方比例尺、对数比例尺、量化比例尺、分位数比例尺、临界值比例尺

第三章:可缩放矢量图形。SVG元素、线生成器、径向线生成器、面积生成器、弧生成器、符号生成器、弦生成器、对角线生成器、轴、刷子

第四章:时间。时间格式、时间间隔、时间计数

第五章:布局。布局有捆绑布局、弦布局、簇布局、力布局、层次布局、直方图布局、包布局、分区布局、饼布局、堆叠布局、树布局、矩形树布局

第六章:地理。地理有地理路径、经纬网生成器、球面数学运算、标准抽象投影、标准投影、流

第七章:几何:有四叉树、凸包、多边形和泰森多边形

第八章:行为:包括拖拽和缩放

初始化布局

1
2
3
4
this.force = d3.forceSimulation().alphaDecay(0.1)
.force("link",d3.forceLink().distance(100))
.force('collide',d3.forceCollide().radius(()=>30))
.force("charge",d3.forceManyBody().strength(-400))
1
2
3
4
this.force.nodes(nodes)
.force('link',d3.forceLink(links).distance(150));
.alpha(1);
.restart();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
force.on('tick',()=>{
nodes.forEach(node => {
if (!node.lock){
d3.select(self.nodes[node.uid].attr)
}
})
links.forEach(link => {
d3.select(self.links[`${link.source.uid}_${link.target.uid}`])
.attr('x1',()=> link.source.x)
.attr('y1',()=> link.source.y)
.attr('x2',()=> link.target.x)
.attr('y2',()=> link.target.y)
})
})
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
render(){
const { width,heigth, nodes, links, scale, translate, selecting, grabbing} = this.props.store;
return (
<svg id="svg" ref="svg" width={width} height={height}
className={cn({
grab: !selecting && grabbing,
grabbing: !selecting && grabbing
})}
>
<g id="outg" ref="outg" transform{`translate(${translate})scale(${scale})`}>
<g ref="lines" className="lines">
links.map(link => (
<line
key = {`${link.source.uid}_${link.target.uid}`}
ref = {child => this.links[`${link.source.uid}_${link.target.uid}`] = child}
x1 = {links.source.x}
y1 = {links.source.y}
x2 = {links.target.x}
y2 = {links.target.y}
/>
))
</g>
<g ref="nodes" className="nodes">
{
nodes.map(node => (
<Node
key = {node.uid}
node = {node}
store = {this.props.store}
addRef = {child => this.nodes[node.uid] = child}
/>
))
}
</g>
</g>
</svg>
)
}
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
class Node extends Component {
render() {
const { node, addRef, store } = this.props;
const { force } = store;
return (
<g className="node"
ref={child => {
this._node = child;
addRef(child);
}}
transform={`translate(${node.x || width / 2}, ${node.y})`}
>
<g id={node.nodeIndex}>
// 节点图片dom
</g>
{
node.locked && (
<Lock
x = {10}
y = {10}
release = {()=>{
node.fixed = false;
node.locked = false;
node.fx = null;
node.fy = null;
force.alpha(0.3).restart();
}}
/>
)
}
</g>
)
}

componentDidMount() {
this._node._data_ = this.props.node;
d3.select(this._node)
.on('click',d=>{
// code
})
}
}
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
let startTime = 0;
this.drag = d3.drag()
.on('start',(d)=>{
start = (new Date().getTime());
d3.event.sourceEvent.stopPropagation();
if (!d3.event.active){
this.force.alphaTarget(0.3).restart();
}
d.fx = d.x;
d.fy = d.y;
})
.on('drag', d => {
this.grabbing = true;
d.fx = d3.event.x;
d.fy = d3.event.y;
})
.on('end', d => {
const nowTime = (new Date()).getTime();
if (!d3.event.active){
this.force.alphaTarget(0);
}
if (nowTime - startTime >= 150){

}
})
1
2
3
4
5
6
7
8
9
10
11
12
13
const self = this;
const outg = d3.select('#outg');
this.zoomObj = d3.zoom()
.scaleExtent([0.2,4])
.on('zoom',()=>{
const = transform = d3.event.transform;
self.scale = transform.k;
self.translate = [transform.x,transform.y];
outg.attr('transform',transform);
})
.on('end',()=> {

})

添加元素

1
2
3
4
5
6
7
8
9
10
11
12
<html>
<head>
<meta charset="utf-8">
<title>D3测试</title>
<script type="text/javascript" src="d3.js"></script>
</head>
<body>
<script type="text/javascript">
d3.select("body").append("p").text("New paragraph!");
</script>
</body>
</html>

条形图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<body></body>
<style>
div .bar {
display: inline-block;
width: 20px;
margin-right: 2px;
background: teal;
}
</style>
const dataset = [ 5, 10, 15, 20, 25]

d3.select("body").selectAll("div")
.data(dataset)
.enter()
.append("div")
.attr("class","bar")
.style("height", function(d) {
return (d * 5) + "px";
})

散点图

1
2
const w = 500;
const h = 100;

力导向图

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
119
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>testD3-22-force.html</title>
<script type="text/javascript" src="d3.js"></script>
<style type="text/css">
</style>
</head>
<body>
<script type="text/javascript">
var h=300;
var w=300;
// 颜色函数
var colors=d3.scale.category20()//创建序数比例尺和包括20中颜色的输出范围

//(1)定义节点和联系对象数组
var dataset={
nodes:[//节点
{ name:"Adam"},
{ name:"Bob"},
{ name:"Carride"},
{ name:"Donovan"},
{ name:"Edward"},
{ name:"Felicity"},
{ name:"George"},
{ name:"Hannah"},
{ name:"Iris"},
{ name:"Jerry"}
],
edges:[//边
{ source:0,target:1,weight:1,color:1},
{ source:0,target:2,weight:3,color:4},
{ source:0,target:3,weight:4,color:6},
{ source:0,target:4,weight:6,color:65},
{ source:1,target:5,weight:3,color:76},
{ source:2,target:5,weight:8,color:879},
{ source:2,target:5,weight:7,color:989},
{ source:3,target:4,weight:9,color:643},
{ source:5,target:8,weight:1,color:54},
{ source:5,target:9,weight:3,color:54},
{ source:6,target:7,weight:4,color:45},
{ source:7,target:8,weight:0,color:43},
{ source:2,target:8,weight:8,color:243},
{ source:3,target:8,weight:1,color:43},
{ source:5,target:8,weight:5,color:13},
{ source:6,target:8,weight:3,color:351},
{ source:8,target:9,weight:4,color:1}
]
};

//(2)转化数据为适合生成力导向图的对象数组
var force=d3.layout.force()
.nodes(dataset.nodes)//加载节点数据
.links(dataset.edges)//加载边数据
.size([w,h])//设置有效空间的大小
.linkDistance(50)//连线的长度
.charge(-200)//负电荷量,相互排斥设置的负值越大越排斥
.start();//设置生效

var svg=d3.select("body")
.append("svg")
.attr("width",w)
.attr("height",h);

//(3)创建作为连线的svg直线
var edges=svg.selectAll("line")
.data(dataset.edges)
.enter()
.append("line")
.style("stroke",function(d){// 设置线的颜色
return colors(d.color);
})
.style("stroke-width",function(d,i){//设置线的宽度
return d.weight;
});

//(4) 创建作为连线的svg圆形
var nodes=svg.selectAll("circle")
.data(dataset.nodes)
.enter()
.append("circle")
.attr("r",function(d){//设置圆点的半径,圆点的度越大weight属性值越大,可以对其做一点数学变换
return Math.log(d.weight)*10;
})
.style("fill",function(d){
return colors(d.weight*d.weight*d.weight);
})
.call(force.drag);//可以拖动

//(5)打点更新,没有的话就显示不出来了
force.on("tick",function(){
//边
edges.attr("x1",function(d){
return d.source.x;
})
.attr("y1",function(d){
return d.source.y;
})
.attr("x2",function(d){
return d.target.x;
})
.attr("y2",function(d){
return d.target.y;
});

//节点
nodes.attr("cx",function(d){
return d.x;
})
.attr("cy",function(d){
return d.y;
});

})
</script>

</body>
</html>

力导向图带文字

点替换文字、图片、提示

1
2
3
4
5
6
7
8
9
10
node.append("svg:image")
.attr("class","circle")
.attr("xlink:href","http://localhost:8080/spring/imgs/myself.PNG")
.attr("x","-8px")
.attr("y","-8px")
.attr("width","16px")
.attr("height","16px")

node.append("svg:title")
.text(function(d) { return d.name})

弧形箭头连线

1
2
3
4
5
6
7
svg.append("svg:defs").selectAll("marker")
.data(["suit","licensing","resolved"])
.enter().append("svg:marker")
.attr("id",String)
.attr("viewBox","0 -5 10 10")
.attr("refX", 15)
.attr("")

缩放与拖拽

1
2


d3-graphviz

d3-graphviz可以对d3的点进行操作,各种变化

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
119
120
121
122
123
124
125
126
127
128
129
130
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src="//d3js.org/d3.v5.min.js"></script>
<script src="https://unpkg.com/@hpcc-js/wasm@0.3.11/dist/index.min.js"></script>
<script src="https://unpkg.com/d3-graphviz@3.0.5/build/d3-graphviz.js"></script>
<div id="graph" style="text-align: center;"></div>
<script>
var dotIndex = 0;
var graphviz = d3.select("#graph").graphviz()
.transition(function () {
return d3.transition("main")
.ease(d3.easeLinear)
.delay(500)
.duration(1500);
})
.logEvents(true)
.on("initEnd", render);

function render() {
var dotLines = dots[dotIndex];
var dot = dotLines.join('');
graphviz
.renderDot(dot)
.on("end", function () {
dotIndex = (dotIndex + 1) % dots.length;
render();
});
}

var dots = [
[
'digraph {',
' node [style="filled"]',
' a [fillcolor="#d62728"]',
' b [fillcolor="#1f77b4"]',
' a -> b',
'}'
],
[
'digraph {',
' node [style="filled"]',
' a [fillcolor="#d62728"]',
' c [fillcolor="#2ca02c"]',
' b [fillcolor="#1f77b4"]',
' a -> b',
' a -> c',
'}'
],
[
'digraph {',
' node [style="filled"]',
' a [fillcolor="#d62728"]',
' b [fillcolor="#1f77b4"]',
' c [fillcolor="#2ca02c"]',
' a -> b',
' a -> c',
'}'
],
[
'digraph {',
' node [style="filled"]',
' a [fillcolor="#d62728", shape="box"]',
' b [fillcolor="#1f77b4", shape="parallelogram"]',
' c [fillcolor="#2ca02c", shape="pentagon"]',
' a -> b',
' a -> c',
' b -> c',
'}'
],
[
'digraph {',
' node [style="filled"]',
' a [fillcolor="yellow", shape="star"]',
' b [fillcolor="yellow", shape="star"]',
' c [fillcolor="yellow", shape="star"]',
' a -> b',
' a -> c',
' b -> c',
'}'
],
[
'digraph {',
' node [style="filled"]',
' a [fillcolor="#d62728", shape="triangle"]',
' b [fillcolor="#1f77b4", shape="diamond"]',
' c [fillcolor="#2ca02c", shape="trapezium"]',
' a -> b',
' a -> c',
' b -> c',
'}'
],
[
'digraph {',
' node [style="filled"]',
' a [fillcolor="#d62728", shape="box"]',
' b [fillcolor="#1f77b4", shape="parallelogram"]',
' c [fillcolor="#2ca02c", shape="pentagon"]',
' a -> b',
' a -> c',
' b -> c',
'}'
],
[
'digraph {',
' node [style="filled"]',
' a [fillcolor="#d62728"]',
' b [fillcolor="#1f77b4"]',
' c [fillcolor="#2ca02c"]',
' a -> b',
' a -> c',
' c -> b',
'}'
],
[
'digraph {',
' node [style="filled"]',
' b [fillcolor="#1f77b4"]',
' c [fillcolor="#2ca02c"]',
' c -> b',
'}'
],
[
'digraph {',
' node [style="filled"]',
' b [fillcolor="#1f77b4"]',
'}'
],
];
</script>

d3资源

Https://d3js.org.cn

Vega - 图表库也能低代码

G2

G2 是支付宝前端团队开发的,虽然当时 Echarts 已经很成熟了,但支付宝还是选择了自己做了一个,也就是 G2 的前身 acharts,它的 API 和 Echarts 基本类似,后来作者看了《The Grammar Of Graphics》那本书,就调整了方向,开始基于这本书的思路开发 G2,这个 G2 的命名就是这本书名里的两个 G。

受这本书影响的可视化库有很多,前面说的 Vega-Lite 在作者的论文里就提到过借鉴了不少了,和 G2 一样参考那本书的还有 chart-parts,不过别看它是微软的项目,其实也只有一个人在开发,提交次数非常不稳定,作者同时还在忙另一个更知名的项目 react-dnd,所以大概率以后会弃坑。

《The Grammar Of Graphics》里作者主要是借鉴了面向对象的思想,将图表拆分成了很多组成部分,比如数据源、数据转换、坐标系、图形等,通过将它们组装起来实现各种展现效果,从技术角度倒是不新奇,但这本书通过数学的方式来进行组合和分析,看起来非常高级。

chart.js

我之前对 Chart.js 这个库了解比较少,几年前第一次发现的时候它的 Star 数就很高了,它现在的 Star 数量高达 49.3k,在 npm 上的周下载量达到百万,和 D3 是一个量级的,恐怕是最火的前端图表库了。

既然怎么火,它在技术上情况怎样呢?这个项目的最早提交时间是 2013 年,7 年来提交没怎么中断,然而整个项目代码量只有 1w 多行,它的图表种类少,可配置项也不多,整体来说比 Echarts/Highcharts 都差很远,看了半天实在没搞懂为什么那么火,或许反应出大部分人对图表要求不高,能显示几种场景图表,有点交互和动画就够了。

Highcharts

创始在 2006 的时候只想给自己的主页加个图表,当时虽然有 FusionCharts/AnyChart 这些 Flash 的商业方案,但他用不惯就开始自己基于 SVG/VML 开发,可能他是最早这么做,极有可能是 Highcharts 后来居上的原因,使用 SVG/VML 最大的好处是方便前端使用,而之前基于 Flash 的方案和 JavaScript 通信麻烦,往往导致整个页面都得用 Flash 开发,成本比较高,所以后来 FusionCharts/AnyChart 也都转向了 SVG/VML 方案。

十四年过去了,它的创始人至今还几乎天天提交代码,这个项目的贡献者中不少是同一个小镇的,多半是他手把手培养起来的乡亲。。。

Highcharts 虽然开源,但商用是需要收费的,很多人看到要花钱就不往下看了,但其实专门做这块的商业公司往往更有优势,前面介绍 D3 的时候提到过,在所有基于 D3 开源的图表库中做得最好的是一个商业公司的产品。

AnyChart

如果你想用商业软件又觉得 Highcharts 太丑,AnyChart 就是个不错的候选,和 Highcharts 类似,AnyChart 也是开源但商用必须收费,它的整体设计比 Highcharts 要漂亮,但影响力远比不上 Highcharts,甚至在 GitHub 上的 Star 只有 248,还不如许多个人发布的玩具项目。

然而在国内某卖控件的网站上,AnyChart 的下载量很靠前,远高于 Highcharts,它们之间的差距甚至达到百倍,所以 AnyChart 可能更好卖,其中颜值可能是主要原因。

FusionCharts

FusionCharts 来自印度,它的创始人 Pallav Nadhani 的父亲是做 Web 设计的,所以他很早就接触网络,在 16 岁的时候就会用 Excel 来做高中作业,他用的过程中觉得 Excel 里的图表不好用,于是给 http://ASPToday.com 投稿了一篇文章,提出了 Flash 不仅能用来做小广告,还可以实现交互式图表的想法,这篇文章给他带来了 1500$ 的零花钱,普通高中生拿到零花钱多半会很快就和小伙伴们一起挥霍掉,而 Nadhani 拿着这笔钱在 17 岁(2002 年)时候成立了公司,开始开发基于 Flash 的图表库,然而高中辍学创业并不容易,没有投资人会相信一个还没成年的小孩,Nadhani 独自在家开发了三年后才招到第一个人,早期只在网上卖,因为网上不容易发现你是个小孩,发现了肯定不敢买,好在图表方面的需求很旺盛,所以公司不断做大,图表库不仅卖给了很多公司,还卖给了美国联邦政府,连美国总统都在用

amCharts

amCharts 也来自小国家,它的总部在立陶宛,最开始是只做地图类的图表,后来才有的饼图折线图,它应该是这里面最小的商业公司,整个团队只有 7 个人,其中参与开发的大概 4-5 个,因为人少,所以它的功能相对其它几个商业库要少点,比如不支持 vml(不过现在没人用 IE8 了),可能正是因为觉得做不过,所以它采用了不同的商业策略,是唯一可以免费商用,只有去 logo 才需要付费,这个策略看起来效果不错,它的搜索量是这几个商业库中排名第二的,使用的网站数仅次于 Highcharts。

Google chart

Google Charts 在 2008 年就推出了,做得非常早,虽然国内现在没人用,但国外用得很多,有个数据分析说它是最流行的图表库,在网站中的使用量 Highcharts 的两倍

Google Charts 有两个版本,一个是通过链接来生成图表图片,另一个是外链的 JavaScript 图表库。

通过链接生成图表图片的做法在十几年前非常常见,比如性能监控领域用了好多年的 RRDtool,即便现在你都能在一些股票网站的 k 线图里看到这种做法,使用它的主要原因是当时的前端技术不成熟,浏览器兼容性差,使用这种方式可以轻松在所有浏览器里得到一致的显示效果,下面是一个例子:

G6

G6 是一个图可视化引擎。它提供了图的绘制、布局、分析、交互、动画等图可视化的基础能力。旨在让关系变得透明,简单。让用户获得关系数据的 Insight。

安装

1
npm install @antv/g6

导入

1
import G6 from '@antv/g6'

创建步骤:1.在html中创建容器

1
<div id="mountNode"></div>

2.引入 G6 的数据源为 JSON 格式的对象。该对象中需要有节点(nodes)和边(edges)字段,分别用数组表示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const data = {
// 点集
nodes: [
{
id: 'node1', // String,该节点存在则必须,节点的唯一标识
x: 100, // Number,可选,节点位置的 x 值
y: 200, // Number,可选,节点位置的 y 值
},
{
id: 'node2', // String,该节点存在则必须,节点的唯一标识
x: 300, // Number,可选,节点位置的 x 值
y: 200, // Number,可选,节点位置的 y 值
},
],
// 边集
edges: [
{
source: 'node1', // String,必须,起始点 id
target: 'node2', // String,必须,目标点 id
},
],
};

3.创建关系图(实例化)时,至少需要为图设置容器、宽和高。

1
2
3
4
5
const graph = new G6.Graph({
container: 'mountNode', // String | HTMLElement,必须,在 Step 1 中创建的容器 id 或容器本身
width: 800, // Number,必须,图的宽度
height: 500, // Number,必须,图的高度
});

4.配置数据源,渲染

1
2
graph.data(data); // 读取 Step 2 中的数据源到图上
graph.render(); // 渲染图

keylines

其他开源图表库

开源图表库还有很多 Star 数量比较高的,这里简单汇总一下:

  • TOAST UI Chart 是韩国 NHN 公司搞的,贡献者比较少,感觉快要弃坑了,大公司里的非主业项目经常这样,表示理解。
  • Chartist.js 别看它有 12.2k 的 Star,看提交历史肯定弃坑了,3 年只提交了 20 次。
  • Frappe Charts 代码只有 3.5k 行,最近提交很少且文档很简陋,13.4k Star 说明他们的推广策略很厉害,也是个值得学的案例。
  • Raphael 特别古老的前端图形库,2008 年就有了,不少图表库的底层基于它,它自己也有个 g.Raphaël 图表库,不过只开发了两年就停了,可能是作者在 Adobe 忙别的事情去了,比如折腾过 Snap.svg,但也弃坑了。
  • vis.js 主要是绘制关系图的,曾经有段时间弃坑过,不过最近还有少量更新,类似的还有 dagreGoJSDraw2D
  • TradingView 专注做股票类的,似乎很专业,有不少分析 k 线的小工具。
  • uPlot 以体积小巧作为主要优点,然而体积小只是因为功能少,2k 多行代码做不了啥,所以它的配置项和交互都很少。
  • Chartkick.js 将 Chart.js、Google Charts 和 Highcharts 的接口封装起来,提供一套更简单的 API,一方面是更简单,另一方面是万一其中某个挂掉了可以直接换别的,然而这也意味着它的功能非常有限,毕竟是取交集。
  • 另外还有些 gis 领域的专用可视化库,比如 cesiumdeck.gl,但国内对测绘是有规定的,最好直接用百度、高德。

连线图表

jsPlumb

jsPlumb适用于必须绘制图表的Web应用程序.例如类似于Visio的应用程序或工作流程设计器等。由于图表项目和连接的所有参数都是非常精细可控的,因此您可以绘制您可以想到的任何类型的图表的!

基本概念

Souce 源节点、Target 目标节点、Anchor 锚点、Endpoint 端点、Connector 连接

vivaGraphJs

springy

graphviz

visjs

echart

高效率绘制各种美观图表

安装echart

1
npm install echarts --save

安装完成后 ECharts 和 zrender 会放在 node_modules 目录下

引入echart

1
import echarts from "echarts"

基础的数据可视化

基本名词解释

名词 描述
chart 是指一个完整的图表,如折线图,饼图等“基本”图表类型或由基本图表组合而成的“混搭”图表,可能包括坐标轴、图例等
axis 直角坐标系中的一个坐标轴,坐标轴可分为类目型、数值型或时间型
xAxis 直角坐标系中的横轴,通常并默认为类目型
yAxis 直角坐标系中的纵轴,通常并默认为数值型
grid 直角坐标系中除坐标轴外的绘图网格,用于定义直角系整体布局
legend 图例,表述数据和图形的关联
dataRange 值域选择,常用于展现地域数据时选择值域范围
dataZoom 数据区域缩放,常用于展现大量数据时选择可视范围
roamController 缩放漫游组件,搭配地图使用
toolbox 辅助工具箱,辅助功能,如添加标线,框选缩放等
tooltip 气泡提示框,常用于展现更详细的数据
timeline 时间轴,常用于展现同一系列数据在时间维度上的多份数据
series 数据系列,一个图表可能包含多个系列,每一个系列可能包含多个数据

图表名词

名词 描述
line 折线图,堆积折线图,区域图,堆积区域图。
bar 柱形图(纵向),堆积柱形图,条形图(横向),堆积条形图。
scatter 散点图,气泡图。散点图至少需要横纵两个数据,更高维度数据加入时可以映射为颜色或大小,当映射到大小时则为气泡图
k K线图,蜡烛图。常用于展现股票交易数据。
pie 饼图,圆环图。饼图支持两种(半径、面积)南丁格尔玫瑰图模式。
radar 雷达图,填充雷达图。高维度数据展现的常用图表。
chord 和弦图。常用于展现关系数据,外层为圆环图,可体现数据占比关系,内层为各个扇形间相互连接的弦,可体现关系数据
force 力导布局图。常用于展现复杂关系网络聚类布局。
map 地图。内置世界地图、中国及中国34个省市自治区地图数据、可通过标准GeoJson扩展地图类型。支持svg扩展类地图应用,如室内地图、运动场、物件构造等。
heatmap 热力图。用于展现密度分布信息,支持与地图、百度地图插件联合使用。
gauge 仪表盘。用于展现关键指标数据,常见于BI类系统。
funnel 漏斗图。用于展现数据经过筛选、过滤等流程处理后发生的数据变化,常见于BI类系统。
evnetRiver 事件河流图。常用于展示具有时间属性的多个事件,以及事件随时间的演化。
treemap 矩形式树状结构图,简称:矩形树图。用于展示树形数据结构,优势是能最大限度展示节点的尺寸特征。
venn 韦恩图。用于展示集合以及它们的交集。
tree 树图。用于展示树形数据结构各节点的层级关系
wordCloud 词云。词云是关键词的视觉化描述,用于汇总用户生成的标签或一个网站的文字内容

实例

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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
//基于准备好的dom,初始化echart图表  
var myChart = ec.init(document.getElementById('mainBar'));
//定义图表option
var option = {
//标题,每个图表最多仅有一个标题控件,每个标题控件可设主副标题
title: {
//主标题文本,'\n'指定换行
text: '2013年广州降水量与蒸发量统计报表',
//主标题文本超链接
link: 'http://www.tqyb.com.cn/weatherLive/climateForecast/2014-01-26/157.html',
//副标题文本,'\n'指定换行
subtext: 'www.stepday.com',
//副标题文本超链接
sublink: 'http://www.stepday.com/myblog/?Echarts',
//水平安放位置,默认为左侧,可选为:'center' | 'left' | 'right' | {number}(x坐标,单位px)
x: 'left',
//垂直安放位置,默认为全图顶端,可选为:'top' | 'bottom' | 'center' | {number}(y坐标,单位px)
y: 'top'
},
//提示框,鼠标悬浮交互时的信息提示
tooltip: {
//触发类型,默认('item')数据触发,可选为:'item' | 'axis'
trigger: 'axis'
},
//图例,每个图表最多仅有一个图例
legend: {
//显示策略,可选为:true(显示) | false(隐藏),默认值为true
show: true,
//水平安放位置,默认为全图居中,可选为:'center' | 'left' | 'right' | {number}(x坐标,单位px)
x: 'center',
//垂直安放位置,默认为全图顶端,可选为:'top' | 'bottom' | 'center' | {number}(y坐标,单位px)
y: 'top',
//legend的data: 用于设置图例,data内的字符串数组需要与sereis数组内每一个series的name值对应
data: ['蒸发量','降水量']
},
//工具箱,每个图表最多仅有一个工具箱
toolbox: {
//显示策略,可选为:true(显示) | false(隐藏),默认值为false
show: true,
//启用功能,目前支持feature,工具箱自定义功能回调处理
feature: {
//辅助线标志
mark: {show: true},
//dataZoom,框选区域缩放,自动与存在的dataZoom控件同步,分别是启用,缩放后退
dataZoom: {
show: true,
title: {
dataZoom: '区域缩放',
dataZoomReset: '区域缩放后退'
}
},
//数据视图,打开数据视图,可设置更多属性,readOnly 默认数据视图为只读(即值为true),可指定readOnly为false打开编辑功能
dataView: {show: true, readOnly: true},
//magicType,动态类型切换,支持直角系下的折线图、柱状图、堆积、平铺转换
magicType: {show: true, type: ['line', 'bar']},
//restore,还原,复位原始图表
restore: {show: true},
//saveAsImage,保存图片(IE8-不支持),图片类型默认为'png'
saveAsImage: {show: true}
}
},
//是否启用拖拽重计算特性,默认关闭(即值为false)
calculable: true,
//直角坐标系中横轴数组,数组中每一项代表一条横轴坐标轴,仅有一条时可省略数值
//横轴通常为类目型,但条形图时则横轴为数值型,散点图时则横纵均为数值型
xAxis: [
{
//显示策略,可选为:true(显示) | false(隐藏),默认值为true
show: true,
//坐标轴类型,横轴默认为类目型'category'
type: 'category',
//类目型坐标轴文本标签数组,指定label内容。 数组项通常为文本,'\n'指定换行
data: ['1月','2月','3月','4月','5月','6月','7月','8月','9月','10月','11月','12月']
}
],
//直角坐标系中纵轴数组,数组中每一项代表一条纵轴坐标轴,仅有一条时可省略数值
//纵轴通常为数值型,但条形图时则纵轴为类目型
yAxis: [
{
//显示策略,可选为:true(显示) | false(隐藏),默认值为true
show: true,
//坐标轴类型,纵轴默认为数值型'value'
type: 'value',
//分隔区域,默认不显示
splitArea: {show: true}
}
],
//sereis的数据: 用于设置图表数据之用。series是一个对象嵌套的结构;对象内包含对象
series: [
{
//系列名称,如果启用legend,该值将被legend.data索引相关
name: '蒸发量',
//图表类型,必要参数!如为空或不支持类型,则该系列数据不被显示。
type: 'bar',
//系列中的数据内容数组,折线图以及柱状图时数组长度等于所使用类目轴文本标签数组axis.data的长度,并且他们间是一一对应的。数组项通常为数值
data: [2.0, 4.9, 7.0, 23.2, 25.6, 76.7, 135.6, 162.2, 32.6, 20.0, 6.4, 3.3],
//系列中的数据标注内容
markPoint: {
data: [
{type: 'max', name: '最大值'},
{type: 'min', name: '最小值'}
]
},
//系列中的数据标线内容
markLine: {
data: [
{type: 'average', name: '平均值'}
]
}
},
{
//系列名称,如果启用legend,该值将被legend.data索引相关
name: '降水量',
//图表类型,必要参数!如为空或不支持类型,则该系列数据不被显示。
type: 'bar',
//系列中的数据内容数组,折线图以及柱状图时数组长度等于所使用类目轴文本标签数组axis.data的长度,并且他们间是一一对应的。数组项通常为数值
data: [2.6, 5.9, 9.0, 26.4, 28.7, 70.7, 175.6, 182.2, 48.7, 18.8, 6.0, 2.3],
//系列中的数据标注内容
markPoint: {
data: [
{type: 'max', name: '最大值'},
{type: 'min', name: '最小值'}
]
},
//系列中的数据标线内容
markLine: {
data: [
{type: 'average', name: '平均值'}
]
}
}
]
};
//为echarts对象加载数据
myChart.setOption(option);

骨架屏实现

骨架屏(Skeleton Screen)是指在页面数据加载完成前,先给用户展示出页面的大致结构(灰色占位图),在拿到接口数据后渲染出实际页面内容然后替换掉。Skeleton Screen 是近两年开始流行的加载控件,本质上是界面加载过程中的过渡效果。

假如能在加载前把网页的大概轮廓预先显示,接着再逐渐加载真正内容,这样既降低了用户的焦灼情绪,又能使界面加载过程变得自然通畅,不会造成网页长时间白屏或者闪烁。这就是 Skeleton Screen !

骨架屏的实现方案:

1.使用图片、svg 或者手动编写骨架屏代码:使用 HTML + CSS 的方式,我们可以很快的完成骨架屏效果,但是面对视觉设计的改版以及需求的更迭,我们对骨架屏的跟进修改会非常被动,这种机械化重复劳作的方式此时未免显得有些机动性不足;

2.通过预渲染手动书写的代码生成相应的骨架屏:该方案做的比较成熟的是 vue-skeleton-webpack-plugin,通过 vueSSR 结合 webpack 在构建时渲染写好的 vue 骨架屏组件,将预渲染生成的 DOM 节点和相关样式插入到最终输出的 html 中。

3.饿了么内部的生成骨架页面的工具:该方案通过一个 webpack 插件 page-skeleton-webpack-plugin 的方式与项目开发无缝集成,属于在自动生成骨架屏方面做的非常强大的了,并且可以启动 UI 界面专门调整骨架屏,但是在面对复杂的页面也会有不尽如人意的地方,而且生成的骨架屏节点是基于页面本身的结构和 CSS,存在嵌套比较深的情况,体积不会太小,并且只支持 history 模式。

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

评论

You forgot to set the app_id or app_key for Valine. Please set it in _config.yml.

 

本文章阅读量:

  0

IT学徒、技术民工、斜杠青年

机器人爱好者、摄影爱好者

PS、PR、LR、达芬奇潜在学习者

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×