Completed
Push — master ( 16569e...29c86e )
by Chris
50s
created

jsondash.handleRes   B

Complexity

Conditions 5
Paths 6

Size

Total Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
c 1
b 0
f 0
nc 6
nop 3
dl 0
loc 17
rs 8.8571
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
        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...
141
        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...
142
        // Look for callbacks potentially registered for third party code.
143
        jsondash.api.runCallbacks(container, config);
144
        jsondash.unload(container);
145
    });
146
};
147
148
/**
149
 * Handler for all vega-lite specifications
150
 */
151
jsondash.handlers.handleVegaLite = function(container, config) {
152
    'use strict';
153
    jsondash.getJSON(container, config, function(error, vlspec){
154
        var SCALE_FACTOR = 0.7; // very important to get sizing jusst right.
155
        var selector = '[data-guid="' + config.guid + '"] .chart-container';
156
        var width = isNaN(config.width) ? jsondash.getDynamicWidth(container, config) : config.width;
157
        var size = d3.max([config.height, width]);
158
        var overrides = {
159
            width: ~~(size * SCALE_FACTOR),
160
            height: ~~(config.height * SCALE_FACTOR)
161
        };
162
        var embedSpec = {
163
            mode: 'vega-lite',
164
            spec: $.extend({}, vlspec, overrides)
165
        };
166
        d3.select(selector).classed(jsondash.util.getCSSClasses(config))
167
        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...
168
            // Callback receiving the View instance and parsed Vega spec
169
            // result.view is the View, which resides under the '#vis' element
170
            if(error) {
171
                throw new Error('Error loading chart: ' + error);
172
            }
173
            // Change look of default buttons
174
            container.select('.vega-actions')
175
                .classed({'btn-group': true})
176
                .selectAll('a')
177
                .classed({'btn btn-xs btn-default': true});
178
            // Look for callbacks potentially registered for third party code.
179
            jsondash.api.runCallbacks(container, config);
180
            jsondash.unload(container);
181
        });
182
    });
183
};
184
185
/**
186
 * Handlers for various widget types. The method signatures are always the same,
187
 * but each handler can handle them differently.
188
 */
189
jsondash.handlers.handleYoutube = function(container, config) {
190
    // Clean up all previous.
191
    'use strict';
192
    function getAttr(prop, props) {
193
        // Return the propery from a list of properties for the iframe.
194
        // e.g. getAttr('width', ["width="900""]) --> "900"
195
        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...
196
            return k.startsWith(prop);
197
        })[0];
198
    }
199
200
201
    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...
202
    var parts = config.dataSource.split(' ');
