D3Charts学习笔记
今天同事GX分享了关于D3Charts的内容,这些我今后都会用到,因此这里做个记录。
程序设计
d3charts是基于百度的ZRender来做的,可以用装修房子来理解:
ZRender:工具箱,里面有各种工具,比如锤子、扳手、螺丝刀……
d3charts:小物件,比如凳子、桌子、床……
产品:房子
d3charts, 底层依赖矢量图形库zrender,提供直观、交互丰富、可定制化的数据可视化图表。对渲染引擎支持的基本元素、绘制特性、用户交互事件以及图形动画进行封装。提供如矩形、圆形、扇形等基本图形,并支持图形的组合和删除,最终以Canvas内容进行输出。
整体的架构设计如下图所示
执行流程
- D3charts.init的过程
- 初始化一个
Zrender实例,提供绘制元素、用户交互事件以及图形动画 - 初始化
Zrender事件 - 创建全局管理GlobalModel,存储
图表和组件的属性,依靠存储属性进行后续渲染工作 - 创建zr.animation,监听组件
isDirty属性,来触发视图更新 - 返回chart实例
- 初始化一个
- Chart.setOption
- 清空原有内容
- 调用GlobalModel.setOption,对每一个Model的option进行处理、合并默认配置项、设置新的配置项。
- 遍历GlobalModel将图表和组件设置为
脏,触发下一帧组件的更新 - 遍历GlobalModel初始化每个Model对应的View
- 下一帧,由于脏位的设置,导致zr.animation中update函数的触发、接着调用doRender函数
- doRender函数调用每一个组件View文件中的render方法进行视图渲染
- 在每一个组件的render方法中首先需要通过model获取option对象的配置内容
- 调用ShapeStorage封装的
setShape函数或者setShapeStorage函数,函数内部的实现即调用zrender中的attr绘图函数、animateTo函数
图形扩展
- 图形的扩展
每个图表或组件包括ExampleModel.js和ExampleView.js以及index.js三个文件。
图形扩展流程图如下图所示。
- 图形事件的外部扩展
- 在
ExampleView.js中实现图表和组件相关事件 - 外部人员通过
registerAction注册事件、dispatchAction触发事件中的回调函数做相应的操作
- 在
数据结构(配置项)
axisPointer
grid
tooltip
dataZoom
series
markArea(这个有点特殊,data是配置在其内部的,不是外部的)
markPoint
animation
data
重点概念
组件(component)
组件的源码位于src/component/下面
每个组件都有一个type属性,标志其是什么类型,比如Legend的type=”legend”,这个值是定义在model中的。
组件相关的类,继承关系如下(以Legend为例):

数据模型(model)
数据模型,主要是指配置项,注意不包含具体的data
视图(view)
展示相关的部分,根据model进行渲染
组(Group)
Group是ZRender里面定义的一个数据存储结构,作用是将一组Shape进行打包,当成一个整体来处理样式、位置、事件等。
以图Legend中的每一个小图例为例,先来一张图来进行说明:

