Completed
Push — master ( 66a6f6...d4f8e2 )
by Chris
01:21
created

jsondash.handlers.handleGraph   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 1
c 1
b 1
f 0
nc 1
nop 2
dl 0
loc 24
rs 8.9713

1 Function

Rating   Name   Duplication   Size   Complexity  
A 0 21 1
1
/** global: jsondash */
2
/** global: c3 */
3
/** global: d3 */
4
/** global: venn */
5
/** global: Plotly */
6
7
jsondash.getJSON = function(container, url, callback) {
8
    if(!url) throw new Error('Invalid URL: ' + url);
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
9
    var err_msg = null;
10
    d3.json(url, function(error, data){
11
        if(error) {
12
            jsondash.unload(container);
13
            err_msg = 'Error: ' + error.status + ' ' + error.statusText;
14
        }
15
        else if(!data) {
16
            jsondash.unload(container);
17
            err_msg = 'No data was found (invalid response).';
18
        }
19
        if(error || !data) {
20
            container.classed({error: true});
21
            container.select('.error-overlay')
22
                .classed({hidden: false})
23
                .select('.alert')
24
                .text(err_msg);
25
            jsondash.unload(container);
26
            return;
27
        }
28
        callback(error, data);
29
    });
30
};
31
32
33
/**
34
 * [getTitleBarHeight Return the height for a chart containers titlebar,
35
 *     plus any other computed box model properties.
36
 */
37
jsondash.getTitleBarHeight = function(container) {
38
    var titlebar = container.select('.widget-title');
39
    var titlebar_height = titlebar.node().getBoundingClientRect().height;
40
    var titlebar_padding = parseInt(titlebar.style('padding-bottom').replace('px', ''), 10);
41
    return titlebar_height + titlebar_padding;
42
};
43
44
/**
45
 * [getDynamicWidth Return the width for a container that has no specified width
46
 * (e.g. grid mode)]
47
 */
48
jsondash.getDynamicWidth = function(container, config) {
49
    if(isNaN(config.width)) {
50
        return d3.round(container.node().getBoundingClientRect().width);
51
    }
52
    return parseInt(config.width, 10);
53
};
54
55
56
/**
57
 * [getDiameter Calculate a valid diameter for a circular widget,
58
 * based on width/height to ensure the size never goes out of the container bounds.]
59
 */
60
jsondash.getDiameter = function(container, config) {
61
    var width = isNaN(config.width) ? jsondash.getDynamicWidth(container, config) : config.width;
62
    return d3.min([d3.round(width), config.height]);
63
};
64
65
/**
66
 * Handler for all sigma.js specifications
67
 */
68
jsondash.handlers.handleSigma = function(container, config) {
69
    'use strict';
70
    var _width = isNaN(config.width) ? jsondash.getDynamicWidth(container, config) : config.width;
71
    // Titlebar + padding + a bit extra to account for the bottom.
72
    var titlebar_offset = jsondash.getTitleBarHeight(container) * 1.2;
73
    // Sigmajs just assumes an ID for the querySelector, so we need to add one
74
    // to the child container.
75
    var new_id = 'sigma-' + jsondash.util.guid();
76
    var width = (_width - 10) + 'px';
77
    var height = (config.height - titlebar_offset) + 'px';
78
    container
79
        .select('.chart-container')
80
        .attr('id', new_id)
81
        .classed(jsondash.util.getCSSClasses(config))
82
        .style({
83
        width: width,
84
        height: height
85
    });
86
    jsondash.getJSON(container, config.dataSource, function(error, data){
87
        var sig = new sigma({
0 ignored issues
show
Unused Code introduced by
The variable sig seems to be never used. Consider removing it.
Loading history...
Coding Style Best Practice introduced by
By convention, constructors like sigma should be capitalized.
Loading history...
Bug introduced by
The variable sigma seems to be never declared. If this is a global, consider adding a /** global: sigma */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
88
          graph: data,
89
          width: width,
90
          height: height,
91
          container: new_id
92
        });
93
        // Look for callbacks potentially registered for third party code.
94
        jsondash.api.runCallbacks(container, config);
95
        jsondash.unload(container);
96
    });
97
};
98
99
/**
100
 * Handler for all cytoscape specifications
101
 */
