Completed
Push — master ( 66e86e...96649a )
by Chris
43s
created

jsondash.handlers.handleNumbersGroup   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
dl 0
loc 6
rs 9.4285
c 1
b 0
f 0
nc 2
nop 1
1
/** global: jsondash */
2
/** global: c3 */
3
/** global: d3 */
4
/** global: venn */
5
/** global: Plotly */
6
7
jsondash.handleRes = function(error, data, container) {
8
    var err_msg = '';
9
    if(error) {
10
        err_msg = 'Error: ' + error.status + ' ' + error.statusText;
11
    }
12
    else if(!data) {
13
        err_msg = 'No data was found (invalid response).';
14
    }
15
    if(error || !data) {
16
        container.classed({error: true});
17
        container.select('.error-overlay')
18
            .classed({hidden: false})
19
            .select('.alert')
20
            .text(err_msg);
21
        jsondash.unload(container);
22
    }
23
};
24
jsondash.getJSON = function(container, config, callback) {
25
    var url     = config.dataSource;
26
    var cached  = config.cachedData;
27
    var err_msg = null;
0 ignored issues
show
Unused Code introduced by
The variable err_msg seems to be never used. Consider removing it.
Loading history...
28
    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...
29
    if(cached && cached !== null && cached !== undefined) {
30
        // Ensure this is not re-used for this cycle. It's somewhat of a pseudo-cache in that sense.
31
        config.cachedData = null;
32
        return callback(null, cached);
33
    }
34
    d3.json(url, function(error, data){
35
        jsondash.handleRes(error, data, container);
36
        if(error || !data) {
37
            return;
38
        }
39
        callback(error, config.key && data.multicharts[config.key] ? data.multicharts[config.key] : data);
40
    });
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
41
};
42
43
44
/**
45
 * [getTitleBarHeight Return the height for a chart containers titlebar,
46
 *     plus any other computed box model properties.
47
 */
48
jsondash.getTitleBarHeight = function(container) {
49
    var titlebar = container.select('.widget-title');
50
    var titlebar_height = titlebar.node().getBoundingClientRect().height;
51
    var titlebar_padding = parseInt(titlebar.style('padding-bottom').replace('px', ''), 10);
52
    return titlebar_height + titlebar_padding;
53
};
54
55
/**
56
 * [getDynamicWidth Return the width for a container that has no specified width
57
 * (e.g. grid mode)]
58
 */
59
jsondash.getDynamicWidth = function(container, config) {
60
    if(isNaN(config.width)) {
61
        return d3.round(container.node().getBoundingClientRect().width);
62
    }
63
    return parseInt(config.width, 10);
64
};
65
66
67
/**
68
 * [getDiameter Calculate a valid diameter for a circular widget,
69
 * based on width/height to ensure the size never goes out of the container bounds.]
70
 */
71
jsondash.getDiameter = function(container, config) {
72
    var width = isNaN(config.width) ? jsondash.getDynamicWidth(container, config) : config.width;
73
    return d3.min([d3.round(width), config.height]);
74
};
75
76
/**
77
 * Handler for all sigma.js specifications
78
 */
79
jsondash.handlers.handleSigma = function(container, config) {
80
    'use strict';
81
    var _width = isNaN(config.width) ? jsondash.getDynamicWidth(container, config) : config.width;
82
    // Titlebar + padding + a bit extra to account for the bottom.
83
    var titlebar_offset = jsondash.getTitleBarHeight(container) * 1.2;
84
    // Sigmajs just assumes an ID for the querySelector, so we need to add one
85
    // to the child container.
86
    var new_id = 'sigma-' + jsondash.util.guid();
87
    var width = (_width - 10) + 'px';
88
    var height = (config.height - titlebar_offset) + 'px';
89
    container
90
        .select('.chart-container')
91
        .attr('id', new_id)
92
        .classed(jsondash.util.getCSSClasses(config))
93
        .style({
94
        width: width,
95
        height: height
96
    });
97
    jsondash.getJSON(container, config, function(error, data){
98
        var sig = new sigma({
0 ignored issues
show
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...
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...
99
          graph: data,
100
          width: width,
101
          height: height,
102
          container: new_id
103
        });
104
        // Look for callbacks potentially registered for third party code.
105
        jsondash.api.runCallbacks(container, config);
106
        jsondash.unload(container);
107
    });
108
};
109
110
/**
111
 * Handler for all cytoscape specifications
112
 */