这个图包含了2个小图例的示例,上面一个是图标形式的图例,图标+图标文本这2个元素,构成了一个Group。
而整个Legend其实是有多个这种小图例的,所有的小图例又会构成一个Group。因此有时候Group是会层层嵌套的。
包围盒(BoundingRect)
图上一个/一组内容的边界,我们可以通过BoundingRect获取到元素的位置信息(x、y)和宽高信息(width、height)。
比如我们要获取页面上的Legend的BoundingRect信息,可以这样:
1 | |
因为LegendView的内容都是放在group中的,因此这里是先获取group属性,在group属性上调用getBoundingRect()方法。
update函数
render函数
配置说明
配置项主要由数据配置项与图形配置项构成
所有的根节点配置(series、axis、markLine等等)都是个数组。
(TODO)data-数据配置项
1 | |
data可以在好几个地方出现;出现的位置不同,其作用域也会有差异。
在根配置中出现,和series和axis同级
这种情况可以在series和axis中使用dataKey和$dataIndex来确定使用具体哪个数据。
dataKey是数据键值,与$dataIndex搭配使用,从数据源中获取的对应的数据信息
若数据源为对象(object)形式,即为对象的键值(key); 若为数组,则是数组下标(0、1、2、…)
配置到具体的series和axis中
这种情况,只能在这个具体的series或者axis中生效,不能在其他地方通过dataKey和$dataIndex进行调用。可以理解为一个局部作用域的data。
originData
既然已经有了data,那么为什么还有originData呢?二者有何区别?
另外data下面也有一个originData属性,这又是为了做什么呢?
询问了ZP,原来这是为了兼容两套写法,可能之前不同的同事有不同的偏好。这算是一个错误的设计吧。
目前推荐的用法,还是上面示例的这种,data内部包含originData。
【重要】$dataIndex、dataKey与axis、series、markLine的关系
文档:https://datav.iwencai.com/platform/doc/configdoc/
数据源的概念
可视化组件是数据驱动渲染的,那么想要画出来各种元素,就肯定得有一个将数据和这些元素绑定的环节。D3Charts中的数据绑定,主要就是依赖于$dataIndex、dataKey、$seriesIndex、$axisIndex、$axisPointerIndex、$gridIndex、$dataZoomIndex等这些配置项来实现的。
数据源是通过data这个一级配置项来指定的,可以同时有多个数据源:
1 | |
关于originData这个特殊的键名:
数据源配置
$dataIndex
数据类型:number
数据源索引,与data配置项联合使用,注意这是一个number数字。
我们设计了可以有多个数据源,所以需要有索引的设计。
1 | |
dataKey
数据类型:number|string
数据键值,与$dataIndex搭配使用,从数据源中获取的对应的数据信息
若数据源为对象(object)形式,即为对象的键值(key); 若为数组,则是数组下标(0、1、2、…)
比如dataKey为键名的情况:
1 | |
比如dataKey为下标的情况:
1 | |
数据依赖配置
数据依赖配置用于指定当前配置的这个元素,其数据源依赖于某个其他已有的元素。
$axisIndex
数据类型:number| Array
该配置一般出现在axis、markLine、markPoint、markArea、tooltip等配置中。
注意这个配置的数据类型有点特殊,可以是一个数组。
当其值是数组时,一般包含2个值,一个代表x轴的下标,一个代表y轴下标。当然,也可以设置3个甚至更多的值。
数组情况多用于axisPointer、series、markLine等,用于确定该元素依赖于哪些坐标轴,也就是用哪些坐标轴的数值来展示该元素的数据,比如下面这样:
1 | |
$seriesIndex
图形配置项

- 系列配置项
- series:系列,如柱状图(bar)、折线图(line)、饼图(pie)等,如下图所示。

- series:系列,如柱状图(bar)、折线图(line)、饼图(pie)等,如下图所示。
- 坐标系配置项
- axis:坐标轴
- axisPointer:坐标轴指示器
- grid:绘制区域
- 组件配置项
- title:标题
- legend:图例
- tooltip: 提示框
- markPoint: 标注
- timeLine:时间轴,提供d3charts在多个option之间切换、播放的功能

- dataZoom:数据区域缩放,帮助用户可以关注细节主体、概览整体、去除一些离散点的影响

- visualMap:视觉映射,将数据映射到视觉元素

- 后期datav文档中组件配置项可参考系列配置项,帮助用户快速定位配置项在文档中的位置,配置项内容可以设计对应
icon
数据
如何更新图表数据?
通过setOption()方法,传入新的配置,进行更新。
假如页面上已经做了一个饼图(图表变量是chart,配置变量是option),现在要更新其数据,可以这样设置:
1 | |
注意setOption()要传入一个完整的配置信息,不能只传入类似这样的简略信息:
1 | |
(TODO)如何将series的数据转为坐标数据?
事件
事件是在src/action/event.js中定义的,这个文件给每个类型的组件都定义了可以支持的事件列表,然后在对应组件的view中注册事件监听。
view中的代码类似这样:
1 | |
global是Charts对象,在src/d3charts.js中定义。registerAction的源码如下:
1 | |
而这个Charts是继承自ZRender的src/mixin/Eventful类的,是林峰写的,其on方法的实现如下:
1 | |
怎么注册事件?
1、获取对应的model
1 | |
2、注册事件监听
1 | |
这里再给一个给markpoint绑定点击事件的例子:
1 | |
(牛逼)时间触发机制(trigger)与切面拦截方法
zrender的src/mixin/Eventful中实现了trigger,而D3Charts的Charts类继承了这个Eventful类。
所以我们可以通过拦截trigger函数,加入一些我们自己的逻辑进去:
1 | |
如何触发自定义事件?
在view的render()方法中,可以看到,其实是通过监听浏览器默认支持的事件,然后手动调用global.dispatchAction()方法来触发组件事件的:
1 | |
这里的shape,是LegendItem对象,每一个LegendItem对象,对应一个Legend数据,因此有几个图例,初始化view的时候就会执行几次事件绑定操作。
我们支持注册哪些事件?
在控制台打印D3Charts.action,可以看到每个元素支持的事件。
可以先看一遍src/action/event.js中定义的事件。
事件对象提供了哪些属性?
了解这个很重要,因为这决定了我们触发事件后可以做哪些事情。
通过上面的代码,打印出来的e就是事件对象,可以查看其属性来进行了解。

