【D3.js数据可视化系列教程】(二十一)--交互图表之条形图排序切换

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/zhang__tianxu/article/details/14101159

最后效果:单击任何条排序时,再用鼠标滑过条不会打断排序;第二次单击切换升降排序 删除事件控制颜色变化。使用样式表控制

  1. 过渡样式


    
    
  1. /*(1)鼠标悬停时变色*/
  2. rect :hover {
  3. fill :red;
  4. }
  5. /*(2)过渡效果*/
  6. rect {
  7. -moz-transiton:all 0.3s;
  8. -o-transiton:all 0.3s;
  9. -webkit-transition:all 0.3s;
  10. transition:all 0.3s
  11. }

  2. 切换排序


    
    
  1. var sortOrders= false;
  2. var sortBars= function(){
  3. sortOrders=!sortOrders; //(3)每点击一次排序方向改变
  4. svg.selectAll( "rect")
  5. .sort( function(a,b){
  6. if(sortOrders){
  7. //对数据集升序排序
  8. return d3.ascending(a.value,b.value); //这个地方注意是键值对所以要加上值的引用b.value
  9. } else{
  10. //对数据集降序排序
  11. return d3.descending(a.value,b.value);
  12. }
  13. })
  • 被打乱的排序

  • 反转排序(水润丝滑的效果不得不丢弃)


    
    
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <title>testD3-18-update.html </title>
  6. <script type="text/javascript" src="http://localhost:8080/spring/js/d3.v3.js"> </script>
  7. <style type="text/css">
  8. /*(1)鼠标悬停时变色*/
  9. rect :hover {
  10. fill :red ;
  11. }
  12. /*(2)过渡效果*/
  13. rect {
  14. -moz-transiton:all 0.3s ;
  15. -o-transiton:all 0.3s ;
  16. -webkit-transition:all 0.3s ;
  17. transition:all 0.3s
  18. }
  19. </style>
  20. </head>
  21. <body>
  22. <button>单击更新 </button>
  23. <br>
  24. <p id="remove">单击删除 </p>
  25. <p id="add">单击添加 </p>
  26. <br>
  27. <script type="text/javascript">
  28. //键值对数据集
  29. var dataset = [
  30. { key: 0 ,value: 5 },
  31. { key: 1 ,value: 10 },
  32. { key: 2 ,value: 13 },
  33. { key: 3 ,value: 19 },
  34. { key: 4 ,value: 21 },
  35. { key: 5 ,value: 25 },
  36. { key: 6 ,value: 22 },
  37. { key: 7 ,value: 18 },
  38. { key: 8 ,value: 15 },
  39. { key: 9 ,value: 13 },
  40. { key: 10 ,value: 11 },
  41. { key: 11 ,value: 12 },
  42. { key: 12 ,value: 15 },
  43. { key: 13 ,value: 20 },
  44. { key: 14 ,value: 18 },
  45. { key: 15 ,value: 17 },
  46. { key: 16 ,value: 16 },
  47. { key: 17 ,value: 18 },
  48. { key: 18 ,value: 23 },
  49. { key: 19 ,value: 25 }];
  50. //设置SVG的高宽
  51. var w= 600 ;
  52. var h= 250 ;
  53. var barPadding = 1 ;
  54. //定义序数比例尺
  55. var xScale=d3.scale.ordinal() //序数比例尺
  56. .domain(d3.range(dataset.length))
  57. .rangeRoundBands([ 0 ,w], 0.05 );
  58. // 更新数据引用,包含下面所有关于要使用到d.value的地方
  59. var yScale=d3.scale.linear() //y仍然是线性比例尺
  60. .domain([ 0 ,d3.max(dataset, function(d) {
  61. return d.value;
  62. })])
  63. .range([ 0 ,h]);
  64. // 定义键函数(简洁),以备数据绑定到元素的时候使用
  65. //把所有.data(dataset)改成.data(dataset,key)
  66. var key= function(d) {
  67. return d.key;
  68. };
  69. //值函数
  70. var value= function(d) {
  71. return d.value;
  72. };
  73. //条排序函数
  74. var sortOrders= false ;
  75. var sortBars= function() {
  76. sortOrders=!sortOrders; //(3)每点击一次排序方向改变
  77. svg.selectAll( "rect" )
  78. .sort( function(a,b) {
  79. if (sortOrders){
  80. //对数据集升序排序
  81. return d3.ascending(a.value,b.value); //这个地方注意是键值对所以要加上值的引用b.value
  82. } else {
  83. //对数据集降序排序
  84. return d3.descending(a.value,b.value);
  85. }
  86. })
  87. .transition()
  88. .duration( 1000 )
  89. .attr( "x" , function(d,i) { //对排序之后的横坐标重排
  90. return xScale(i);
  91. });
  92. };
  93. //Create SVG element
  94. var svg = d3.select( "body" ) //选中DOM中的目标元素
  95. .append( "svg" ) //为目标元素附加上一个svg子元素
  96. .attr( "width" , w) //设置这个svg的宽
  97. .attr( "height" , h); //设置这个svg的高
  98. //为SVG添加条形
  99. svg.selectAll( "rect" ) //选中空元素,表示即将创建这样的元素
  100. .data(dataset,key) //对此后的方法都执行dataset.length遍
  101. .enter() //数据元素值比前面选中的DOM元素多就创建一个新的DOM元素
  102. .append( "rect" ) //取得enter的占位元素,并把rect追加到对应的DOM中
  103. .attr( "x" , function(d, i) { //设置横坐标,从0开始每次右移元素宽那么长(w / dataset.length)
  104. //return i * (w / dataset.length);
  105. return xScale(i); //这里使用序数比例尺,自己去找刚才划分好的档位
  106. })
  107. .attr( "y" , function(d) { //设置纵坐标,纵坐标正方向是从上往下的,所以条有多长就要设置起点是相对于h再向上移动条长
  108. return h - yScale(d.value);
  109. })
  110. //.attr("width", w / dataset.length - barPadding)//设置元素宽,留出间隙宽barPadding。
  111. .attr( "width" , xScale.rangeBand()) //这里xScale比例尺已经设置间距了所以直接用
  112. .attr( "height" , function(d) {
  113. return yScale(d.value);
  114. })
  115. .attr( "fill" , function(d) { //设置RGB颜色与数值的关系
  116. return "rgb(0, 0, " + (d.value * 10 ) + ")" ;
  117. })
  118. //点击排序
  119. .on( "click" , function() {
  120. sortBars();
  121. });
  122. //为条加上数值
  123. svg.selectAll( "text" )
  124. .data(dataset,key)
  125. .enter()
  126. .append( "text" )
  127. .text( function(d) {
  128. return d.value;
  129. })
  130. .attr( "text-anchor" , "middle" )
  131. .attr( "x" , function(d, i) {
  132. return xScale(i)+xScale.rangeBand()/ 2 ;
  133. })
  134. .attr( "y" , function(d) {
  135. return h - yScale(d.value) + 14 ;
  136. })
  137. .attr( "font-family" , "sans-serif" )
  138. .attr( "font-size" , function(d) {
  139. return xScale.rangeBand()/ 2 ;
  140. })
  141. .attr( "fill" , "white" );
  142. //删除一条、添加一条
  143. d3.select( "p" )
  144. .on( "click" , function() {
  145. //根据ID确定点击的是哪个标签
  146. var paragraphID=d3.select( this ).attr( "id" ) ;
  147. console .log(paragraphID);
  148. //添加删除组合起来
  149. if (paragraphID== "add" ){
  150. //数据集最后添加数值
  151. var maxValue= 75 ;
  152. var newNumber = Math .floor( Math .random()*maxValue); //0-24的整数
  153. //根据最后一个key添加一个值
  154. var lastKeyValue=dataset[dataset.length- 1 ].key;
  155. dataset.push({
  156. key:lastKeyValue+ 1 ,
  157. value:newNumber
  158. });
  159. //更新X轴比例尺
  160. xScale.domain(d3.range(dataset.length));
  161. //选择所有条
  162. var bars=svg.selectAll( "rect" )
  163. .data(dataset,key); //绑定数据到元素集,返回更新的元素集
  164. var texts=svg.selectAll( "text" )
  165. .data(dataset,key);
  166. //添加条形元素到最右边
  167. bars.enter()
  168. .append( "rect" )
  169. .attr( "x" ,w); //在SVG最右边,不可见
  170. //
  171. texts.enter()
  172. .append( "text" );
  173. //更新新矩形到可见范围内
  174. //并在这个时候根据数据集为每个条设置对应的属性
  175. bars.transition()
  176. .duration( 500 )
  177. .attr( "x" , function(d, i) {
  178. return xScale(i) ;
  179. }) //每个X对应到它相应的档位上
  180. .attr( "y" , function(d) {
  181. return h - yScale(d.value) ;
  182. })
  183. .attr( "width" , xScale.rangeBand()) //这里xScale比例尺已经设置间距了所以直接用
  184. .attr( "height" , function(d) {
  185. return yScale(d.value);
  186. })
  187. .attr( "fill" , function(d) { //设置RGB颜色与数值的关系
  188. return "rgb(0, 0, " + (d.value * 10 ) + ")" ;
  189. });
  190. //
  191. texts.transition()
  192. .duration( 500 )
  193. .text( function(d) {
  194. return d.value;
  195. })
  196. .attr( "text-anchor" , "middle" )
  197. .attr( "x" , function(d, i) {
  198. return xScale(i)+xScale.rangeBand()/ 2 ;
  199. })
  200. .attr( "y" , function(d) {
  201. return h - yScale(d.value) + 14 ;
  202. })
  203. .attr( "font-family" , "sans-serif" )
  204. .attr( "font-size" , "12px" )
  205. .attr( "fill" , "red" );
  206. } else if (paragraphID== "remove" ){
  207. //删除的操作
  208. //选择所有条
  209. dataset.shift();
  210. //更新X轴比例尺
  211. xScale.domain(d3.range(dataset.length));
  212. var bars=svg.selectAll( "rect" )
  213. .data(dataset,key);
  214. //从左侧退出
  215. bars.exit()
  216. .transition()
  217. .duration( 500 )
  218. .attr( "x" , -xScale.rangeBand()) //w-xScale.rangeBand()间隙宽其实其他负数也行
  219. .remove();
  220. }
  221. });
  222. // 更新条形数长短的代码,需要一个button标签配合
  223. //特别注意:这里选中的元素必须在d3选择器之前,或许要先加载完了元素才能被选中
  224. d3.select( "button" )
  225. .on( "click" , function() {
  226. // 新数据集,随机数组
  227. var numValues=dataset.length;
  228. dataset=[];
  229. var maxValue= 75 ;
  230. var newNumber;
  231. for ( var i= 0 ;i<numValues;i++){
  232. newNumber= Math .floor( Math .random()*maxValue); //0-24的整数
  233. //根据i添加一个值
  234. dataset.push({
  235. key:i,
  236. value:newNumber
  237. });
  238. }
  239. // 更新比例尺,免使纵坐标超出范围
  240. yScale.domain([ 0 ,d3.max(dataset,value)]); //只要更新定义域就行了,映射到的值域不变
  241. //更新所有的矩形
  242. svg.selectAll( "rect" )
  243. .data(dataset,key)
  244. .transition() // 加上过渡动画
  245. .delay( function(d,i) {
  246. return i/dataset.length* 1000 ;
  247. }) //指定过度什么时间开始,可以用函数控制每一条的动画时间,这样就可得到钢琴版的效果
  248. .duration( 2000 ) // 加上动画的持续时间,以毫秒计算
  249. .ease( "linear" ) // 缓动函数:有circle(加速)elastic(伸缩),linear(匀速),bounce(弹跳)
  250. .attr( "y" , function(d) {
  251. return h-yScale(d.value);
  252. })
  253. .attr( "height" , function(d) {
  254. return yScale(d.value);
  255. });
  256. // 更新条上的数值
  257. svg.selectAll( "text" )
  258. .data(dataset,key)
  259. .text( function(d) {
  260. return d.value;
  261. })
  262. .attr( "text-anchor" , "middle" )
  263. .attr( "x" , function(d, i) {
  264. return xScale(i)+xScale.rangeBand()/ 2 ;
  265. })
  266. .attr( "y" , function(d) {
  267. return h - yScale(d.value) + 14 ;
  268. })
  269. .attr( "font-family" , "sans-serif" )
  270. .attr( "font-size" , "12px" )
  271. .attr( "fill" , "red" );
  272. });
  273. </script>
  274. </body>
  275. </html>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值