blob: d2b27d512430b495cee97b113965d91998eece15 [file] [log] [blame]
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Reveal.js</title>
<base target="_blank"/>
<link rel="stylesheet" href="./asset/md2reveal-0.1.7/css/reveal.css">
<link rel="stylesheet" href="./asset/md2reveal-0.1.7/css/theme/black.css" id="theme">
<link rel="stylesheet" href="./asset/md2reveal-0.1.7/css/theme/black-md2reveal.css" id="themeMine">
<!-- For syntax highlighting -->
<link rel="stylesheet" href="./asset/md2reveal-0.1.7/lib/css/zenburn.css">
</head>
<body>
<div class="reveal">
<div class="slides"><section data-markdown><script type="text/template">
# echarts 结构和演进
百度前端技术部 echarts 团队
</script></section><section data-markdown><script type="text/template">
#### echarts
+ 浏览器端数据可视化图表组件库
+ <https://github.com/ecomfe/echarts>
+ <http://gallery.echartsjs.com>
+ 15000
</script></section><section data-markdown><script type="text/template">
### 纲要
+ 结构概览
+ 基本设定
+ 数据结构的抽象
+ 组件间的依赖和交互
+ 工作流程
+ 视觉编码
+ 反思
</script></section><section ><section data-markdown><script type="text/template">
### Level 0
![](./asset/img2/hierarchy-level0.png)
</script></section><section data-markdown><script type="text/template">
### zrender
+ <div class="fragment" data-fragment-index="0">渲染引擎隔离(canvas (in browser/nodejs) / vml / svg / ...)</div>
+ <div class="fragment" data-fragment-index="1">对象抽象 & 状态维护(Element / Group / Layer / ...)</div>
+ <div class="fragment" data-fragment-index="2">用户交互封装(mouse event / touch / gesture / drag / ...)</div>
+ <div class="fragment" data-fragment-index="3">动画(frame / easing / ...)</div>
+ <div class="fragment" data-fragment-index="4">图形支持(transformable / contain / curve / ...)</div>
+ <div class="fragment" data-fragment-index="5">其他基本工具(eventful / color / array diff / svg path converter / ...)</div>
</script></section><section data-markdown><script type="text/template">
### echarts
<div class="fragment" data-fragment-index="0">图表 / 组件 / 交互行为 / API</div>
<div class="fragment" data-fragment-index="0">![](./asset/img2/ec-general.png)</div>
> + <div class="fragment" data-fragment-index="1">变化多、需扩展、需易维护</div>
> + <div class="fragment" data-fragment-index="2">架构、演变</div>
</script></section></section><section ><section data-markdown><script type="text/template">
#### 声明式接口
> <div class="fragment" data-fragment-index="0">
所有数据、组件、布局、行为、... <br>
由用户声明的 **option** 描述 <br>
</div>
<aside class="notes" data-markdown>在基本设定(声明式,数据驱动,单向流)下才有后面的讨论。</aside></script></section><section data-markdown><script type="text/template">
<iframe style="width:1200px;height:600px;" data-md2r-src="./asset/ec-demo/scatter-weight.html"></iframe>
</script></section><section data-markdown><script type="text/template">
### 数据流 Level 0
![](./asset/img2/dataflow-level0.png)
</script></section><section data-markdown><script type="text/template">
#### echarts 2.x Arch
<div class="fragment" data-fragment-index="0">![](./asset/img2/ec2-arch.png)</div>
+ <div class="fragment" data-fragment-index="1">flat and intuitive => easy to understand and learn</div>
+ <div class="fragment" data-fragment-index="2">interaction, othogonality, extensibility => inadequate</div>
</script></section><section data-markdown><script type="text/template">
下面在这几方面介绍架构的设计和进化
+ <div class="fragment" data-fragment-index="0">数据结构的抽象</div>
+ <div class="fragment" data-fragment-index="1">工作流程</div>
+ <div class="fragment" data-fragment-index="2">视觉编码</div>
</script></section></section><section ><section data-markdown><script type="text/template">
## 数据结构的抽象
<aside class="notes" data-markdown>下面的介绍,按『需求』->『解决』(按需抽象)的逻辑</aside></script></section><section data-markdown><script type="text/template">
### 需求: 正交(1
<div style="min-width: 1050px">
<div style="float:left;">
<div class="fragment" data-fragment-index="0">
scatter on cartesian
<iframe style="width:350px;height:400px;" data-md2r-src="./asset/ec-demo/orthogonal1-scatter-cartesian.html"></iframe>
</div>
</div>
<div style="float:left;">
<div class="fragment" data-fragment-index="1">
scatter on polar
<iframe style="width:350px;height:400px;" data-md2r-src="./asset/ec-demo/orthogonal1-scatter-polar.html"></iframe>
</div>
</div>
<div style="float:left;">
<div class="fragment" data-fragment-index="2">
scatter on geo
<iframe style="width:350px;height:400px;" data-md2r-src="./asset/ec-demo/orthogonal1-scatter-geo.html"></iframe>
</div>
</div>
</script></section><section data-markdown><script type="text/template">
### 需求: 正交(2
<div style="min-width: 1050px">
<div style="float:left;">
<div class="fragment" data-fragment-index="0">
line on cartesian
<iframe style="width:350px;height:400px;" data-md2r-src="./asset/ec-demo/orthogonal2-cartesian-line.html"></iframe>
</div>
</div>
<div style="float:left;">
<div class="fragment" data-fragment-index="1">
boxplot on cartesian
<iframe style="width:350px;height:400px;" data-md2r-src="./asset/ec-demo/orthogonal2-cartesian-boxplot.html"></iframe>
</div>
</div>
<div style="float:left;">
<div class="fragment" data-fragment-index="2">
graph on cartesian
<iframe style="width:350px;height:400px;" data-md2r-src="./asset/ec-demo/orthogonal2-cartesian-graph.html"></iframe>
</div>
</div>
</script></section><section data-markdown><script type="text/template">
### 需求: 混合排布
<div class="fragment" data-fragment-index="1"><iframe style="width:800px;height:500px;" data-md2r-src="./asset/ec-demo/grid-on-geo.html"></iframe></div>
</script></section><section data-markdown><script type="text/template">
### 抽象
+ <div class="fragment" data-fragment-index="0">**coordinate system** : cartesian / polar / geo / single / parallel ...</div>
+ <div class="fragment" data-fragment-index="0">**chart** : line / bar / scatter / pie / candlestick ...</div>
<aside class="notes" data-markdown>coord 有公用的 interface(如 dataToPoint)。coord 有单独的阶段。</aside></script></section><section data-markdown><script type="text/template">
### 需求: 一个功能的多种用户交互形式
<div class="fragment" data-fragment-index="0"><iframe style="width:800px;height:400px;" data-md2r-src="./asset/ec-demo/interaction-multi-one.html"></iframe></div>
+ <div class="fragment" data-fragment-index="1">Generalization: <br> dataZoom => insideZoom / sliderZoom / toolboxZoom</div>
</script></section><section data-markdown><script type="text/template">
### 需求: 统一的位置、尺寸描述方式
+ <div class="fragment" data-fragment-index="0">六元:left / right / top / bottom / width / height</div>
+ <div class="fragment" data-fragment-index="1">绝对值 / 百分比 / 'center'</div>
</script></section><section data-markdown><script type="text/template">
### 需求: 逻辑的复用(以 axis / scale 为例)
<div style="min-width: 1060px;">
<div style="float:left;">
<div class="fragment" data-fragment-index="0">
axes in radar
<iframe style="width:350px;height:400px;" data-md2r-src="./asset/ec-demo/reuse-axis-radar.html"></iframe>
</div>
</div>
<div style="float:left;">
<div class="fragment" data-fragment-index="1">
axes in parallel
<iframe style="width:350px;height:400px;" data-md2r-src="./asset/ec-demo/reuse-axis-parallel.html"></iframe>
</div>
</div>
<div style="float:left;">
<div class="fragment" data-fragment-index="2">
axis in timeline
<iframe style="width:350px;height:400px;" data-md2r-src="./asset/ec-demo/reuse-axis-timeline.html"></iframe>
</div>
</div>
</div>
</script></section><section data-markdown><script type="text/template">
### 需求: 逻辑的复用(以 axis / scale 为例)
<div style="min-width: 1050px; text-align: center;">
<div style="display:inline-block;">
<div class="fragment" data-fragment-index="0">
different shapes and angles
<iframe style="width:450px;height:400px;" data-md2r-src="./asset/ec-demo/different-axis-position.html"></iframe>
</div>
</div>
<div style="display:inline-block;">
<div class="fragment" data-fragment-index="1">
different scales
<iframe style="width:450px;height:400px;" data-md2r-src="./asset/ec-demo/different-axis-scale.html"></iframe>
</div>
</div>
</div>
</script></section><section data-markdown><script type="text/template">
### 抽象
+ <div class="fragment" data-fragment-index="0">**axis** : model / view</div>
+ <div class="fragment" data-fragment-index="1">**scale** : interval / ordinal / time / log / ...</div>
</script></section><section data-markdown><script type="text/template">
### 需求: 逻辑的复用(以 data 为例)
<div>
<div class="fragment" data-fragment-index="0"><iframe style="width:1100px;height:500px;" data-md2r-src="./asset/ec-demo/list-sample1.html"></iframe></div>
</div>
<div class="fragment" data-fragment-index="1">dataZoom 组件如何处理不同的图表中不同格式的数据?<br>(<del>if-else</del>)</div>
</script></section><section data-markdown><script type="text/template">
### 抽象
+ <div class="fragment" data-fragment-index="0">**List** : line / bar / scatter / pie / parallel / candlestick / ...</div>
+ <div class="fragment" data-fragment-index="0">**Graph** : force / chord / sankey / ...</div>
+ <div class="fragment" data-fragment-index="0">**Tree** : treemap / tree / ...</div>
</script></section><section data-markdown><script type="text/template">
### 各种数据结构的抽象
+ Coordinate System
+ Scale
+ Axis
+ List / Graph / Tree
+ Symbol
+ RoamController
+ ComponentModel
+ ...
</script></section><section data-markdown><script type="text/template">
### Model & View
+ <div class="fragment" data-fragment-index="0">option cascade</div>
+ <div class="fragment" data-fragment-index="1">state maintenance</div>
+ <div class="fragment" data-fragment-index="2">transition animation (view reuse)</div>
+ <div class="fragment" data-fragment-index="3">option management (reset, timeline, responsive)</div>
<aside class="notes" data-markdown>过渡动画指的是:option 不放在 view 里管理,从而 view 能重用,从而能在非 merge 模式有过渡动画。
引入Model后这些feature的实现会清晰。</aside></script></section><section data-markdown><script type="text/template">
![](./asset/img2/model-cascade.png)
option cascade
</script></section><section data-markdown><script type="text/template">
<iframe style="width:1200px;height:500px;" data-md2r-src="./asset/ec-demo/timeline.html"></iframe>
option management: timeline
</script></section><section data-markdown><script type="text/template">
<iframe style="width:1200px;height:500px;" data-md2r-src="./asset/ec-demo/media-query.html"></iframe>
option management: responsive (media query)
</script></section></section><section ><section data-markdown><script type="text/template">
## 组件间的依赖和交互
</script></section><section data-markdown><script type="text/template">
![](./asset/img2/ec2-arch.png)
回顾: echarts2 ARCH
<aside class="notes" data-markdown>下面从『组件依赖』这个例子来介绍引入『工作流程』的意义。</aside></script></section><section data-markdown><script type="text/template">
【组件间的依赖】
<div>
<div class="fragment" data-fragment-index="0"><iframe style="width:1100px;height:300px;" data-md2r-src="./asset/ec-demo/workflow-basic.html"></iframe></div>
</div><div style="margin-top:-320px">
<div class="fragment" data-fragment-index="1"><iframe style="width:1100px;height:300px;" data-md2r-src="./asset/ec-demo/workflow-basic-mask.html"></iframe></div>
</div>
<div class="fragment" data-fragment-index="2">依赖声明和拓扑</div>
<div class="fragment" data-fragment-index="3">![](./asset/img2/topology.png)</div>
<aside class="notes" data-markdown>dependency: ec2#echarts.js: dataZoom.syncOption。</aside></script></section><section data-markdown><script type="text/template">
【组件间的交互】
<div>
<div class="fragment" data-fragment-index="0"><iframe style="width:1100px;height:300px;" data-md2r-src="./asset/ec-demo/workflow-basic.html"></iframe></div>
</div><div style="margin-top:-320px">
<div class="fragment" data-fragment-index="1"><iframe style="width:1100px;height:300px;" data-md2r-src="./asset/ec-demo/workflow-basic-mask2.html"></iframe></div>
</div>
+ <div class="fragment" data-fragment-index="1">行为:过滤数据、显示 / 隐藏、改变范围、...</div>
+ <div class="fragment" data-fragment-index="2"><del>一个组件间直接调用另一个组件</del></div>
</script></section><section data-markdown><script type="text/template">
【组件间的交互】
echarts2:事件通讯
![](./asset/img2/ec2-message.png)
<div class="fragment" data-fragment-index="0">消除了组件的『实例间的依赖』</div>
</script></section><section data-markdown><script type="text/template">
问题 1:需主动监听其他组件的事件。
<div class="fragment" data-fragment-index="0"><iframe style="width:1100px;height:220px;" data-md2r-src="./asset/ec-demo/workflow-basic.html"></iframe></div>
<div class="fragment" data-fragment-index="1">![](./asset/img2/type-know.png)</div>
<div class="fragment" data-fragment-index="2">组件之间仍然要互相知晓(类型的依赖)</div>
<aside class="notes" data-markdown>onlegendselected 中,tooltip 要主动监听,并更新自己的 selectedMap,从而才能遍历 series 时候避开没有选中的。各个 component 都要主动监听,则扩展性问题。</aside></script></section><section data-markdown><script type="text/template">
问题 2
```javascript
// 因为交互行为导致的后续过程(如清除、刷新等)可能有所不同,
// echarts main 只得主动监听一些组件事件,从而形成了 switch case。
switch (eventType) {
case ecConfig.EVENT.LEGEND_SELECTED :
this._onlegendSelected(param);
break;
case ecConfig.EVENT.DATA_ZOOM :
...
this._ondataZoom(param);
break;
case ecConfig.EVENT.DATA_RANGE :
fromMyself && this._ondataRange(param);
break;
case ecConfig.EVENT.MAGIC_TYPE_CHANGED :
...
this._onmagicTypeChanged(param);
break;
case ecConfig.EVENT.DATA_VIEW_CHANGED :
fromMyself && this._ondataViewChanged(param);
break;
case ecConfig.EVENT.TOOLTIP_HOVER :
fromMyself && this._tooltipHover(param);
break;
case ecConfig.EVENT.RESTORE :
case ecConfig.EVENT.REFRESH :
case ecConfig.EVENT.TOOLTIP_IN_GRID :
case ecConfig.EVENT.TOOLTIP_OUT_GRID :
...
```
<div class="fragment" data-fragment-index="1">纯粹的『事件模式』并不足以指导后续行为</div>
<aside class="notes" data-markdown>一些后续行为,如 clearEffect 之类,是公用的,不适于写在每个组件的事件响应函数中。</aside></script></section></section><section ><section data-markdown><script type="text/template">
## echarts 工作流程
</script></section><section data-markdown><script type="text/template">
<div class="fragment" data-fragment-index="0">![](./asset/img2/type-know.png)</div>
+ <div class="fragment" data-fragment-index="1">用户行为触发 => 组件改变各自状态 => 处理数据 => 更新视图</div>
+ <div class="fragment" data-fragment-index="2">公共操作对象的归纳和抽离:**数据**</div>
<div class="fragment" data-fragment-index="2">![](./asset/img2/data-focus.png)</div>
<aside class="notes" data-markdown>无非都是(1)改变状态(2)更新数据(3)刷新视图 和具体事件无关(刷新的类型稍微有点变化,比如tooltip不需要全局刷新)。
所以可以进一步解耦抽象:阶段。</aside></script></section><section data-markdown><script type="text/template">
+ <div class="fragment" data-fragment-index="0">对数据的处理规则:**阶段** & 注册</div>
<div class="fragment" data-fragment-index="0">![](./asset/img2/phases.png)</div>
</script></section><section data-markdown><script type="text/template">
![](./asset/img2/ec3-workflow.png)
echarts3 workflow
</script></section></section><section ><section data-markdown><script type="text/template">
## 视觉编码
<aside class="notes" data-markdown>从视觉编码这例子来看工作流程。</aside></script></section><section data-markdown><script type="text/template">
#### 概念
+ 数据 => 视觉元素
+ <div class="fragment" data-fragment-index="0">标记:点、线、面</div>
+ <div class="fragment" data-fragment-index="1">视觉通道</div>
+ <div class="fragment" data-fragment-index="1">颜色</div>
<div class="fragment" data-fragment-index="1">亮度、饱和度、透明度、色调</div>
+ <div class="fragment" data-fragment-index="1">尺寸</div>
+ <div class="fragment" data-fragment-index="1">形状</div>
+ <div class="fragment" data-fragment-index="1">纹理</div>
+ <div class="fragment" data-fragment-index="1">方向</div>
+ <div class="fragment" data-fragment-index="1">动画</div>
</script></section><section data-markdown><script type="text/template">
<iframe style="width:1100px;height:500px;" data-md2r-src="./asset/ec-demo/visualmap-sample1.html"></iframe>
</script></section><section data-markdown><script type="text/template">
<iframe style="width:1100px;height:550px;" data-md2r-src="./asset/ec-demo/visualmap-sample2.html"></iframe>
</script></section><section data-markdown><script type="text/template">
<iframe style="width:800px;height:500px;" data-md2r-src="./asset/ec-demo/mix-sample1.html"></iframe>
</script></section><section data-markdown><script type="text/template">
![](./asset/img2/ec3-workflow.png)
</script></section><section data-markdown><script type="text/template">
![](./asset/img2/visual-map.png)
<aside class="notes" data-markdown>不同组件都能干涉 visualvisaulMap 组件,brush 组件,原生组件)
legend 对颜色的干涉 ec2 中存在 legend)</aside></script></section></section><section ><section data-markdown><script type="text/template">
# ?
<div class="fragment" data-fragment-index="0">尽量解耦?</div>
<div class="fragment" data-fragment-index="1">尽量抽象?</div>
<br>
+ <div class="fragment" data-fragment-index="2">工程妥协(优化、开发效率)</div>
+ <div class="fragment" data-fragment-index="3">过度设计</div>
</script></section><section data-markdown><script type="text/template">
+ <div class="fragment" data-fragment-index="0">上层架构和约定应考究</div>
+ <div class="fragment" data-fragment-index="1">细节从权</div>
</script></section></section><section data-markdown><script type="text/template">
## The End
</script></section></div>
</div>
<script src="./asset/md2reveal-0.1.7/lib/js/head.min.js"></script>
<script src="./asset/md2reveal-0.1.7/js/reveal.js"></script>
<script src="./asset/md2reveal-0.1.7/js/md2reveal.js"></script>
<script>
function extend() {
var target = {};
for (var i = 0; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (source.hasOwnProperty(key)) {
target[key] = source[key];
}
}
}
return target;
}
// Optional libraries used to extend on reveal.js
var deps = [
{ src: './asset/md2reveal-0.1.7/lib/js/classList.js', condition: function() { return !document.body.classList; } },
{ src: './asset/md2reveal-0.1.7/plugin/markdown/marked.js', condition: function() { return !!document.querySelector('[data-markdown]'); } },
{ src: './asset/md2reveal-0.1.7/plugin/markdown/markdown.js', condition: function() { return !!document.querySelector('[data-markdown]'); } },
{ src: './asset/md2reveal-0.1.7/plugin/highlight/highlight.js', async: true, callback: function() { hljs.initHighlightingOnLoad(); } },
{ src: './asset/md2reveal-0.1.7/plugin/notes/notes.js', async: true, condition: function() { return !!document.body.classList; } }
// { src: './asset/md2reveal-0.1.7/plugin/math/math.js', async: true }
];
// default options to init reveal.js
var defaultOptions = {
controls: true,
progress: true,
history: true,
center: true,
transition: 'default',
dependencies: deps
};
// options from URL query string
var queryOptions = Reveal.getQueryHash() || {};
var options = {};
options = extend(defaultOptions, options, queryOptions);
Reveal.initialize(options);
</script>
</body>
</html>