echarts 怎样用js自定义图表数据

JavaScript016

echarts 怎样用js自定义图表数据,第1张

引入ECharts

echarts提供多种引入方式,请根据你的项目类型选择合适的方式:

模块化包引入

如果你熟悉模块化开发,你的项目本身就是模块化且遵循AMD规范的,那引入echarts将很简单,使用一个符合AMD规范的模块加载器,如esl.js,只需要配置好packages路径指向src即可,你将享受到图表的按需加载等最大的灵活性,由于echarts依赖底层zrender,你需要同时下载zrender到本地,可参考demo,你需要配置如下。

需要注意的是,包引入提供了开发阶段最大的灵活性,但并不适合直接上线,减少请求的文件数量是前端性能优化中最基本但很重要的规则,务必在上线时做文件的连接压缩。

//from echarts example

require.config({

packages: [

{

name: 'echarts',

location: '../../src',

main: 'echarts'

},

{

name: 'zrender',

location: '../../../zrender/src', // zrender与echarts在同一级目录

main: 'zrender'

}

]

})

模块化单文件引入(推荐)

如果你使用模块化开发但并没有自己的打包合并环境,或者说你不希望在你的项目里引入第三方库的源文件,我们建议你使用单文件引入,同模块化包引入一样,你需要熟悉模块化开发。

自2.1.8起,我们为echarts开发了专门的合并压缩工具echarts-optimizer。如你所发现的,build文件夹下已经包含了由echarts-optimizer生成的单文件:

dist(文件夹) : 经过合并、压缩的单文件

line.js : 折线图(如需折柱动态类型切换,require时还需要echarts/chart/bar)

bar.js : 柱形图(如需折柱动态类型切换,require时还需要echarts/chart/line)

scatter.js : 散点图

k.js : K线图

pie.js : 饼图(如需饼漏斗图动态类型切换,require时还需要echarts/chart/funnel)

radar.js : 雷达图

map.js : 地图

force.js : 力导向布局图(如需力导和弦动态类型切换,require时还需要echarts/chart/chord)

chord.js : 和弦图(如需力导和弦动态类型切换,require时还需要echarts/chart/force)

funnel.js : 漏斗图(如需饼漏斗图动态类型切换,require时还需要echarts/chart/pie)

gauge.js : 仪表盘

eventRiver.js : 事件河流图

treemap.js : 矩阵树图

venn.js : 韦恩图

echarts.js : 这是包含AMD加载器的echarts主文件,需要通过script最先引入

chart(文件夹) : echarts-optimizer通过依赖关系分析同时去除与echarts.js的重复模块后为echarts的每一个图表类型单独打包生成一个独立文件,根据应用需求可实现图表类型按需加载

source(文件夹) : 经过合并,但并没有压缩的单文件,内容同dist,可用于调试

采用单一文件使用例子见ECharts单一文件引入,存放在example/www下,首先你需要通过script标签引入echarts主文件

//from echarts example

<body>

   <div id="main" style="height:400px"></div>

   ...

   <script src="./js/echarts.js"></script>

</body>

在主文件引入后你将获得一个AMD环境,配置require.conifg如下:

//from echarts example

<body>

   <div id="main" style="height:400px"></div>

   ...

   <script src="./js/echarts.js"></script>

   <script type="text/javascript">

       require.config({

           paths: {

               echarts: './js/dist'

           }

       })

   </script>

</body>

require.config配置后就可以通过动态加载使用echarts

//from echarts example

<body>

   <div id="main" style="height:400px"></div>

   ...

   <script src="./js/echarts.js"></script>

   <script type="text/javascript">

       require.config({

           paths: {

               echarts: './js/dist'

           }

       })

       require(

           [

               'echarts',

               'echarts/chart/line',   // 按需加载所需图表,如需动态类型切换功能,别忘了同时加载相应图表

               'echarts/chart/bar'

           ],

           function (ec) {

               var myChart = ec.init(document.getElementById('main'))

               var option = {

                   ...

               }

               myChart.setOption(option)

           }

       )

   </script>

</body>

总结来说,模块化单文件引入ECharts,你需要如下4步:

为ECharts准备一个具备大小(宽高)的Dom(当然可以是动态生成的)

通过script标签引入echarts主文件

为模块加载器配置echarts的路径,从当前页面链接到echarts.js所在目录,见上述说明

