1 
  2 
  3 vq.PaCo= function() {
  4     vq.Vis.call(this);
  5 
  6         //set option variables to useful values before options are set.
  7         this.height(400);     // defaults
  8         this.width(600);     // defaults
  9         this.vertical_padding(0);
 10         this.horizontal_padding(0);
 11 
 12 };
 13 
 14 vq.PaCo.prototype = pv.extend(vq.Vis);
 15 
 16 vq.PaCo.prototype._setOptionDefaults = function(options) {
 17 
 18         if (options.height != null) {
 19             this.height(options.height);
 20         }
 21 
 22         if (options.width != null) {
 23             this.width(options.width);
 24         }
 25 
 26         if (options.vertical_padding != null) {
 27             this.vertical_padding(options.vertical_padding);
 28         }
 29 
 30         if (options.horizontal_padding != null) {
 31             this.horizontal_padding(options.horizontal_padding);
 32         }
 33 
 34         if (options.container != null) {
 35             this.container(options.container);
 36         }
 37 };
 38 
 39 vq.PaCo.prototype.draw = function(data) {
 40 
 41         this._pa_co_data = new vq.models.PaCoData(data);
 42 
 43         if (this._pa_co_data.isDataReady()) {
 44             this._setOptionDefaults(this._pa_co_data);
 45             this.render();
 46         }
 47 
 48 };
 49 
 50 vq.PaCo.prototype.getFiltered = function() {
 51     var that = this,
 52         dataObj = that._pa_co_data;
 53     var data = dataObj._data;
 54     filtered_data = data.filter(
 55                                function(d) { return dataObj._dims.every(function(dim) {return d[dim] != undefined;}) &&
 56                                        dataObj._dims.every( function(dim) { return d[dim] <= that.filter[dim].max &&
 57                                                d[dim] >= that.filter[dim].min  ;});});
 58 
 59     return filtered_data;
 60 };
 61 
 62 vq.PaCo.prototype.getSelected = function() {
 63     return this._pa_co_data.selected||null;
 64 };
 65 
 66 vq.PaCo.prototype.render = function() {
 67     var that = this;
 68     var w = that.width(),
 69             h = that.height(),
 70             div = that.container(),
 71             dataObj = that._pa_co_data,
 72             cursor = [{x:0,y:0,dx:0,dy:0}],
 73             cursor_label = {label:'',coordinate:'',value:0.0};
 74 
 75     dataObj.hovered = null;
 76 
 77 
 78     var x = pv.Scale.ordinal(dataObj._dims).splitFlush(0, w),
 79             y = {},
 80             c = {};
 81 
 82     dataObj._dims.forEach( function(t) {
 83         if (dataObj._coordinates[dataObj._coordinates_map[t]].scale_type == undefined) {
 84             dataObj._coordinates[dataObj._coordinates_map[t]].scale_type = 'linear';
 85         }
 86 
 87         var config = dataObj._coordinates[dataObj._coordinates_map[t]];
 88         var min_val = config.min_value != undefined ? config.min_value :
 89                 pv.min(dataObj._data,function(a) { return a[t];});
 90 
 91         var max_val  = config.max_value != undefined ? config.max_value :
 92                 pv.max(dataObj._data,function(a) { return a[t];});
 93 
 94         switch(config.scale_type) {
 95             case('log'):
 96                 min_val = min_val > 0 ? min_val : 0.1;
 97                 y[t] = pv.Scale.log( min_val, max_val).range(0,h).nice();
 98                 c[t] = pv.Scale.log( min_val,max_val).range("steelblue", "brown").nice();
 99                 break;
100             case('linear') :
101             case('default'):
102                 y[t]= pv.Scale.linear( min_val, max_val).range(0,h);
103                 c[t]= pv.Scale.linear( min_val, max_val).range("steelblue", "brown");
104                 break;
105         }});
106 
107     /* Interaction state. */
108     that.filter = pv.dict(dataObj._dims, function(t) {
109         return {min: y[t].domain()[0], max: y[t].domain()[1]};
110     }), active = dataObj._dims[0];
111 
112     var vis = new pv.Panel()
113             .width(w)
114             .height(h)
115             .left(that.horizontal_padding())
116             .right(that.horizontal_padding())
117             .top(that.vertical_padding())
118             .bottom(that.vertical_padding())
119             .canvas(div);
120 
121     // The parallel coordinates display.
122     vis.add(pv.Panel)
123             .data(dataObj._data)
124             .visible(function(d) { return dataObj._dims.every(function(t)
125     { return d[t] <= that.filter[t].max &&
126             d[t] >= that.filter[t].min ;});})
127             .add(pv.Line)
128           .data(dataObj._dims)
129             .left(function(t) { return x(t);})
130             .bottom(function(t, d) { return y[t](d[t]);})
131             .strokeStyle("#ddd")
132             .lineWidth(1)
133             .antialias(false);
134 
135     // Rule per dimension.
136     rule = vis.add(pv.Rule)
137             .data(dataObj._dims)
138             .left(x);
139 
140     // Dimension label
141     rule.anchor("top").add(pv.Label)
142             .top(-12)
143             .font("bold 16px sans-serif")
144             .text(function(d) { return d;});
145 
146 
147     // The parallel coordinates display.
148     var change = vis.add(pv.Panel);
149 
150 
151     function filter_data() {
152         return dataObj._data.filter(function(d) {
153                     return dataObj._dims.every(function(t)
154                                         { return d[t] <= that.filter[t].max &&
155                                                 d[t] >= that.filter[t].min ;});});
156     }
157 
158     function invert_x(d) {
159         var closest_dim=dataObj._dims[0];
160         var distance = 999999;
161                dataObj._dims.forEach(function(dim) {var dist = Math.abs(x(dim)-d);
162                                         if(distance > dist) {closest_dim=dim; distance = dist; }});
163                    return closest_dim;
164     }
165             //separate click event from handle events
166     var line_panel = change.add(pv.Panel)
167         .event('click', function(c) {dataObj.selected = dataObj.hovered; highlight.render();})
168             .events('all');
169 
170     function overLine(c,d) {
171                     var cursor_label = {};
172                     dataObj.hovered = d;
173                     cursor[0] = this.mouse();
174                     var dim = invert_x(cursor[0].x);
175                     cursor_label.label = d[dataObj._label_column];
176                     cursor_label.coordinate = dim;
177                     cursor_label.value = d[dim];
178                     var config={};
179                     config[cursor_label['label']] =  function(cursor) { return cursor.coordinate + ' ' + cursor.value;};
180              pv.Behavior.flextip( {
181                         include_header : false,
182                         include_footer : false,
183                         timeout : 20,
184                         param_data:true,
185                         on_mark:false,
186                         close_timeout : 'inf',
187                        data_config : config
188                    } ).call(this.parent,cursor_label);
189                     dataObj.highlight.render();
190         }
191 
192 
193     var line = line_panel.add(pv.Panel)
194             .data(filter_data)
195 
196             .add(pv.Line)
197             .data(dataObj._dims)
198             .events('painted')
199             .event('click', function(c) {dataObj.selected = dataObj.hovered; highlight.render();})
200             .event('mouseover', overLine)
201             .left(function(t, d) { return x(t);})
202             .bottom(function(t, d) { return y[t](d[t]);})
203             .strokeStyle(function(t, d) { return c[active](d[active]);})
204             .lineWidth(1);
205 
206 
207 
208     var highlight = change.add(pv.Panel)
209             .data(function() {return [dataObj.hovered,dataObj.selected];})
210             .event('click', function(c) {dataObj.selected = dataObj.hovered; highlight.render();})
211             .visible(function(d) { return d != undefined;});
212     highlight.add(pv.Line)
213             .data(dataObj._dims)
214             .events('painted')
215             .event('mouseover',overLine)
216             .strokeStyle(function(t,d) {return this.parent.index == 1 ? 'red' : 'yellow';})
217             .left(function(t, d) { return x(t);})
218             .lineWidth(2.5)
219             .bottom(function(t, d) { return y[t](d[t]);});
220 
221     dataObj.highlight = highlight;
222 
223     var handle = change.add(pv.Panel);
224 
225     // Updater for slider and resizer.
226     function update(d) {
227         var t = d.dim;
228         that.filter[t].min = Math.max(y[t].domain()[0], y[t].invert(h - d.y - d.dy));
229         that.filter[t].max = Math.min(y[t].domain()[1], y[t].invert(h - d.y));
230         active = t;
231         change.render();
232         return false;
233     }
234 
235     // Updater for slider and resizer.
236     function selectAll(d) {
237         if (d.dy < 3) {
238             var t = d.dim;
239             that.filter[t].min = Math.max(y[t].domain()[0], y[t].invert(0));
240             that.filter[t].max = Math.min(y[t].domain()[1], y[t].invert(h));
241             d.y = 0; d.dy = h;
242             active = t;
243             change.render();
244         }
245         return false;
246     }
247 
248     /* Handle select and drag */
249         handle
250             .data(dataObj._dims.map(function(dim) { return {y:0, dy:h, dim:dim}; }))
251             .left(function(t) { return x(t.dim) - 15;})
252             .width(30)
253             .fillStyle("rgba(0,0,0,.1)")
254             .strokeStyle("rgba(0,0,0,.5)")
255             .lineWidth(".2px")
256                 .events('all')
257             .cursor("crosshair")
258             .event("mousedown", pv.Behavior.select())
259             .event("select", update)
260             .event("selectend", selectAll)
261           .add(pv.Bar)
262             .left(10)
263             .top(function(d) { return d.y;})
264             .width(10)
265             .height(function(d) { return d.dy;})
266             .fillStyle(function(t) { return t.dim == active
267             ? c[t.dim]((that.filter[t.dim].max + that.filter[t.dim].min) / 2)
268             : "hsla(0,0,50%,.5)";})
269             .strokeStyle("white")
270             .cursor("move")
271             .event("mousedown", pv.Behavior.drag())
272             .event("dragstart", update)
273             .event("drag", update);
274 
275     handle.anchor("bottom").add(pv.Label)
276             .textBaseline("top")
277             .text(function(d) { return that.filter[d.dim].min.toPrecision(3);});
278 
279     handle.anchor("top").add(pv.Label)
280             .textBaseline("bottom")
281             .text(function(d) { return that.filter[d.dim].max.toPrecision(3);});
282 
283     vis.render();
284 };
285 
286 vq.models.PaCoData = function(data) {
287 
288     vq.models.VisData.call(this,data);
289     this.setDataModel();
290     if (this.getDataType() == 'vq.models.PaCoData') {
291         this._build_data(this.getContents());
292     } else {
293         console.warn('Unrecognized JSON object.  Expected vq.models.PaCoData object.');
294     }
295 };
296 
297 vq.models.PaCoData.prototype = pv.extend(vq.models.VisData);
298 
299 
300 /**
301  * @private Builds the data structure up.
302  * @param data Contents of JSON data structure
303  */
304 vq.models.PaCoData.prototype._build_data  = function(data) {
305     var that = this;
306 
307     this._processData(data);
308 
309     if (this._coordinates != null) {
310         this._dims=this._coordinates.map(function(coord) { return coord.id;});
311         this._coordinates_map = pv.numerate(that._coordinates,function(d) {return d.id;});
312         this.setDataReady(true);
313     } else {
314         console.error('Coordinate configuration not passed to constructor!');
315     }
316 };
317 
318 vq.models.PaCoData.prototype.setDataModel = function () {
319     this._dataModel = [
320         {label: 'width', id: 'PLOT.width', cast : Number, defaultValue: 700},
321         {label: 'height', id: 'PLOT.height', cast : Number, defaultValue: 300},
322         {label : 'container', id:'PLOT.container', optional : true},
323         {label:  'vertical_padding', id: 'PLOT.vertical_padding', cast : Number, defaultValue: 20},
324         {label:  'horizontal_padding', id: 'PLOT.horizontal_padding',cast : Number,  defaultValue:30},
325         {label : '_data', id: 'data_array', defaultValue : [] },
326         {label : '_identifier_column', id: 'CONFIGURATION.identifier_column ',cast : String, defaultValue : ''},
327         {label : '_label_column', id: 'CONFIGURATION.label_column',cast : String, defaultValue : ''},
328         {label : '_coordinates', id: 'CONFIGURATION.COORD_COLUMN_ARRAY', defaultValue : []},
329         {label : 'tooltipItems', id: 'tooltip_items', defaultValue : {
330             Name : 'nodeName',
331             Parent : 'parentNode.nodeName'
332         }  },
333         {label : '_notifier', id: 'notifier', cast : Function, defaultValue : function() {return null;}}
334     ];
335 };