像这里有offsetX、offsetY属性,表示点击位置的x、y值,可以用于做一些特殊交互效果,比如在点击的位置出现一个tip。
legend点击事件
禁止左右滑动页面(解决在canvas元素上滑动时,触发页面前进后退的问题)
可以通过禁用默认的touchmove事件来解决:
1 | |
PS:常规app中,快速滑动的意图就是翻页,所以图表应该对touch事件做个处理:当用户按下超过一定时间时,才触发图表内部的事件;如果是快速滑动,则触发浏览器本身的事件。
延迟交互(移动端通用交互方案)
自定义元素的缩放跟随
比如散点图,要求绘制自定义的图形元素,改元素的定位和具体的散点绑定,当缩放平移时要随之同步移动。
方案一:如果有父group,则跟随父group移动
方案二:拦截缩放事件,重新定位
动画
自定义动画,经常会用到遮罩层+裁剪框来解决。
因为D3Charts有layer的设计,因此裁剪框是可以和series处于同一层级来对齐的,不用担心会把坐标轴给遮住了。
也可以由业务代码来进行裁剪框的位置计算,确保裁剪框大小和想要遮住的图形完全匹配。
如果想要关闭动画,设置option.animation = false即可。
折线图从左到右显示的动画
可以通过控制一个遮罩的矩形的动画来实现:
1 | |
鼠标
禁用鼠标滚动
通过option.preventDefaultMouseWheel进行配置。默认是true,即在图形区域滚动鼠标,只会操控图形,不会滚动页面。
坐标系
获取鼠标点击位置的坐标值
1 | |
富文本标签
为什么要叫富文本标签?因为这个只对label生效。
我们这个是完全参考ECharts的富文本标签的设计,因此可以查看ECharts的文档:https://echarts.apache.org/zh/tutorial.html
示例代码如下:
1 | |
注意我们的富文本标签比ECharts弱很多,他们在ZRender之上做了一些关于富文本标签的强化,特别是背景、位置这一块。如果我们想要修改位置,只能通过调整textLineHeight、textPadding等属性进行有限的修改;position和padding是无效的,这种只对legend有效,即本质是对图形上面画文本的这种有效果。
常见配置问题
我通过二个单词量统计和一个上证估值的图形来实践这些配置:
单词量统计:
------上证估值:
------style自定义样式
注意:style整体支持自定义函数,但是style下面的子属性是不支持自定义函数的。
比如这样是错误的:
1 | |
这样才是正确的:
1 | |
颜色
渐变
通过series[x].itemStyle.nomal.fill.colorStops进行配置:
1 | |
线(Line)
折线的点怎么显示?
series.symbol相关的配置。
比如我要配置点的形式为圆圈,且在鼠标选中时变成实心填充,那么可以在series[x]下面这样配置:
1 | |
如何画虚线?
series下面的line下面的lineDash:
1 | |
如何画横线?比如中位数
option[x].markline
1 | |
如何将折线图配置成阶梯状的图形?
通过series[x].curve.type属性进行配置,将其设置为step即可。
如果发现一字板涨停的,线贴到了底部的轴上面,可能是因为 Y 轴设置了最大最小值;这种情况应该要自定义一个 y 轴的 tickValues,因为 y 轴就一个数值。
如何分段着色?
通过series[x].piece来设置,这个值是一个数组。
这个是参考百度的配置的:*//echarts.baidu.com/option.html#visualMap-piecewise.pieces*
参考示例://datav.iwencai.com/platform/chartconfig.html#chartId=229
1 | |
如何让图形和顶部贴合(涨停价)