113
jsondash.handlers.handleCytoscape = function(container, config) {
114
    'use strict';
115
    var _width = isNaN(config.width) ? jsondash.getDynamicWidth(container, config) : config.width;
116
    // Titlebar + padding + a bit extra to account for the bottom.
117
    var titlebar_offset = jsondash.getTitleBarHeight(container) * 1.2;
118
    container
119
        .select('.chart-container')
120
        .classed(jsondash.util.getCSSClasses(config))
121
        .style({
122
        width: (_width - 10) + 'px',
123
        height: (config.height - titlebar_offset) + 'px'
124
    });
125
    jsondash.getJSON(container, config, function(error, cyspec){
126
        // the `document.getElementByID` declaration in the cytoscape
127
        // spec is not serializable so we will ignore anything user
128
        // sent and just drop our selector in place of it.
129
        var override = {
130
            container: document.querySelector('[data-guid="' + config.guid + '"] .chart-container'),
131
            // We intentionally override w/h with null values,
132
            // so the graph is forced to be
133
            // constrained to the parent dimensions.
134
            layout: {
135
                width: null,
136
                height: null
137
            },
138
        };
139
        var spec = $.extend(cyspec, override);
140
        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...
141
        // Look for callbacks potentially registered for third party code.
142
        jsondash.api.runCallbacks(container, config);
143
        jsondash.unload(container);
144
    });
145
};
146
147
/**
148
 * Handler for all vega-lite specifications
149
 */
150
jsondash.handlers.handleVegaLite = function(container, config) {
151
    'use strict';
152
    jsondash.getJSON(container, config, function(error, vlspec){
153
        var SCALE_FACTOR = 0.7; // very important to get sizing jusst right.
154
        var selector = '[data-guid="' + config.guid + '"] .chart-container';
155
        var width = isNaN(config.width) ? jsondash.getDynamicWidth(container, config) : config.width;
156
        var size = d3.max([config.height, width]);
157
        var overrides = {
158
            width: ~~(size * SCALE_FACTOR),
159
            height: ~~(config.height * SCALE_FACTOR)
160
        };
161
        var embedSpec = {
162
            mode: 'vega-lite',
163
            spec: $.extend({}, vlspec, overrides)
164
        };
165
        d3.select(selector).classed(jsondash.util.getCSSClasses(config))
166
        vg.embed(selector, embedSpec, function(error, result) {
0 ignored issues
show
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...
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...
167
            // Callback receiving the View instance and parsed Vega spec
168
            // result.view is the View, which resides under the '#vis' element
169
            if(error) {
170
                throw new Error('Error loading chart: ' + error);
171
            }
172
            // Change look of default buttons
173
            container.select('.vega-actions')
174
                .classed({'btn-group': true})
175
                .selectAll('a')
176
                .classed({'btn btn-xs btn-default': true});
177
            // Look for callbacks potentially registered for third party code.
178
            jsondash.api.runCallbacks(container, config);
179
            jsondash.unload(container);
180
        });
181
    });
182
};
183
184
/**
185
 * Handlers for various widget types. The method signatures are always the same,
186
 * but each handler can handle them differently.
187
 */
188
jsondash.handlers.handleYoutube = function(container, config) {
189
    // Clean up all previous.
190
    'use strict';
191
    function getAttr(prop, props) {
192
        // Return the propery from a list of properties for the iframe.
193
        // e.g. getAttr('width', ["width="900""]) --> "900"
194
        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...
195
            return k.startsWith(prop);
196
        })[0];
197
    }
198
199
200
    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...
201
    var parts = config.dataSource.split(' ');
