1 
  2 
  3 //intialize with var data ={DATATYPE : "vq.models.StemPlotData", CONTENTS : {DATAARRAY : data_array} };
  4 // notifier = function(x,dx) where x = position within scroll bar range,  dx = total length of window in scale of scroll bar
  5 
  6 //draw with draw (data ={DATATYPE : "vq.models.StemPlotData", {DATAARRAY : data_array} }
  7 //				and options = {plotHeight: xx, plotWidth : xx, vertical_padding: xx,
  8 //				horizontal_padding : xx , maxPosition: xx, minPosition: xx,
  9 //				maxRange: xx, minRange: xx, dblclick_notifier : function(x,dx),
 10 //				fixedWindowWidth: xx, scaleMultiplier : xx, interval : xx, font : "fontname"}
 11 //note dblclick_notifer is the last listed option.  This can be used to create a "zoom" effect by re-instanstiating the scroll bar with new parameters.
 12 
 13 
 14 vq.StemPlot = function() {
 15     vq.Vis.call(this);
 16 
 17         //set option variables to useful values before options are set.
 18         this.height(500);     // defaults
 19         this.width(500);     // defaults
 20         this.vertical_padding(30);
 21         this.horizontal_padding(30);
 22 
 23     };
 24     vq.StemPlot.prototype = pv.extend(vq.Vis);
 25 
 26 vq.StemPlot.prototype._setOptionDefaults =  function(options) {
 27 
 28     if (options.height != null) { this.height(options.height); }
 29 
 30      if (options.width != null) { this.width(options.width); }
 31 
 32      if (options.container) { this.container(options.container); }
 33 
 34      if (options.vertical_padding != null) { this.vertical_padding(options.vertical_padding); }
 35 
 36      if (options.horizontal_padding != null) { this.horizontal_padding(options.horizontal_padding); }
 37 
 38     };
 39 
 40     vq.StemPlot.prototype.setXRange = function(x,dx){
 41         this.posX.domain(x, x+dx);
 42         this.redraw();
 43 };
 44 
 45     vq.StemPlot.prototype.draw = function(data) {
 46 
 47         this._bl_data = new vq.models.StemPlotData(data);
 48         if (this._bl_data.isDataReady()) {
 49             this._setOptionDefaults(this._bl_data);
 50            this.render();
 51         }
 52     };
 53 
 54     vq.StemPlot.prototype.render = function() {
 55         var that = this;
 56         this._data = this._bl_data._data;
 57         this.visibleWidth = (this.width() - 2 * this.horizontal_padding());
 58         this.visibleHeight = (this.height() - this.vertical_padding() * 2);
 59         this.context_height = 50;
 60         this.focus_height = this.visibleHeight - this.context_height;
 61          var x_id = that._bl_data.COLUMNID.x, y_id = that._bl_data.COLUMNID.y;
 62                this.posX =  pv.Scale.linear().range(0,that.visibleWidth);
 63                 this.posY = pv.Scale.linear().range(0,that.focus_height);
 64             this.context_posX = pv.Scale.linear(0, pv.max(that._data.map(function(d){
 65                     return d[x_id];}))).range(0,that.visibleWidth).nice();
 66             this.context_posY =  pv.Scale.linear(0, pv.max(that._data.map(function(d){
 67                     return d[y_id];}))).range(0,that.context_height).nice();
 68 
 69         that.window = {x:that.context_posX.range()[0]*.2,dx:(that.context_posX.range()[1] - that.context_posX.range()[0]) *.6};
 70 
 71          var s;
 72          var x = that._bl_data.COLUMNID.x, y = that._bl_data.COLUMNID.y;
 73 
 74 
 75         var dispatchEvent = function(d) {
 76             notifier(d);
 77         };
 78 
 79         var vis = new pv.Panel()
 80                 .width(that.width())
 81                 .height(that.height())
 82                 .left(that.horizontal_padding())
 83                 .right(that.horizontal_padding())
 84                 .bottom(that.vertical_padding())
 85                 .top(that.vertical_padding())
 86                 .canvas(that.container());
 87 
 88         var	drawPanel = vis.add(pv.Panel);
 89 
 90         var focus = drawPanel.add(pv.Panel)
 91                 .def("init", function() {
 92                                 var d1 = that.context_posX.invert(that.window.x),
 93                                         d2 = that.context_posX.invert(that.window.x + that.window.dx),
 94                                         dd = that._data.slice(Math.max(0, pv.search.index(that._data, d1, function(d) {return d[x];} ) - 1),
 95                                     pv.search.index(that._data, d2, function(d) { return d[x]; } ) + 1);
 96                                     that.posX.domain(d1, d2);
 97                                     that.posY.domain(that.context_posY.domain());
 98                                     return dd;
 99                             })
100                 .top(0)
101                 .height(that.focus_height);
102 
103         var plot = focus.add(pv.Panel)
104                 .overflow('hidden')
105 
106         //        Stem plot
107                 .add(pv.Bar)
108                     .data(function() { return focus.init();})
109                     .left(function(t) { return that.posX(t[x]);})
110                      .height(function(t){ return that.posY(t[y]);})
111                      .bottom(1)
112                      .width(.5)                       
113                      .strokeStyle("red")
114                      .fillStyle("red")
115              .anchor("top").add(pv.Label)
116                      .fillStyle(null)
117                      .visible(function(t) { return t[y] > pv.mean(that.posY.domain()) / 2;})
118                      .textBaseline("bottom")
119                      .textAlign("right")
120                      .textAngle(-Math.PI / 2)
121                      .text(function(t){ return parseInt(t[y]);});
122         
123 
124         var xtick = focus.add(pv.Rule)
125                 .data(function() { return that.posX.ticks();} )
126                 .left(that.posX)
127                 .strokeStyle("#eee");
128             xtick.anchor("bottom").add(pv.Label)
129                 .text(that.posX.tickFormat);
130 
131 
132         /* Y-axis ticks. */
133         var ytick = focus.add(pv.Rule)
134                 .data(function() { return that.posY.ticks(7);} )
135                 .bottom(that.posY)
136                 .strokeStyle("#aaa")
137         /* Left label. */
138             .anchor("left").add(pv.Label)
139                 .text(that.posY.tickFormat);
140 
141 /* Context panel (zoomed out). */
142         var context = drawPanel.add(pv.Panel)
143             .bottom(0)
144             .height(that.context_height);
145 
146 /* X-axis ticks. */
147         context.add(pv.Rule)
148             .data(that.context_posX.ticks())
149             .left(that.context_posX)
150             .strokeStyle("#eee")
151           .anchor("bottom").add(pv.Label)
152             .text(that.context_posX.tickFormat);
153 
154 /* Y-axis ticks. */
155         context.add(pv.Rule)
156             .bottom(0);
157 
158 /* Context area chart. */
159         context.add(pv.Bar)
160             .data(that._data)
161             .left(function(d) {return that.context_posX(d[x]);})
162             .width(1)
163             .bottom(1)
164             .height(function(d) { return that.context_posY(d[y]);})
165             .fillStyle("blue");
166  
167 
168 /* The selectable, draggable focus region. */
169         context.add(pv.Panel)
170             .data([that.window])
171             .cursor("crosshair")
172             .events("all")
173             .event("mousedown", pv.Behavior.select())
174             .event("select", focus)
175           .add(pv.Bar)
176             .left(function(d) { return d.x;})
177             .width(function(d) {return d.dx;})
178             .fillStyle("rgba(255, 128, 128, .4)")
179             .cursor("move")
180             .event("mousedown", pv.Behavior.drag())
181             .event("drag", focus);
182 
183         vis.render();
184 
185     };
186 
187 
188 vq.models.StemPlotData = function(data) {
189     vq.models.VisData.call(this,data);
190 
191     this.setDataModel();
192 
193             if (this.getDataType() == 'vq.models.StemPlotData') {
194                 this._build_data(this.getContents());
195             } else {
196                 console.warn('Unrecognized JSON object.  Expected vq.models.StemPlotData object.');
197             }
198         };
199 vq.models.StemPlotData.prototype = pv.extend(vq.models.VisData);
200 
201 vq.models.StemPlotData.prototype._build_data = function(data) {
202         this._processData(data);
203         if (this._data.length) {
204                 this.setDataReady(true);
205             }
206 
207         };
208 
209 
210 vq.models.StemPlotData.prototype.setDataModel = function () {
211     this._dataModel = [
212      {label: 'width', id: 'PLOT.width', cast : Number, defaultValue: 400},
213      {label: 'height', id: 'PLOT.height', cast : Number, defaultValue: 400},
214      {label : 'container', id:'PLOT.container', optional : true},
215      {label: 'vertical_padding', id: 'PLOT.vertical_padding', cast : Number, defaultValue: 0},
216      {label: 'horizontal_padding', id: 'PLOT.horizontal_padding',cast : Number,  defaultValue: 0},
217         {label: 'COLUMNID.x', id: 'xcolumnid',cast : String, defaultValue : 'x'},
218             {label: 'COLUMNID.y', id: 'ycolumnid',cast : String, defaultValue : 'y'},
219         {label : '_data', id: 'data_array', defaultValue : [] }
220 
221      ];
222 };
223 
224