动态加载echarts及所需图表然后在回调函数中开始使用(容我罗嗦一句,当你确保同一页面已经加载过echarts,再使用时直接require('echarts').init(dom)就行)

详见入门教程 ( Getting started ) »

标签式单文件引入

自1.3.5开始,ECharts提供标签式引入。如果你的项目本身并不是基于模块化开发的,或者是基于CMD规范(如使用的是seajs),那么引入基于AMD模块化的echarts可能并不方便,我们建议你采用srcipt标签式引入,忘掉require。Srcipt标签引入echarts后将可以直接使用两个全局的命名空间:echarts,zrender,可参考ECharts标签式引入,需要注意的是excanvas依赖body标签插入Canvas节点去判断Canvas的支持,如果你把引用echarts的script标签放置head内在IE8-的浏览器中会出现报错,解决的办法就是把标签移动到body内(后)。

标签式引入环境中,常用模块的引用可通过命名空间直取,同模块化下的路径结构,如:

echarts.config = require('echarts/config'), zrender.tool.color = require('zrender/tool/color')

//from echarts example

<body>

   <div id="main" style="height:400px"></div>

   ...

   <script src="example/www2/js/dist/echarts-all.js"></script>

   <script>

       var myChart = echarts.init(document.getElementById('main'))

       var option = {

           ...

       }

       myChart.setOption(option)

   </script>

</body>

○  触发:监听、单击、联动

○  反应:赋值、透明度、文本、停止、颜色、旋转、排序、重置

○  变量:数字变量及其计算表达

在计时器的三大流程(设置时间➡计时过程中➡时间到达提示)中,设置时间流程中,用户操作按钮显示“开始”和“取消”,其中取消按钮不可用。计时开始后,操作按钮变为“暂停”和可用的“取消”按钮,用户点击“暂停”按钮使计时暂停及继续,同时按钮文本也会随点击在“继续”和“暂停”中进行切换;用户点击“取消”,本次计时操作不再进行,回到计时开始前的设置时间页面。时间到达后,页面中其他按钮消失,显示“确定”按钮,点击确定使计时器回到初始状态。

滚动选择器是手机端常见的一种选择器,选择器会罗列所有的选项,用户可以通过滚动拨盘确认所需要的具体项。在实现的思路上,先利用protopie中滑页容器层实现按档位的滑动效果,而后可以通过联动触发将滑页值与具体选项的值关联起来。如果滑动过程中需要进行尺寸和透明度变化使其更接近真机效果,理论上也可以通过联动层进行设置。

计时器的剩余时间与之前时钟和秒表的案例正好相反,属于倒数计算,而且具体剩余时分秒数值的显示需要涉及时间单位的换算。首先将滚动选择器选定的时分秒数值统一换算成总秒数,才可以通过每秒-1实现当前剩余时间计算。然后需要将这个剩余时间再转换为时、分、秒的显示,这里利用了Protopie的数学函数floor()的取整函数。举例来说,当剩余时间为12340秒时,其中小时数为floor(12340/3600) → 3小时,分钟数为floor((12340-3*3600)/60) → 25分钟,秒数12340-3*3600-25*60 → 40秒,可以表达为03:25:40。

在实现剩余时间的环状百分的实现上最大的难点在于Protopie中对图形描边的设置只有颜色、透明度、位置和宽度可以设置,想要实现最终效果上的环状百分比图的效果需要使用一些障眼法,对环状图进行切分后做旋转设置。

有两种思路:

a.将黑色圆环做切割后做旋转设置。具体切割方法见下图说明将圆环不断进行对半切割,实现效果就是将1号线段先进行角度旋转后,当其旋转180度后隐藏并开始旋转2号线段,旋转90度后隐藏开始旋转3号线段,以此类推。(我实现过程中发现这种方法图层很多,管理起来太复杂基本pass这个方案,有兴趣的可以自行尝试)

b.将黑色圆环做对半切割,左右分别做旋转设置,同时在左侧增加与背景一致的遮挡图层,使得右半侧圆环可以旋转入内,具体图层关系如下。这样图层管理更便捷,下面的具体实现步骤中使用的就是这种方法。

新建Protopie文件,实现滚动选择器及按钮的基本视效。

