diff --git a/panoramix/assets/javascripts/dashboard.js b/panoramix/assets/javascripts/dashboard.js index c196e6ac2bc44..18ce5818e1c97 100644 --- a/panoramix/assets/javascripts/dashboard.js +++ b/panoramix/assets/javascripts/dashboard.js @@ -12,51 +12,79 @@ require('select2'); require('../node_modules/gridster/dist/jquery.gridster.min.js'); -var Dashboard = function (dashboardData) { +var Dashboard = function(dashboardData) { var dashboard = $.extend(dashboardData, { filters: {}, - init: function () { + init: function() { this.initDashboardView(); var sliceObjects = [], dash = this; - dashboard.slices.forEach(function (data) { - var slice = px.Slice(data, dash); - $("#slice_" + data.slice_id).find('a.refresh').click(function () { - slice.render(); - }); - sliceObjects.push(slice); + dashboard.slices.forEach(function(data) { + var slice = px.Slice(data, dash); + $("#slice_" + data.slice_id).find('a.refresh').click(function() { slice.render(); }); - this.slices = sliceObjects; + sliceObjects.push(slice); + slice.render(); + }); + this.slices = sliceObjects; }, - addFilter: function (slice_id, filters) { - this.filters[slice_id] = filters; + setFilter: function(slice_id, col, vals) { + console.log([slice_id, col, vals]); + this.addFilter(slice_id, col, vals, false); + }, + addFilter: function(slice_id, col, vals, merge) { + if (merge === undefined) { + merge = true; + } + if (!(slice_id in this.filters)) { + this.filters[slice_id] = {}; + } + if (!(col in this.filters[slice_id]) || !merge) { + this.filters[slice_id][col] = vals; + } else { + this.filters[slice_id][col] = d3.merge([this.filters[slice_id][col], vals]); + } this.refreshExcept(slice_id); }, - readFilters: function () { + readFilters: function() { // Returns a list of human readable active filters return JSON.stringify(this.filters, null, 4); }, - refreshExcept: function (slice_id) { + refreshExcept: function(slice_id) { var immune = this.metadata.filter_immune_slices; - this.slices.forEach(function (slice) { - if(slice.data.slice_id !== slice_id && immune.indexOf(slice.data.slice_id) === -1) { + this.slices.forEach(function(slice) { + if (slice.data.slice_id !== slice_id && immune.indexOf(slice.data.slice_id) === -1) { slice.render(); } }); }, - clearFilter: function (slice_id) { + clearFilters: function(slice_id) { delete this.filters[slice_id]; this.refreshExcept(slice_id); }, - getSlice: function (slice_id) { - this.slices.forEach(function (slice, i) { + removeFilter: function(slice_id, col, vals) { + if (slice_id in this.filters) { + if (col in this.filters[slice_id]) { + var a = []; + this.filters[slice_id][col].forEach(function(v) { + if (vals.indexOf(v) < 0) { + a.push(v); + } + }); + this.filters[slice_id][col] = a; + } + } + this.refreshExcept(slice_id); + }, + getSlice: function(slice_id) { + this.slices.forEach(function(slice, i) { if (slice.slice_id === slice_id) { return slice; } }); }, - initDashboardView: function () { + initDashboardView: function() { dashboard = this; var gridster = $(".gridster ul").gridster({ widget_margins: [5, 5], @@ -66,12 +94,12 @@ var Dashboard = function (dashboardData) { }, resize: { enabled: true, - stop: function (e, ui, element) { + stop: function(e, ui, element) { var slice_data = $(element).data('slice'); dashboard.getSlice(slice_data.slice_id).resize(); } }, - serialize_params: function (_w, wgd) { + serialize_params: function(_w, wgd) { return { slice_id: $(_w).attr('slice_id'), col: wgd.col, @@ -82,12 +110,12 @@ var Dashboard = function (dashboardData) { }, }).data('gridster'); $("div.gridster").css('visibility', 'visible'); - $("#savedash").click(function () { + $("#savedash").click(function() { var expanded_slices = {}; - $.each($(".slice_info"), function (i, d) { + $.each($(".slice_info"), function(i, d) { var widget = $(this).parents('.widget'); var slice_description = widget.find('.slice_description'); - if(slice_description.is(":visible")) + if (slice_description.is(":visible")) expanded_slices[$(d).attr('slice_id')] = true; }); var data = { @@ -98,9 +126,15 @@ var Dashboard = function (dashboardData) { $.ajax({ type: "POST", url: '/panoramix/save_dash/' + dashboard.id + '/', - data: {'data': JSON.stringify(data)}, - success: function () {alert("Saved!");}, - error: function () {alert("Error :(");}, + data: { + 'data': JSON.stringify(data) + }, + success: function() { + alert("Saved!"); + }, + error: function() { + alert("Error :("); + }, }); }); @@ -114,34 +148,36 @@ var Dashboard = function (dashboardData) { }); editor.getSession().setMode("ace/mode/css"); - $(".select2").select2({dropdownAutoWidth : true}); - $("#css_template").on("change", function () { + $(".select2").select2({ + dropdownAutoWidth: true + }); + $("#css_template").on("change", function() { var css = $(this).find('option:selected').data('css'); editor.setValue(css); $('#dash_css').val(css); $("#user_style").html(css); }); - $('#filters').click( function () { + $('#filters').click(function() { alert(dashboard.readFilters()); }); - $("a.closeslice").click(function () { + $("a.closeslice").click(function() { var li = $(this).parents("li"); gridster.remove_widget(li); }); - $(".slice_info").click(function () { + $(".slice_info").click(function() { var widget = $(this).parents('.widget'); var slice_description = widget.find('.slice_description'); - slice_description.slideToggle(500, function () { + slice_description.slideToggle(500, function() { widget.find('.refresh').click(); }); }); - $("table.slice_header").mouseover(function () { + $("table.slice_header").mouseover(function() { $(this).find("td.icons nobr").show(); }); - $("table.slice_header").mouseout(function () { + $("table.slice_header").mouseout(function() { $(this).find("td.icons nobr").hide(); }); - editor.on("change", function () { + editor.on("change", function() { var css = editor.getValue(); $('#dash_css').val(css); $("#user_style").html(css); @@ -152,6 +188,6 @@ var Dashboard = function (dashboardData) { return dashboard; }; -$(document).ready(function () { +$(document).ready(function() { var dashboard = Dashboard($('.dashboard').data('dashboard')); }); diff --git a/panoramix/assets/javascripts/explore.js b/panoramix/assets/javascripts/explore.js index 8ed350cccb0d8..60c7f9be4d592 100644 --- a/panoramix/assets/javascripts/explore.js +++ b/panoramix/assets/javascripts/explore.js @@ -21,44 +21,58 @@ require('../vendor/pygments.css'); require('../node_modules/bootstrap-toggle/css/bootstrap-toggle.min.css'); var slice; -function prepForm(){ + +function prepForm() { var i = 1; // Assigning the right id to form elements in filters $("#filters > div").each(function() { - $(this).attr("id", function() {return "flt_" + i;}) + $(this).attr("id", function() { + return "flt_" + i; + }) $(this).find("#flt_col_0") - .attr("id", function() {return "flt_col_" + i;}) - .attr("name", function() {return "flt_col_" + i;}); + .attr("id", function() { + return "flt_col_" + i; + }) + .attr("name", function() { + return "flt_col_" + i; + }); $(this).find("#flt_op_0") - .attr("id", function() {return "flt_op_" + i;}) - .attr("name", function() {return "flt_op_" + i;}); + .attr("id", function() { + return "flt_op_" + i; + }) + .attr("name", function() { + return "flt_op_" + i; + }); $(this).find("#flt_eq_0") - .attr("id", function() {return "flt_eq_" + i;}) - .attr("name", function() {return "flt_eq_" + i;}); + .attr("id", function() { + return "flt_eq_" + i; + }) + .attr("name", function() { + return "flt_eq_" + i; + }); i++; }); } -function renderSlice(){ +function renderSlice() { prepForm(); slice.render(); } function initExploreView() { - function druidify(){ + function druidify() { $('div.alert').remove(); history.pushState({}, document.title, slice.querystring()); renderSlice(); } - function get_collapsed_fieldsets(){ + function get_collapsed_fieldsets() { var collapsed_fieldsets = $("#collapsed_fieldsets").val(); - if (collapsed_fieldsets != undefined && collapsed_fieldsets != "") { + if (collapsed_fieldsets !== undefined && collapsed_fieldsets !== "") { collapsed_fieldsets = collapsed_fieldsets.split('||'); - } - else { + } else { collapsed_fieldsets = []; } return collapsed_fieldsets; @@ -68,33 +82,31 @@ function initExploreView() { var parent = legend.parent(); var fieldset = parent.find(".legend_label").text(); var collapsed_fieldsets = get_collapsed_fieldsets(); - - if (!parent.hasClass("collapsed")){ + var index; + if (!parent.hasClass("collapsed")) { if (animation) { parent.find(".fieldset_content").slideUp(); - } - else { + } else { parent.find(".fieldset_content").hide(); } parent.addClass("collapsed"); parent.find("span.collapser").text("[+]"); - var index = collapsed_fieldsets.indexOf(fieldset); + index = collapsed_fieldsets.indexOf(fieldset); if (index === -1 && fieldset !== "" && fieldset !== undefined) { collapsed_fieldsets.push(fieldset); } } else { if (animation) { parent.find(".fieldset_content").slideDown(); - } - else { + } else { parent.find(".fieldset_content").show(); } parent.removeClass("collapsed"); parent.find("span.collapser").text("[-]"); // removing from array, js is overcomplicated - var index = collapsed_fieldsets.indexOf(fieldset); + index = collapsed_fieldsets.indexOf(fieldset); if (index !== -1) { collapsed_fieldsets.splice(index, 1); } @@ -102,11 +114,11 @@ function initExploreView() { $("#collapsed_fieldsets").val(collapsed_fieldsets.join("||")); } - $('legend').click(function () { + $('legend').click(function() { toggle_fieldset($(this), true); }); - function copyURLToClipboard (url) { + function copyURLToClipboard(url) { var textArea = document.createElement("textarea"); textArea.style.position = 'fixed'; textArea.style.left = '-1000px'; @@ -127,19 +139,26 @@ function initExploreView() { return successful; } - $('#shortner').click(function () { + $('#shortner').click(function() { $.ajax({ type: "POST", url: '/r/shortner/', - data: {'data': '/' + window.location.pathname + slice.querystring()}, + data: { + 'data': '/' + window.location.pathname + slice.querystring() + }, success: function(data) { - var close = ''; - var copy = ''; - var spaces = '   ' + var close = ''; + var copy = ''; + var spaces = '   ' var popover = data + spaces + copy + spaces + close; var $shortner = $('#shortner') - .popover({content: popover, placement: 'left', html: true, trigger: 'manual'}) + .popover({ + content: popover, + placement: 'left', + html: true, + trigger: 'manual' + }) .popover('show'); $('#copy_url').tooltip().click(function() { @@ -152,31 +171,43 @@ function initExploreView() { }, 1200); } }); - $('#close_shortner').click(function(){ + $('#close_shortner').click(function() { $shortner.popover('destroy'); }); }, - error: function() {alert("Error :(");}, + error: function() { + alert("Error :("); + }, }); }); - $("#viz_type").change(function() {$("#query").submit();}); + $("#viz_type").change(function() { + $("#query").submit(); + }); var collapsed_fieldsets = get_collapsed_fieldsets(); - for(var i=0; i < collapsed_fieldsets.length; i++){ + for (var i = 0; i < collapsed_fieldsets.length; i++) { toggle_fieldset($('legend:contains("' + collapsed_fieldsets[i] + '")'), false); } - $(".select2").select2({dropdownAutoWidth : true}); - $(".select2Sortable").select2({dropdownAutoWidth : true}); - $(".select2Sortable").select2Sortable({bindOrder: 'sortableStop'}); + $(".select2").select2({ + dropdownAutoWidth: true + }); + $(".select2Sortable").select2({ + dropdownAutoWidth: true + }); + $(".select2Sortable").select2Sortable({ + bindOrder: 'sortableStop' + }); $("form").show(); - $('[data-toggle="tooltip"]').tooltip({container: 'body'}); + $('[data-toggle="tooltip"]').tooltip({ + container: 'body' + }); $(".ui-helper-hidden-accessible").remove(); // jQuery-ui 1.11+ creates a div for every tooltip - function set_filters(){ - for (var i = 1; i < 10; i++){ + function set_filters() { + for (var i = 1; i < 10; i++) { var eq = px.getParam("flt_eq_" + i); - if (eq != ''){ + if (eq !== '') { add_filter(i); } } @@ -187,7 +218,7 @@ function initExploreView() { var cp = $("#flt0").clone(); $(cp).appendTo("#filters"); $(cp).show(); - if (i != undefined){ + if (i !== undefined) { $(cp).find("#flt_eq_0").val(px.getParam("flt_eq_" + i)); $(cp).find("#flt_op_0").val(px.getParam("flt_op_" + i)); $(cp).find("#flt_col_0").val(px.getParam("flt_col_" + i)); @@ -208,16 +239,16 @@ function initExploreView() { $("#plus").click(add_filter); - $("#btn_save").click(function () { + $("#btn_save").click(function() { var slice_name = prompt("Name your slice!"); - if (slice_name != "" && slice_name != null) { + if (slice_name !== "" && slice_name !== null) { $("#slice_name").val(slice_name); prepForm(); $("#action").val("save"); $("#query").submit(); } }); - $("#btn_overwrite").click(function () { + $("#btn_overwrite").click(function() { var flag = confirm("Overwrite slice [" + $("#slice_name").val() + "] !?"); if (flag) { $("#action").val("overwrite"); @@ -233,37 +264,51 @@ function initExploreView() { return this.text.localeCompare(term) === 0; }); if (filtered.length === 0) { - return {id: term, text: term}; + return { + id: term, + text: term + }; } } + function initSelectionToValue(element, callback) { - callback({id: element.val(), text: element.val()}); + callback({ + id: element.val(), + text: element.val() + }); } + function list_data(arr) { var obj = []; - for (var i=0; i' + '' ); - $("input[name='" + name +"']").select2({ + $("input[name='" + name + "']").select2({ createSearchChoice: create_choices, initSelection: initSelectionToValue, - dropdownAutoWidth : true, + dropdownAutoWidth: true, multiple: false, data: l, }); @@ -279,7 +324,7 @@ $(document).ready(function() { px.registerViz(visType); - var data = $('.slice').data('slice'); + var data = $('.slice').data('slice'); slice = px.Slice(data); // @@ -290,9 +335,11 @@ $(document).ready(function() { // make checkbox inputs display as toggles $(':checkbox') - .addClass('pull-right') - .attr("data-onstyle", "default") - .bootstrapToggle({size: 'mini'}); + .addClass('pull-right') + .attr("data-onstyle", "default") + .bootstrapToggle({ + size: 'mini' + }); $('div.toggle').addClass('pull-right'); }); diff --git a/panoramix/assets/javascripts/featured.js b/panoramix/assets/javascripts/featured.js index c8e542c2076f6..dc54d4e116632 100644 --- a/panoramix/assets/javascripts/featured.js +++ b/panoramix/assets/javascripts/featured.js @@ -5,10 +5,12 @@ require('datatables-bootstrap3-plugin'); require('bootstrap'); $(document).ready(function() { - $('#dataset-table').DataTable({ - "bPaginate": false, - "order": [[ 1, "asc" ]] - }); - $('#dataset-table_info').remove(); - $('#dataset-table').show(); -} ); + $('#dataset-table').DataTable({ + "bPaginate": false, + "order": [ + [1, "asc"] + ] + }); + $('#dataset-table_info').remove(); + $('#dataset-table').show(); +}); diff --git a/panoramix/assets/javascripts/modules/panoramix.js b/panoramix/assets/javascripts/modules/panoramix.js index 7228b03cd781a..8500f337dfcd0 100644 --- a/panoramix/assets/javascripts/modules/panoramix.js +++ b/panoramix/assets/javascripts/modules/panoramix.js @@ -1,31 +1,32 @@ -var $ = require('jquery'), jQuery = $; +var $ = require('jquery'), + jQuery = $; var d3 = require('d3'); // vis sources var sourceMap = { - area: 'nvd3_vis.js', - bar: 'nvd3_vis.js', - bubble: 'nvd3_vis.js', - big_number: 'big_number.js', - compare: 'nvd3_vis.js', - dist_bar: 'nvd3_vis.js', + area: 'nvd3_vis.js', + bar: 'nvd3_vis.js', + bubble: 'nvd3_vis.js', + big_number: 'big_number.js', + compare: 'nvd3_vis.js', + dist_bar: 'nvd3_vis.js', directed_force: 'directed_force.js', - filter_box: 'filter_box.js', - heatmap: 'heatmap.js', - iframe: 'iframe.js', - line: 'nvd3_vis.js', - markup: 'markup.js', - para: 'parallel_coordinates.js', - pie: 'nvd3_vis.js', - pivot_table: 'pivot_table.js', - sankey: 'sankey.js', - sunburst: 'sunburst.js', - table: 'table.js', - word_cloud: 'word_cloud.js', - world_map: 'world_map.js', + filter_box: 'filter_box.js', + heatmap: 'heatmap.js', + iframe: 'iframe.js', + line: 'nvd3_vis.js', + markup: 'markup.js', + para: 'parallel_coordinates.js', + pie: 'nvd3_vis.js', + pivot_table: 'pivot_table.js', + sankey: 'sankey.js', + sunburst: 'sunburst.js', + table: 'table.js', + word_cloud: 'word_cloud.js', + world_map: 'world_map.js', }; -var color = function(){ +var color = function() { // Color related utility functions go in this object var bnbColors = [ //rausch hackb kazan babu lima beach barol @@ -38,116 +39,131 @@ var color = function(){ 'fire': ['white', 'yellow', 'red', 'black'], 'white_black': ['white', 'black'], 'black_white': ['black', 'white'], - } + }; var colorBnb = function() { // Color factory var seen = {}; return function(s) { // next line is for dashed series that should have the same color s = s.replace('---', ''); - if(seen[s] === undefined) + if (seen[s] === undefined) seen[s] = Object.keys(seen).length; return this.bnbColors[seen[s] % this.bnbColors.length]; }; }; - var colorScalerFactory = function (colors, data, accessor){ + var colorScalerFactory = function(colors, data, accessor) { // Returns a linear scaler our of an array of color - if(!Array.isArray(colors)) + if (!Array.isArray(colors)) { colors = spectrums[colors]; - if(data !== undefined) - var ext = d3.extent(data, accessor); - else - var ext = [0,1]; + } + + var ext = [0, 1]; + if (data !== undefined) { + ext = d3.extent(data, accessor); + } var points = []; var chunkSize = (ext[1] - ext[0]) / colors.length; - $.each(colors, function(i, c){ - points.push(i * chunkSize) + $.each(colors, function(i, c) { + points.push(i * chunkSize); }); return d3.scale.linear().domain(points).range(colors); - } + }; return { bnbColors: bnbColors, category21: colorBnb(), colorScalerFactory: colorScalerFactory, - } + }; }; var px = (function() { var visualizations = {}; - var dashboard = undefined; - var slice = undefined; + var dashboard; + var slice; function getParam(name) { name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]"); var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"), results = regex.exec(location.search); - return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " ")); + return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " ")); } - function UTC(dttm){ - return new Date(dttm.getUTCFullYear(), dttm.getUTCMonth(), dttm.getUTCDate(), dttm.getUTCHours(), dttm.getUTCMinutes(), dttm.getUTCSeconds()); + function UTC(dttm) { + return new Date(dttm.getUTCFullYear(), dttm.getUTCMonth(), dttm.getUTCDate(), dttm.getUTCHours(), dttm.getUTCMinutes(), dttm.getUTCSeconds()); } var tickMultiFormat = d3.time.format.multi([ - [".%L", function(d) { return d.getMilliseconds(); }], // If there are millisections, show only them - [":%S", function(d) { return d.getSeconds(); }], // If there are seconds, show only them - ["%a %b %d, %I:%M %p", function(d) { return d.getMinutes()!=0; }], // If there are non-zero minutes, show Date, Hour:Minute [AM/PM] - ["%a %b %d, %I %p", function(d) { return d.getHours() != 0; }], // If there are hours that are multiples of 3, show date and AM/PM - ["%a %b %d, %Y", function(d) { return d.getDate() != 1; }], // If not the first of the month, do "month day, year." - ["%B %Y", function(d) { return d.getMonth() != 0 && d.getDate() == 1; }], // If the first of the month, do "month day, year." - ["%Y", function(d) { return true; }] // fall back on month, year + [".%L", function(d) { + return d.getMilliseconds(); + }], // If there are millisections, show only them + [":%S", function(d) { + return d.getSeconds(); + }], // If there are seconds, show only them + ["%a %b %d, %I:%M %p", function(d) { + return d.getMinutes() !== 0; + }], // If there are non-zero minutes, show Date, Hour:Minute [AM/PM] + ["%a %b %d, %I %p", function(d) { + return d.getHours() !== 0; + }], // If there are hours that are multiples of 3, show date and AM/PM + ["%a %b %d, %Y", function(d) { + return d.getDate() !== 1; + }], // If not the first of the month, do "month day, year." + ["%B %Y", function(d) { + return d.getMonth() !== 0 && d.getDate() === 1; + }], // If the first of the month, do "month day, year." + ["%Y", function(d) { + return true; + }] // fall back on month, year ]); + function formatDate(dttm) { var d = UTC(new Date(dttm)); //d = new Date(d.getTime() - 1 * 60 * 60 * 1000); return tickMultiFormat(d); } + function timeFormatFactory(d3timeFormat) { - var f = d3.time.format(d3timeFormat) - return function(dttm){ + var f = d3.time.format(d3timeFormat); + return function(dttm) { var d = UTC(new Date(dttm)); return f(d); }; } - var Slice = function(data, dashboard){ + var Slice = function(data, dashboard) { var timer; var token = $('#' + data.token); var container_id = data.token + '_con'; var selector = '#' + container_id; var container = $(selector); var slice_id = data.slice_id; - var name = data['viz_name']; + var name = data.viz_name; var dttm = 0; - var timer; - var stopwatch = function () { + var stopwatch = function() { dttm += 10; var num = dttm / 1000; $('#timer').text(num.toFixed(2) + " sec"); - } + }; var qrystr = ''; var always = function(data) { //Private f, runs after done and error clearInterval(timer); $('#timer').removeClass('btn-warning'); - } + }; slice = { data: data, container: container, container_id: container_id, selector: selector, - querystring: function(){ + querystring: function() { var parser = document.createElement('a'); parser.href = data.json_endpoint; - if (dashboard !== undefined){ + if (dashboard !== undefined) { var flts = encodeURIComponent(JSON.stringify(dashboard.filters)); qrystr = parser.search + "&extra_filters=" + flts; - } - else if ($('#query').length == 0){ + } else if ($('#query').length === 0) { qrystr = parser.search; - } - else { + } else { qrystr = '?' + $('#query').serialize(); } return qrystr; @@ -158,34 +174,41 @@ var px = (function() { var endpoint = parser.pathname + this.querystring() + "&json=true"; return endpoint; }, - done: function (data) { + done: function(data) { clearInterval(timer); - token.find("img.loading").hide() + token.find("img.loading").hide(); container.show(); - if(data !== undefined) + if (data !== undefined) { $("#query_container").html(data.query); + } $('#timer').removeClass('btn-warning'); $('#timer').addClass('btn-success'); $('span.query').removeClass('disabled'); - $('#json').click(function(){window.location=data.json_endpoint}); - $('#standalone').click(function(){window.location=data.standalone_endpoint}); - $('#csv').click(function(){window.location=data.csv_endpoint}); + $('#json').click(function() { + window.location = data.json_endpoint; + }); + $('#standalone').click(function() { + window.location = data.standalone_endpoint; + }); + $('#csv').click(function() { + window.location = data.csv_endpoint; + }); $('.btn-group.results span').removeAttr('disabled'); always(data); }, - error: function (msg) { + error: function(msg) { token.find("img.loading").hide(); - var err = '
' + msg + '
'; + var err = '
' + msg + '
'; container.html(err); container.show(); $('span.query').removeClass('disabled'); $('#timer').addClass('btn-danger'); always(data); }, - width: function(){ + width: function() { return token.width(); }, - height: function(){ + height: function() { var others = 0; var widget = container.parents('.widget'); var slice_description = widget.find('.slice_description'); @@ -195,7 +218,7 @@ var px = (function() { return widget.height() - others; }, render: function() { - $('.btn-group.results span').attr('disabled','disabled'); + $('.btn-group.results span').attr('disabled', 'disabled'); token.find("img.loading").show(); container.hide(); container.html(''); @@ -213,19 +236,27 @@ var px = (function() { this.viz.resize(); }, addFilter: function(col, vals) { - if(dashboard !== undefined) + if (dashboard !== undefined) dashboard.addFilter(slice_id, col, vals); }, + setFilter: function(col, vals) { + if (dashboard !== undefined) + dashboard.setFilter(slice_id, col, vals); + }, clearFilter: function() { - if(dashboard !== undefined) + if (dashboard !== undefined) delete dashboard.clearFilter(slice_id); }, + removeFilter: function(col, vals) { + if (dashboard !== undefined) + delete dashboard.removeFilter(slice_id, col, vals); + }, }; var visType = data.form_data.viz_type; px.registerViz(visType); - slice['viz'] = visualizations[data.form_data.viz_type](slice); + slice.viz = visualizations[data.form_data.viz_type](slice); return slice; - } + }; function registerViz(name) { var visSource = sourceMap[name]; @@ -235,12 +266,48 @@ var px = (function() { if (typeof visFactory === 'function') { visualizations[name] = visFactory; } - } - else { + } else { console.error("require(", visType, ") failed."); } } + function prepForm() { + var i = 1; + // Assigning the right id to form elements in filters + $("#filters > div").each(function() { + $(this).attr("id", function() { + return "flt_" + i; + }); + $(this).find("#flt_col_0") + .attr("id", function() { + return "flt_col_" + i; + }) + .attr("name", function() { + return "flt_col_" + i; + }); + $(this).find("#flt_op_0") + .attr("id", function() { + return "flt_op_" + i; + }) + .attr("name", function() { + return "flt_op_" + i; + }); + $(this).find("#flt_eq_0") + .attr("id", function() { + return "flt_eq_" + i; + }) + .attr("name", function() { + return "flt_eq_" + i; + }); + i++; + }); + } + + function renderSlice() { + prepForm(); + slice.render(); + } + // Export public functions return { registerViz: registerViz, @@ -249,7 +316,7 @@ var px = (function() { timeFormatFactory: timeFormatFactory, color: color(), getParam: getParam, - } + }; })(); module.exports = px; diff --git a/panoramix/assets/javascripts/sql.js b/panoramix/assets/javascripts/sql.js index ab2386629484c..57f2f79065064 100644 --- a/panoramix/assets/javascripts/sql.js +++ b/panoramix/assets/javascripts/sql.js @@ -12,35 +12,41 @@ $(document).ready(function() { function getParam(name) { name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]"); var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"), - results = regex.exec(location.search); + results = regex.exec(location.search); return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " ")); } + function initSqlEditorView() { var database_id = $('#database_id').val(); var editor = ace.edit("sql"); - editor.$blockScrolling = Infinity + editor.$blockScrolling = Infinity; editor.getSession().setUseWrapMode(true); var textarea = $('#sql').hide(); editor.setTheme("ace/theme/crimson_editor"); editor.setOptions({ - minLines: 16, - maxLines: Infinity, + minLines: 16, + maxLines: Infinity, }); editor.getSession().setMode("ace/mode/sql"); editor.focus(); - $("select").select2({dropdownAutoWidth : true}); + $("select").select2({ + dropdownAutoWidth: true + }); + function showTableMetadata() { $(".metadata").load( - '/panoramix/table/' + database_id + '/' + $("#dbtable").val() + '/'); + '/panoramix/table/' + database_id + '/' + $("#dbtable").val() + '/'); } $("#dbtable").on("change", showTableMetadata); showTableMetadata(); - $("#create_view").click(function(){alert("Not implemented");}); + $("#create_view").click(function() { + alert("Not implemented"); + }); $(".sqlcontent").show(); - $("#select_star").click(function(){ - $.ajax('/panoramix/select_star/' + database_id + '/' + $("#dbtable").val() + '/') - .done(function(msg){ + $("#select_star").click(function() { + $.ajax('/panoramix/select_star/' + database_id + '/' + $("#dbtable").val() + '/') + .done(function(msg) { editor.setValue(msg); }); }); @@ -62,9 +68,10 @@ $(document).ready(function() { url: '/panoramix/runsql/', data: { 'data': JSON.stringify({ - 'database_id': $('#database_id').val(), - 'sql': editor.getSession().getValue(), - })}, + 'database_id': $('#database_id').val(), + 'sql': editor.getSession().getValue(), + }) + }, success: function(data) { $('#loading').hide(0); $('#results').show(0); diff --git a/panoramix/assets/visualizations/big_number.js b/panoramix/assets/visualizations/big_number.js index 8b0d9038003e0..db46745e1aadf 100644 --- a/panoramix/assets/visualizations/big_number.js +++ b/panoramix/assets/visualizations/big_number.js @@ -11,16 +11,16 @@ function bigNumberVis(slice) { var div = d3.select(slice.selector); function render() { - d3.json(slice.jsonEndpoint(), function(error, payload){ + d3.json(slice.jsonEndpoint(), function(error, payload) { //Define the percentage bounds that define color from red to green - if (error != null){ + if (error !== null) { slice.error(error.responseText); return ''; } var fd = payload.form_data; var json = payload.data; var color_range = [-1, 1]; - var compare_pos = -23 + var compare_pos = -23; var target_url = 'd3js.org'; var f = d3.format(fd.y_axis_format); @@ -34,44 +34,54 @@ function bigNumberVis(slice) { var compare_suffix = ' ' + json.compare_suffix; var v_compare = null; var v = data[data.length - 1][1]; - if (json.compare_lag > 0){ + if (json.compare_lag > 0) { var pos = data.length - (json.compare_lag + 1); - if (pos >= 0){ + if (pos >= 0) { v_compare = (v / data[pos][1]) - 1; } } - var date_ext = d3.extent(data, function(d) { return d[0]; }); - var value_ext = d3.extent(data, function(d) { return d[1]; }); + var date_ext = d3.extent(data, function(d) { + return d[0]; + }); + var value_ext = d3.extent(data, function(d) { + return d[1]; + }); var margin = 20; var scale_x = d3.time.scale.utc().domain(date_ext).range([margin, width - margin]); var scale_y = d3.scale.linear().domain(value_ext).range([height - (margin), margin]); var colorRange = [d3.hsl(0, 1, 0.3), d3.hsl(120, 1, 0.3)]; var scale_color = d3.scale - .linear().domain(color_range) - .interpolate(d3.interpolateHsl) - .range(colorRange).clamp(true); + .linear().domain(color_range) + .interpolate(d3.interpolateHsl) + .range(colorRange).clamp(true); var line = d3.svg.line() - .x(function(d) { return scale_x(d[0]); }) - .y(function(d) { return scale_y(d[1]); }) - .interpolate("basis"); + .x(function(d) { + return scale_x(d[0]); + }) + .y(function(d) { + return scale_y(d[1]); + }) + .interpolate("basis"); //Drawing trend line var g = svg.append('g'); var path = g.append('path') - .attr('d', function(d) { return line(data); }) - .attr('stroke-width', 5) - .attr('opacity', 0.5) - .attr('fill', "none") - .attr('stroke-linecap',"round") - .attr('stroke', "grey"); - - var g = svg.append('g') - .attr('class', 'digits') - .attr('opacity', 1); + .attr('d', function(d) { + return line(data); + }) + .attr('stroke-width', 5) + .attr('opacity', 0.5) + .attr('fill', "none") + .attr('stroke-linecap', "round") + .attr('stroke', "grey"); + + g = svg.append('g') + .attr('class', 'digits') + .attr('opacity', 1); var y = height / 2; - if (v_compare != null) { + if (v_compare !== null) { y = (height / 8) * 3; } @@ -86,15 +96,15 @@ function bigNumberVis(slice) { .style('cursor', 'pointer') .text(f(v)) .style('font-size', d3.min([height, width]) / 3.5) - .attr('fill','white'); + .attr('fill', 'white'); var c = scale_color(v_compare); //Printing compare % - if (v_compare != null) { + if (v_compare !== null) { g.append('text') .attr('x', width / 2) - .attr('y', (height / 16) *12) + .attr('y', (height / 16) * 12) .text(fp(v_compare) + compare_suffix) .style('font-size', d3.min([height, width]) / 8) .style('text-anchor', 'middle') @@ -103,7 +113,7 @@ function bigNumberVis(slice) { } var g_axis = svg.append('g').attr('class', 'axis').attr('opacity', 0); - var g = g_axis.append('g'); + g = g_axis.append('g'); var x_axis = d3.svg.axis() .scale(scale_x) .orient('bottom') @@ -112,7 +122,7 @@ function bigNumberVis(slice) { g.call(x_axis); g.attr('transform', 'translate(0,' + (height - margin) + ')'); - var g = g_axis.append('g').attr('transform', 'translate(' + (width - margin) + ',0)'); + g = g_axis.append('g').attr('transform', 'translate(' + (width - margin) + ',0)'); var y_axis = d3.svg.axis() .scale(scale_y) .orient('left') @@ -121,34 +131,34 @@ function bigNumberVis(slice) { g.call(y_axis); g.selectAll('text') .style('text-anchor', 'end') - .attr('y','-7') - .attr('x','-4'); + .attr('y', '-7') + .attr('x', '-4'); g.selectAll("text") .style('font-size', '10px'); div.on('mouseover', function(d) { - var div = d3.select(this); - div.select('path').transition().duration(500).attr('opacity', 1) - .style('stroke-width', '2px'); - div.select('g.digits').transition().duration(500).attr('opacity', 0.1); - div.select('g.axis').transition().duration(500).attr('opacity', 1); - }) - .on('mouseout', function(d) { - var div = d3.select(this); - div.select('path').transition().duration(500).attr('opacity', 0.5) - .style('stroke-width', '5px'); - div.select('g.digits').transition().duration(500).attr('opacity', 1); - div.select('g.axis').transition().duration(500).attr('opacity', 0); - }); + var div = d3.select(this); + div.select('path').transition().duration(500).attr('opacity', 1) + .style('stroke-width', '2px'); + div.select('g.digits').transition().duration(500).attr('opacity', 0.1); + div.select('g.axis').transition().duration(500).attr('opacity', 1); + }) + .on('mouseout', function(d) { + var div = d3.select(this); + div.select('path').transition().duration(500).attr('opacity', 0.5) + .style('stroke-width', '5px'); + div.select('g.digits').transition().duration(500).attr('opacity', 1); + div.select('g.axis').transition().duration(500).attr('opacity', 0); + }); slice.done(payload); }); - }; + } return { render: render, resize: render, - } -}; + }; +} module.exports = bigNumberVis; diff --git a/panoramix/assets/visualizations/directed_force.js b/panoramix/assets/visualizations/directed_force.js index 812cc769eded9..28fe1834c3924 100644 --- a/panoramix/assets/visualizations/directed_force.js +++ b/panoramix/assets/visualizations/directed_force.js @@ -7,15 +7,15 @@ require('./directed_force.css'); /* Modified from http://bl.ocks.org/d3noob/5141278 */ function directedForceVis(slice) { var div = d3.select(slice.selector); - var link_length = slice.data.form_data['link_length'] || 200; - var charge = slice.data.form_data['charge'] || -500; + var link_length = slice.data.form_data.link_length || 200; + var charge = slice.data.form_data.charge || -500; var render = function() { var width = slice.width(); var height = slice.height() - 25; d3.json(slice.jsonEndpoint(), function(error, json) { - if (error != null){ + if (error !== null) { slice.error(error.responseText); return ''; } @@ -23,134 +23,144 @@ function directedForceVis(slice) { var nodes = {}; // Compute the distinct nodes from the links. links.forEach(function(link) { - link.source = nodes[link.source] || (nodes[link.source] = {name: link.source}); - link.target = nodes[link.target] || (nodes[link.target] = {name: link.target}); - link.value = +link.value; - - var target_name = link.target.name; - var source_name = link.source.name; - - if (nodes[target_name]['total'] === undefined) { - nodes[target_name]['total'] = link.value; - } - if (nodes[source_name]['total'] === undefined) { - nodes[source_name]['total'] = 0; - } - if (nodes[target_name]['max'] === undefined) { - nodes[target_name]['max'] = 0; - } - if (link.value > nodes[target_name]['max']) { - nodes[target_name]['max'] = link.value; - } - if (nodes[target_name]['min'] === undefined) { - nodes[target_name]['min'] = 0; - } - if (link.value > nodes[target_name]['min']) { - nodes[target_name]['min'] = link.value; - } - - nodes[target_name]['total'] += link.value; + link.source = nodes[link.source] || (nodes[link.source] = { + name: link.source + }); + link.target = nodes[link.target] || (nodes[link.target] = { + name: link.target + }); + link.value = +link.value; + + var target_name = link.target.name; + var source_name = link.source.name; + + if (nodes[target_name].total === undefined) { + nodes[target_name].total = link.value; + } + if (nodes[source_name].total === undefined) { + nodes[source_name].total = 0; + } + if (nodes[target_name].max === undefined) { + nodes[target_name].max = 0; + } + if (link.value > nodes[target_name].max) { + nodes[target_name].max = link.value; + } + if (nodes[target_name].min === undefined) { + nodes[target_name].min = 0; + } + if (link.value > nodes[target_name].min) { + nodes[target_name].min = link.value; + } + + nodes[target_name].total += link.value; }); var force = d3.layout.force() - .nodes(d3.values(nodes)) - .links(links) - .size([width, height]) - .linkDistance(link_length) - .charge(charge) - .on("tick", tick) - .start(); + .nodes(d3.values(nodes)) + .links(links) + .size([width, height]) + .linkDistance(link_length) + .charge(charge) + .on("tick", tick) + .start(); var svg = div.append("svg") - .attr("width", width) - .attr("height", height); + .attr("width", width) + .attr("height", height); // build the arrow. svg.append("svg:defs").selectAll("marker") - .data(["end"]) // Different link/path types can be defined here - .enter().append("svg:marker") // This section adds in the arrows - .attr("id", String) - .attr("viewBox", "0 -5 10 10") - .attr("refX", 15) - .attr("refY", -1.5) - .attr("markerWidth", 6) - .attr("markerHeight", 6) - .attr("orient", "auto") + .data(["end"]) // Different link/path types can be defined here + .enter().append("svg:marker") // This section adds in the arrows + .attr("id", String) + .attr("viewBox", "0 -5 10 10") + .attr("refX", 15) + .attr("refY", -1.5) + .attr("markerWidth", 6) + .attr("markerHeight", 6) + .attr("orient", "auto") .append("svg:path") - .attr("d", "M0,-5L10,0L0,5"); + .attr("d", "M0,-5L10,0L0,5"); var edgeScale = d3.scale.linear() - .range([0.1, 0.5]); + .range([0.1, 0.5]); // add the links and the arrows var path = svg.append("svg:g").selectAll("path") - .data(force.links()) + .data(force.links()) .enter().append("svg:path") - .attr("class", "link") - .style("opacity", function(d){ - return edgeScale(d.value/d.target.max); - }) - .attr("marker-end", "url(#end)"); + .attr("class", "link") + .style("opacity", function(d) { + return edgeScale(d.value / d.target.max); + }) + .attr("marker-end", "url(#end)"); // define the nodes var node = svg.selectAll(".node") - .data(force.nodes()) + .data(force.nodes()) .enter().append("g") - .attr("class", "node") - .on("mouseenter", function(d){ - d3.select(this) - .select("circle") - .transition() - .style('stroke-width', 5); - - d3.select(this) - .select("text") - .transition() - .style('font-size', 25); - }) - .on("mouseleave", function(d){ - d3.select(this) - .select("circle") - .transition() - .style('stroke-width', 1.5); - d3.select(this) - .select("text") - .transition() - .style('font-size', 12); - }) - .call(force.drag); + .attr("class", "node") + .on("mouseenter", function(d) { + d3.select(this) + .select("circle") + .transition() + .style('stroke-width', 5); + + d3.select(this) + .select("text") + .transition() + .style('font-size', 25); + }) + .on("mouseleave", function(d) { + d3.select(this) + .select("circle") + .transition() + .style('stroke-width', 1.5); + d3.select(this) + .select("text") + .transition() + .style('font-size', 12); + }) + .call(force.drag); // add the nodes - var ext = d3.extent(d3.values(nodes), function(d) { return Math.sqrt(d.total); }); + var ext = d3.extent(d3.values(nodes), function(d) { + return Math.sqrt(d.total); + }); var circleScale = d3.scale.linear() - .domain(ext) - .range([3, 30]); + .domain(ext) + .range([3, 30]); node.append("circle") - .attr("r", function(d){return circleScale(Math.sqrt(d.total));}); + .attr("r", function(d) { + return circleScale(Math.sqrt(d.total)); + }); // add the text node.append("text") - .attr("x", 6) - .attr("dy", ".35em") - .text(function(d) { return d.name; }); + .attr("x", 6) + .attr("dy", ".35em") + .text(function(d) { + return d.name; + }); // add the curvy lines function tick() { - path.attr("d", function(d) { - var dx = d.target.x - d.source.x, - dy = d.target.y - d.source.y, - dr = Math.sqrt(dx * dx + dy * dy); - return "M" + - d.source.x + "," + - d.source.y + "A" + - dr + "," + dr + " 0 0,1 " + - d.target.x + "," + - d.target.y; - }); - - node.attr("transform", function(d) { - return "translate(" + d.x + "," + d.y + ")"; - }); + path.attr("d", function(d) { + var dx = d.target.x - d.source.x, + dy = d.target.y - d.source.y, + dr = Math.sqrt(dx * dx + dy * dy); + return "M" + + d.source.x + "," + + d.source.y + "A" + + dr + "," + dr + " 0 0,1 " + + d.target.x + "," + + d.target.y; + }); + + node.attr("transform", function(d) { + return "translate(" + d.x + "," + d.y + ")"; + }); } slice.done(json); diff --git a/panoramix/assets/visualizations/filter_box.js b/panoramix/assets/visualizations/filter_box.js index 5ced2eacd347a..2b43d6531e58c 100644 --- a/panoramix/assets/visualizations/filter_box.js +++ b/panoramix/assets/visualizations/filter_box.js @@ -5,33 +5,34 @@ var d3 = window.d3 || require('d3'); require('./filter_box.css'); function filterBox(slice) { - var slice = slice; var filtersObj = {}; var d3token = d3.select(slice.selector); var fltChanged = function() { - var filters = [] for (var filter in filtersObj) { var obj = filtersObj[filter]; var val = obj.val(); + var vals = []; if (val !== '') { - filters.push([filter, val.split(',')]); + vals = val.split(','); } + slice.setFilter(filter, vals); } - slice.addFilter(filters); - } + }; var refresh = function() { - d3token.selectAll("*").remove(); - var container = d3token - .append('div') - .classed('padded', true); + d3token.selectAll("*").remove(); + var container = d3token + .append('div') + .classed('padded', true); - $.getJSON(slice.jsonEndpoint(), function(payload) { + $.getJSON(slice.jsonEndpoint(), function(payload) { var maxes = {}; for (var filter in payload.data) { var data = payload.data[filter]; - maxes[filter] = d3.max(data, function(d){return d.metric}); + maxes[filter] = d3.max(data, function(d) { + return d.metric; + }); var id = 'fltbox__' + filter; var div = container.append('div'); @@ -44,12 +45,12 @@ function filterBox(slice) { .attr('id', id); filtersObj[filter] = $('#' + id).select2({ - placeholder: "Select [" + filter + ']', - containment: 'parent', - dropdownAutoWidth : true, - data:data, - multiple: true, - formatResult: function(result, container, query, escapeMarkup) { + placeholder: "Select [" + filter + ']', + containment: 'parent', + dropdownAutoWidth: true, + data: data, + multiple: true, + formatResult: function(result, container, query, escapeMarkup) { var perc = Math.round((result.metric / maxes[result.filter]) * 100); var style = 'padding: 2px 5px;'; style += "background-image: "; @@ -58,16 +59,16 @@ function filterBox(slice) { $(container).attr('style', 'padding: 0px; background: white;'); $(container).addClass('filter_box'); return '
' + result.text + '
'; - }, - }) - .on('change', fltChanged); + }, + }) + .on('change', fltChanged); } slice.done(); }) .fail(function(xhr) { - slice.error(xhr.responseText); - }); - }; + slice.error(xhr.responseText); + }); + }; return { render: refresh, resize: refresh, diff --git a/panoramix/assets/visualizations/heatmap.js b/panoramix/assets/visualizations/heatmap.js index 039a2c507c6cf..895cae8922faf 100644 --- a/panoramix/assets/visualizations/heatmap.js +++ b/panoramix/assets/visualizations/heatmap.js @@ -1,5 +1,5 @@ // JS -var $ = window.$ || require('jquery'); +var $ = window.$ || require('jquery'); var px = window.px || require('../javascripts/modules/panoramix.js'); var d3 = require('d3'); @@ -11,27 +11,34 @@ require('./heatmap.css'); // Inspired from http://bl.ocks.org/mbostock/3074470 // https://jsfiddle.net/cyril123/h0reyumq/ function heatmapVis(slice) { - var margins = {t:10, r:10, b:50, l:60}; + var margins = { + t: 10, + r: 10, + b: 50, + l: 60 + }; + function refresh() { var width = slice.width(); var height = slice.height(); - var hmWidth = width - (margins.l + margins.r) - var hmHeight = height - (margins.b + margins.t) + var hmWidth = width - (margins.l + margins.r); + var hmHeight = height - (margins.b + margins.t); var fp = d3.format('.3p'); d3.json(slice.jsonEndpoint(), function(error, payload) { var matrix = {}; - if (error){ + if (error) { slice.error(error.responseText); return ''; } var fd = payload.form_data; var data = payload.data; + function ordScale(k, rangeBands, reverse) { if (reverse === undefined) { reverse = false; } var domain = {}; - $.each(data, function(i, d){ + $.each(data, function(i, d) { domain[d[k]] = true; }); domain = Object.keys(domain).sort(function(a, b) { @@ -42,8 +49,7 @@ function heatmapVis(slice) { } if (rangeBands === undefined) { return d3.scale.ordinal().domain(domain).range(d3.range(domain.length)); - } - else { + } else { return d3.scale.ordinal().domain(domain).rangeBands(rangeBands); } } @@ -51,71 +57,72 @@ function heatmapVis(slice) { var yScale = ordScale('y', undefined, true); var xRbScale = ordScale('x', [0, hmWidth]); var yRbScale = ordScale('y', [hmHeight, 0]); - var X = 0, Y = 1; + var X = 0, + Y = 1; var heatmapDim = [xRbScale.domain().length, yRbScale.domain().length]; var color = px.color.colorScalerFactory(fd.linear_color_scheme); var scale = [ d3.scale.linear() - .domain([0, heatmapDim[X]]) - .range([0, hmWidth]), + .domain([0, heatmapDim[X]]) + .range([0, hmWidth]), d3.scale.linear() - .domain([0, heatmapDim[Y]]) - .range([0, hmHeight]) + .domain([0, heatmapDim[Y]]) + .range([0, hmHeight]) ]; var container = d3.select(slice.selector) - .style("left", "0px") - .style("position", "relative") - .style("top", "0px"); + .style("left", "0px") + .style("position", "relative") + .style("top", "0px"); var canvas = container.append("canvas") - .attr("width", heatmapDim[X]) - .attr("height", heatmapDim[Y]) - .style("width", hmWidth + "px") - .style("height", hmHeight + "px") - .style("image-rendering", fd.canvas_image_rendering) - .style("left", margins.l + "px") - .style("top", margins.t + "px") - .style("position", "absolute"); + .attr("width", heatmapDim[X]) + .attr("height", heatmapDim[Y]) + .style("width", hmWidth + "px") + .style("height", hmHeight + "px") + .style("image-rendering", fd.canvas_image_rendering) + .style("left", margins.l + "px") + .style("top", margins.t + "px") + .style("position", "absolute"); var svg = container.append("svg") - .attr("width", width) - .attr("height", height) - .style("left", "0px") - .style("top", "0px") - .style("position", "absolute"); + .attr("width", width) + .attr("height", height) + .style("left", "0px") + .style("top", "0px") + .style("position", "absolute"); var rect = svg.append('g') - .attr("transform", "translate(" + margins.l + "," + margins.t + ")") + .attr("transform", "translate(" + margins.l + "," + margins.t + ")") .append('rect') - .style('fill-opacity', 0) - .attr('stroke', 'black') - .attr("width", hmWidth) - .attr("height", hmHeight); + .style('fill-opacity', 0) + .attr('stroke', 'black') + .attr("width", hmWidth) + .attr("height", hmHeight); var tip = d3.tip() - .attr('class', 'd3-tip') - .offset(function(){ - var k = d3.mouse(this); - var x = k[0] - (hmWidth/ 2); - return [k[1] - 20, x]; - }) - .html(function (d) { - var k = d3.mouse(this); - var m = Math.floor(scale[0].invert(k[0])); - var n = Math.floor(scale[1].invert(k[1])); - if(m in matrix && n in matrix[m]) { - var obj = matrix[m][n]; - var s = ""; - s += "
" + fd.all_columns_x + ": " + obj.x + "
" - s += "
" + fd.all_columns_y +": " + obj.y + "
" - s += "
" + fd.metric + ": " + obj.v + "
" - s += "
%: " + fp(obj.perc) + "
" - return s; - } - }); + .attr('class', 'd3-tip') + .offset(function() { + var k = d3.mouse(this); + var x = k[0] - (hmWidth / 2); + return [k[1] - 20, x]; + }) + .html(function(d) { + var k = d3.mouse(this); + var m = Math.floor(scale[0].invert(k[0])); + var n = Math.floor(scale[1].invert(k[1])); + if (m in matrix && n in matrix[m]) { + var obj = matrix[m][n]; + var s = ""; + s += "
" + fd.all_columns_x + ": " + obj.x + "
"; + s += "
" + fd.all_columns_y + ": " + obj.y + "
"; + s += "
" + fd.metric + ": " + obj.v + "
"; + s += "
%: " + fp(obj.perc) + "
"; + return s; + } + }); rect.call(tip); @@ -123,32 +130,36 @@ function heatmapVis(slice) { var yscale_skip = 2; var xAxis = d3.svg.axis() - .scale(xRbScale) - .tickValues(xRbScale.domain().filter( - function(d, i) { return !(i % (parseInt(fd.xscale_interval))); })) - .orient("bottom"); + .scale(xRbScale) + .tickValues(xRbScale.domain().filter( + function(d, i) { + return !(i % (parseInt(fd.xscale_interval))); + })) + .orient("bottom"); var yAxis = d3.svg.axis() - .scale(yRbScale) - .tickValues(yRbScale.domain().filter( - function(d, i) { return !(i % (parseInt(fd.yscale_interval))); })) - .orient("left"); + .scale(yRbScale) + .tickValues(yRbScale.domain().filter( + function(d, i) { + return !(i % (parseInt(fd.yscale_interval))); + })) + .orient("left"); svg.append("g") - .attr("class", "x axis") - .attr("transform", "translate(" + margins.l + "," + (margins.t + hmHeight) + ")") - .call(xAxis) - .selectAll("text") - .style("text-anchor", "end") - .attr("transform", "rotate(-45)") - .style("font-weight", "bold"); + .attr("class", "x axis") + .attr("transform", "translate(" + margins.l + "," + (margins.t + hmHeight) + ")") + .call(xAxis) + .selectAll("text") + .style("text-anchor", "end") + .attr("transform", "rotate(-45)") + .style("font-weight", "bold"); svg.append("g") - .attr("class", "y axis") - .attr("transform", "translate(" + margins.l + ", 0)") - .call(yAxis); + .attr("class", "y axis") + .attr("transform", "translate(" + margins.l + ", 0)") + .call(yAxis); - rect.on('mousemove', tip.show); - rect.on('mouseout', tip.hide); + rect.on('mousemove', tip.show); + rect.on('mouseout', tip.hide); var context = canvas.node().getContext("2d"); context.imageSmoothingEnabled = false; @@ -163,28 +174,28 @@ function heatmapVis(slice) { var image = context.createImageData(heatmapDim[0], heatmapDim[1]); var pixs = {}; $.each(data, function(i, d) { - var c = d3.rgb(color(d.perc)); - var x = xScale(d.x); - var y = yScale(d.y); - pixs[x + (y*xScale.domain().length)] = c; - if (matrix[x] === undefined) - matrix[x] = {} - if (matrix[x][y] === undefined) - matrix[x][y] = d; + var c = d3.rgb(color(d.perc)); + var x = xScale(d.x); + var y = yScale(d.y); + pixs[x + (y * xScale.domain().length)] = c; + if (matrix[x] === undefined) + matrix[x] = {}; + if (matrix[x][y] === undefined) + matrix[x][y] = d; }); var p = -1; - for(var i = 0; i < heatmapDim[0] * heatmapDim[1]; i++){ - var c = pixs[i]; - var alpha = 255; - if (c === undefined){ - c = d3.rgb('#F00'); - alpha = 0; - } - image.data[++p] = c.r; - image.data[++p] = c.g; - image.data[++p] = c.b; - image.data[++p] = alpha; + for (var i = 0; i < heatmapDim[0] * heatmapDim[1]; i++) { + var c = pixs[i]; + var alpha = 255; + if (c === undefined) { + c = d3.rgb('#F00'); + alpha = 0; + } + image.data[++p] = c.r; + image.data[++p] = c.g; + image.data[++p] = c.b; + image.data[++p] = alpha; } context.putImageData(image, 0, 0); imageObj.src = canvas.node().toDataURL(); diff --git a/panoramix/assets/visualizations/iframe.js b/panoramix/assets/visualizations/iframe.js index 546c28230f4a5..f2faae8f690a8 100644 --- a/panoramix/assets/visualizations/iframe.js +++ b/panoramix/assets/visualizations/iframe.js @@ -3,7 +3,7 @@ var $ = window.$ || require('jquery'); function iframeWidget(slice) { function refresh() { - $('#code').attr('rows', '15') + $('#code').attr('rows', '15'); $.getJSON(slice.jsonEndpoint(), function(payload) { slice.container.html(''); var iframe = slice.container.find('iframe'); @@ -14,7 +14,7 @@ function iframeWidget(slice) { .fail(function(xhr) { slice.error(xhr.responseText); }); - }; + } return { render: refresh, @@ -22,4 +22,4 @@ function iframeWidget(slice) { }; } -module.exports = iframeWidget +module.exports = iframeWidget; diff --git a/panoramix/assets/visualizations/markup.js b/panoramix/assets/visualizations/markup.js index 4fe808b4e4d3e..3c31ce5a14ef8 100644 --- a/panoramix/assets/visualizations/markup.js +++ b/panoramix/assets/visualizations/markup.js @@ -12,7 +12,7 @@ function markupWidget(slice) { .fail(function(xhr) { slice.error(xhr.responseText); }); - }; + } return { render: refresh, diff --git a/panoramix/assets/visualizations/nvd3_vis.js b/panoramix/assets/visualizations/nvd3_vis.js index 1ee5ef09853bf..14a4191c2db10 100644 --- a/panoramix/assets/visualizations/nvd3_vis.js +++ b/panoramix/assets/visualizations/nvd3_vis.js @@ -1,5 +1,5 @@ // JS -var $ = window.$ || require('jquery'); +var $ = window.$ || require('jquery'); var px = window.px || require('../javascripts/modules/panoramix.js'); require('nvd3'); @@ -7,198 +7,189 @@ require('nvd3'); require('../node_modules/nvd3/build/nv.d3.min.css'); function nvd3Vis(slice) { - var chart = undefined; + var chart; var data = {}; var render = function() { $.getJSON(slice.jsonEndpoint(), function(payload) { - var fd = payload.form_data; - var viz_type = fd.viz_type; + var fd = payload.form_data; + var viz_type = fd.viz_type; + + var f = d3.format('.3s'); + var colorKey = 'key'; + + nv.addGraph(function() { + switch (viz_type) { + + case 'line': + if (fd.show_brush) { + chart = nv.models.lineWithFocusChart(); + chart.lines2.xScale(d3.time.scale.utc()); + chart.x2Axis + .showMaxMin(fd.x_axis_showminmax) + .staggerLabels(true); + } else { + chart = nv.models.lineChart(); + } + // To alter the tooltip header + // chart.interactiveLayer.tooltip.headerFormatter(function(){return '';}); + chart.xScale(d3.time.scale.utc()); + chart.interpolate(fd.line_interpolation); + chart.xAxis + .showMaxMin(fd.x_axis_showminmax) + .staggerLabels(true); + break; + + case 'bar': + chart = nv.models.multiBarChart() + .showControls(true) + .groupSpacing(0.1); + + chart.xAxis + .showMaxMin(false) + .staggerLabels(true); + + chart.stacked(fd.bar_stacked); + break; + + case 'dist_bar': + chart = nv.models.multiBarChart() + .showControls(true) //Allow user to switch between 'Grouped' and 'Stacked' mode. + .reduceXTicks(false) + .rotateLabels(45) + .groupSpacing(0.1); //Distance between each group of bars. + + chart.xAxis + .showMaxMin(false); + + chart.stacked(fd.bar_stacked); + break; + + case 'pie': + chart = nv.models.pieChart(); + colorKey = 'x'; + chart.valueFormat(f); + if (fd.donut) { + chart.donut(true); + chart.labelsOutside(true); + } + chart.labelsOutside(true); + chart.cornerRadius(true); + break; + + case 'column': + chart = nv.models.multiBarChart() + .reduceXTicks(false) + .rotateLabels(45); + break; + + case 'compare': + chart = nv.models.cumulativeLineChart(); + chart.xScale(d3.time.scale.utc()); + chart.xAxis + .showMaxMin(false) + .staggerLabels(true); + break; + + case 'bubble': + var row = function(col1, col2) { + return "" + col1 + "" + col2 + ""; + }; + chart = nv.models.scatterChart(); + chart.showDistX(true); + chart.showDistY(true); + chart.tooltip.contentGenerator(function(obj) { + var p = obj.point; + var s = ""; + s += ''; + s += row(fd.x, f(p.x)); + s += row(fd.y, f(p.y)); + s += row(fd.size, f(p.size)); + s += "
' + p[fd.entity] + ' (' + p.group + ')
"; + return s; + }); + chart.pointRange([5, fd.max_bubble_size * fd.max_bubble_size]); + break; + + case 'area': + chart = nv.models.stackedAreaChart(); + chart.style(fd.stacked_style); + chart.xScale(d3.time.scale.utc()); + chart.xAxis + .showMaxMin(false) + .staggerLabels(true); + break; + + default: + console.error("unrecognized visualization for nvd3", viz_type); + } - var f = d3.format('.3s'); - var colorKey = 'key'; + if ("showLegend" in chart && typeof fd.show_legend !== 'undefined') { + chart.showLegend(fd.show_legend); + } - nv.addGraph(function() { - switch (viz_type) { + var height = slice.height(); - case 'line': - if (fd.show_brush) { - chart = nv.models.lineWithFocusChart(); - chart.lines2.xScale(d3.time.scale.utc()); - chart.x2Axis - .showMaxMin(fd.x_axis_showminmax) - .staggerLabels(false); - } else { - chart = nv.models.lineChart() - } - // To alter the tooltip header - // chart.interactiveLayer.tooltip.headerFormatter(function(){return '';}); - chart.xScale(d3.time.scale.utc()); - chart.interpolate(fd.line_interpolation); - chart.xAxis - .showMaxMin(fd.x_axis_showminmax) - .staggerLabels(true); - break; - - case 'bar': - chart = nv.models.multiBarChart() - .showControls(true) - .groupSpacing(0.1); - - chart.xAxis - .showMaxMin(false) - .staggerLabels(true); - - chart.stacked(fd.bar_stacked); - break; - - case 'dist_bar': - chart = nv.models.multiBarChart() - .showControls(true) //Allow user to switch between 'Grouped' and 'Stacked' mode. - .reduceXTicks(false) - .rotateLabels(45) - .groupSpacing(0.1); //Distance between each group of bars. - - chart.xAxis - .showMaxMin(false); - - chart.stacked(fd.bar_stacked); - break; - - case 'pie': - chart = nv.models.pieChart() - colorKey = 'x'; - chart.valueFormat(f); - if (fd.donut) { - chart.donut(true); - chart.labelsOutside(true); - } - chart.labelsOutside(true); - chart.cornerRadius(true); - break; - - case 'column': - chart = nv.models.multiBarChart() - .reduceXTicks(false) - .rotateLabels(45); - break; - - case 'compare': - chart = nv.models.cumulativeLineChart(); - chart.xScale(d3.time.scale.utc()); - chart.xAxis - .showMaxMin(false) - .staggerLabels(true); - break; - - case 'bubble': - var row = function(col1, col2) { - return "" + col1 + "" + col2 + ""; - }; - chart = nv.models.scatterChart(); - chart.showDistX(true); - chart.showDistY(true); - chart.tooltip.contentGenerator(function (obj) { - var p = obj.point; - var s = ""; - s += ''; - s += row(fd.x, f(p.x)); - s += row(fd.y, f(p.y)); - s += row(fd.size, f(p.size)); - s += "
' + p[fd.entity] + ' (' + p.group + ')
"; - return s; - }); - chart.pointRange([5, fd.max_bubble_size * fd.max_bubble_size]); - break; - - case 'area': - chart = nv.models.stackedAreaChart(); - chart.style(fd.stacked_style); - chart.xScale(d3.time.scale.utc()); - chart.xAxis - .showMaxMin(false) - .staggerLabels(true); - break; - - default: - console.error("unrecognized visualization for nvd3", viz_type); - } - - if ("showLegend" in chart && typeof fd.show_legend !== 'undefined') { - chart.showLegend(fd.show_legend); - } - - var height = slice.height(); - - if(chart.hasOwnProperty("x2Axis")) { - height += 30; - } - chart.height(height); - slice.container.css('height', height + 'px'); - - if ((viz_type === "line" || viz_type === "area") && fd.rich_tooltip) { - chart.useInteractiveGuideline(true); - } - if (fd.y_axis_zero) { - chart.forceY([0, 1]); - } - else if (fd.y_log_scale) { - chart.yScale(d3.scale.log()); - } - if (fd.x_log_scale) { - chart.xScale(d3.scale.log()); - } - if (viz_type === 'bubble') { - chart.xAxis.tickFormat(d3.format('.3s')); - } - else if (fd.x_axis_format == 'smart_date') { - chart.xAxis.tickFormat(px.formatDate); - if(chart.hasOwnProperty("x2Axis")) { - chart.x2Axis.tickFormat(px.formatDate); + if (chart.hasOwnProperty("x2Axis")) { + height += 30; } - } - else if (fd.x_axis_format !== undefined) { - var tf = px.timeFormatFactory(fd.x_axis_format); - chart.xAxis.tickFormat(tf); - if(chart.hasOwnProperty("x2Axis")) { - chart.x2Axis.tickFormat(tf); + chart.height(height); + slice.container.css('height', height + 'px'); + + if ((viz_type === "line" || viz_type === "area") && fd.rich_tooltip) { + chart.useInteractiveGuideline(true); } - } - if (chart.yAxis !== undefined) { - chart.yAxis.tickFormat(d3.format('.3s')); - } - - if (fd.contribution || fd.num_period_compare || viz_type == 'compare') { - chart.yAxis.tickFormat(d3.format('.3p')); - if (chart.y2Axis != undefined) { - chart.y2Axis.tickFormat(d3.format('.3p')); + if (fd.y_axis_zero) { + chart.forceY([0, 1]); + } else if (fd.y_log_scale) { + chart.yScale(d3.scale.log()); + } + if (fd.x_log_scale) { + chart.xScale(d3.scale.log()); } - } else if (fd.y_axis_format) { - chart.yAxis.tickFormat(d3.format(fd.y_axis_format)); + if (viz_type === 'bubble') { + chart.xAxis.tickFormat(d3.format('.3s')); + } else if (fd.x_axis_format == 'smart_date') { + chart.xAxis.tickFormat(px.formatDate); + } else if (fd.x_axis_format !== undefined) { + chart.xAxis.tickFormat(px.timeFormatFactory(fd.x_axis_format)); + } + if (chart.yAxis !== undefined) { + chart.yAxis.tickFormat(d3.format('.3s')); + } + + if (fd.contribution || fd.num_period_compare || viz_type == 'compare') { + chart.yAxis.tickFormat(d3.format('.3p')); + if (chart.y2Axis !== undefined) { + chart.y2Axis.tickFormat(d3.format('.3p')); + } + } else if (fd.y_axis_format) { + chart.yAxis.tickFormat(d3.format(fd.y_axis_format)); - if (chart.y2Axis != undefined) { - chart.y2Axis.tickFormat(d3.format(fd.y_axis_format)); + if (chart.y2Axis !== undefined) { + chart.y2Axis.tickFormat(d3.format(fd.y_axis_format)); + } } - } - chart.color(function(d, i){ - return px.color.category21(d[colorKey]); - }); + chart.color(function(d, i) { + return px.color.category21(d[colorKey]); + }); - d3.select(slice.selector).append("svg") - .datum(payload.data) - .transition().duration(500) - .attr('height', height) - .call(chart); + d3.select(slice.selector).html(''); + d3.select(slice.selector).append("svg") + .datum(payload.data) + .transition().duration(500) + .attr('height', height) + .call(chart); - return chart; - }); + return chart; + }); - slice.done(payload); - }) - .fail(function(xhr) { - slice.error(xhr.responseText); - }); + slice.done(payload); + }) + .fail(function(xhr) { + slice.error(xhr.responseText); + }); }; var update = function() { @@ -211,6 +202,6 @@ function nvd3Vis(slice) { render: render, resize: update, }; -}; +} module.exports = nvd3Vis; diff --git a/panoramix/assets/visualizations/parallel_coordinates.js b/panoramix/assets/visualizations/parallel_coordinates.js index fa80224bd1c8e..575db6d3c168f 100644 --- a/panoramix/assets/visualizations/parallel_coordinates.js +++ b/panoramix/assets/visualizations/parallel_coordinates.js @@ -1,7 +1,7 @@ // JS var d3 = window.d3 || require('d3'); d3.parcoords = require('../vendor/parallel_coordinates/d3.parcoords.js'); -d3.divgrid = require('../vendor/parallel_coordinates/divgrid.js'); +d3.divgrid = require('../vendor/parallel_coordinates/divgrid.js'); // CSS require('../vendor/parallel_coordinates/d3.parcoords.css'); @@ -9,20 +9,22 @@ require('../vendor/parallel_coordinates/d3.parcoords.css'); function parallelCoordVis(slice) { function refresh() { - $('#code').attr('rows', '15') - $.getJSON(slice.jsonEndpoint(), function(payload) { + $('#code').attr('rows', '15'); + $.getJSON(slice.jsonEndpoint(), function(payload) { var data = payload.data; var fd = payload.form_data; - var ext = d3.extent(data, function(d){ + var ext = d3.extent(data, function(d) { return d[fd.secondary_metric]; }); - ext = [ext[0], (ext[1]-ext[0])/2,ext[1]]; + ext = [ext[0], (ext[1] - ext[0]) / 2, ext[1]]; var cScale = d3.scale.linear() .domain(ext) .range(['red', 'grey', 'blue']) .interpolate(d3.interpolateLab); - var color = function(d){return cScale(d[fd.secondary_metric])}; + var color = function(d) { + return cScale(d[fd.secondary_metric]); + }; var container = d3.select(slice.selector); var eff_height = fd.show_datatable ? (slice.height() / 2) : slice.height(); @@ -48,23 +50,27 @@ function parallelCoordVis(slice) { // create data table, row hover highlighting var grid = d3.divgrid(); container.append("div") - .datum(data.slice(0,10)) + .datum(data.slice(0, 10)) .attr('id', "grid") .call(grid) .classed("parcoords", true) .selectAll(".row") .on({ - "mouseover": function(d) { parcoords.highlight([d]) }, + "mouseover": function(d) { + parcoords.highlight([d]); + }, "mouseout": parcoords.unhighlight }); // update data table on brush event parcoords.on("brush", function(d) { d3.select("#grid") - .datum(d.slice(0,10)) + .datum(d.slice(0, 10)) .call(grid) .selectAll(".row") .on({ - "mouseover": function(d) { parcoords.highlight([d]) }, + "mouseover": function(d) { + parcoords.highlight([d]); + }, "mouseout": parcoords.unhighlight }); }); @@ -72,14 +78,14 @@ function parallelCoordVis(slice) { slice.done(); }) .fail(function(xhr) { - slice.error(xhr.responseText); - }); - }; + slice.error(xhr.responseText); + }); + } return { render: refresh, resize: refresh, }; -}; +} module.exports = parallelCoordVis; diff --git a/panoramix/assets/visualizations/pivot_table.js b/panoramix/assets/visualizations/pivot_table.js index 398815faa3b21..dc74253d60eb5 100644 --- a/panoramix/assets/visualizations/pivot_table.js +++ b/panoramix/assets/visualizations/pivot_table.js @@ -1,28 +1,27 @@ - var $ = window.$ = require('jquery'); var jQuery = window.jQuery = $; require('datatables'); require('./pivot_table.css'); -require('../node_modules/datatables-bootstrap3-plugin/media/css/datatables-bootstrap3.css') +require('../node_modules/datatables-bootstrap3-plugin/media/css/datatables-bootstrap3.css'); module.exports = function(slice) { var container = slice.container; var form_data = slice.data.form_data; function refresh() { - $.getJSON(slice.jsonEndpoint(), function(json){ + $.getJSON(slice.jsonEndpoint(), function(json) { container.html(json.data); - if (form_data.groupby.length == 1){ + if (form_data.groupby.length == 1) { var table = container.find('table').DataTable({ paging: false, searching: false, }); - table.column('-1').order( 'desc' ).draw(); + table.column('-1').order('desc').draw(); } slice.done(json); - }).fail(function(xhr){ - slice.error(xhr.responseText); + }).fail(function(xhr) { + slice.error(xhr.responseText); }); } return { diff --git a/panoramix/assets/visualizations/sankey.js b/panoramix/assets/visualizations/sankey.js index dc6cd76b972e1..aeaccd57992e1 100644 --- a/panoramix/assets/visualizations/sankey.js +++ b/panoramix/assets/visualizations/sankey.js @@ -9,96 +9,133 @@ function sankeyVis(slice) { var div = d3.select(slice.selector); var render = function() { - var margin = {top: 5, right: 5, bottom: 5, left: 5}; - var width = slice.width() - margin.left - margin.right; - var height = slice.height() - margin.top - margin.bottom; + var margin = { + top: 5, + right: 5, + bottom: 5, + left: 5 + }; + var width = slice.width() - margin.left - margin.right; + var height = slice.height() - margin.top - margin.bottom; - var formatNumber = d3.format(",.0f"), - format = function(d) { return formatNumber(d) + " TWh"; }; + var formatNumber = d3.format(",.0f"), + format = function(d) { + return formatNumber(d) + " TWh"; + }; - var svg = div.append("svg") - .attr("width", width + margin.left + margin.right) - .attr("height", height + margin.top + margin.bottom) - .append("g") - .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); + var svg = div.append("svg") + .attr("width", width + margin.left + margin.right) + .attr("height", height + margin.top + margin.bottom) + .append("g") + .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); - var sankey = d3.sankey() - .nodeWidth(15) - .nodePadding(10) - .size([width, height]); + var sankey = d3.sankey() + .nodeWidth(15) + .nodePadding(10) + .size([width, height]); - var path = sankey.link(); + var path = sankey.link(); - d3.json(slice.jsonEndpoint(), function(error, json) { - if (error != null){ - slice.error(error.responseText); - return ''; - } - var links = json.data; - var nodes = {}; - // Compute the distinct nodes from the links. - links.forEach(function(link) { - link.source = nodes[link.source] || - (nodes[link.source] = {name: link.source}); - link.target = nodes[link.target] || - (nodes[link.target] = {name: link.target}); - link.value = +link.value; - }); - nodes = d3.values(nodes); + d3.json(slice.jsonEndpoint(), function(error, json) { + if (error !== null) { + slice.error(error.responseText); + return ''; + } + var links = json.data; + var nodes = {}; + // Compute the distinct nodes from the links. + links.forEach(function(link) { + link.source = nodes[link.source] || + (nodes[link.source] = { + name: link.source + }); + link.target = nodes[link.target] || + (nodes[link.target] = { + name: link.target + }); + link.value = +link.value; + }); + nodes = d3.values(nodes); - sankey - .nodes(nodes) - .links(links) - .layout(32); + sankey + .nodes(nodes) + .links(links) + .layout(32); - var link = svg.append("g").selectAll(".link") - .data(links) - .enter().append("path") - .attr("class", "link") - .attr("d", path) - .style("stroke-width", function(d) { return Math.max(1, d.dy); }) - .sort(function(a, b) { return b.dy - a.dy; }); + var link = svg.append("g").selectAll(".link") + .data(links) + .enter().append("path") + .attr("class", "link") + .attr("d", path) + .style("stroke-width", function(d) { + return Math.max(1, d.dy); + }) + .sort(function(a, b) { + return b.dy - a.dy; + }); - link.append("title") - .text(function(d) { return d.source.name + " → " + d.target.name + "\n" + format(d.value); }); + link.append("title") + .text(function(d) { + return d.source.name + " → " + d.target.name + "\n" + format(d.value); + }); - var node = svg.append("g").selectAll(".node") - .data(nodes) - .enter().append("g") - .attr("class", "node") - .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }) - .call(d3.behavior.drag() - .origin(function(d) { return d; }) - .on("dragstart", function() { this.parentNode.appendChild(this); }) - .on("drag", dragmove)); + var node = svg.append("g").selectAll(".node") + .data(nodes) + .enter().append("g") + .attr("class", "node") + .attr("transform", function(d) { + return "translate(" + d.x + "," + d.y + ")"; + }) + .call(d3.behavior.drag() + .origin(function(d) { + return d; + }) + .on("dragstart", function() { + this.parentNode.appendChild(this); + }) + .on("drag", dragmove)); - node.append("rect") - .attr("height", function(d) { return d.dy; }) - .attr("width", sankey.nodeWidth()) - .style("fill", function(d) { return d.color = px.color.category21(d.name.replace(/ .*/, "")); }) - .style("stroke", function(d) { return d3.rgb(d.color).darker(2); }) - .append("title") - .text(function(d) { return d.name + "\n" + format(d.value); }); + node.append("rect") + .attr("height", function(d) { + return d.dy; + }) + .attr("width", sankey.nodeWidth()) + .style("fill", function(d) { + return d.color = px.color.category21(d.name.replace(/ .*/, "")); + }) + .style("stroke", function(d) { + return d3.rgb(d.color).darker(2); + }) + .append("title") + .text(function(d) { + return d.name + "\n" + format(d.value); + }); - node.append("text") - .attr("x", -6) - .attr("y", function(d) { return d.dy / 2; }) - .attr("dy", ".35em") - .attr("text-anchor", "end") - .attr("transform", null) - .text(function(d) { return d.name; }) - .filter(function(d) { return d.x < width / 2; }) - .attr("x", 6 + sankey.nodeWidth()) - .attr("text-anchor", "start"); + node.append("text") + .attr("x", -6) + .attr("y", function(d) { + return d.dy / 2; + }) + .attr("dy", ".35em") + .attr("text-anchor", "end") + .attr("transform", null) + .text(function(d) { + return d.name; + }) + .filter(function(d) { + return d.x < width / 2; + }) + .attr("x", 6 + sankey.nodeWidth()) + .attr("text-anchor", "start"); - function dragmove(d) { - d3.select(this).attr("transform", "translate(" + d.x + "," + (d.y = Math.max(0, Math.min(height - d.dy, d3.event.y))) + ")"); - sankey.relayout(); - link.attr("d", path); - } - slice.done(json); - }); - } + function dragmove(d) { + d3.select(this).attr("transform", "translate(" + d.x + "," + (d.y = Math.max(0, Math.min(height - d.dy, d3.event.y))) + ")"); + sankey.relayout(); + link.attr("d", path); + } + slice.done(json); + }); + }; return { render: render, resize: render, diff --git a/panoramix/assets/visualizations/sunburst.js b/panoramix/assets/visualizations/sunburst.js index e9435478e050a..07940662e3f8d 100644 --- a/panoramix/assets/visualizations/sunburst.js +++ b/panoramix/assets/visualizations/sunburst.js @@ -1,8 +1,7 @@ require('./sunburst.css'); -/* - Modified from http://bl.ocks.org/kerryrodden/7090426 - */ +// Modified from http://bl.ocks.org/kerryrodden/7090426 + function sunburstVis(slice) { var container = d3.select(slice.selector); var render = function() { @@ -27,18 +26,28 @@ function sunburstVis(slice) { var partition = d3.layout.partition() .size([2 * Math.PI, radius * radius]) - .value(function(d) { return d.m1; }); + .value(function(d) { + return d.m1; + }); var arc = d3.svg.arc() - .startAngle(function(d) { return d.x; }) - .endAngle(function(d) { return d.x + d.dx; }) - .innerRadius(function(d) { return Math.sqrt(d.y); }) - .outerRadius(function(d) { return Math.sqrt(d.y + d.dy); }); + .startAngle(function(d) { + return d.x; + }) + .endAngle(function(d) { + return d.x + d.dx; + }) + .innerRadius(function(d) { + return Math.sqrt(d.y); + }) + .outerRadius(function(d) { + return Math.sqrt(d.y + d.dy); + }); var ext; - d3.json(slice.jsonEndpoint(), function(error, json){ + d3.json(slice.jsonEndpoint(), function(error, json) { - if (error != null){ + if (error !== null) { slice.error(error.responseText); return ''; } @@ -62,23 +71,29 @@ function sunburstVis(slice) { .filter(function(d) { return (d.dx > 0.005); // 0.005 radians = 0.29 degrees }); - ext = d3.extent(nodes, function(d){return d.m2 / d.m1;}); + ext = d3.extent(nodes, function(d) { + return d.m2 / d.m1; + }); var colorScale = d3.scale.linear() - .domain([ext[0], ext[0] + ((ext[1] - ext[0]) / 2), ext[1]]) - .range(["#00D1C1", "white","#FFB400"]); + .domain([ext[0], ext[0] + ((ext[1] - ext[0]) / 2), ext[1]]) + .range(["#00D1C1", "white", "#FFB400"]); var path = arcs.data([json]).selectAll("path") - .data(nodes) + .data(nodes) .enter().append("svg:path") - .attr("display", function(d) { return d.depth ? null : "none"; }) - .attr("d", arc) - .attr("fill-rule", "evenodd") - .style("stroke", "grey") - .style("stroke-width", "1px") - .style("fill", function(d) { return colorScale(d.m2/d.m1); }) - .style("opacity", 1) - .on("mouseenter", mouseenter); + .attr("display", function(d) { + return d.depth ? null : "none"; + }) + .attr("d", arc) + .attr("fill-rule", "evenodd") + .style("stroke", "grey") + .style("stroke-width", "1px") + .style("fill", function(d) { + return colorScale(d.m2 / d.m1); + }) + .style("opacity", 1) + .on("mouseenter", mouseenter); // Add the mouseleave handler to the bounding circle. @@ -86,7 +101,7 @@ function sunburstVis(slice) { // Get total size of the tree = value of root node from partition. totalSize = path.node().__data__.value; - }; + } var f = d3.format(".3s"); var fp = d3.format(".3p"); @@ -110,9 +125,10 @@ function sunburstVis(slice) { .classed("middle", true) .style("font-size", "15px") .attr("y", "50") - .text("m2/m1: " + fp(d.m2/d.m1)); + .text("m2/m1: " + fp(d.m2 / d.m1)); var sequenceArray = getAncestors(d); + function breadcrumbPoints(d, i) { var points = []; points.push("0,0"); @@ -129,10 +145,10 @@ function sunburstVis(slice) { // Update the breadcrumb trail to show the current sequence and percentage. function updateBreadcrumbs(nodeArray, percentageString) { var l = []; - for(var i=0; i ') + var s = l.join(' > '); gMiddleText.append("text") .text(s) .classed("middle", true) @@ -142,8 +158,8 @@ function sunburstVis(slice) { // Fade all the segments. arcs.selectAll("path") - .style("stroke-width", "1px") - .style("opacity", 0.3); + .style("stroke-width", "1px") + .style("opacity", 0.3); // Then highlight only those that are an ancestor of the current segment. arcs.selectAll("path") @@ -193,25 +209,28 @@ function sunburstVis(slice) { } function buildHierarchy(rows) { - var root = {"name": "root", "children": []}; + var root = { + "name": "root", + "children": [] + }; for (var i = 0; i < rows.length; i++) { var row = rows[i]; - var m1 = +row[row.length-2]; - var m2 = +row[row.length-1]; - var parts = row.slice(0, row.length-2); + var m1 = +row[row.length - 2]; + var m2 = +row[row.length - 1]; + var parts = row.slice(0, row.length - 2); if (isNaN(m1)) { // e.g. if this is a header row continue; } var currentNode = root; for (var j = 0; j < parts.length; j++) { - var children = currentNode["children"]; + var children = currentNode.children; var nodeName = parts[j]; var childNode; if (j + 1 < parts.length) { // Not yet at the end of the sequence; move down the tree. var foundChild = false; for (var k = 0; k < children.length; k++) { - if (children[k]["name"] == nodeName) { + if (children[k].name == nodeName) { childNode = children[k]; foundChild = true; break; @@ -219,40 +238,48 @@ function sunburstVis(slice) { } // If we don't already have a child node for this branch, create it. if (!foundChild) { - childNode = {"name": nodeName, "children": []}; + childNode = { + "name": nodeName, + "children": [] + }; children.push(childNode); } currentNode = childNode; } else { // Reached the end of the sequence; create a leaf node. - childNode = {"name": nodeName, "m1": m1, 'm2': m2}; + childNode = { + "name": nodeName, + "m1": m1, + 'm2': m2 + }; children.push(childNode); } } } - function recurse(node){ - if (node.children){ + + function recurse(node) { + if (node.children) { var sums; var m1 = 0; var m2 = 0; - for (var i=0; i=0}; + return { + col: c, + val: row[c], + isMetric: metrics.indexOf(c) >= 0 + }; }); - }).enter() - .append('td') - .style('background-image', function(d){ - if (d.isMetric){ + }).enter() + .append('td') + .style('background-image', function(d) { + if (d.isMetric) { var perc = Math.round((d.val / maxes[d.col]) * 100); return "linear-gradient(to right, lightgrey, lightgrey " + perc + "%, rgba(0,0,0,0) " + perc + "%"; } - }) - .attr('title', function(d){ - if (!isNaN(d.val)) - return fC(d.val); - }) - .attr('data-sort', function(d){ + }) + .attr('title', function(d) { + if (!isNaN(d.val)) + return fC(d.val); + }) + .attr('data-sort', function(d) { if (d.isMetric) return d.val; - }) - .on("click", function(d){ - if(!d.isMetric){ + }) + .on("click", function(d) { + if (!d.isMetric) { var td = d3.select(this); - if (td.classed('filtered')){ - slice.clearFilter(d.col, [d.val]); - table.selectAll('.filtered').classed('filtered', false); + if (td.classed('filtered')) { + slice.removeFilter(d.col, [d.val]); + d3.select(this).classed('filtered', false); } else { - table.selectAll('.filtered').classed('filtered', false); d3.select(this).classed('filtered', true); - slice.addFilter([[d.col, [d.val]]]); + slice.addFilter(d.col, [d.val]); } } - }) - .style("cursor", function(d){ - if(!d.isMetric){ - return 'pointer'; - } - }) - .html(function(d){ + }) + .style("cursor", function(d) { + if (!d.isMetric) { + return 'pointer'; + } + }) + .html(function(d) { if (d.isMetric) return f(d.val); else return d.val; - }); + }); var datatable = slice.container.find('.dataTable').DataTable({ paging: false, searching: form_data.include_search, @@ -93,19 +99,19 @@ function tableVis(slice) { // Sorting table by main column if (form_data.metrics.length > 0) { var main_metric = form_data.metrics[0]; - datatable.column(data.columns.indexOf(main_metric)).order( 'desc' ).draw(); + datatable.column(data.columns.indexOf(main_metric)).order('desc').draw(); } slice.done(json); slice.container.parents('.widget').find('.tooltip').remove(); - }).fail(function(xhr){ + }).fail(function(xhr) { slice.error(xhr.responseText); }); } return { render: refresh, - resize: function(){}, + resize: function() {}, }; -}; +} module.exports = tableVis; diff --git a/panoramix/assets/visualizations/word_cloud.js b/panoramix/assets/visualizations/word_cloud.js index 257f7947a0da6..7a000693bdad4 100644 --- a/panoramix/assets/visualizations/word_cloud.js +++ b/panoramix/assets/visualizations/word_cloud.js @@ -3,11 +3,11 @@ var d3 = window.d3 || require('d3'); var cloudLayout = require('d3-cloud'); function wordCloudChart(slice) { - var slice = slice; var chart = d3.select(slice.selector); + function refresh() { d3.json(slice.jsonEndpoint(), function(error, json) { - if (error != null){ + if (error !== null) { slice.error(error.responseText); return ''; } @@ -17,20 +17,27 @@ function wordCloudChart(slice) { json.form_data.size_to, ]; var rotation = json.form_data.rotation; + var f_rotation; if (rotation == "square") { - var f_rotation = function() { return ~~(Math.random() * 2) * 90; }; - } - else if (rotation == "flat") { - var f_rotation = function() { return 0 }; - } - else { - var f_rotation = function() { return (~~(Math.random() * 6) - 3) * 30; }; + f_rotation = function() { + return ~~(Math.random() * 2) * 90; + }; + } else if (rotation == "flat") { + f_rotation = function() { + return 0; + }; + } else { + f_rotation = function() { + return (~~(Math.random() * 6) - 3) * 30; + }; } var size = [slice.width(), slice.height()]; var scale = d3.scale.linear() .range(range) - .domain(d3.extent(data, function(d) { return d.size; })); + .domain(d3.extent(data, function(d) { + return d.size; + })); var layout = cloudLayout() .size(size) @@ -38,7 +45,9 @@ function wordCloudChart(slice) { .padding(5) .rotate(f_rotation) .font("serif") - .fontSize(function(d) { return scale(d.size); }) + .fontSize(function(d) { + return scale(d.size); + }) .on("end", draw); layout.start(); @@ -47,21 +56,27 @@ function wordCloudChart(slice) { chart.selectAll("*").remove(); chart.append("svg") - .attr("width", layout.size()[0]) - .attr("height", layout.size()[1]) + .attr("width", layout.size()[0]) + .attr("height", layout.size()[1]) .append("g") - .attr("transform", "translate(" + layout.size()[0] / 2 + "," + layout.size()[1] / 2 + ")") + .attr("transform", "translate(" + layout.size()[0] / 2 + "," + layout.size()[1] / 2 + ")") .selectAll("text") - .data(words) - .enter().append("text") - .style("font-size", function(d) { return d.size + "px"; }) - .style("font-family", "Impact") - .style("fill", function(d, i) {return px.color.category21(d.text); }) - .attr("text-anchor", "middle") - .attr("transform", function(d) { - return "translate(" + [d.x, d.y] + ") rotate(" + d.rotate + ")"; - }) - .text(function(d) { return d.text; }); + .data(words) + .enter().append("text") + .style("font-size", function(d) { + return d.size + "px"; + }) + .style("font-family", "Impact") + .style("fill", function(d, i) { + return px.color.category21(d.text); + }) + .attr("text-anchor", "middle") + .attr("transform", function(d) { + return "translate(" + [d.x, d.y] + ") rotate(" + d.rotate + ")"; + }) + .text(function(d) { + return d.text; + }); } slice.done(data); }); diff --git a/panoramix/assets/visualizations/world_map.js b/panoramix/assets/visualizations/world_map.js index 155039337815d..986653f0f24ce 100644 --- a/panoramix/assets/visualizations/world_map.js +++ b/panoramix/assets/visualizations/world_map.js @@ -13,31 +13,35 @@ function worldMapChart(slice) { container.css('height', slice.height()); - d3.json(slice.jsonEndpoint(), function(error, json){ + d3.json(slice.jsonEndpoint(), function(error, json) { var fd = json.form_data; - if (error != null){ + if (error !== null) { slice.error(error.responseText); return ''; } - var ext = d3.extent(json.data, function(d){return d.m1}); - var extRadius = d3.extent(json.data, function(d){return d.m2}); + var ext = d3.extent(json.data, function(d) { + return d.m1; + }); + var extRadius = d3.extent(json.data, function(d) { + return d.m2; + }); var radiusScale = d3.scale.linear() .domain([extRadius[0], extRadius[1]]) .range([1, fd.max_bubble_size]); - json.data.forEach(function(d){ - d.radius = radiusScale(d.m2); - }); + json.data.forEach(function(d) { + d.radius = radiusScale(d.m2); + }); var colorScale = d3.scale.linear() .domain([ext[0], ext[1]]) .range(["#FFF", "black"]); var d = {}; - for (var i=0; i' + data.name + '
'+ f(data.m1) + '
'; + return '
' + data.name + '
' + f(data.m1) + '
'; }, }, bubblesConfig: { @@ -70,7 +74,7 @@ function worldMapChart(slice) { popupOnHover: true, radius: null, popupTemplate: function(geo, data) { - return '
' + data.name + '
'+ f(data.m2) + '
'; + return '
' + data.name + '
' + f(data.m2) + '
'; }, fillOpacity: 0.5, animate: true, @@ -95,7 +99,7 @@ function worldMapChart(slice) { slice.done(json); }); - } + }; return { render: render, diff --git a/panoramix/templates/panoramix/featured.html b/panoramix/templates/panoramix/featured.html index 86e71a60ec735..29a646b704a1f 100644 --- a/panoramix/templates/panoramix/featured.html +++ b/panoramix/templates/panoramix/featured.html @@ -24,7 +24,7 @@

{{ dataset.table_name }}

{{ dataset.database }} - {{ dataset.owner }} + {{ dataset.owner or '' }} {% endfor %} diff --git a/panoramix/viz.py b/panoramix/viz.py index e719704e8ac46..7196270105ad3 100644 --- a/panoramix/viz.py +++ b/panoramix/viz.py @@ -156,15 +156,13 @@ def query_filters(self): filters.append((col, op, eq)) # Extra filters (coming from dashboard) - extra_filters = form_data.get('extra_filters', []) + extra_filters = form_data.get('extra_filters') if extra_filters: extra_filters = json.loads(extra_filters) for slice_filters in extra_filters.values(): - if slice_filters: - for col, vals in slice_filters: - if col and vals: - filters += [(col, 'in', ",".join(vals))] - + for col, vals in slice_filters.items(): + if col and vals: + filters += [(col, 'in', ",".join(vals))] return filters def query_obj(self):