202
    var yt_width = parseInt(getAttr('width', parts).split('=')[1].replace(/"/gi, ''), 10);
203
    var height = parseInt(getAttr('height', parts).split('=')[1].replace(/"/gi, ''), 10);
204
    var width = isNaN(config.width) ? '100%' : yt_width;
205
    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 200. 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...
206
207
    // In the case of YouTube, we have to override the config dimensions
208
    // as this will be wonky when the aspect ratio is calculated. We will
209
    // defer to YouTube calculations instead.
210
    container
211
        .select('.chart-container')
212
        .append('iframe')
213
        .classed(jsondash.util.getCSSClasses(config))
214
        .attr('width', width)
215
        .attr('height', height)
216
        .attr('src', url)
217
        .attr('allowfullscreen', true)
218
        .attr('frameborder', 0);
219
    // Look for callbacks potentially registered for third party code.
220
    jsondash.api.runCallbacks(container, config);
221
    jsondash.unload(container);
222
};
223
224
/**
225
 * [handleGraph creates graphs using the dot format
226
 * spec with d3 and dagre-d3]
227
 */
228
jsondash.handlers.handleGraph = function(container, config) {
229
    'use strict';
230
    jsondash.getJSON(container, config, function(error, data){
231
        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...
232
        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...
233
        var svg = container
234
            .select('.chart-container')
235
            .append('svg')
236
            .classed(jsondash.util.getCSSClasses(config))
237
            .classed({'chart-graph': true});
238
        var svg_group = svg.append('g');
239
        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...
240
        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...
241
        // Create the renderer
242
        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...
243
        render(svg_group, g);
244
        bbox = svg.node().getBBox();
245
        svg.attr('width', bbox.width)
246
            .attr('height', bbox.height);
247
        // Look for callbacks potentially registered for third party code.
248
        jsondash.api.runCallbacks(container, config);
249
        jsondash.unload(container);
250
    });
251
};
252
253
/**
254
 * [handleWordCloud create word clouds using the d3-cloud extension.]
255
 */
256
jsondash.handlers.handleWordCloud = function(container, config) {
257
    'use strict';
258
    jsondash.getJSON(container, config, function(error, data){
259
        var h     = config.height - jsondash.config.WIDGET_MARGIN_Y;
260
        var w     = config.width - jsondash.config.WIDGET_MARGIN_X;
261
        var svg   = container
262
            .select('.chart-container')
263
            .append('svg')
264
            .classed(jsondash.util.getCSSClasses(config))
265
            .classed({'wordcloud': true});
266
        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...
267
        var cloud = d3.layout.cloud;
268
        var words = data.map(function(d) {
269
            return {text: d.text, size: d.size};
270
        });
271
        var layout = cloud()
272
            .size([w, h])
273
            .words(words)
274
            .padding(4)
275
            .rotate(function() {return ~~(Math.random() * 1) * 90;})
276
            .font('Arial')
277
            .fontSize(function(d) {return d.size;})
278
            .on('end', draw);
279
280
        layout.start();
281
282
        function draw(words) {
283
          svg
284
              .attr('width', layout.size()[0])
285
              .attr('height', layout.size()[1])
286
            .append('g')
287
              .attr('transform', 'translate(' + layout.size()[0] / 2 + ',' + layout.size()[1] / 2 + ')')
288
            .selectAll('text').data(words)
289
            .enter().append('text')
290
              .style('font-size', function(d) { return d.size + 'px'; })
291
              .style('font-family', 'arial')
292
              .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...
293
              .attr('text-anchor', 'middle')
294
              .attr('transform', function(d) {
295
                return 'translate(' + [d.x, d.y] + ')rotate(' + d.rotate + ')';
296
              })
297
              .text(function(d) { return d.text; });
298
        }
299
300
        // Look for callbacks potentially registered for third party code.
301
        jsondash.api.runCallbacks(container, config);
302
        jsondash.unload(container);
303
    });
304
};
305
306
jsondash.handlers.handleC3 = function(container, config) {
307
    var _width = isNaN(config.width) ? jsondash.getDynamicWidth(container, config) : config.width;
308
    'use strict';
309
    var init_config = {
310
        bindto: '[data-guid="' + config.guid + '"] .chart-container',
311
        legend: {
312
            show: true
313
        },
314
        size: {
315
            height: config.height - jsondash.config.WIDGET_MARGIN_Y,
316
            width: _width - jsondash.config.WIDGET_MARGIN_X
317
        },
318
        data: {},
319
        onrendered: function(){
320
            // Look for callbacks potentially registered for third party code.
321
            jsondash.api.runCallbacks(container, config);
322
            jsondash.unload(container);
323
        }
324
    };
325
326
    container
327
        .select('.chart-container')
328
        .classed(jsondash.util.getCSSClasses(config))
329
330
    /**
331
     * [normalizeData Transform data from a standardized jsondash
332
     *     format into one suitable for c3.]
333
     */
334
    function normalizeData(data, type) {
335
        // For most cases, we build out N columns into ['label', 0, 1, 2, 3] format
336
        // from data in format: {'foo': [1, 2]} or format {'foo': 1}
337
        var cols = [];
338
        if(type === 'donut' || type === 'gauge' || type === 'pie') {
339
            $.each(data, function(label, val){
340
                cols.push([label, val]);
341
            });
342
            return cols;
343
        }
344
        if(type === 'timeseries') {
345
            var dates = ['x'];
346
            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...
347
                dates.push(date);
348
            });
349
            cols.push(dates);
350
        }
351
        $.each(data, function(label, vals){
352
            if(label !== 'dates') {
353
                var newarr = [label];
354
                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...
355
                    newarr.push(val);
356
                });
357
                cols.push(newarr);
358
            }
359
        });
360
        return cols;
361
    }