○  建立秒选择、分钟选择、小时选择三个滑页容器层,高度可以显示7个文本高度,将0-59、0-59、0-23的多层文本层分别放置其中。并将滑页设置如下,自定义高度为文本高度,案例中为40 。由于第一个文本和最后一个文本都需要滑动到中间的位置,所以还需要在文本前后,加上段前和段后的与背景色一致的矩形,高度为3个文本高度。

实现滚动选择器的滚动渐变效果,并建立三个变量分别命名为 hour 、 min 、 sec 使变量与滚动选择器选择的小时、分钟、秒数关联起来。

○  在滚动选择器滚动过程中的渐变效果有两种实现方式:

方式一:通过联动滑页容器的滚页值与单个具体文本的透明度进行联动设置,具体设置如下,但是这个方法需要对滑页容器中每个文本进行单独设置,较为繁琐,不建议使用。

方式二:可以直接在滚页容器层上添加背景色渐变的蒙版,模拟渐变效果。

○  利用联动将变量 hour 、 min 、 sec 与滚动选择器选择的小时、分钟、秒数关联起来。由于我们自定义了每次滑页值,所以可以直接使用单条联动范围设定,对应可以直接得到整数值。实现这一步后可以开启变量显示,预览一下具体效果。

新建变量 all 、 now ,对应用户设定计时的总时长和当前剩余时长。使用户点击“开始”后支持计时倒数,而开始后也支持计时的暂停、继续及取消。

○  当用户设定的时间为0时点击“开始”不起效,为了进行操作判断,变量 all 的即用户设定的总时长最好是可以在用户滚动时可以直接进行赋值计算,所以首先对变量 hour 、 min 、 sec 添加监听,每次变化都对变量 all 进行一次赋值,表达式: (hour*3600)+(min*60)+sec

○  对开始的文本添加单击触发,当文本为“开始”且变量 all≠0 时,对变量 now 进行两次赋值,首先使其等于变量 all 的值,而后使其0.01秒减少0.01,延迟0.01进行,这边使用0.01的时间精度使得暂停和继续不用做复杂单秒内的时间判断。

○  当文本为“暂停”时停止变量 now 的倒数计时;当文本为“继续”时重新进行每0.01秒减少0.01,延迟0.01进行的设置。

○  最后对这几种状况的文本内容、文本颜色、文本透明度进行设定将操作连贯起来。

将设定时间的滚动选择器隐藏,并剩余时间的数字表达和环形百分比资源导入,以实现倒计时过程中的基本视效。

○  数字表达中需要拆分时分秒,使用不同的文本图层

○  环形百分比主要分为三部分:①运动点&固定点,实现描边的圆角效果;②右半圆环分为底部黑色圆环和上部白色半透遮挡层(旋转180°、默认透明度0%);③左半圆环分为底部黑色圆环和上部白色半透遮挡层(旋转180°、默认透明度90%)。由于图层关系,默认效果显示为一个黑色正圆。

新建变量 ceilnow 、 lasth 、 lastm 、 lasts ,计算具体的剩余时间,将计算时间换算并显示为具体文本,实现计时过程中数字计时部分。

○  由于变量 now 之前设置中计算精度为0.01秒,所以计算剩余时间时先要进行一次去小数点后整数进一的设置,利用 ceil() 表达式,并复制给变量 ceilnow 。

○  结合前文对时间换算的思考,增加对变量 now 的监听触发,对变量 ceilnow 、 lasth 、 lastm 、 lasts ,分别进行赋值设置。

         变量ceilnow=ceil(now)

         变量lasth=floor((ceilnow/3600))

         变量lastm=floor((ceilnow-3600*lasth)/60)

         变量lasts=ceilnow-3600*lasth-60*lastm

○  对变量 lasth 、 lastm 、 lasts 添加监听,对时分秒的文本内容进行设置,使其在显示上永远显示00:00:00的六位格式。

实现倒计时过程中,环形剩余时间百分比的显示。

○  首先是圆环边缘圆角的小圆点的旋转设置,在对变量 now 的监听触发下增加运动点的旋转设置。使其旋转角度与剩余时间与设定时间的比例相关,旋转至使用表达式 (now/all)*360

○  然后是左右半圆的旋转设置,案例中主要是对白色半透遮挡层进行旋转设置。左右半边的旋转看为两个阶段,使用条件判断后进行设置。A.当变量 now>all/2 时,增加排序的设置,将左侧半圆及其遮挡层放置于右侧半圆及遮挡层之后,右侧半圆遮挡透明度设为0%,再添加左侧遮挡的旋转表达式,案例中使用的是 (now/all)*360-180 ,实际的话需要结合各自使用的切图资源。B.变量 now<all/2且≥0 时,增加排序使得右侧半圆及其遮挡层放置于左侧之后,将右侧半圆遮挡透明度设为90%,使其显示并添加与右侧一致的旋转表达式。