比如上图就是没有贴合的,这不符合我们的客户端效果。
可以通过将yaxis的domainScale设置为1来实现。
如果是一字板涨停,用上面的方式就行不通了,因为一字板涨停只有一个数值。
针对这种情况,我们需要在图表上,将昨收也画出来,只画一个点,这样和今天的涨停价形成差异,就可以把涨停价画到最上面了。
图形把tooltip遮住了

类似这种,而且这个问题只有在ios13的机型下才会复现。
这可能是因为设置了transform: translateZ,导致z-index失效了。
可以给父级设置overflow: hidden试试。
柱子(Bar)
修改柱子宽度
调整series[x].rectWidth属性,仅适用于x轴为连续类型坐标轴(linear、time等),也就是说你得把x轴的axis的type属性设置为linear或者time。
而柱状图一般都是非连续类型的坐标轴,因此设置其宽度,不能通过rectWidth来实现。我们是通过axis[x]下面的paddingInner和paddingOutter这2个属性的百分比计算来实现的。
还有一种奇特的思路:可以考虑扩充data数据到最小长度(比如给三个柱子的数据但是首位柱子不进行绘制)来做处理。
做出左右布局的柱子效果

想要做出类似上图的效果,可以将下面几个柱子的数值乘以-1
柱子的圆角配置
可以通过bar.rectRadius进行配置。
数值的形状
通过series[x].symbol进行配置
tooltip
tooltip常见的问题是定位,比如最近贝贝问到的:
画图这个tooltip,目前交互规范是手指放在右边tip提示显示在左上方,手指在左边tip显示右上方,如果要实现这种,你们这边有什么方法吗?
类似这样的效果:http://testm.10jqka.com.cn/mobile/info/f10_front/dist/index.html#/cashflowchart
可以通过给tooltip的position属性传入一个function来实现:
1 | |
注意这种方式,仅限有双Y轴的图形。
单Y轴的图形,会因为右侧预留了一块Y轴区域,导致tooltip显示在右侧时,会超出grid范围。
还可以这样通过获取各个元素的包围盒,计算后得出tooltip的位置:
1 | |
图例(Legend)
图例太多,显示不下怎么办?
可以获取图例的高度,然后将作图区域下移即可,如下为相关的代码:
1 | |
网格grid
双y轴如何只设置一种分割线?
在axis对应的轴设置splitLine: {show: false}
数值
如何对数值做精度处理?
如果是想对坐标轴的数值做处理,可以在option.axis[x].lable.formatter中进行配置
默认展示的数值:
series[x].label.nomal.formatter
鼠标移上去出现的数值:
series[x].label.emphasis.formatter
如何限制显示的数值的最大值/最小值?
axis[x].max
axis[x].min
如何让包含负数的图形,将负数展示在下方区域?
axis[x].line.onZero = true
这个是只针对柱状图的,折线图没有这个需求
如何让线/柱子上的数值一直显示?
如果是柱状图,配置series[x].label.show=all即可
如果是折线图,必须要把symbol开启(配置series[x].symbol.nomal.show=all), 如果不想看到它可以把size设成0。
1 | |
show=all 表示一直显示
show=true 会根据数量自动选择一部分显示
如何配置对数数值?
对数数值要注意负数的情况。
同事ZHQ采用了一个很牛逼的思路:先将数据做对数处理,然后用处理完的数据,做一个线性比例尺,再作图。
坐标轴
自定义label样式
可以通过将lable的style设置为一个Lambda函数来实现个性化样式:
1 | |
数值倾斜
axis[x].lable.rotate 设置倾斜角度
1 | |
自定义坐标轴显示的刻度(数值和数量)
可以先通过你传入的data计算一下你希望显示的x轴上标签的数量和内容,然后通过axis[x].tickValues传入这个数组。
可以参考这个Demo,tickValues取均值显示。
另外还可以设置interval属性来控制显示的坐标值的间隔,比如设置为2,就可以每2个才显示一次:

不显示坐标轴
1 | |
默认选中某个axisPointer
1 | |
待补充
axisName
tick显示具体某几个值splitNumber、tickValues
回调中的domain
标记线(markLine)
如何绑定数据?
注意事项
markLine一定得定义2个点
markLine如果设置了yValue就不需要和series绑定了(即无需配置$seriesIndex),因为和series绑定就是为了确定Y的值
(待定)markLine中的value,似乎是定义标签内容的,不是确定线的位置的
1 | |
标记点(markPoint)
自定义图标
这部分内容摘自Echarts的文档。
考虑到通用性和扩展性,一般图标我们都是采用svg和自定义图片来实现的
svg就是用户自己传入一个图标的path标签的d路径的值;
自定义图片就是用户传入一个图片的url,一般可以通过 'image://url' 设置为图片,其中 URL 为图片的链接,或者 dataURI。
URL 为图片链接例如:
1 | |
URL 为 dataURI 例如:
1 | |
可以通过 'path://' 将图标设置为任意的矢量路径。这种方式相比于使用图片的方式,不用担心因为缩放而产生锯齿或模糊,而且可以设置为任意颜色。路径图形会自适应调整为合适的大小。路径的格式参见 SVG PathData。可以从 Adobe Illustrator 等工具编辑导出。
例如:
1 | |
给指定的数据设置相同的markPoint
给指定的数据设置不同的markPoint
http://datav.iwencai.com/platform/chartconfig.html#chartId=261
可以通过label.nomal.formatter来设置
如何让svg画的markPoint的边框自适应文字的大小和高宽?
svg是不能自适应文字的,因此这个需要动态计算。
方案一:可以拿到scale,算出x,y,然后自己通过dom实现定位,加上去;然后监听缩放事件,每次触发缩放,重新获取每个元素的位置,去设置自定义的dom的位置。
方案二:动态计算svg的path的值,给不同长度的文本,生成不同大小的外框。
(TODO)通过重绘markPoint实现每个图形加一些特殊效果
参考郑浩琦的例子。鼠标滑过每个柱子时,修改markPoint的数据,进而数据驱动图形变更。
堆叠图
在series下的每个图的配置中,增加stack属性即可,其值可以随便写,类似这样:
1 | |
缩放
字体
如何解决引入的字体文件非https协议的问题?
可以引入这个css文件来解决:
1 | |
兼容性问题
K线的tip在iOS上,文字会下移