102
jsondash.handlers.handleCytoscape = function(container, config) {
103
    'use strict';
104
    var _width = isNaN(config.width) ? jsondash.getDynamicWidth(container, config) : config.width;
105
    // Titlebar + padding + a bit extra to account for the bottom.
106
    var titlebar_offset = jsondash.getTitleBarHeight(container) * 1.2;
107
    container
108
        .select('.chart-container')
109
        .classed(jsondash.util.getCSSClasses(config))
110
        .style({
111
        width: (_width - 10) + 'px',
112
        height: (config.height - titlebar_offset) + 'px'
113
    });
114
    jsondash.getJSON(container, config.dataSource, function(error, cyspec){
115
        // the `document.getElementByID` declaration in the cytoscape
116
        // spec is not serializable so we will ignore anything user
117
        // sent and just drop our selector in place of it.
118
        var override = {
119
            container: document.querySelector('[data-guid="' + config.guid + '"] .chart-container'),
120
            // We intentionally override w/h with null values,
121
            // so the graph is forced to be
122
            // constrained to the parent dimensions.
123
            layout: {
124
                width: null,
125
                height: null
126
            },
127
        };
128
        var spec = $.extend(cyspec, override);
129
        console.log(spec);
0 ignored issues
show
Debugging Code introduced by
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
130
        var cy = cytoscape(spec);
0 ignored issues
show
Unused Code introduced by
The variable cy seems to be never used. Consider removing it.
Loading history...
131
        // Look for callbacks potentially registered for third party code.
132
        jsondash.api.runCallbacks(container, config);
133
        jsondash.unload(container);
134
    });
135
};
136
137
/**
138
 * Handler for all vega-lite specifications
139
 */
140
jsondash.handlers.handleVegaLite = function(container, config) {
141
    'use strict';
142
    jsondash.getJSON(container, config.dataSource, function(error, vlspec){
143
        var SCALE_FACTOR = 0.7; // very important to get sizing jusst right.
144
        var selector = '[data-guid="' + config.guid + '"] .chart-container';
145
        var width = isNaN(config.width) ? jsondash.getDynamicWidth(container, config) : config.width;
146
        var size = d3.max([config.height, width]);
147
        var overrides = {
148
            width: ~~(size * SCALE_FACTOR),
149
            height: ~~(config.height * SCALE_FACTOR)
150
        };
151
        var embedSpec = {
152
            mode: 'vega-lite',
153
            spec: $.extend({}, vlspec, overrides)
154
        };
155
        d3.select(selector).classed(jsondash.util.getCSSClasses(config))
156
        vg.embed(selector, embedSpec, function(error, result) {
0 ignored issues
show
Bug introduced by
The variable vg seems to be never declared. If this is a global, consider adding a /** global: vg */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
Unused Code introduced by
The parameter result is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
157
            // Callback receiving the View instance and parsed Vega spec
158
            // result.view is the View, which resides under the '#vis' element
159
            if(error) {
160
                throw new Error('Error loading chart: ' + error);
161
            }
162
            // Change look of default buttons
163
            container.select('.vega-actions')
164
                .classed({'btn-group': true})
165
                .selectAll('a')
166
                .classed({'btn btn-xs btn-default': true});
167
            // Look for callbacks potentially registered for third party code.
168
            jsondash.api.runCallbacks(container, config);
169
            jsondash.unload(container);
170
        });
171
    });
172
};
173
174
/**
175
 * Handlers for various widget types. The method signatures are always the same,
176
 * but each handler can handle them differently.
177
 */