○  设置完成后测试了一下,对几个节点值再增加旋转设置以保证效果:①当变量 now =变量 all 时,即用户开始计时的时候将左右半圆的上层遮挡均设为不被遮挡。②当变量 now = all /2 时,再做一次左右遮挡的旋转设置,使其显示为左侧完全遮挡、右侧完全显示。③变量 now =0且开始文本内容为“暂停”时,停止变量 now ,并且将右侧的遮挡半圆完全遮挡右侧半圈。

增加“时间到!”文本和“确定”按钮,当到达计时时间时显示出来。确认按钮支持点击操作,实现完整的操作逻辑。

○  增加“时间到!”和“确定”两个文本图层,监听变量 now 当其=0且开始文本内容为“暂停”时,添加透明度的设置,使其显示为下面右图所示效果。

○  对本文“确定”添加点击触发,添加一个重置,使其点击后使场景重置,恢复到最初效果。

最后整体整理一下所有图层透明度关系,使页面所有元素在不同的计时阶段中下进行正常的显示及隐藏。

大功告成!!!可以直接在预览窗中查看效果~~

https://cloud.protopie.io/p/ada86850ea

(源文件中有三个不同场景,对应“时钟”、“秒表”、“计时器”)

相关教程:Protopie进阶教程--动态时钟(上)

相关教程:Protopie进阶教程--动态时钟(中)

1 require.config({

2 paths: {

3 "echarts": "/Content/js/echarts-2.0.4/build/echarts",

4 "echarts/chart/pie": "/Content/js/echarts-2.0.4/build/echarts"

5 }

6 })

7 // 使用