如果是字的话,可能是安卓使用微软雅黑默认字体,会稍稍偏上一点(安卓的微软雅黑居中就是偏上一些的,所以一般是建议设置固定字体)
解决方法可以是换一个字体试一试。
如果还是不行,可以试试设置textStyle: {y: 3}
其他问题
程序入口在哪里?
HTML页面上初始化D3Charts的时候:
1 | |
不过d3charts.js这个文件中,并未注明导出的类名是D3Charts,那么是在什么地方配置这个类名的呢?
TODO: 不知道是不是在build/pack.js中构建时定义的。
View是怎么最终渲染到页面上的??
TODO : 好像是通过View的setShape方法,传入配置作图的。这个方法实际上是在ShapeStorage这个类中定义的。
这个方法会传入配置数据、图形类型(比如Rect、Circle),然后由对应图形的类去做渲染操作。这个设计很不错,将数据和渲染分离了,采用了配置化思维。
所有shape都是相对父元素做的绝对定位(left, top),因为这是用Canvas实现
render()何时被调用?
是d3charts.js中的update()方法调用的,在下面三种场景会触发:
1、初始化
初始化D3Charts的时候,在构造函数里面,通过zr.animation.on注册了每一帧的事件监听,一旦发现model中有脏数据,就会触发重新渲染。
页面初始化时的渲染,虽然程序中有显式调用chart.setOption()方法,但是实际上仍然是通过frame事件触发的;页面内容修改后,比如我点击一个legend使其不显示,也仍然是触发了frame事件进行的渲染。
2、setOption()
3、resize
TODO : ZRender也有resize,稍后看下怎么实现的:
1 | |
脏(dirty)的设计
这个设计来自ZRender,不是我们自己想的。
(TODO)控制台这么多默认输出,怎么清理掉?
为什么LegendView中会传入seriesModel对象?
因为Legend的有些配置,是直接根据series来设置的,比如图例的颜色、名称等等。因此这个seriesModel不可或缺。
(TODO)为什么Echarts的源码无法点击跟进,而D3Charts可以?
不是全部都不可用,是有的可以有的不行。
TODO : 需要找到原因。
Echarts的defaultOption的设计?
不是作为类属性,只是默认值而已。
TODO : 应该在extendComponentModel中有自动将未定义的属性挂上去的操作吧?
为什么import的ZRender里面的内容无法跟进去?
为什么VSCode只显示一个打开的文件?
如何阅读源码?
1、从页面元素的渲染入手
2、从事件触发后的流程入手
如何修改某个元素的定位?
获取元素的model引用
1 | |
获取位置信息
通过事件来获取:
1 | |
修改定位信息
比如修改坐标信息、样式信息。
不能直接通过model.xxx来修改model的属性,因为这样不会触发重新绘制;必须通过model.set()来设置。
(TODO:未生效)tooltip没有left和top,但是有offset属性和position属性,默认position=undefined
1 | |
legend的group有left和top属性,但是没有offset属性;有个position属性,里面包含left、right、top、width:
1 | |
series的定位,则不同形状不一样,以弧形来说,就是修改其center属性,即圆心位置:
1 | |
怎么在触发事件后,显示tip/如何定位tooltip?
(TODO)怎么实现各种圆润的动画?
比如tip的浮动、出现、隐藏等等,要有平滑感和科技感
我们的移动端是怎么实现的?也是media么?
不是,我们没有考虑自适应,是通过应用方自己设置高宽来解决的
我们的D3Charts是基于ZRender哪个版本?相当于Echarts哪个版本?
ZRender4.0.7,是2019.02.25发布的,算比较新的
(TODO)Canvas的重绘到底有多高效?我看拖拽这种是每次都会重绘,为什么我之前画的那个棋盘就很卡呢?
我们有grapic么?
没有,不过有markpoint可以自定义形状,但是注意这个markPoint是series的下属属性,而grapic是和series平级的属性,可以在画布上随意画图形
ECharts也有markPoint
我们的可视化新人培训教程,看是否科学
时间上感觉够呛,还有就是参考资料不够多,估计还是需要一对一讲解把。
我缺少了CSS、JS基础、行情图、数据池、扩展、实践等内容
如果我去教别人用d3charts,我会怎么教?
难在入门。一旦入门,就很简单了。
入门阶段不要怕问人,这个阶段问人的性价比极高。
名词定义
设计原理
常用配置的实现
把这个页面的图形,都去配置一遍:
//activity.10jqka.com.cn/acmake/cache/523.html#/index
概念名词和API讲解
这个过程可能会比较痛苦一些,尽量压缩在一两天内完成,然后借助Anki背诵、复习、记忆。
要想玩的溜,必须要把小的东西(名词、常用概念、常用API)掌握得特别熟。这一关免不了。
跟着上面的执行流程走一遍代码
遇到问题怎么查资料?
时间评估
SXY:
从开始接触d3charts到画出竹节图,大约耗时2周
这次的Legend实现,SXY评估需要3天
如何编写新的组件?
README文档
文档先行,这是首要原则。
跟业务方的开发确认好API后,就不要改动API了,不然别人使用会很麻烦。
如何编写组件
我们有一个组件模板,通过该模板编写成npm组件,上传到公司内部的组件库,其他部门的同事就可以安装使用了。
内部npm仓库:
1 | |
上传npm的组件,推荐使用 thsc-datav-xxxx格式的命名,比如thsc-datav-waterwave,避免和第三方组件重名。
可以参考这个组件。
如何上传组件Demo到datav平台?
具体信息见我的Evernote笔记《如何上传组件到datav?》
后台地址:https://172.20.207.139/zfontology/
这个后台是用Zend框架写的,和问财其他后台耦合到一起了目前暂时不接过来,由张浩继续维护;后面有大的修改再接过来,用Node重写下。
Demo的源码在http://gitlab.10jqka.com.cn/datav/chart-config-doc这个项目下:
- chart-config:Demo
Demo右侧的代码编辑区域,是通过Code Mirror插件实现的。
最近增加了配置高亮功能,是根据url参数,添加class样式高亮来实现的。
- chart-config-better:ZHQ弄的高性能版
- chartPlatform:文档类的都在这里
文档类的,是先通过js文件编写,然后通过工具转为markdown格式,再通过工具转为html格式的。
极大提升表现力的技巧
D3Charts+自定义DOM元素+定位
如果你想要在页面上展示一些很个性的内容,那么可以这样处理。
比如下面这个图:

就可以获取“持仓占比XX%”这个label的位置,然后自己定义一个DOM,放到左侧或者右侧,展示类似“货币基金”那一块的内容。
获取label位置的代码如下:
1 | |
如何解决布局问题?
个性化问题,绝大部分都是布局问题和局部元素的定制化问题。
如果我能够把这2个问题抽象出来解决掉,那就可以极大扩展D3Charts的能力了。
比如下面这个需求:

这就是一个布局问题,不同的数据,布局不一样。这种如何方便、可扩展的实现呢?