362
363
    jsondash.getJSON(container, config, function(error, data){
364
        if(jsondash.util.isOverride(config)) {
365
            // Just use the raw payload for this widgets' options.
366
            // Keep existing options if not specified.
367
            init_config = $.extend(init_config, data);
368
        } else {
369
            if(config.type === 'timeseries') {
370
                // Map the corresponding data key and list of dates
371
                // to the `x` property.
372
                init_config.axis = {
373
                    x: {type: 'timeseries'}
374
                };
375
                init_config.data.x = 'x';
376
            } else {
377
                init_config.data.type = config.type;
378
            }
379
            init_config.data.columns = normalizeData(data, config.type);
380
        }
381
        c3.generate(init_config);
382
    });
383
};
384
385
jsondash.handlers.handleBasic = function(container, config) {
386
    'use strict';
387
    if(config.type === 'numbergroup') { return jsondash.handlers.handleNumbersGroup(container, config); }
388
    if(config.type === 'number') { return jsondash.handlers.handleSingleNum(container, config); }
389
    if(config.type === 'iframe') { return jsondash.handlers.handleIframe(container, config); }
390
    if(config.type === 'image') { return jsondash.handlers.handleImage(container, config); }
391
    if(config.type === 'youtube') { return jsondash.handlers.handleYoutube(container, config); }
392
    if(config.type === 'custom') { return jsondash.handlers.handleCustom(container, config); }
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if config.type === "custom" is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
393
};
394
395
jsondash.handlers.handleD3 = function(container, config) {
396
    'use strict';
397
    // Handle specific types.
398
    if(config.type === 'radial-dendrogram') { return jsondash.handlers.handleRadialDendrogram(container, config); }
399
    if(config.type === 'dendrogram') { return jsondash.handlers.handleDendrogram(container, config); }
400
    if(config.type === 'voronoi') { return jsondash.handlers.handleVoronoi(container, config); }
401
    if(config.type === 'treemap') { return jsondash.handlers.handleTreemap(container, config); }
402
    if(config.type === 'circlepack') { return jsondash.handlers.handleCirclePack(container, config); }
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if config.type === "circlepack" is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
403
};
404
405
jsondash.handlers.handleCirclePack = function(container, config) {
406
    'use strict';
407
    // Adapted from https://bl.ocks.org/mbostock/4063530
408
    var margin = jsondash.config.WIDGET_MARGIN_Y;
409
    var diameter = jsondash.getDiameter(container, config) - margin;
410
    var format = d3.format(',d');
411
    var pack = d3.layout.pack()
412
        .size([diameter, diameter])
413
        .value(function(d) { return d.size; });
414
    var svg = container
415
        .select('.chart-container')
416
        .append('svg')
417
        .classed(jsondash.util.getCSSClasses(config))
418
        .attr('width', diameter)
419
        .attr('height', diameter)
420
        .append('g');
421
422
    jsondash.getJSON(container, config, function(error, data) {
423
        var node = svg.datum(data).selectAll('.node')
424
        .data(pack.nodes)
425
        .enter().append('g')
426
        .attr('class', function(d) { return d.children ? 'node' : 'leaf node'; })
427
        .attr('transform', function(d) { return 'translate(' + d.x + ',' + d.y + ')'; });
428
429
        node.append('title')
430
        .text(function(d) { return d.name + (d.children ? '' : ': ' + format(d.size)); });
431
432
        node.append('circle')
433
        .attr('r', function(d) { return d.r; });
434
435
        node.filter(function(d) { return !d.children; }).append('text')
436
        .attr('dy', '.3em')
437
        .style('text-anchor', 'middle')
438
        .text(function(d) { return d.name.substring(0, d.r / 3); });
439
        // Look for callbacks potentially registered for third party code.
440
        jsondash.api.runCallbacks(container, config);
441
        jsondash.unload(container);
442
    });
443
    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...
444
};
445
446
jsondash.handlers.handleTreemap = function(container, config) {
447
    'use strict';
448
    // Adapted from http://bl.ocks.org/mbostock/4063582
449
    var margin = {
0 ignored issues
show
Unused Code introduced by
The variable margin seems to be never used. Consider removing it.
Loading history...
450
        top: jsondash.config.WIDGET_MARGIN_Y / 2,
451
        bottom: jsondash.config.WIDGET_MARGIN_Y / 2,
452
        left: jsondash.config.WIDGET_MARGIN_X / 2,
453
        right: jsondash.config.WIDGET_MARGIN_X / 2
454
    };
455
    var _width = isNaN(config.width) ? jsondash.getDynamicWidth(container, config) : config.width;
456
    var width = _width - jsondash.config.WIDGET_MARGIN_X;
457
    var height = config.height - jsondash.config.WIDGET_MARGIN_Y;
458
    var color = d3.scale.category20c();
459
    var treemap = d3.layout.treemap()
460
        .size([width, height])
461
        .sticky(true)
462
        .value(function(d) { return d.size; });
463
    var div = container
464
        .select('.chart-container')
465
        .append('div')
466
        .classed(jsondash.util.getCSSClasses(config))
467
        .classed({treemap: true, 'chart-centered': true})
468
        .style('position', 'relative')
469
        .style('width', width + 'px')
470
        .style('height', height + 'px');
471
472
    jsondash.getJSON(container, config, function(error, root) {
473
        var node = div.datum(root).selectAll('.node')
474
            .data(treemap.nodes)
475
            .enter().append('div')
476
            .attr('class', 'node')
477
            .call(position)
478
            .style('border', '1px solid white')
479
            .style('font', '10px sans-serif')
480
            .style('line-height', '12px')
481
            .style('overflow', 'hidden')
482
            .style('position', 'absolute')
483
            .style('text-indent', '2px')
484
            .style('background', function(d) {
485
                return d.children ? color(d.name) : null;
486
            })
487
            .text(function(d) {
488
                return d.children ? null : d.name;
489
            });
490
        d3.selectAll('input').on('change', function change() {
491
            var value = this.value === 'count'
492
            ? function() { return 1; }
493
            : function(d) { return d.size;};
494
            node
495
            .data(treemap.value(value).nodes)
496
            .transition()
497
            .duration(1500)
498
            .call(position);
499
        });
500
        // Look for callbacks potentially registered for third party code.
501
        jsondash.api.runCallbacks(container, config);
502
        jsondash.unload(container);
503
    });
504
505
    function position() {
506
        this.style('left', function(d) { return d.x + 'px'; })
507
            .style('top', function(d) { return d.y + 'px'; })
508
            .style('width', function(d) { return Math.max(0, d.dx - 1) + 'px'; })
509
            .style('height', function(d) { return Math.max(0, d.dy - 1) + 'px'; });
510
    }
511
};
512
513
jsondash.handlers.handleRadialDendrogram = function(container, config) {
514
    'use strict';
515
    // Code taken (and refactored for use here) from:
516
    // https://bl.ocks.org/mbostock/4339607
517
    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...
518
    var radius = jsondash.getDiameter(container, config);
519
    var cluster = d3.layout.cluster()
520
        .size([360, radius / 2 - 150]); // reduce size relative to `radius`
521
    var diagonal = d3.svg.diagonal.radial()
522
        .projection(function(d) { return [d.y, d.x / 180 * Math.PI]; });
523
    var svg = container
524
        .select('.chart-container')
525
        .append('svg')
526
        .classed(jsondash.util.getCSSClasses(config))
527
        .attr('width', radius)
528
        .attr('height', radius);
529
    var g = svg.append('g');
530
    g.attr('transform', 'translate(' + radius / 2 + ',' + radius / 2 + ')');
531
532
    jsondash.getJSON(container, config, function(error, root) {
533
        if (error) { throw error; }
534
        var nodes = cluster.nodes(root);
535
        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...
536
            .data(cluster.links(nodes))
537
            .enter().append('path')
538
            .attr('class', 'link')
539
            .attr('d', diagonal);
540
        var node = g.selectAll('g.node')
541
            .data(nodes)
542
            .enter().append('g')
543
            .attr('class', 'node')
544
            .attr('transform', function(d) { return 'rotate(' + (d.x - 90) + ')translate(' + d.y + ')'; });
545
        node.append('circle')
546
            .attr('r', 4.5);
547
        node.append('text')
548
            .attr('dy', '.31em')
549
            .attr('text-anchor', function(d) { return d.x < 180 ? 'start' : 'end'; })
550
            .attr('transform', function(d) { return d.x < 180 ? 'translate(8)' : 'rotate(180)translate(-8)'; })
551
            .text(function(d) { return d.name; });
552
        // Look for callbacks potentially registered for third party code.
553
        jsondash.api.runCallbacks(container, config);
554
        jsondash.unload(container);
555
    });
556
    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...
557
};
558
559
jsondash.handlers.handleDendrogram = function(container, config) {
560
    'use strict';
561
    var _width = isNaN(config.width) ? jsondash.getDynamicWidth(container, config) : config.width;
562
    // A general padding for the svg inside of the widget.
563
    // The cluster dendrogram will also need to have padding itself, so
564
    // the bounds are not clipped in the svg.
565
    var svg_pad = 20;
566
    var width = _width - svg_pad;
567
    var height = config.height - svg_pad;
568
    var PADDING = width / 4;
569
    var cluster = d3.layout.cluster()
570
        .size([height * 0.85, width - PADDING]);
571
    var diagonal = d3.svg.diagonal()
572
        .projection(function(d) { return [d.y, d.x]; });
573
    var svg = container
574
        .select('.chart-container')
575
        .append('svg')
576
        .classed(jsondash.util.getCSSClasses(config))
577
        .attr('width', width)
578
        .attr('height', height);
579
    var g = svg.append('g')
580
        .attr('transform', 'translate(40, 0)');
581
582
    jsondash.getJSON(container, config, function(error, root) {
583
        var nodes = cluster.nodes(root);
584
        var links = cluster.links(nodes);
585
        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...
586
        .data(links)
587
        .enter().append('path')
588
        .attr('class', 'link')
589
        .attr('d', diagonal);
590
591
        var node = g.selectAll('.node')
592
        .data(nodes)
593
        .enter().append('g')
594
        .attr('class', 'node')
595
        .attr('transform', function(d) { return 'translate(' + d.y + ',' + d.x + ')'; });
596
597
        node.append('circle').attr('r', 4.5);
598
        node.append('text')
599
        .attr('dx', function(d) { return d.children ? -8 : 8; })
600
        .attr('dy', 3)
601
        .style('text-anchor', function(d) { return d.children ? 'end' : 'start'; })
602
        .text(function(d) { return d.name; });
603
604
        // Look for callbacks potentially registered for third party code.
605
        jsondash.api.runCallbacks(container, config);
606
        jsondash.unload(container);
607
    });
608
};
609
610
jsondash.handlers.handleVoronoi = function(container, config) {
611
    'use strict';
612
    jsondash.getJSON(container, config, function(error, data){
613
        var _width   = isNaN(config.width) ? jsondash.getDynamicWidth(container, config) : config.width;
614
        var width    = _width - jsondash.config.WIDGET_MARGIN_X;
615
        var height   = config.height - jsondash.config.WIDGET_MARGIN_Y;
616
        var vertices = data;
617
        var voronoi  = d3.geom.voronoi().clipExtent([[0, 0], [width, height]]);
618
        var svg = container
619
            .select('.chart-container')
620
            .append('svg')
621
            .classed(jsondash.util.getCSSClasses(config))
622
            .attr('width', width)
623
            .attr('height', height);
624
        var path = svg.append('g').selectAll('path');
625
        svg.selectAll('circle')
626
            .data(vertices.slice(1))
627
            .enter().append('circle')
628
            .attr('transform', function(d) { return 'translate(' + d + ')'; })
629
            .attr('r', 1.5);
630
            redraw();
631
632
        function redraw() {
633
            path = path.data(voronoi(vertices), jsondash.util.polygon);
634
            path.exit().remove();
635
            path.enter().append('path')
636
            .attr('class', function(d, i) { return 'q' + (i % 9) + '-9'; })
637
            .attr('d', jsondash.util.polygon);
638
            path.order();
639
        }
640
        // Look for callbacks potentially registered for third party code.
641
        jsondash.api.runCallbacks(container, config);
642
        jsondash.unload(container);
643
    });
644
};
645
646
jsondash.handlers.handleSparkline = function(container, config) {
647
    'use strict';
648
    var sparkline_type = config.type.split('-')[1];
649
    var spark = container
650
        .select('.chart-container')
651
        .append('div')
652
        .classed(jsondash.util.getCSSClasses(config))
653
        .classed({
654
            'sparkline-container': true,
655
            'text-center': true
656
        });
657
    spark = $(spark[0]);
658
    jsondash.getJSON(container, config, function(data){
659
        var opts = {
660
            type: sparkline_type,
661
            width: config.width - jsondash.config.WIDGET_MARGIN_X,
662
            height: config.height - jsondash.config.WIDGET_MARGIN_Y
663
        };
664
        spark.sparkline(data, opts);
665
        // Look for callbacks potentially registered for third party code.
666
        jsondash.api.runCallbacks(container, config);
667
        jsondash.unload(container);
668
    });
669
};
670
671
jsondash.handlers.handleDataTable = function(container, config) {
672
    'use strict';
673
    jsondash.getJSON(container, config, function(error, res) {
674
        var keys = d3.keys(res[0]).map(function(d){
675
            return {data: d, title: d};
676
        });
677
        var titlebar_offset = jsondash.getTitleBarHeight(container) * 2.5;
0 ignored issues
show
Unused Code introduced by
The variable titlebar_offset seems to be never used. Consider removing it.
Loading history...
678
        var table_class_defaults = ['table', 'table-bordered', 'table-striped'];
679
        var classes = jsondash.util.getCSSClasses(config, table_class_defaults);
680
        container
681
            .select('.chart-container')
682
            .append('table')
683
            .classed(classes);
684
        var opts = config.override ? res : {data: res, columns: keys};
685
        $(container.select('table')[0])
686
            .dataTable(opts).css({
687
                width: 'auto',
688
        });
689
        // Look for callbacks potentially registered for third party code.
690
        jsondash.api.runCallbacks(container, config);
691
        jsondash.unload(container);
692
    });
693
};
694
695
jsondash.handlers.handleNumbersGroup = function(container, config) {
696
    'use strict';
697
698
    function getStylesForColumn(d) {
699
        if(d.color && d.noformat !== false) {
700
            return 'color: ' + d.color;
701
        }
702
        return '';
703
    }
704
705
    jsondash.getJSON(container, config, function(error, data){
706
        container
707
        .select('.chart-container')
708
        .append('table')
709
        .classed({numgroup: true, 'table': true})
710
        .classed(jsondash.util.getCSSClasses(config))
711
        .append('tr')
712
        .selectAll('td')
713
        .data(data)
714
        .enter()
715
        .append('td')
716
        .attr('width', function(d, i){
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...
717
            return d.width !== null && d.width !== undefined ? d.width : null;
718
        })
719
        .attr('class', function(d, i){
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...
720
            if(!d.noformat) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if !d.noformat is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
721
                var classes = '';
722
                classes += typeof d === 'string' && d.startsWith('-') ? 'text-danger' : '';
723
                classes += typeof d === 'string' && !d.startsWith('-') ? 'text-success' : '';
724
                return classes;
725
            }
726
        })
727
        .html(function(d, i){
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...
728
            var styles = getStylesForColumn(d);
729
            var title = '<p class="numgroup-title">' + d.title + '</p>';
730
            var units = d.units ? '<span class="numgroup-val-units"> ' + d.units + '</span>' : '';
731
            var num = '<h4 class="numgroup-val" style="' + styles + '">' + d.data + units + '</h4>';
732
            var desc = '<small class="numgroup-desc">' + (d.description ? d.description : '') + '</small>';
733
            return title + desc + num;
734
        });
735
        // Look for callbacks potentially registered for third party code.
736
        jsondash.api.runCallbacks(container, config);
737
        jsondash.unload(container);
738
    });
