Protovis.Line.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. Protovis.Line = new Class({
  2. Extends : Protovis,
  3. options : {
  4. lineWidth : 1,
  5. interactive : true,
  6. xvis : 'this.index > 0',
  7. xprecision: 0,
  8. yvis : '!(this.index % 2)',
  9. yprecision : 0
  10. },
  11. initialize : function(el,options){
  12. this.parent(el,options);
  13. this.prepData();
  14. this.setScale();
  15. this.makeGraph();
  16. this.render();
  17. },
  18. prepData : function(){
  19. this.data = []; var d = this.options.data, x = [], y = [];
  20. var len = d[0].length - 1;
  21. if(len < 1) return;
  22. // initialize sub arrays
  23. for(var l = 0; l < len; l++) this.data[l] = [];
  24. // build line data
  25. for(var i = 0; i < d.length; i++){
  26. for(var l = 1; l <= len; l++){
  27. this.data[l-1].push({'x' : parseFloat(d[i][0]), 'y': parseFloat(d[i][l])});
  28. x.push(d[i][0]); y.push(d[i][l]);
  29. }
  30. }
  31. this.limits = { xmin : pv.min(x), xmax : pv.max(x), ymin : pv.min(y), ymax : pv.max(y) };
  32. },
  33. setScale : function(){
  34. this.parent();
  35. this.x = pv.Scale.linear(this.limits.xmin,Math.ceil(this.limits.xmax)).range(0,this.width);
  36. this.y = pv.Scale.linear(this.limits.ymin,Math.ceil(this.limits.ymax)).range(0,this.height);
  37. },
  38. makeGraph : function(){
  39. this.parent();
  40. this.addYTicks();
  41. this.addXTicks();
  42. this.makePanel();
  43. this.plot();
  44. if(this.options.interactive) this.makeInteractive();
  45. },
  46. addYTicks : function(){
  47. this.yTicks = this.graph.add(pv.Rule)
  48. .data(this.y.ticks())
  49. .visible(function(){ return !(this.index % 2);})
  50. .bottom(function(d) { return Math.round(this.y(d)) - .5}.bind(this))
  51. .strokeStyle(function(d){ return d ? "#ddd" : "#000";})
  52. .anchor("left").add(pv.Label)
  53. .text(function(d){ return d.toFixed(this.options.yprecision); }.bind(this));
  54. },
  55. addXTicks : function(){
  56. this.xTicks = this.graph.add(pv.Rule);
  57. this.xTicks
  58. .data(this.x.ticks())
  59. .visible(function(d){ return this.index > 0; })
  60. .left(function(d){ return Math.round(this.x(d)) - .5 }.bind(this))
  61. .strokeStyle(function(d){ return d ? "#ddd" : "#000"; })
  62. .anchor("bottom").add(pv.Label)
  63. .text(function(d){ return d.toFixed(this.options.xprecision); }.bind(this));
  64. },
  65. plot : function(){
  66. this.line = this.panel.add(pv.Line)
  67. .data(function(d){ return d;})
  68. .left(function(d){ return this.x(d.x);}.bind(this))
  69. .bottom(function(d){ return this.y(d.y);}.bind(this))
  70. .lineWidth(this.options.lineWidth);
  71. },
  72. makeInteractive : function(){
  73. this.idx = -1;
  74. /* The mouseover dots and label. */
  75. this.line.add(pv.Dot)
  76. .visible(function(){ return this.idx >= 0 }.bind(this))
  77. .data(function(d){ return [d[this.idx]] }.bind(this))
  78. .fillStyle(function(){ return this.line.strokeStyle(); }.bind(this))
  79. .strokeStyle("#000")
  80. .size(20)
  81. .lineWidth(1)
  82. .add(pv.Dot)
  83. .left(10)
  84. .bottom(function(){ return (this.parent.index * 12 + 10); })
  85. .anchor("right").add(pv.Label)
  86. .text(function(d){ return d.y.toFixed(2); });
  87. /* An invisible bar to capture events (without flickering). */
  88. this.graph.add(pv.Bar)
  89. .fillStyle("rgba(0,0,0,.001)")
  90. .event("mouseout", function() {
  91. this.idx = -1;
  92. return this.graph;
  93. }.bind(this))
  94. .event("mousemove", function() {
  95. var mx = this.x.invert(this.graph.mouse().x);
  96. this.idx = pv.search(this.data[0].map(function(d){return d.x }), mx);
  97. this.idx = this.idx < 0 ? (-this.idx - 2) : this.idx;
  98. return this.graph;
  99. }.bind(this));
  100. }
  101. });