178
jsondash.handlers.handleYoutube = function(container, config) {
179
    // Clean up all previous.
180
    'use strict';
181
    function getAttr(prop, props) {
182
        // Return the propery from a list of properties for the iframe.
183
        // e.g. getAttr('width', ["width="900""]) --> "900"
184
        return props.filter(function(k, v){
0 ignored issues
show
Unused Code introduced by
The parameter v is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
185
            return k.startsWith(prop);
186
        })[0];
187
    }
188
189
190
    var url = config.dataSource;
0 ignored issues
show
Unused Code introduced by
The assignment to variable url seems to be never used. Consider removing it.
Loading history...
191
    var parts = config.dataSource.split(' ');
192
    var yt_width = parseInt(getAttr('width', parts).split('=')[1].replace(/"/gi, ''), 10);
193
    var height = parseInt(getAttr('height', parts).split('=')[1].replace(/"/gi, ''), 10);
194
    var width = isNaN(config.width) ? '100%' : yt_width;
195
    var url = getAttr('src', parts).replace('src=', '').replace(/"/gi, '');
0 ignored issues
show
Comprehensibility Naming Best Practice introduced by
The variable url already seems to be declared on line 190. Consider using another variable name or omitting the var keyword.

This check looks for variables that are declared in multiple lines. There may be several reasons for this.

In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs.

If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared.

Loading history...
196
197
    // In the case of YouTube, we have to override the config dimensions
198
    // as this will be wonky when the aspect ratio is calculated. We will
199
    // defer to YouTube calculations instead.
200
    container
201
        .select('.chart-container')
202
        .append('iframe')
203
        .classed(jsondash.util.getCSSClasses(config))
204
        .attr('width', width)
205
        .attr('height', height)
206
        .attr('src', url)
207
        .attr('allowfullscreen', true)
208
        .attr('frameborder', 0);
209
    // Look for callbacks potentially registered for third party code.
210
    jsondash.api.runCallbacks(container, config);
211
    jsondash.unload(container);
212
};
213
214
/**
215
 * [handleGraph creates graphs using the dot format
216
 * spec with d3 and dagre-d3]
217
 */
218
jsondash.handlers.handleGraph = function(container, config) {
219
    'use strict';
220
    jsondash.getJSON(container, config.dataSource, function(error, data){
221
        var h = config.height - jsondash.config.WIDGET_MARGIN_Y;
0 ignored issues
show
Unused Code introduced by
The variable h seems to be never used. Consider removing it.
Loading history...
222
        var w = config.width - jsondash.config.WIDGET_MARGIN_X;
0 ignored issues
show
Unused Code introduced by
The variable w seems to be never used. Consider removing it.
Loading history...
223
        var svg = container
224
            .select('.chart-container')
225
            .append('svg')
226
            .classed(jsondash.util.getCSSClasses(config))
227
            .classed({'chart-graph': true});
228
        var svg_group = svg.append('g');
229
        var g = graphlibDot.read(data.graph);
0 ignored issues
show
Bug introduced by
The variable graphlibDot seems to be never declared. If this is a global, consider adding a /** global: graphlibDot */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
230
        var bbox = null;
0 ignored issues
show
Unused Code introduced by
The assignment to bbox seems to be never used. If you intend to free memory here, this is not necessary since the variable leaves the scope anyway.
Loading history...
231
        // Create the renderer
232
        var render = new dagreD3.render();
0 ignored issues
show
Bug introduced by
The variable dagreD3 seems to be never declared. If this is a global, consider adding a /** global: dagreD3 */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
233
        render(svg_group, g);
234
        bbox = svg.node().getBBox();
235
        svg.attr('width', bbox.width)
236
            .attr('height', bbox.height);
237
        // Look for callbacks potentially registered for third party code.
238
        jsondash.api.runCallbacks(container, config);
239
        jsondash.unload(container);
240
    });
241
};
242
243
/**
244
 * [handleWordCloud create word clouds using the d3-cloud extension.]
245
 */
246
jsondash.handlers.handleWordCloud = function(container, config) {
247
    'use strict';
248
    jsondash.getJSON(container, config.dataSource, function(error, data){
249
        var h     = config.height - jsondash.config.WIDGET_MARGIN_Y;
250
        var w     = config.width - jsondash.config.WIDGET_MARGIN_X;
251
        var svg   = container
252
            .select('.chart-container')
253
            .append('svg')
254
            .classed(jsondash.util.getCSSClasses(config))
255
            .classed({'wordcloud': true});
256
        var fill  = d3.scale.category20();
0 ignored issues
show
Unused Code introduced by
The variable fill seems to be never used. Consider removing it.
Loading history...
257
        var cloud = d3.layout.cloud;
258
        var words = data.map(function(d) {
259
            return {text: d.text, size: d.size};
260
        });
261
        var layout = cloud()
262
            .size([w, h])
263
            .words(words)
264
            .padding(4)
265
            .rotate(function() {return ~~(Math.random() * 1) * 90;})
266
            .font('Arial')
267
            .fontSize(function(d) {return d.size;})
268
            .on('end', draw);
269
270
        layout.start();
271
272
        function draw(words) {
273
          svg
274
              .attr('width', layout.size()[0])
275
              .attr('height', layout.size()[1])
276
            .append('g')
277
              .attr('transform', 'translate(' + layout.size()[0] / 2 + ',' + layout.size()[1] / 2 + ')')
278
            .selectAll('text').data(words)
279
            .enter().append('text')
280
              .style('font-size', function(d) { return d.size + 'px'; })
281
              .style('font-family', 'arial')
282
              .style('fill', function(d, i) { return "#000"; })
0 ignored issues
show
Unused Code introduced by
The parameter i is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter d is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
283
              .attr('text-anchor', 'middle')
284
              .attr('transform', function(d) {
285
                return 'translate(' + [d.x, d.y] + ')rotate(' + d.rotate + ')';
286
              })
287
              .text(function(d) { return d.text; });
288
        }
289
290
        // Look for callbacks potentially registered for third party code.
291
        jsondash.api.runCallbacks(container, config);
292
        jsondash.unload(container);
293
    });
294
};
295
296
jsondash.handlers.handleC3 = function(container, config) {
297
    var _width = isNaN(config.width) ? jsondash.getDynamicWidth(container, config) : config.width;
298
    'use strict';
299
    var init_config = {
300
        bindto: '[data-guid="' + config.guid + '"] .chart-container',
301
        legend: {
302
            show: true
303
        },
304
        size: {
305
            height: config.height - jsondash.config.WIDGET_MARGIN_Y,
306
            width: _width - jsondash.config.WIDGET_MARGIN_X
307
        },
308
        data: {},
309
        onrendered: function(){
310
            // Look for callbacks potentially registered for third party code.
311
            jsondash.api.runCallbacks(container, config);
312
            jsondash.unload(container);
313
        }
314
    };
315
316
    container
317
        .select('.chart-container')
318
        .classed(jsondash.util.getCSSClasses(config))
319
320
    /**
321
     * [normalizeData Transform data from a standardized jsondash
322
     *     format into one suitable for c3.]
323
     */
324
    function normalizeData(data, type) {
325
        // For most cases, we build out N columns into ['label', 0, 1, 2, 3] format
326
        // from data in format: {'foo': [1, 2]} or format {'foo': 1}
327
        var cols = [];
328
        if(type === 'donut' || type === 'gauge' || type === 'pie') {
329
            $.each(data, function(label, val){
330
                cols.push([label, val]);
331
            });
332
            return cols;
333
        }
334
        if(type === 'timeseries') {
335
            var dates = ['x'];
336
            data.dates.map(function(date, _){
0 ignored issues
show
Unused Code introduced by
The parameter _ is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
337
                dates.push(date);
338
            });
339
            cols.push(dates);
340
        }
341
        $.each(data, function(label, vals){
342
            if(label !== 'dates') {
343
                var newarr = [label];
344
                vals.map(function(val, _){
0 ignored issues
show
Unused Code introduced by
The parameter _ is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
345
                    newarr.push(val);
346
                });
347
                cols.push(newarr);
348
            }
349
        });
350
        return cols;
351
    }
352
353
    jsondash.getJSON(container, config.dataSource, function(error, data){
354
        if(jsondash.util.isOverride(config)) {
355
            // Just use the raw payload for this widgets' options.
356
            // Keep existing options if not specified.
357
            init_config = $.extend(init_config, data);
358
        } else {
359
            if(config.type === 'timeseries') {
360
                // Map the corresponding data key and list of dates
361
                // to the `x` property.
362
                init_config.axis = {
363
                    x: {type: 'timeseries'}
364
                };
365
                init_config.data.x = 'x';
366
            } else {
367
                init_config.data.type = config.type;
368
            }
369
            init_config.data.columns = normalizeData(data, config.type);
370
        }
371
        c3.generate(init_config);
372
    });
373
};
374
375
jsondash.handlers.handleD3 = function(container, config) {
376
    'use strict';
377
    // Handle specific types.
378
    if(config.type === 'radial-dendrogram') { return jsondash.handlers.handleRadialDendrogram(container, config); }
379
    if(config.type === 'dendrogram') { return jsondash.handlers.handleDendrogram(container, config); }
380
    if(config.type === 'voronoi') { return jsondash.handlers.handleVoronoi(container, config); }
381
    if(config.type === 'treemap') { return jsondash.handlers.handleTreemap(container, config); }
382
    if(config.type === 'circlepack') { return jsondash.handlers.handleCirclePack(container, config); }
383
    throw new Error('Unknown type: ' + config.type);
384
};
385
386
jsondash.handlers.handleCirclePack = function(container, config) {
387
    'use strict';
388
    // Adapted from https://bl.ocks.org/mbostock/4063530
389
    var margin = jsondash.config.WIDGET_MARGIN_Y;
390
    var diameter = jsondash.getDiameter(container, config) - margin;
391
    var format = d3.format(',d');
392
    var pack = d3.layout.pack()
393
        .size([diameter, diameter])
394
        .value(function(d) { return d.size; });
395
    var svg = container
396
        .select('.chart-container')
397
        .append('svg')
398
        .classed(jsondash.util.getCSSClasses(config))
399
        .attr('width', diameter)
400
        .attr('height', diameter)
401
        .append('g');
402
403
    jsondash.getJSON(container, config.dataSource, function(error, data) {
404
        var node = svg.datum(data).selectAll('.node')
405
        .data(pack.nodes)
406
        .enter().append('g')
407
        .attr('class', function(d) { return d.children ? 'node' : 'leaf node'; })
408
        .attr('transform', function(d) { return 'translate(' + d.x + ',' + d.y + ')'; });
409
410
        node.append('title')
411
        .text(function(d) { return d.name + (d.children ? '' : ': ' + format(d.size)); });
412
413
        node.append('circle')
414
        .attr('r', function(d) { return d.r; });
415
416
        node.filter(function(d) { return !d.children; }).append('text')
417
        .attr('dy', '.3em')
418
        .style('text-anchor', 'middle')
419
        .text(function(d) { return d.name.substring(0, d.r / 3); });
420
        // Look for callbacks potentially registered for third party code.
421
        jsondash.api.runCallbacks(container, config);
422
        jsondash.unload(container);
423
    });
424
    d3.select(self.frameElement).style("height", diameter + "px");
0 ignored issues
show
Bug introduced by
The variable self seems to be never declared. If this is a global, consider adding a /** global: self */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
425
};
426
427
jsondash.handlers.handleTreemap = function(container, config) {
428
    'use strict';
429
    // Adapted from http://bl.ocks.org/mbostock/4063582
430
    var margin = {
0 ignored issues
show
Unused Code introduced by
The variable margin seems to be never used. Consider removing it.
Loading history...
431
        top: jsondash.config.WIDGET_MARGIN_Y / 2,
432
        bottom: jsondash.config.WIDGET_MARGIN_Y / 2,
433
        left: jsondash.config.WIDGET_MARGIN_X / 2,
434
        right: jsondash.config.WIDGET_MARGIN_X / 2
435
    };
436
    var _width = isNaN(config.width) ? jsondash.getDynamicWidth(container, config) : config.width;
437
    var width = _width - jsondash.config.WIDGET_MARGIN_X;
438
    var height = config.height - jsondash.config.WIDGET_MARGIN_Y;
439
    var color = d3.scale.category20c();
440
    var treemap = d3.layout.treemap()
441
        .size([width, height])
442
        .sticky(true)
443
        .value(function(d) { return d.size; });
444
    var div = container
445
        .select('.chart-container')
446
        .append('div')
447
        .classed(jsondash.util.getCSSClasses(config))
448
        .classed({treemap: true, 'chart-centered': true})
449
        .style('position', 'relative')
450
        .style('width', width + 'px')
451
        .style('height', height + 'px');
452
453
    jsondash.getJSON(container, config.dataSource, function(error, root) {
454
        var node = div.datum(root).selectAll('.node')
455
            .data(treemap.nodes)
456
            .enter().append('div')
457
            .attr('class', 'node')
458
            .call(position)
459
            .style('border', '1px solid white')
460
            .style('font', '10px sans-serif')
461
            .style('line-height', '12px')
462
            .style('overflow', 'hidden')
463
            .style('position', 'absolute')
464
            .style('text-indent', '2px')
465
            .style('background', function(d) {
466
                return d.children ? color(d.name) : null;
467
            })
468
            .text(function(d) {
469
                return d.children ? null : d.name;
470
            });
471
        d3.selectAll('input').on('change', function change() {
472
            var value = this.value === 'count'
473
            ? function() { return 1; }
474
            : function(d) { return d.size;};
475
            node
476
            .data(treemap.value(value).nodes)
477
            .transition()
478
            .duration(1500)
479
            .call(position);
480
        });
481
        // Look for callbacks potentially registered for third party code.
482
        jsondash.api.runCallbacks(container, config);
483
        jsondash.unload(container);
484
    });
485
486
    function position() {
487
        this.style('left', function(d) { return d.x + 'px'; })
488
            .style('top', function(d) { return d.y + 'px'; })
489
            .style('width', function(d) { return Math.max(0, d.dx - 1) + 'px'; })
490
            .style('height', function(d) { return Math.max(0, d.dy - 1) + 'px'; });
491
    }
492
};
493
494
jsondash.handlers.handleRadialDendrogram = function(container, config) {
495
    'use strict';
496
    // Code taken (and refactored for use here) from:
497
    // https://bl.ocks.org/mbostock/4339607
498
    var _width = isNaN(config.width) ? jsondash.getDynamicWidth(container, config) : config.width;
0 ignored issues
show
Unused Code introduced by
The variable _width seems to be never used. Consider removing it.
Loading history...
499
    var radius = jsondash.getDiameter(container, config);
500
    var cluster = d3.layout.cluster()
501
        .size([360, radius / 2 - 150]); // reduce size relative to `radius`
502
    var diagonal = d3.svg.diagonal.radial()
503
        .projection(function(d) { return [d.y, d.x / 180 * Math.PI]; });
504
    var svg = container
505
        .select('.chart-container')
506
        .append('svg')
507
        .classed(jsondash.util.getCSSClasses(config))
508
        .attr('width', radius)
509
        .attr('height', radius);
510
    var g = svg.append('g');
511
    g.attr('transform', 'translate(' + radius / 2 + ',' + radius / 2 + ')');
512
513
    jsondash.getJSON(container, config.dataSource, function(error, root) {
514
        if (error) { throw error; }
515
        var nodes = cluster.nodes(root);
516
        var link = g.selectAll('path.link')
0 ignored issues
show
Unused Code introduced by
The variable link seems to be never used. Consider removing it.
Loading history...
517
            .data(cluster.links(nodes))
518
            .enter().append('path')
519
            .attr('class', 'link')
520
            .attr('d', diagonal);
521
        var node = g.selectAll('g.node')
522
            .data(nodes)
523
            .enter().append('g')
524
            .attr('class', 'node')
525
            .attr('transform', function(d) { return 'rotate(' + (d.x - 90) + ')translate(' + d.y + ')'; });
526
        node.append('circle')
527
            .attr('r', 4.5);
528
        node.append('text')
529
            .attr('dy', '.31em')
530
            .attr('text-anchor', function(d) { return d.x < 180 ? 'start' : 'end'; })
531
            .attr('transform', function(d) { return d.x < 180 ? 'translate(8)' : 'rotate(180)translate(-8)'; })
532
            .text(function(d) { return d.name; });
533
        // Look for callbacks potentially registered for third party code.
534
        jsondash.api.runCallbacks(container, config);
535
        jsondash.unload(container);
536
    });
537
    d3.select(self.frameElement).style('height', radius * 2 + 'px');
0 ignored issues
show
Bug introduced by
The variable self seems to be never declared. If this is a global, consider adding a /** global: self */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
538
};
539
540
jsondash.handlers.handleDendrogram = function(container, config) {
541
    'use strict';
542
    var _width = isNaN(config.width) ? jsondash.getDynamicWidth(container, config) : config.width;
543
    // A general padding for the svg inside of the widget.
544
    // The cluster dendrogram will also need to have padding itself, so
545
    // the bounds are not clipped in the svg.
546
    var svg_pad = 20;
547
    var width = _width - svg_pad;
548
    var height = config.height - svg_pad;
549
    var PADDING = width / 4;
550
    var cluster = d3.layout.cluster()
551
        .size([height * 0.85, width - PADDING]);
552
    var diagonal = d3.svg.diagonal()
553
        .projection(function(d) { return [d.y, d.x]; });
554
    var svg = container
555
        .select('.chart-container')
556
        .append('svg')
557
        .classed(jsondash.util.getCSSClasses(config))
558
        .attr('width', width)
559
        .attr('height', height);
560
    var g = svg.append('g')
561
        .attr('transform', 'translate(40, 0)');
562
563
    jsondash.getJSON(container, config.dataSource, function(error, root) {
564
        var nodes = cluster.nodes(root);
565
        var links = cluster.links(nodes);
566
        var link = g.selectAll('.link')
0 ignored issues
show
Unused Code introduced by
The variable link seems to be never used. Consider removing it.
Loading history...
567
        .data(links)
568
        .enter().append('path')
569
        .attr('class', 'link')
570
        .attr('d', diagonal);
571
572
        var node = g.selectAll('.node')
573
        .data(nodes)
574
        .enter().append('g')
575
        .attr('class', 'node')
576
        .attr('transform', function(d) { return 'translate(' + d.y + ',' + d.x + ')'; });
577
578
        node.append('circle').attr('r', 4.5);
579
        node.append('text')
580
        .attr('dx', function(d) { return d.children ? -8 : 8; })
581
        .attr('dy', 3)
582
        .style('text-anchor', function(d) { return d.children ? 'end' : 'start'; })
583
        .text(function(d) { return d.name; });
584
585
        // Look for callbacks potentially registered for third party code.
586
        jsondash.api.runCallbacks(container, config);
587
        jsondash.unload(container);
588
    });
589
};
590
591
jsondash.handlers.handleVoronoi = function(container, config) {
592
    'use strict';
593
    jsondash.getJSON(container, config.dataSource, function(error, data){
594
        var _width   = isNaN(config.width) ? jsondash.getDynamicWidth(container, config) : config.width;
595
        var width    = _width - jsondash.config.WIDGET_MARGIN_X;
596
        var height   = config.height - jsondash.config.WIDGET_MARGIN_Y;
597
        var vertices = data;
598
        var voronoi  = d3.geom.voronoi().clipExtent([[0, 0], [width, height]]);
599
        var svg = container
600
            .select('.chart-container')
601
            .append('svg')
602
            .classed(jsondash.util.getCSSClasses(config))
603
            .attr('width', width)
604
            .attr('height', height);
605
        var path = svg.append('g').selectAll('path');
606
        svg.selectAll('circle')
607
            .data(vertices.slice(1))
608
            .enter().append('circle')
609
            .attr('transform', function(d) { return 'translate(' + d + ')'; })
610
            .attr('r', 1.5);
611
            redraw();
612
613
        function redraw() {
614
            path = path.data(voronoi(vertices), jsondash.util.polygon);
615
            path.exit().remove();
616
            path.enter().append('path')
617
            .attr('class', function(d, i) { return 'q' + (i % 9) + '-9'; })
618
            .attr('d', jsondash.util.polygon);
619
            path.order();
620
        }
621
        // Look for callbacks potentially registered for third party code.
622
        jsondash.api.runCallbacks(container, config);
623
        jsondash.unload(container);
624
    });
625
};
626
627
jsondash.handlers.handleSparkline = function(container, config) {
628
    'use strict';
629
    var sparkline_type = config.type.split('-')[1];
630
    var spark = container
631
        .select('.chart-container')
632
        .append('div')
633
        .classed(jsondash.util.getCSSClasses(config))
634
        .classed({
635
            'sparkline-container': true,
636
            'text-center': true
637
        });
638
    spark = $(spark[0]);
639
    jsondash.getJSON(container, config.dataSource, function(data){
640
        var opts = {
641
            type: sparkline_type,
642
            width: config.width - jsondash.config.WIDGET_MARGIN_X,
643
            height: config.height - jsondash.config.WIDGET_MARGIN_Y
644
        };
645
        spark.sparkline(data, opts);
646
        // Look for callbacks potentially registered for third party code.
647
        jsondash.api.runCallbacks(container, config);
648
        jsondash.unload(container);
649
    });
650
};
651
652
jsondash.handlers.handleDataTable = function(container, config) {
653
    'use strict';
654
    jsondash.getJSON(container, config.dataSource, function(error, res) {
655
        var keys = d3.keys(res[0]).map(function(d){
656
            return {data: d, title: d};
657
        });
658
        var titlebar_offset = jsondash.getTitleBarHeight(container) * 2.2;
659
        var table_class_defaults = ['table', 'table-bordered', 'table-striped'];
660
        var classes = jsondash.util.getCSSClasses(config, table_class_defaults);
661
        container
662
            .select('.chart-container')
663
            .append('table')
664
            .classed(classes);
665
        var opts = config.override ? res : {data: res, columns: keys};
666
        $(container.select('table')[0])
667
            .dataTable(opts).css({
668
                width: 'auto',
669
                height: $(container[0]).innerHeight() - titlebar_offset
670
        });
671
        // Look for callbacks potentially registered for third party code.
672
        jsondash.api.runCallbacks(container, config);
673
        jsondash.unload(container);
674
    });
675
};
676
677
jsondash.handlers.handleSingleNum = function(container, config) {
678
    'use strict';
679
    jsondash.getJSON(container, config.dataSource, function(error, res){
680
        var data = res.data.data ? res.data.data : res.data;
681
        var num = container
682
            .select('.chart-container')
683
            .append('div')
684
            .classed({singlenum: true})
685
            .classed(jsondash.util.getCSSClasses(config))
686
            .text(data);
687
        data = String(data);
688
        // Add red or green, depending on if the number appears to be pos/neg.
689
        if(!res.noformat) {
690
            num.classed({
691
                'text-danger': data.startsWith('-'),
692
                'text-success': !data.startsWith('-')
693
            });
694
        }
695
        // Allow custom colors.
696
        if(res.color && res.noformat) {
697
            num.style('color', res.color);
698
        }
699
        // Get title height to offset box.
700
        var title_h = container
0 ignored issues
show
Unused Code introduced by
The variable title_h seems to be never used. Consider removing it.
Loading history...
701
            .select('.widget-title')
702
            .node()
703
            .getBoundingClientRect()
704
            .height;
705
        var h = config.height - jsondash.config.WIDGET_MARGIN_Y;
706
        num.style({
707
            'line-height': h + 'px',
708
            height: h + 'px',
709
            width: config.width - jsondash.config.WIDGET_MARGIN_X
710
        });
711
        var digits = String(data).length;
712
        var size = jsondash.util.getDigitSize()(digits);
713
        num.style('font-size', size + 'px');
714
        // Look for callbacks potentially registered for third party code.
715
        jsondash.api.runCallbacks(container, config);
716
        jsondash.unload(container);
717
    });
718
};
719
720
jsondash.handlers.handleTimeline = function(container, config) {
721
    'use strict';
722
    jsondash.getJSON(container, config.dataSource, function(data){
723
        container
724
            .append('div')
725
            .classed(jsondash.util.getCSSClasses(config))
726
            .attr('id', 'widget-' + config.guid);
727
        var timeline = new TL.Timeline('widget-' + config.guid, data);
0 ignored issues
show
Bug introduced by
The variable TL seems to be never declared. If this is a global, consider adding a /** global: TL */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
Unused Code introduced by
The variable timeline seems to be never used. Consider removing it.
Loading history...
728
        // Look for callbacks potentially registered for third party code.
729
        jsondash.api.runCallbacks(container, config);
730
        jsondash.unload(container);
731
    });
732
};
733
734
/**
735
 * [handleImage Embed an image src directly.]
736
 */
737
jsondash.handlers.handleImage = function(container, config) {
738
    'use strict';
739
    var img = container.select('.chart-container').append('img');
740
    var height = (config.height - jsondash.config.WIDGET_MARGIN_Y) + 'px';
741
    img.attr({
742
        src: config.dataSource,
743
        height: height
744
    });
745
    img.classed({img: true});
746
    img.classed(jsondash.util.getCSSClasses(config));
747
    // Look for callbacks potentially registered for third party code.
748
    jsondash.api.runCallbacks(container, config);
749
    jsondash.unload(container);
750
};
751
752
jsondash.handlers.handleIframe = function(container, config) {
753
    'use strict';
754
    var iframe = container
755
        .select('.chart-container')
756
        .append('iframe');
757
    iframe.attr({
758
        border: 0,
759
        src: config.dataSource,
760
        height: config.height - jsondash.config.WIDGET_MARGIN_Y,
761
        width: isNaN(config.width) ? '100%' : config.width - jsondash.config.WIDGET_MARGIN_X
762
    });
763
    iframe.classed(jsondash.util.getCSSClasses(config));
764
    // Look for callbacks potentially registered for third party code.
765
    jsondash.api.runCallbacks(container, config);
766
    jsondash.unload(container);
767
};
768
769
jsondash.handlers.handleCustom = function(container, config) {
770
    'use strict';
771
    $.get(config.dataSource, function(html){
772
        container
773
            .select('.chart-container')
774
            .append('div')
775
            .classed({'custom-container': true})
776
            .classed(jsondash.util.getCSSClasses(config))
777
            .html(html);
778
        // Look for callbacks potentially registered for third party code.
779
        jsondash.api.runCallbacks(container, config);
780
        jsondash.unload(container);
781
    });
782
};
783
784
jsondash.handlers.handleVenn = function(container, config) {
785
    'use strict';
786
    jsondash.getJSON(container, config.dataSource, function(error, data){
787
        var chart = venn.VennDiagram();
788
        var cont = container
789
            .select('.chart-container')
790
            .append('div')
791
            .classed(jsondash.util.getCSSClasses(config))
792
            .classed({venn: true});
793
        cont.datum(data).call(chart);
794
        cont.select('svg')
795
            .attr('width', config.width - jsondash.config.WIDGET_MARGIN_X)
796
            .attr('height', config.height - jsondash.config.WIDGET_MARGIN_Y);
797
        // Look for callbacks potentially registered for third party code.
798
        jsondash.api.runCallbacks(container, config);
799
        jsondash.unload(container);
800
    });
801
};
802
803
jsondash.handlers.handlePlotly = function(container, config) {
804
    'use strict';
805
    var id = 'plotly-' + config.guid;
806
    var _width = isNaN(config.width) ? jsondash.getDynamicWidth(container, config) : config.width;
807
    container
808
        .select('.chart-container')
809
        .append('div')
810
        .classed(jsondash.util.getCSSClasses(config))
811
        .classed({'plotly-container': true})
812
        .attr('id', id);
813
    jsondash.getJSON(container, config.dataSource, function(error, data){
814
        var plotly_wrapper =  d3.select('#' + id);
815
        delete data.layout.height;
816
        delete data.layout.width;
817
        data.layout.margin = {l: 20, r: 20, b: 20, t: 50};
818
        if(config.override) {
819
            Plotly.plot(id, data.data, data.layout || {}, data.options || {});
820
        } else {
821
            Plotly.plot(id, data);
822
        }
823
       plotly_wrapper.select('.svg-container').style({
824
            'margin': '0 auto',
825
            'width': isNaN(config.width) ? '100%' : config.width,
826
            'height': config.height
827
        });
828
        plotly_wrapper.select('#scene').style({
829
            'width': _width,
830
            'height': config.height
831
        });
832
        // Look for callbacks potentially registered for third party code.
833
        jsondash.api.runCallbacks(container, config);
834
        jsondash.unload(container);
835
    });
836
};
837