739
};
740
741
jsondash.handlers.handleSingleNum = function(container, config) {
742
    'use strict';
743
    jsondash.getJSON(container, config, function(error, res){
744
        var data = res.data.data ? res.data.data : res.data;
745
        var num = container
746
            .select('.chart-container')
747
            .append('div')
748
            .classed({singlenum: true})
749
            .classed(jsondash.util.getCSSClasses(config))
750
            .text(data);
751
        data = String(data);
752
        // Add red or green, depending on if the number appears to be pos/neg.
753
        if(!res.noformat) {
754
            num.classed({
755
                'text-danger': data.startsWith('-'),
756
                'text-success': !data.startsWith('-')
757
            });
758
        }
759
        // Allow custom colors.
760
        if(res.color && res.noformat) {
761
            num.style('color', res.color);
762
        }
763
        // Get title height to offset box.
764
        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...
765
            .select('.widget-title')
766
            .node()
767
            .getBoundingClientRect()
768
            .height;
769
        var h = config.height - jsondash.config.WIDGET_MARGIN_Y;
770
        num.style({
771
            'line-height': h + 'px',
772
            height: h + 'px',
773
            width: config.width - jsondash.config.WIDGET_MARGIN_X
774
        });
775
        var digits = String(data).length;
776
        var size = jsondash.util.getDigitSize()(digits);
777
        num.style('font-size', size + 'px');
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.handleTimeline = function(container, config) {
785
    'use strict';
786
    jsondash.getJSON(container, config, function(data){
787
        container
788
            .append('div')
789
            .classed(jsondash.util.getCSSClasses(config))
790
            .attr('id', 'widget-' + config.guid);
791
        var timeline = new TL.Timeline('widget-' + config.guid, data);
0 ignored issues
show
Unused Code introduced by
The variable timeline seems to be never used. Consider removing it.
Loading history...
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...
792
        // Look for callbacks potentially registered for third party code.
793
        jsondash.api.runCallbacks(container, config);
794
        jsondash.unload(container);
795
    });
796
};
797
798
/**
799
 * [handleImage Embed an image src directly.]
800
 */
801
jsondash.handlers.handleImage = function(container, config) {
802
    'use strict';
803
    var img = container.select('.chart-container').append('img');
804
    var height = (config.height - jsondash.config.WIDGET_MARGIN_Y) + 'px';
805
    img.attr({
806
        src: config.dataSource,
807
        height: height
808
    });
809
    img.classed({img: true});
810
    img.classed(jsondash.util.getCSSClasses(config));
811
    // Look for callbacks potentially registered for third party code.
812
    jsondash.api.runCallbacks(container, config);
813
    jsondash.unload(container);
814
};
815
816
jsondash.handlers.handleIframe = function(container, config) {
817
    'use strict';
818
    var iframe = container
819
        .select('.chart-container')
820
        .append('iframe');
821
    iframe.attr({
822
        border: 0,
823
        src: config.dataSource,
824
        height: config.height - jsondash.config.WIDGET_MARGIN_Y,
825
        width: isNaN(config.width) ? '100%' : config.width - jsondash.config.WIDGET_MARGIN_X
826
    });
827
    iframe.classed(jsondash.util.getCSSClasses(config));
828
    // Look for callbacks potentially registered for third party code.
829
    jsondash.api.runCallbacks(container, config);
830
    jsondash.unload(container);
831
};
832
833
jsondash.handlers.handleCustom = function(container, config) {
834
    'use strict';
835
    $.get(config.dataSource, function(html){
836
        container
837
            .select('.chart-container')
838
            .append('div')
839
            .classed({'custom-container': true})
840
            .classed(jsondash.util.getCSSClasses(config))
841
            .html(html);
842
        // Look for callbacks potentially registered for third party code.
843
        jsondash.api.runCallbacks(container, config);
844
        jsondash.unload(container);
845
    });
846
};
847
848
jsondash.handlers.handleVenn = function(container, config) {
849
    'use strict';
850
    jsondash.getJSON(container, config, function(error, data){
851
        var chart = venn.VennDiagram();
852
        var cont = container
853
            .select('.chart-container')
854
            .append('div')
855
            .classed(jsondash.util.getCSSClasses(config))
856
            .classed({venn: true});
857
        cont.datum(data).call(chart);
858
        cont.select('svg')
859
            .attr('width', config.width - jsondash.config.WIDGET_MARGIN_X)
860
            .attr('height', config.height - jsondash.config.WIDGET_MARGIN_Y);
861
        // Look for callbacks potentially registered for third party code.
862
        jsondash.api.runCallbacks(container, config);
863
        jsondash.unload(container);
864
    });
865
};
866
867
jsondash.handlers.handlePlotly = function(container, config) {
868
    'use strict';
869
    var id = 'plotly-' + config.guid;
870
    var _width = isNaN(config.width) ? jsondash.getDynamicWidth(container, config) : config.width;
871
    container
872
        .select('.chart-container')
873
        .append('div')
874
        .classed(jsondash.util.getCSSClasses(config))
875
        .classed({'plotly-container': true})
876
        .attr('id', id);
877
    jsondash.getJSON(container, config, function(error, data){
878
        var plotly_wrapper =  d3.select('#' + id);
879
        delete data.layout.height;
880
        delete data.layout.width;
881
        data.layout.margin = {l: 20, r: 20, b: 20, t: 50};
882
        if(config.override) {
883
            Plotly.plot(id, data.data, data.layout || {}, data.options || {});
884
        } else {
885
            Plotly.plot(id, data);
886
        }
887
       plotly_wrapper.select('.svg-container').style({
888
            'margin': '0 auto',
889
            'width': isNaN(config.width) ? '100%' : config.width,
890
            'height': config.height
891
        });
892
        plotly_wrapper.select('#scene').style({
893
            'width': _width,
894
            'height': config.height
895
        });
896
        // Look for callbacks potentially registered for third party code.
897
        jsondash.api.runCallbacks(container, config);
898
        jsondash.unload(container);
899
    });
900
};
901