203
    var yt_width = parseInt(getAttr('width', parts).split('=')[1].replace(/"/gi, ''), 10);
204
    var height = parseInt(getAttr('height', parts).split('=')[1].replace(/"/gi, ''), 10);
205
    var width = isNaN(config.width) ? '100%' : yt_width;
206
    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 201. 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...
207
208
    // In the case of YouTube, we have to override the config dimensions
209
    // as this will be wonky when the aspect ratio is calculated. We will
210
    // defer to YouTube calculations instead.
211
    container
212
        .select('.chart-container')
213
        .append('iframe')
214
        .classed(jsondash.util.getCSSClasses(config))
215
        .attr('width', width)
216
        .attr('height', height)
217
        .attr('src', url)
218
        .attr('allowfullscreen', true)
219
        .attr('frameborder', 0);
220
    // Look for callbacks potentially registered for third party code.
221
    jsondash.api.runCallbacks(container, config);
222
    jsondash.unload(container);
223
};
224
225
/**
226
 * [handleGraph creates graphs using the dot format
227
 * spec with d3 and dagre-d3]
228
 */
229
jsondash.handlers.handleGraph = function(container, config) {
230
    'use strict';
231
    jsondash.getJSON(container, config, function(error, data){
232
        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...
233
        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...
234
        var svg = container
235
            .select('.chart-container')
236
            .append('svg')
237
            .classed(jsondash.util.getCSSClasses(config))
238
            .classed({'chart-graph': true});
239
        var svg_group = svg.append('g');
240
        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...
241
        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...
242
        // Create the renderer
243
        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...
244
        render(svg_group, g);
245
        bbox = svg.node().getBBox();
246
        svg.attr('width', bbox.width)
247
            .attr('height', bbox.height);
248
        // Look for callbacks potentially registered for third party code.
249
        jsondash.api.runCallbacks(container, config);
250
        jsondash.unload(container);
251
    });
252
};
253
254
/**
255
 * [handleWordCloud create word clouds using the d3-cloud extension.]
256
 */
257
jsondash.handlers.handleWordCloud = function(container, config) {
258
    'use strict';
259
    jsondash.getJSON(container, config, function(error, data){
260
        var h     = config.height - jsondash.config.WIDGET_MARGIN_Y;
261
        var w     = config.width - jsondash.config.WIDGET_MARGIN_X;
262
        var svg   = container
263
            .select('.chart-container')
264
            .append('svg')
265
            .classed(jsondash.util.getCSSClasses(config))
266
            .classed({'wordcloud': true});
267
        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...
268
        var cloud = d3.layout.cloud;
269
        var words = data.map(function(d) {
270
            return {text: d.text, size: d.size};
271
        });
272
        var layout = cloud()
273
            .size([w, h])
274
            .words(words)
275
            .padding(4)
276
            .rotate(function() {return ~~(Math.random() * 1) * 90;})
277
            .font('Arial')
278
            .fontSize(function(d) {return d.size;})
279
            .on('end', draw);
280
281
        layout.start();
282
283
        function draw(words) {
284
          svg
285
              .attr('width', layout.size()[0])
286
              .attr('height', layout.size()[1])
287
            .append('g')
288
              .attr('transform', 'translate(' + layout.size()[0] / 2 + ',' + layout.size()[1] / 2 + ')')
289
            .selectAll('text').data(words)
290
            .enter().append('text')
291
              .style('font-size', function(d) { return d.size + 'px'; })
292
              .style('font-family', 'arial')
293
              .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...
294
              .attr('text-anchor', 'middle')
295
              .attr('transform', function(d) {
296
                return 'translate(' + [d.x, d.y] + ')rotate(' + d.rotate + ')';
297
              })
298
              .text(function(d) { return d.text; });
299
        }
300
301
        // Look for callbacks potentially registered for third party code.
302
        jsondash.api.runCallbacks(container, config);
303
        jsondash.unload(container);
304
    });
305
};
306
307
jsondash.handlers.handleC3 = function(container, config) {
308
    var _width = isNaN(config.width) ? jsondash.getDynamicWidth(container, config) : config.width;
309
    'use strict';
310
    var init_config = {
311
        bindto: '[data-guid="' + config.guid + '"] .chart-container',
312
        legend: {
313
            show: true
314
        },
315
        size: {
316
            height: config.height - jsondash.config.WIDGET_MARGIN_Y,
317
            width: _width - jsondash.config.WIDGET_MARGIN_X
318
        },
319
        data: {},
320
        onrendered: function(){
321
            // Look for callbacks potentially registered for third party code.
322
            jsondash.api.runCallbacks(container, config);
323
            jsondash.unload(container);
324
        }
325
    };
326
327
    container
328
        .select('.chart-container')
329
        .classed(jsondash.util.getCSSClasses(config))
330
331
    /**
332
     * [normalizeData Transform data from a standardized jsondash
333
     *     format into one suitable for c3.]
334
     */
335
    function normalizeData(data, type) {
336
        // For most cases, we build out N columns into ['label', 0, 1, 2, 3] format
337
        // from data in format: {'foo': [1, 2]} or format {'foo': 1}
338
        var cols = [];
339
        if(type === 'donut' || type === 'gauge' || type === 'pie') {
340
            $.each(data, function(label, val){
341
                cols.push([label, val]);
342
            });
343
            return cols;
344
        }
345
        if(type === 'timeseries') {
346
            var dates = ['x'];
347
            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...
348
                dates.push(date);
349
            });
350
            cols.push(dates);
351
        }
352
        $.each(data, function(label, vals){
353
            if(label !== 'dates') {
354
                var newarr = [label];
355
                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...
356
                    newarr.push(val);
357
                });
358
                cols.push(newarr);
359
            }
360
        });
361
        return cols;
362
    }
363
364
    jsondash.getJSON(container, config, function(error, data){
365
        if(jsondash.util.isOverride(config)) {
366
            // Just use the raw payload for this widgets' options.
367
            // Keep existing options if not specified.
368
            init_config = $.extend(init_config, data);
369
        } else {
370
            if(config.type === 'timeseries') {
371
                // Map the corresponding data key and list of dates
372
                // to the `x` property.
373
                init_config.axis = {
374
                    x: {type: 'timeseries'}
375
                };
376
                init_config.data.x = 'x';
377
            } else {
378
                init_config.data.type = config.type;
379
            }
380
            init_config.data.columns = normalizeData(data, config.type);
381
        }
382
        c3.generate(init_config);
383
    });