8 require(

9 [

10 'echarts',

11 'echarts/chart/pie' // 使用柱状图就加载bar模块,按需加载

12 ],

13 function (ec) {

14 // 基于准备好的dom,初始化echarts图表

15 var myChart = ec.init(document.getElementById('main'))

16 option = {

17 title: {

18 text: row.ProjectName,

19 x: 'center'

20 },

21 tooltip: {

22 trigger: 'item',

23 formatter: "{a} <br/>{b} : {c} ({d}%)"

24 },

25 legend: {

26 orient: 'vertical',

27 x: 'left',

28 data: (function () {

29 var name = []

30 com.ajax({

31 type: 'GET',

32 cache: false,

33 url: '/api/Operation/SafetyCheckReport/GetDangerName',

34 data: { "UpCode": DangerType },

35 success: function (d) {

36 for (var i = 0i <d.lengthi++) {

37 name.push(d[i].Name)

38 }

39 }

40 })

41 return name

42 })()

43 },

44 toolbox: {

45 show: true,

46 feature: {

47 restore: { show: true },

48 saveAsImage: { show: true }

49 }

50 },

51 calculable: false,

52 series: [

53 {

54 type: 'pie',

55 radius: '50%',

56 center: ['50%', '50%'],

57 data: (function () {

58 var arr = []

59 $.ajax({

60 type: 'GET',

61 async: false,

62 cache: false,

63 url: self.urls.querytow,

64 data: { "ProjectID": row.ProjectID, "UpCode": DangerType },

65 success: function (d) {

66 if (d[0].koujian != 0) {

67 arr.push({ value: d[0].koujian, name: '扣件式脚手架'})

68 } else {

69 arr.push({ value: d[0].koujian, name: '扣件式脚手架', itemStyle : { normal: {label : {show: false},labelLine: { show: false }}}})

70 }

71 if (d[0].menshi != 0) {

72 arr.push({ value: d[0].menshi, name: '门式脚手架'})

73 } else {

74 arr.push({ value: d[0].menshi, name: '门式脚手架', itemStyle : { normal: {label : {show: false},labelLine: { show: false }}}})

75 }

76 if (d[0].shuangpai != 0) {

77 arr.push({ value: d[0].shuangpai, name: '双排外竹脚手架'})

78 } else {

79 arr.push({ value: d[0].shuangpai, name: '双排外竹脚手架', itemStyle : { normal: {label : {show: false},labelLine: { show: false }}}})

80 }

81 if (d[0].wankou != 0) {

82 arr.push({ value: d[0].wankou, name: '碗扣式脚手架'})

83 } else {

84 arr.push({ value: d[0].wankou, name: '碗扣式脚手架', itemStyle : { normal: {label : {show: false},labelLine: { show: false }}}})

85 }

86 if (d[0].sanjiao != 0) {

87 arr.push({ value: d[0].sanjiao, name: '三角形钢管悬挑脚手架'})

88 } else {

89 arr.push({ value: d[0].sanjiao, name: '三角形钢管悬挑脚手架', itemStyle : { normal: {label : {show: false},labelLine: { show: false }}}})

90 }

91 if (d[0].xinggang != 0) {

92 arr.push({ value: d[0].xinggang, name: '型钢悬挑脚手架(阳角A)'})

93 } else {

94 arr.push({ value: d[0].xinggang, name: '型钢悬挑脚手架(阳角A)', itemStyle : { normal: {label : {show: false},labelLine: { show: false }}}})

95 }

96 if (d[0].duopai != 0) {

97 arr.push({ value: d[0].duopai, name: '多排悬挑架主梁验算'})

98 } else {

99 arr.push({ value: d[0].duopai, name: '多排悬挑架主梁验算', itemStyle : { normal: {label : {show: false},labelLine: { show: false }}}})

100 }

101 if (d[0].fuzhe != 0) {

102 arr.push({ value: d[0].fuzhe, name: '附着升降脚手架'})

103 } else {

104 arr.push({ value: d[0].fuzhe, name: '附着升降脚手架', itemStyle : { normal: {label : {show: false},labelLine: { show: false }}}})

105 }

106 if (d[0].xuangua != 0) {

107 arr.push({ value: d[0].xuangua, name: '悬挂式吊篮'})

108 } else {

109 arr.push({ value: d[0].xuangua, name: '悬挂式吊篮', itemStyle : { normal: {label : {show: false},labelLine: { show: false }}}})

110 }

111 if (d[0].gangguan != 0) {

112 arr.push({ value: d[0].gangguan, name: '钢管落地卸料平台'})

113 } else {

114 arr.push({ value: d[0].gangguan, name: '钢管落地卸料平台',itemStyle : { normal: {label : {show: false},labelLine: { show: false }}}})

115 }

116 if (d[0].pingtai != 0) {

117 arr.push({ value: d[0].pingtai, name: '型钢悬挑卸料平台'})

118 } else {

119 arr.push({ value: d[0].pingtai, name: '型钢悬挑卸料平台',itemStyle : { normal: {label : {show: false},labelLine: { show: false }}}})

120 }

121 if (d[0].jingjia != 0) {

122 arr.push({ value: d[0].jingjia, name: '井架落地卸料平台'})

123 } else {

124 arr.push({ value: d[0].jingjia, name: '井架落地卸料平台', itemStyle : { normal: {label : {show: false},labelLine: { show: false }}}})

125 }

126 if (d[0].fanghu != 0) {

127 arr.push({ value: d[0].fanghu, name: '防护棚'})

128 } else {

129 arr.push({ value: d[0].fanghu, name: '防护棚', itemStyle : { normal: {label : {show: false},labelLine: { show: false }}}})

130 }

131 if (d[0].mujiao != 0) {

132 arr.push({ value: d[0].mujiao, name: '木脚手架'})

133 } else {

134 arr.push({ value: d[0].mujiao, name: '木脚手架', itemStyle : { normal: {label : {show: false},labelLine: { show: false }}}})

135 }

136 if (d[0].xiedao != 0) {

137 arr.push({ value: d[0].xiedao, name: '斜道'})

138 } else {

139 arr.push({ value: d[0].xiedao, name: '斜道', itemStyle : { normal: {label : {show: false},labelLine: { show: false }}}})

140 }

141 if (d[0].xuantiao != 0) {

142 arr.push({ value: d[0].xuantiao, name: '悬挑防护棚'})

143 } else {

144 arr.push({ value: d[0].xuantiao, name: '悬挑防护棚', itemStyle : { normal: {label : {show: false},labelLine: { show: false }}}})

145 }

146

147 }

148 })

149 return arr

150 })()

151 }

152 ]

153 }

154 // 为echarts对象加载数据

155 myChart.setOption(option)

156 }

157 )