Completed
Push — master ( 674ec9...77360c )
by Chris
01:15
created

jsondash.handlers.handleYoutube   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

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

1 Function

Rating   Name   Duplication   Size   Complexity  
A 0 7 1
1
/** global: jsondash */
2
/** global: c3 */
3
/** global: d3 */
4
/** global: venn */
5
/** global: Plotly */
6
7
jsondash.getJSON = function(url, callback) {
8
    return d3.json(url, callback);
9
};
10
11
/**
12
 * Handlers for various widget types. The method signatures are always the same,
13
 * but each handler can handle them differently.
14
 */
15
jsondash.handlers.handleYoutube = function(container, config) {
16
    // Clean up all previous.
17
    'use strict';
18
    container.selectAll('iframe').remove();
19
20
    function getAttr(prop, props) {
21
        // Return the propery from a list of properties for the iframe.
22
        // e.g. getAttr('width', ["width="900""]) --> "900"
23
        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...
24
            return k.startsWith(prop);
25
        })[0];
26
    }
27
28
    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...
29
    var parts = config.dataSource.split(' ');
30
    var height = parseInt(getAttr('height', parts).split('=')[1].replace(/"/gi, ''), 10);
31
    var width = parseInt(getAttr('width', parts).split('=')[1].replace(/"/gi, ''), 10);
32
    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 28. 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...
33
34
    // In the case of YouTube, we have to override the config dimensions
35
    // as this will be wonky when the aspect ratio is calculated. We will
36
    // defer to YouTube calculations instead.
37
    container.append('iframe')
38
        .attr('width', width)
39
        .attr('height', height)
40
        .attr('src', url)
41
        .attr('allowfullscreen', true)
42
        .attr('frameborder', 0);
43
    jsondash.unload(container);
44
};
45
46
jsondash.handlers.handleC3 = function(container, config) {
47
    'use strict';
48
    var init_config = {
49
        bindto: '[data-guid="' + config.guid + '"] .chart-container',
50
        legend: {
51
            show: true
52
        },
53
        size: {
54
            height: config.height - jsondash.config.WIDGET_MARGIN_Y,
55
            width: config.width - jsondash.config.WIDGET_MARGIN_X
56
        },
57
        data: {
58
            type: config.type,
59
            url: config.dataSource,
60
            mimeType: 'json'
61
        },
62
        onrendered: function(){
63
            jsondash.unload(container);
64
        }
65
    };
66
    if(jsondash.util.isOverride(config)) {
67
        // Just use the raw payload for this widgets' options.
68
        jsondash.getJSON(config.dataSource, function(error, data){
69
            if(error) { throw new Error("Could not load url: " + config.dataSource); }
70
            // Keep existing options if not specified.
71
            config = $.extend(init_config, data);
72
            c3.generate(init_config);
73
        });
74
        return;
75
    }
76
    if(config.type === 'timeseries') {
77
        init_config.axis = {
78
            x: {type: 'timeseries'}
79
        };
80
        // Map the corresponding data key and list of dates
81
        // to the `x` property.
82
        init_config.data.x = 'dates';
83
    }
84
    c3.generate(init_config);
85
};
86
87
jsondash.handlers.handleD3 = function(container, config) {
88
    'use strict';
89
    // Clean up all D3 charts in one step.
90
    container.selectAll('svg').remove();
91
    // Handle specific types.
92
    if(config.type === 'radial-dendrogram') { return jsondash.handlers.handleRadialDendrogram(container, config); }
93
    if(config.type === 'dendrogram') { return jsondash.handlers.handleDendrogram(container, config); }
94
    if(config.type === 'voronoi') { return jsondash.handlers.handleVoronoi(container, config); }
95
    if(config.type === 'treemap') { return jsondash.handlers.handleTreemap(container, config); }
96
    if(config.type === 'circlepack') { return jsondash.handlers.handleCirclePack(container, config); }
97
    throw new Error('Unknown type: ' + config.type);
98
};
99
100
jsondash.handlers.handleCirclePack = function(container, config) {
101
    'use strict';
102
    // Adapted from https://bl.ocks.org/mbostock/4063530
103
    var margin = jsondash.config.WIDGET_MARGIN_Y;
104
    var diameter = d3.max([config.width, config.height]) - margin;
105
    var format = d3.format(',d');
106
107
    var pack = d3.layout.pack()
108
        .size([diameter, diameter])
109
        .value(function(d) { return d.size; });
110
111
    var svg = container
112
        .append('svg')
113
        .attr('width', diameter)
114
        .attr('height', diameter)
115
        .append('g');
116
117
    jsondash.getJSON(config.dataSource, function(error, data) {
118
        if(error) { throw new Error("Could not load url: " + config.dataSource); }
119
120
        var node = svg.datum(data).selectAll('.node')
121
        .data(pack.nodes)
122
        .enter().append('g')
123
        .attr('class', function(d) { return d.children ? 'node' : 'leaf node'; })
124
        .attr('transform', function(d) { return 'translate(' + d.x + ',' + d.y + ')'; });
125
126
        node.append('title')
127
        .text(function(d) { return d.name + (d.children ? '' : ': ' + format(d.size)); });
128
129
        node.append('circle')
130
        .attr('r', function(d) { return d.r; });
131
132
        node.filter(function(d) { return !d.children; }).append('text')
133
        .attr('dy', '.3em')
134
        .style('text-anchor', 'middle')
135
        .text(function(d) { return d.name.substring(0, d.r / 3); });
136
        jsondash.unload(container);
137
    });
138
139
    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...
140
};
141
142
jsondash.handlers.handleTreemap = function(container, config) {
143
    'use strict';
144
    // Adapted from http://bl.ocks.org/mbostock/4063582
145
    var margin = {
0 ignored issues
show
Unused Code introduced by
The variable margin seems to be never used. Consider removing it.
Loading history...
146
        top: jsondash.config.WIDGET_MARGIN_Y / 2,
147
        bottom: jsondash.config.WIDGET_MARGIN_Y / 2,
148
        left: jsondash.config.WIDGET_MARGIN_X / 2,
149
        right: jsondash.config.WIDGET_MARGIN_X / 2
150
    };
151
    var width = config.width - jsondash.config.WIDGET_MARGIN_X;
152
    var height = config.height - jsondash.config.WIDGET_MARGIN_Y;
153
    var color = d3.scale.category20c();
154
    var treemap = d3.layout.treemap()
155
        .size([width, height])
156
        .sticky(true)
157
        .value(function(d) { return d.size; });
158
    // Cleanup
159
    container.selectAll('.treemap').remove();
160
    var div = container
161
        .append('div')
162
        .classed({treemap: true, 'chart-centered': true})
163
        .style('position', 'relative')
164
        .style('width', width + 'px')
165
        .style('height', height + 'px');
166
167
    jsondash.getJSON(config.dataSource, function(error, root) {
168
        if(error) { throw new Error('Could not load url: ' + config.dataSource); }
169
        var node = div.datum(root).selectAll('.node')
170
            .data(treemap.nodes)
171
            .enter().append('div')
172
            .attr('class', 'node')
173
            .call(position)
174
            .style('border', '1px solid white')
175
            .style('font', '10px sans-serif')
176
            .style('line-height', '12px')
177
            .style('overflow', 'hidden')
178
            .style('position', 'absolute')
179
            .style('text-indent', '2px')
180
            .style('background', function(d) {
181
                return d.children ? color(d.name) : null;
182
            })
183
            .text(function(d) {
184
                return d.children ? null : d.name;
185
            });
186
        d3.selectAll('input').on('change', function change() {
187
            var value = this.value === 'count'
188
            ? function() { return 1; }
189
            : function(d) { return d.size;};
190
            node
191
            .data(treemap.value(value).nodes)
192
            .transition()
193
            .duration(1500)
194
            .call(position);
195
        });
196
        jsondash.unload(container);
197
    });
198
199
    function position() {
200
        this.style('left', function(d) { return d.x + 'px'; })
201
            .style('top', function(d) { return d.y + 'px'; })
202
            .style('width', function(d) { return Math.max(0, d.dx - 1) + 'px'; })
203
            .style('height', function(d) { return Math.max(0, d.dy - 1) + 'px'; });
204
    }
205
};
206
207
jsondash.handlers.handleRadialDendrogram = function(container, config) {
208
    'use strict';
209
    container.selectAll('svg').remove();
210
    // Code taken (and refactored for use here) from:
211
    // https://bl.ocks.org/mbostock/4339607
212
    var radius = (config.width > config.height ? config.width : config.height) / 2;
213
    var cluster = d3.layout.cluster()
214
        .size([360, radius * 0.65]); // reduce size relative to `radius`
215
    var diagonal = d3.svg.diagonal.radial()
216
        .projection(function(d) { return [d.y, d.x / 180 * Math.PI]; });
217
    var svg = container.append('svg')
218
        .attr('width', radius * 2)
219
        .attr('height', radius * 2)
220
        .append('g')
221
        .attr('transform', 'translate(' + radius + ',' + radius + ')');
222
    jsondash.getJSON(config.dataSource, function(error, root) {
223
        if (error) { throw error; }
224
        var nodes = cluster.nodes(root);
225
        var link = svg.selectAll('path.link')
0 ignored issues
show
Unused Code introduced by
The variable link seems to be never used. Consider removing it.
Loading history...
226
            .data(cluster.links(nodes))
227
            .enter().append('path')
228
            .attr('class', 'link')
229
            .attr('d', diagonal);
230
        var node = svg.selectAll('g.node')
231
            .data(nodes)
232
            .enter().append('g')
233
            .attr('class', 'node')
234
            .attr('transform', function(d) { return 'rotate(' + (d.x - 90) + ')translate(' + d.y + ')'; });
235
        node.append('circle')
236
            .attr('r', 4.5);
237
        node.append('text')
238
            .attr('dy', '.31em')
239
            .attr('text-anchor', function(d) { return d.x < 180 ? 'start' : 'end'; })
240
            .attr('transform', function(d) { return d.x < 180 ? 'translate(8)' : 'rotate(180)translate(-8)'; })
241
            .text(function(d) { return d.name; });
242
        jsondash.unload(container);
243
    });
244
    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...
245
};
246
247
jsondash.handlers.handleDendrogram = function(container, config) {
248
    'use strict';
249
    container.selectAll('svg').remove();
250
    var PADDING = 100;
251
    var width = config.width - jsondash.config.WIDGET_MARGIN_X;
252
    var height = config.height - jsondash.config.WIDGET_MARGIN_Y;
253
    var cluster = d3.layout.cluster()
254
        .size([height, width - PADDING]);
255
    var diagonal = d3.svg.diagonal()
256
        .projection(function(d) { return [d.y, d.x]; });
257
    var svg = container
258
        .append('svg')
259
        .attr('width', width)
260
        .attr('height', height)
261
        .append('g')
262
        .attr('transform', 'translate(40,0)');
263
264
    jsondash.getJSON(config.dataSource, function(error, root) {
265
        if(error) { throw new Error('Could not load url: ' + config.dataSource); }
266
267
        var nodes = cluster.nodes(root),
268
        links = cluster.links(nodes);
269
270
        var link = svg.selectAll('.link')
0 ignored issues
show
Unused Code introduced by
The variable link seems to be never used. Consider removing it.
Loading history...
271
        .data(links)
272
        .enter().append('path')
273
        .attr('class', 'link')
274
        .attr('d', diagonal);
275
276
        var node = svg.selectAll('.node')
277
        .data(nodes)
278
        .enter().append('g')
279
        .attr('class', 'node')
280
        .attr('transform', function(d) { return 'translate(' + d.y + ',' + d.x + ')'; });
281
282
        node.append('circle').attr('r', 4.5);
283
        node.append('text')
284
        .attr('dx', function(d) { return d.children ? -8 : 8; })
285
        .attr('dy', 3)
286
        .style('text-anchor', function(d) { return d.children ? 'end' : 'start'; })
287
        .text(function(d) { return d.name; });
288
289
        jsondash.unload(container);
290
    });
291
};
292
293
jsondash.handlers.handleVoronoi = function(container, config) {
294
    'use strict';
295
    jsondash.getJSON(config.dataSource, function(error, data){
296
        if(error) { throw new Error('Could not load url: ' + config.dataSource); }
297
        var width = config.width - jsondash.config.WIDGET_MARGIN_X;
298
        var height = config.height - jsondash.config.WIDGET_MARGIN_Y;
299
        var vertices = data;
300
        var voronoi = d3.geom.voronoi().clipExtent([[0, 0], [width, height]]);
301
        // Cleanup
302
        var svg = container
303
        .append('svg')
304
        .attr('width', width)
305
        .attr('height', height);
306
        var path = svg.append('g').selectAll('path');
307
        svg.selectAll('circle')
308
        .data(vertices.slice(1))
309
        .enter().append('circle')
310
        .attr('transform', function(d) { return 'translate(' + d + ')'; })
311
        .attr('r', 1.5);
312
        redraw();
313
314
        function redraw() {
315
            path = path.data(voronoi(vertices), jsondash.util.polygon);
316
            path.exit().remove();
317
            path.enter().append('path')
318
            .attr('class', function(d, i) { return 'q' + (i % 9) + '-9'; })
319
            .attr('d', jsondash.util.polygon);
320
            path.order();
321
        }
322
        jsondash.unload(container);
323
    });
324
};
325
326
jsondash.handlers.handleSparkline = function(container, config) {
327
    'use strict';
328
    // Clean up old canvas elements
329
    container.selectAll('.sparkline-container').remove();
330
    var sparkline_type = config.type.split('-')[1];
331
    var spark = container
332
        .append('div')
333
        .classed({
334
            'sparkline-container': true,
335
            'text-center': true
336
        });
337
    spark = $(spark[0]);
338
    jsondash.getJSON(config.dataSource, function(data){
339
        var opts = {
340
            type: sparkline_type,
341
            width: config.width - jsondash.config.WIDGET_MARGIN_X,
342
            height: config.height - jsondash.config.WIDGET_MARGIN_Y
343
        };
344
        spark.sparkline(data, opts);
345
        jsondash.unload(container);
346
    });
347
};
348
349
jsondash.handlers.handleDataTable = function(container, config) {
350
    'use strict';
351
    // Clean up old tables if they exist, during reloading.
352
    container.selectAll('.dataTables_wrapper').remove();
353
    jsondash.getJSON(config.dataSource, function(error, res) {
354
        if(error) { throw new Error('Could not load url: ' + config.dataSource); }
355
        var keys = d3.keys(res[0]).map(function(d){
356
            return {data: d, title: d};
357
        });
358
        container
359
            .append('table')
360
            .classed({
361
                table: true,
362
                'table-striped': true,
363
                'table-bordered': true,
364
                'table-condensed': true
365
            });
366
        var opts = config.override ? res : {data: res, columns: keys};
367
        $(container.select('table')[0]).dataTable(opts).css({width: 'auto'});
368
        jsondash.unload(container);
369
    });
370
};
371
372
jsondash.handlers.handleSingleNum = function(container, config) {
373
    'use strict';
374
    container.selectAll('.singlenum').remove();
375
    jsondash.getJSON(config.dataSource, function(data){
376
        var num = container.append('div')
377
            .classed({singlenum: true})
378
            .text(data);
379
        data = String(data);
380
        // Add red or green, depending on if the number appears to be pos/neg.
381
        num.classed({
382
            'text-danger': data.startsWith('-'),
383
            'text-success': !data.startsWith('-')
384
        });
385
        // Get title height to offset box.
386
        var title_h = container
387
            .select('.widget-title')
388
            .node()
389
            .getBoundingClientRect()
390
            .height;
391
        var inner_box_height = config.height - title_h; // factor in rough height of title.
392
        container.style({
393
            'line-height': inner_box_height + 'px',
394
            height: inner_box_height + 'px'
395
        });
396
        var digits = String(data).length;
397
        var size = jsondash.util.getDigitSize()(digits);
398
        num.style('font-size', size + 'px');
399
        jsondash.unload(container);
400
    });
401
};
402
403
jsondash.handlers.handleTimeline = function(container, config) {
404
    'use strict';
405
    jsondash.getJSON(config.dataSource, function(data){
406
        container.append('div').attr('id', 'widget-' + config.guid);
407
        var timeline = new TL.Timeline('widget-' + config.guid, data);
0 ignored issues
show
Bug introduced by
The variable TL seems to be never declared. If this is a global, consider adding a /** global: TL */ comment.

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

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

Loading history...
Unused Code introduced by
The variable timeline seems to be never used. Consider removing it.
Loading history...
408
        jsondash.unload(container);
409
    });
410
};
411
412
jsondash.handlers.handleIframe = function(container, config) {
413
    'use strict';
414
    container.selectAll('iframe').remove();
415
    var iframe = container.append('iframe');
416
    iframe.attr({
417
        border: 0,
418
        src: config.dataSource,
419
        height: '100%',
420
        width: '100%'
421
    });
422
    jsondash.unload(container);
423
};
424
425
jsondash.handlers.handleCustom = function(container, config) {
426
    'use strict';
427
    container.selectAll('.custom-container').remove();
428
    $.get(config.dataSource, function(html){
429
        container.append('div').classed({'custom-container': true}).html(html);
430
        jsondash.unload(container);
431
    });
432
};
433
434
jsondash.handlers.handleVenn = function(container, config) {
435
    'use strict';
436
    container.selectAll('.venn').remove();
437
    jsondash.getJSON(config.dataSource, function(error, data){
438
        if(error) { throw new Error('Could not load url: ' + config.dataSource); }
439
        var chart = venn.VennDiagram();
440
        var cont = container
441
            .append('div')
442
            .classed({venn: true});
443
        cont.datum(data).call(chart);
444
        cont.select('svg')
445
            .attr('width', config.width - jsondash.config.WIDGET_MARGIN_X)
446
            .attr('height', config.height - jsondash.config.WIDGET_MARGIN_Y);
447
        jsondash.unload(container);
448
    });
449
};
450
451
jsondash.handlers.handlePlotly = function(container, config) {
452
    'use strict';
453
    var id = 'plotly-' + config.guid;
454
    container.selectAll('.plotly-container').remove();
455
    container.append('div')
456
        .classed({'plotly-container': true})
457
        .attr('id', id);
458
    jsondash.getJSON(config.dataSource, function(error, data){
459
        if(error) { throw new Error('Could not load url: ' + config.dataSource); }
460
        if(config.override) {
461
            if(data.layout && data.layout.margin) {
462
                // Remove margins, they mess up the
463
                // layout and are already accounted for.
464
                delete data.layout['margin'];
465
            }
466
            Plotly.plot(id, data.data, data.layout || {}, data.options || {});
467
        } else {
468
            Plotly.plot(id, data);
469
        }
470
        d3.select('#' + id).select('.svg-container').style({'margin': '0 auto'})
471
        jsondash.unload(container);
472
    });
473
};
474