以下是我基于nvd3开发组件时的一些心得:
1、任何复杂的图表基本的元素其实并不多(很多复杂的系统都是基于一些简单的规则组合而成),svg中的图形元素大概就以下几种:line、rect 、polyline、 path 、ellipse 、circle ,正如“一生二、二生三、三生万物”所言,我们基于这些元素可以做出很复杂很美观的图表,前提是要对基本的元素灵活应用,了如指掌,所以基于svg做图表库要对svg中的这些基本元素烂熟于心。
2、nvd3是基于d3做的,api风格与d3也是一致的,需要对d3的api很熟悉,最好能系统的看一遍d3的api,不用熟悉每一个方法,但是心里要有个大概印象,知道d3提供了哪些功能,需要使用的时候可以查看具体细节,也可以防止不知道d3的功能而去重复造轮子
3、我们需要熟悉nvd3已提供的组件和nvd3编写组件的风格,与一个组件相关的元素(不限于nvd3):子组件、配置选项、事件、数据、舞台。分别做一下简单介绍,(1)一个好的组件化体系组件之间肯定可以相互组合、搭配使用生成一个更大的组件,所以我们编写的图表组件也是基于一些更基本的组件组合而成,nvd3中一些基本的组件有legend、tooltip、line、axis、multibar、pie等。(2)配置选项,一个好的组件必须有很灵活的配置选项,比如width、height、margin、color、showControls等。(3)组件的相关事件legendClick、elementMouseover.tooltip、renderEnd等。(4)组件要展示的数据,图表没有数据展示个毛。(5)所谓的舞台其实就是指定一个页面上的svg节点,然后组件在这个svg元素下去绘制。
下面是一个组件的使用例子,
chart = nv.models.multiBarPlusLineChart()
这行代码实例化一个组件
.showControls(true) .showLegend(true .controlLabels({ grouped:"分组", stacked:"堆积" }) .duration(200)
这部分代码为组件设置一些配置项
d3.select('#chart1 svg’)
为组件指定舞台
.datum(testdata)
为组件设置数据
.call(chart);
让组件去渲染
d3里为组件设置数据的方式比较奇特,d3.select('#chart1 svg') .datum(testdata),把数据设置到了要渲染的舞台上,组件在渲染的时候自己会去舞台上取数据。
nvd3组件的实现风格:下面是multiBarPlusLineChart的代码
nv.models.multiBarPlusLineChart = function () { "use strict"; //================================== // Public Variables with Default Settings //----------------------------------------------- var multiBar = chart.multibar = nv.models.multiBar() , lines = chart.lines = nv.models.line() , xAxis = chart.xAxis = nv.models.axis() , yAxis = chart.yAxis = nv.models.axis() , yAxis2 = chart.yAxis2 = nv.models.axis() , legend = chart.legend = nv.models.legend() , controls = chart.controls = nv.models.legend() , tooltip = chart.tooltip = nv.models.tooltip() ; var margin = {top: 30, right: 20, bottom: 50, left: 60} , width = null , height = null , color = nv.utils.defaultColor() , showControls = true , showLegend = true , controlLabels = {} , duration = 250 ;
上面第一部分为组件的子组件,第二部分为组件的配置项
lines.clipEdge(true); multiBar.stacked(true); multiBar.duration(0); xAxis.showMaxMin(false);
这部分对子组件进行了一些默认设置
//================================= // Private Variables //-------------------------------- var controlsData = []
这部分是私有变量
function chart(selection){ …. }
这部分就是组件的具体实现,call(chart)时,其实就是调用chart方法
//================================= // Event Handling/Dispatching (out of chart's scope) //--------------------------------------------- controls.dispatch.on('legendClick', function (d, i) { if (!d.disabled) return; switch (d.code) { case 'Grouped': multiBar.stacked(false); break; case 'Stacked': multiBar.stacked(true); break; } chart.update(); });
这部分是监听子组件的事件
chart.options = Object.create({}, { showControls: { get: function () { return showControls; }, set: function () { showControls = ; } } , controlLabels: { get: function () { return controlLabels; }, set: function () { controlLabels = _; } }})
nv.utils.initOptions(chart);
这部分为组件配置项设置set、get方法
nvd3不能直接根据注释生成文档,我们后续可以考虑一下使用jsdoc的注释风格,可以根据注释生成API文档。