384
};
385
386
jsondash.handlers.handleBasic = function(container, config) {
387
    'use strict';
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.handleSingleNum = function(container, config) {
696
    'use strict';
697
    jsondash.getJSON(container, config, function(error, res){
698
        var data = res.data.data ? res.data.data : res.data;
699
        var num = container
700
            .select('.chart-container')
701
            .append('div')
702
            .classed({singlenum: true})
703
            .classed(jsondash.util.getCSSClasses(config))
704
            .text(data);
705
        data = String(data);
706
        // Add red or green, depending on if the number appears to be pos/neg.
707
        if(!res.noformat) {
708
            num.classed({
709
                'text-danger': data.startsWith('-'),
710
                'text-success': !data.startsWith('-')
711
            });
712
        }
713
        // Allow custom colors.
714
        if(res.color && res.noformat) {
715
            num.style('color', res.color);
716
        }
717
        // Get title height to offset box.
718
        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...
719
            .select('.widget-title')
720
            .node()
721
            .getBoundingClientRect()
722
            .height;
723
        var h = config.height - jsondash.config.WIDGET_MARGIN_Y;
724
        num.style({
725
            'line-height': h + 'px',
726
            height: h + 'px',
727
            width: config.width - jsondash.config.WIDGET_MARGIN_X
728
        });
729
        var digits = String(data).length;
730
        var size = jsondash.util.getDigitSize()(digits);
731
        num.style('font-size', size + 'px');
732
        // Look for callbacks potentially registered for third party code.
733
        jsondash.api.runCallbacks(container, config);
734
        jsondash.unload(container);
735
    });
736
};
737
738
jsondash.handlers.handleTimeline = function(container, config) {
739
    'use strict';
740
    jsondash.getJSON(container, config, function(data){
741
        container
742
            .append('div')
743
            .classed(jsondash.util.getCSSClasses(config))
744
            .attr('id', 'widget-' + config.guid);
745
        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...
746
        // Look for callbacks potentially registered for third party code.
747
        jsondash.api.runCallbacks(container, config);
748
        jsondash.unload(container);
749
    });
750
};
751
752
/**
753
 * [handleImage Embed an image src directly.]
754
 */
755
jsondash.handlers.handleImage = function(container, config) {
756
    'use strict';
757
    var img = container.select('.chart-container').append('img');
758
    var height = (config.height - jsondash.config.WIDGET_MARGIN_Y) + 'px';
759
    img.attr({
760
        src: config.dataSource,
761
        height: height
762
    });
763
    img.classed({img: true});
764
    img.classed(jsondash.util.getCSSClasses(config));
765
    // Look for callbacks potentially registered for third party code.
766
    jsondash.api.runCallbacks(container, config);
767
    jsondash.unload(container);
768
};
769
770
jsondash.handlers.handleIframe = function(container, config) {
771
    'use strict';
772
    var iframe = container
773
        .select('.chart-container')
774
        .append('iframe');
775
    iframe.attr({
776
        border: 0,
777
        src: config.dataSource,
778
        height: config.height - jsondash.config.WIDGET_MARGIN_Y,
779
        width: isNaN(config.width) ? '100%' : config.width - jsondash.config.WIDGET_MARGIN_X
780
    });
781
    iframe.classed(jsondash.util.getCSSClasses(config));
782
    // Look for callbacks potentially registered for third party code.
783
    jsondash.api.runCallbacks(container, config);
784
    jsondash.unload(container);
785
};
786
787
jsondash.handlers.handleCustom = function(container, config) {
788
    'use strict';
789
    $.get(config.dataSource, function(html){
790
        container
791
            .select('.chart-container')
792
            .append('div')
793
            .classed({'custom-container': true})
794
            .classed(jsondash.util.getCSSClasses(config))
795
            .html(html);
796
        // Look for callbacks potentially registered for third party code.
797
        jsondash.api.runCallbacks(container, config);
798
        jsondash.unload(container);
799
    });
800
};
801
802
jsondash.handlers.handleVenn = function(container, config) {
803
    'use strict';
804
    jsondash.getJSON(container, config, function(error, data){
805
        var chart = venn.VennDiagram();
806
        var cont = container
807
            .select('.chart-container')
808
            .append('div')
809
            .classed(jsondash.util.getCSSClasses(config))
810
            .classed({venn: true});
811
        cont.datum(data).call(chart);
812
        cont.select('svg')
813
            .attr('width', config.width - jsondash.config.WIDGET_MARGIN_X)
814
            .attr('height', config.height - jsondash.config.WIDGET_MARGIN_Y);
815
        // Look for callbacks potentially registered for third party code.
816
        jsondash.api.runCallbacks(container, config);
817
        jsondash.unload(container);
818
    });
819
};
820
821
jsondash.handlers.handlePlotly = function(container, config) {
822
    'use strict';
823
    var id = 'plotly-' + config.guid;
824
    var _width = isNaN(config.width) ? jsondash.getDynamicWidth(container, config) : config.width;
825
    container
826
        .select('.chart-container')
827
        .append('div')
828
        .classed(jsondash.util.getCSSClasses(config))
829
        .classed({'plotly-container': true})
830
        .attr('id', id);
831
    jsondash.getJSON(container, config, function(error, data){
832
        var plotly_wrapper =  d3.select('#' + id);
833
        delete data.layout.height;
834
        delete data.layout.width;
835
        data.layout.margin = {l: 20, r: 20, b: 20, t: 50};
836
        if(config.override) {
837
            Plotly.plot(id, data.data, data.layout || {}, data.options || {});
838
        } else {
839
            Plotly.plot(id, data);
840
        }
841
       plotly_wrapper.select('.svg-container').style({
842
            'margin': '0 auto',
843
            'width': isNaN(config.width) ? '100%' : config.width,
844
            'height': config.height
845
        });
846
        plotly_wrapper.select('#scene').style({
847
            'width': _width,
848
            'height': config.height
849
        });
850
        // Look for callbacks potentially registered for third party code.
851
        jsondash.api.runCallbacks(container, config);
852
        jsondash.unload(container);
853
    });
854
};
855