mirror of
https://github.com/apache/superset.git
synced 2026-04-19 08:04:53 +00:00
Refactor around how visualizations/*.js are required (#913)
* Refactor around how visualizations/*.js are required * Reactifying FilterBox further * Fixing the auto-refresh on filtering events * Fixing preselected filters
This commit is contained in:
committed by
GitHub
parent
198226a39f
commit
e243a14c64
@@ -154,7 +154,7 @@ function dashboardContainer(dashboardData) {
|
||||
refreshExcept(sliceId) {
|
||||
const immune = this.metadata.filter_immune_slices || [];
|
||||
this.slices.forEach(function (slice) {
|
||||
if (slice.data.sliceId !== sliceId && immune.indexOf(slice.data.sliceId) === -1) {
|
||||
if (slice.data.slice_id !== sliceId && immune.indexOf(slice.data.sliceId) === -1) {
|
||||
slice.render();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -475,9 +475,6 @@ $(document).ready(function () {
|
||||
|
||||
initExploreView();
|
||||
|
||||
// Dynamically register this visualization
|
||||
px.registerViz(data.viz_name || 'table');
|
||||
|
||||
slice = px.Slice(data);
|
||||
|
||||
$('.slice').data('slice', slice);
|
||||
|
||||
@@ -1,210 +1,19 @@
|
||||
import $ from 'jquery';
|
||||
const d3 = require('d3');
|
||||
const Mustache = require('mustache');
|
||||
const utils = require('./utils');
|
||||
// vis sources
|
||||
/* eslint camel-case: 0 */
|
||||
const sourceMap = {
|
||||
area: 'nvd3_vis.js',
|
||||
bar: 'nvd3_vis.js',
|
||||
bubble: 'nvd3_vis.js',
|
||||
big_number: 'big_number.js',
|
||||
big_number_total: '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',
|
||||
separator: 'markup.js',
|
||||
para: 'parallel_coordinates.js',
|
||||
pie: 'nvd3_vis.js',
|
||||
box_plot: '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',
|
||||
treemap: 'treemap.js',
|
||||
cal_heatmap: 'cal_heatmap.js',
|
||||
horizon: 'horizon.js',
|
||||
mapbox: 'mapbox.jsx',
|
||||
histogram: 'histogram.js',
|
||||
};
|
||||
const color = function () {
|
||||
// Color related utility functions go in this object
|
||||
const bnbColors = [
|
||||
'#ff5a5f', // rausch
|
||||
'#7b0051', // hackb
|
||||
'#007A87', // kazan
|
||||
'#00d1c1', // babu
|
||||
'#8ce071', // lima
|
||||
'#ffb400', // beach
|
||||
'#b4a76c', // barol
|
||||
'#ff8083',
|
||||
'#cc0086',
|
||||
'#00a1b3',
|
||||
'#00ffeb',
|
||||
'#bbedab',
|
||||
'#ffd266',
|
||||
'#cbc29a',
|
||||
'#ff3339',
|
||||
'#ff1ab1',
|
||||
'#005c66',
|
||||
'#00b3a5',
|
||||
'#55d12e',
|
||||
'#b37e00',
|
||||
'#988b4e',
|
||||
];
|
||||
const spectrums = {
|
||||
blue_white_yellow: [
|
||||
'#00d1c1',
|
||||
'white',
|
||||
'#ffb400',
|
||||
],
|
||||
fire: [
|
||||
'white',
|
||||
'yellow',
|
||||
'red',
|
||||
'black',
|
||||
],
|
||||
white_black: [
|
||||
'white',
|
||||
'black',
|
||||
],
|
||||
black_white: [
|
||||
'black',
|
||||
'white',
|
||||
],
|
||||
};
|
||||
const colorBnb = function () {
|
||||
// Color factory
|
||||
const seen = {};
|
||||
return function (s) {
|
||||
if (!s) {
|
||||
return;
|
||||
}
|
||||
let stringifyS = String(s);
|
||||
// next line is for caravel series that should have the same color
|
||||
stringifyS = stringifyS.replace('---', '');
|
||||
if (seen[stringifyS] === undefined) {
|
||||
seen[stringifyS] = Object.keys(seen).length;
|
||||
}
|
||||
/* eslint consistent-return: 0 */
|
||||
return this.bnbColors[seen[stringifyS] % this.bnbColors.length];
|
||||
};
|
||||
};
|
||||
const colorScalerFactory = function (colors, data, accessor) {
|
||||
// Returns a linear scaler our of an array of color
|
||||
if (!Array.isArray(colors)) {
|
||||
/* eslint no-param-reassign: 0 */
|
||||
colors = spectrums[colors];
|
||||
}
|
||||
let ext = [
|
||||
0,
|
||||
1,
|
||||
];
|
||||
if (data !== undefined) {
|
||||
ext = d3.extent(data, accessor);
|
||||
}
|
||||
const points = [];
|
||||
const chunkSize = (ext[1] - ext[0]) / colors.length;
|
||||
$.each(colors, function (i) {
|
||||
points.push(i * chunkSize);
|
||||
});
|
||||
return d3.scale.linear().domain(points).range(colors);
|
||||
};
|
||||
return {
|
||||
bnbColors,
|
||||
category21: colorBnb(),
|
||||
colorScalerFactory,
|
||||
};
|
||||
};
|
||||
import vizMap from '../../visualizations/main.js';
|
||||
|
||||
/* eslint wrap-iife: 0*/
|
||||
const px = function () {
|
||||
const visualizations = {};
|
||||
let slice;
|
||||
function getParam(name) {
|
||||
name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
|
||||
const regex = new RegExp('[\\?&]' + name + '=([^&#]*)');
|
||||
const formattedName = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
|
||||
const regex = new RegExp('[\\?&]' + formattedName + '=([^&#]*)');
|
||||
const results = regex.exec(location.search);
|
||||
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()
|
||||
);
|
||||
}
|
||||
const 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',
|
||||
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 () {
|
||||
return true;
|
||||
},
|
||||
], // fall back on month, year
|
||||
]);
|
||||
function formatDate(dttm) {
|
||||
const d = UTC(new Date(dttm));
|
||||
// d = new Date(d.getTime() - 1 * 60 * 60 * 1000);
|
||||
return tickMultiFormat(d);
|
||||
}
|
||||
function timeFormatFactory(d3timeFormat) {
|
||||
const f = d3.time.format(d3timeFormat);
|
||||
return function (dttm) {
|
||||
const d = UTC(new Date(dttm));
|
||||
return f(d);
|
||||
};
|
||||
}
|
||||
function initFavStars() {
|
||||
const baseUrl = '/caravel/favstar/';
|
||||
// Init star behavihor for favorite
|
||||
@@ -267,12 +76,12 @@ const px = function () {
|
||||
containerId,
|
||||
selector,
|
||||
querystring(params) {
|
||||
params = params || {};
|
||||
const newParams = params || {};
|
||||
const parser = document.createElement('a');
|
||||
parser.href = data.json_endpoint;
|
||||
if (dashboard !== undefined) {
|
||||
const flts =
|
||||
params.extraFilters === false ? '' :
|
||||
newParams.extraFilters === false ? '' :
|
||||
encodeURIComponent(JSON.stringify(dashboard.filters));
|
||||
qrystr = parser.search + '&extra_filters=' + flts;
|
||||
} else if ($('#query').length === 0) {
|
||||
@@ -293,10 +102,10 @@ const px = function () {
|
||||
return Mustache.render(s, context);
|
||||
},
|
||||
jsonEndpoint(params) {
|
||||
params = params || {};
|
||||
const newParams = params || {};
|
||||
const parser = document.createElement('a');
|
||||
parser.href = data.json_endpoint;
|
||||
let endpoint = parser.pathname + this.querystring({ extraFilters: params.extraFilters });
|
||||
let endpoint = parser.pathname + this.querystring({ extraFilters: newParams.extraFilters });
|
||||
endpoint += '&json=true';
|
||||
endpoint += '&force=' + this.force;
|
||||
return endpoint;
|
||||
@@ -413,9 +222,10 @@ const px = function () {
|
||||
},
|
||||
render(force) {
|
||||
if (force === undefined) {
|
||||
force = false;
|
||||
this.force = false;
|
||||
} else {
|
||||
this.force = force;
|
||||
}
|
||||
this.force = force;
|
||||
token.find('img.loading').show();
|
||||
container.css('height', this.height());
|
||||
dttm = 0;
|
||||
@@ -457,32 +267,14 @@ const px = function () {
|
||||
}
|
||||
},
|
||||
};
|
||||
const visType = data.form_data.viz_type;
|
||||
px.registerViz(visType);
|
||||
slice.viz = visualizations[data.form_data.viz_type](slice);
|
||||
slice.viz = vizMap[data.form_data.viz_type](slice);
|
||||
return slice;
|
||||
};
|
||||
function registerViz(name) {
|
||||
const visSource = sourceMap[name];
|
||||
if (visSource) {
|
||||
/* eslint global-require: 0 */
|
||||
const visFactory = require('../../visualizations/' + visSource);
|
||||
if (typeof visFactory === 'function') {
|
||||
visualizations[name] = visFactory;
|
||||
}
|
||||
} else {
|
||||
throw new Error('require(' + name + ') failed.');
|
||||
}
|
||||
}
|
||||
// Export public functions
|
||||
return {
|
||||
color: color(),
|
||||
formatDate,
|
||||
getParam,
|
||||
initFavStars,
|
||||
registerViz,
|
||||
Slice,
|
||||
timeFormatFactory,
|
||||
};
|
||||
}();
|
||||
module.exports = px;
|
||||
|
||||
85
caravel/assets/javascripts/modules/colors.js
Normal file
85
caravel/assets/javascripts/modules/colors.js
Normal file
@@ -0,0 +1,85 @@
|
||||
import $ from 'jquery';
|
||||
const d3 = require('d3');
|
||||
|
||||
// Color related utility functions go in this object
|
||||
export const bnbColors = [
|
||||
'#ff5a5f', // rausch
|
||||
'#7b0051', // hackb
|
||||
'#007A87', // kazan
|
||||
'#00d1c1', // babu
|
||||
'#8ce071', // lima
|
||||
'#ffb400', // beach
|
||||
'#b4a76c', // barol
|
||||
'#ff8083',
|
||||
'#cc0086',
|
||||
'#00a1b3',
|
||||
'#00ffeb',
|
||||
'#bbedab',
|
||||
'#ffd266',
|
||||
'#cbc29a',
|
||||
'#ff3339',
|
||||
'#ff1ab1',
|
||||
'#005c66',
|
||||
'#00b3a5',
|
||||
'#55d12e',
|
||||
'#b37e00',
|
||||
'#988b4e',
|
||||
];
|
||||
|
||||
const spectrums = {
|
||||
blue_white_yellow: [
|
||||
'#00d1c1',
|
||||
'white',
|
||||
'#ffb400',
|
||||
],
|
||||
fire: [
|
||||
'white',
|
||||
'yellow',
|
||||
'red',
|
||||
'black',
|
||||
],
|
||||
white_black: [
|
||||
'white',
|
||||
'black',
|
||||
],
|
||||
black_white: [
|
||||
'black',
|
||||
'white',
|
||||
],
|
||||
};
|
||||
|
||||
export const category21 = (function () {
|
||||
// Color factory
|
||||
const seen = {};
|
||||
return function (s) {
|
||||
if (!s) {
|
||||
return;
|
||||
}
|
||||
let stringifyS = String(s);
|
||||
// next line is for caravel series that should have the same color
|
||||
stringifyS = stringifyS.replace('---', '');
|
||||
if (seen[stringifyS] === undefined) {
|
||||
seen[stringifyS] = Object.keys(seen).length;
|
||||
}
|
||||
/* eslint consistent-return: 0 */
|
||||
return bnbColors[seen[stringifyS] % bnbColors.length];
|
||||
};
|
||||
}());
|
||||
|
||||
export const colorScalerFactory = function (colors, data, accessor) {
|
||||
// Returns a linear scaler our of an array of color
|
||||
if (!Array.isArray(colors)) {
|
||||
/* eslint no-param-reassign: 0 */
|
||||
colors = spectrums[colors];
|
||||
}
|
||||
let ext = [0, 1];
|
||||
if (data !== undefined) {
|
||||
ext = d3.extent(data, accessor);
|
||||
}
|
||||
const points = [];
|
||||
const chunkSize = (ext[1] - ext[0]) / colors.length;
|
||||
$.each(colors, function (i) {
|
||||
points.push(i * chunkSize);
|
||||
});
|
||||
return d3.scale.linear().domain(points).range(colors);
|
||||
};
|
||||
74
caravel/assets/javascripts/modules/dates.js
Normal file
74
caravel/assets/javascripts/modules/dates.js
Normal file
@@ -0,0 +1,74 @@
|
||||
const d3 = require('d3');
|
||||
|
||||
function UTC(dttm) {
|
||||
return new Date(
|
||||
dttm.getUTCFullYear(),
|
||||
dttm.getUTCMonth(),
|
||||
dttm.getUTCDate(),
|
||||
dttm.getUTCHours(),
|
||||
dttm.getUTCMinutes(),
|
||||
dttm.getUTCSeconds()
|
||||
);
|
||||
}
|
||||
export const 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',
|
||||
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 () {
|
||||
return true;
|
||||
},
|
||||
], // fall back on month, year
|
||||
]);
|
||||
export const formatDate = function (dttm) {
|
||||
const d = UTC(new Date(dttm));
|
||||
// d = new Date(d.getTime() - 1 * 60 * 60 * 1000);
|
||||
return tickMultiFormat(d);
|
||||
};
|
||||
export const timeFormatFactory = function (d3timeFormat) {
|
||||
const f = d3.time.format(d3timeFormat);
|
||||
return function (dttm) {
|
||||
const d = UTC(new Date(dttm));
|
||||
return f(d);
|
||||
};
|
||||
};
|
||||
@@ -1,5 +1,5 @@
|
||||
const $ = require('jquery');
|
||||
const d3 = require('d3');
|
||||
const $ = require('jquery');
|
||||
/*
|
||||
Utility function that takes a d3 svg:text selection and a max width, and splits the
|
||||
text's text across multiple tspan lines such that any given line does not exceed max width
|
||||
@@ -7,7 +7,7 @@ const d3 = require('d3');
|
||||
If text does not span multiple lines AND adjustedY is passed,
|
||||
will set the text to the passed val
|
||||
*/
|
||||
function wrapSvgText(text, width, adjustedY) {
|
||||
export function wrapSvgText(text, width, adjustedY) {
|
||||
const lineHeight = 1;
|
||||
// ems
|
||||
text.each(function () {
|
||||
|
||||
@@ -59,6 +59,7 @@
|
||||
"nvd3": "1.8.4",
|
||||
"react": "^15.2.1",
|
||||
"react-bootstrap": "^0.28.3",
|
||||
"react-bootstrap-datetimepicker": "0.0.22",
|
||||
"react-bootstrap-table": "^2.3.7",
|
||||
"react-dom": "^0.14.8",
|
||||
"react-grid-layout": "^0.12.3",
|
||||
|
||||
@@ -107,7 +107,7 @@
|
||||
.btn + .btn-group,
|
||||
.btn-group + .btn,
|
||||
.btn-group + .btn-group {
|
||||
margin-left: -1;
|
||||
margin-left: -2;
|
||||
}
|
||||
|
||||
&-vertical {
|
||||
|
||||
93
caravel/assets/stylesheets/react-select/select.less
Normal file
93
caravel/assets/stylesheets/react-select/select.less
Normal file
@@ -0,0 +1,93 @@
|
||||
// @mistercrunch
|
||||
@select-primary-color: black;
|
||||
|
||||
/**
|
||||
* React Select
|
||||
* ============
|
||||
* Created by Jed Watson and Joss Mackison for KeystoneJS, http://www.keystonejs.com/
|
||||
* https://twitter.com/jedwatson https://twitter.com/jossmackison https://twitter.com/keystonejs
|
||||
* MIT License: https://github.com/keystonejs/react-select
|
||||
*/
|
||||
|
||||
// Variables
|
||||
// ------------------------------
|
||||
|
||||
// common
|
||||
//@select-primary-color: #007eff;
|
||||
|
||||
// control options
|
||||
@select-input-bg: #fff;
|
||||
@select-input-bg-disabled: #f9f9f9;
|
||||
@select-input-border-color: #ccc;
|
||||
@select-input-border-radius: 4px;
|
||||
@select-input-border-focus: @select-primary-color;
|
||||
@select-input-border-width: 1px;
|
||||
@select-input-height: 36px;
|
||||
@select-input-internal-height: (@select-input-height - (@select-input-border-width * 2));
|
||||
@select-input-placeholder: #aaa;
|
||||
@select-text-color: #333;
|
||||
@select-link-hover-color: @select-input-border-focus;
|
||||
|
||||
@select-padding-vertical: 8px;
|
||||
@select-padding-horizontal: 10px;
|
||||
|
||||
// menu options
|
||||
@select-menu-zindex: 1;
|
||||
@select-menu-max-height: 200px;
|
||||
|
||||
@select-option-color: lighten(@select-text-color, 20%);
|
||||
@select-option-bg: @select-input-bg;
|
||||
@select-option-focused-color: @select-text-color;
|
||||
@select-option-focused-bg: fade(@select-primary-color, 8%);
|
||||
@select-option-focused-bg-fb: mix(@select-primary-color, @select-option-bg, 8%); // Fallback color for IE 8
|
||||
@select-option-selected-color: @select-text-color;
|
||||
@select-option-selected-bg: fade(@select-primary-color, 4%);
|
||||
@select-option-selected-bg-fb: mix(@select-primary-color, @select-option-bg, 4%); // Fallback color for IE 8
|
||||
@select-option-disabled-color: lighten(@select-text-color, 60%);
|
||||
|
||||
@select-noresults-color: lighten(@select-text-color, 40%);
|
||||
|
||||
// clear "x" button
|
||||
@select-clear-size: floor((@select-input-height / 2));
|
||||
@select-clear-color: #999;
|
||||
@select-clear-hover-color: #D0021B; // red
|
||||
@select-clear-width: (@select-input-internal-height / 2);
|
||||
|
||||
// arrow indicator
|
||||
@select-arrow-color: #999;
|
||||
@select-arrow-color-hover: #666;
|
||||
@select-arrow-width: 5px;
|
||||
|
||||
// loading indicator
|
||||
@select-loading-size: 16px;
|
||||
@select-loading-color: @select-text-color;
|
||||
@select-loading-color-bg: @select-input-border-color;
|
||||
|
||||
// multi-select item
|
||||
@select-item-font-size: .9em;
|
||||
|
||||
@select-item-bg: fade(@select-primary-color, 8%);
|
||||
@select-item-bg-fb: mix(@select-primary-color, @select-input-bg, 8%); // Fallback color for IE 8
|
||||
@select-item-color: @select-primary-color;
|
||||
@select-item-border-color: fade(@select-primary-color, 24%);
|
||||
@select-item-border-color-fb: mix(@select-primary-color, @select-input-bg, 24%); // Fallback color for IE 8
|
||||
@select-item-hover-color: darken(@select-item-color, 5%);
|
||||
@select-item-hover-bg: darken(@select-item-bg, 5%);
|
||||
@select-item-hover-bg-fb: mix(darken(@select-primary-color, 5%), @select-item-bg-fb, 8%); // Fallback color for IE 8
|
||||
@select-item-disabled-color: #333;
|
||||
@select-item-disabled-bg: #fcfcfc;
|
||||
@select-item-disabled-border-color: darken(@select-item-disabled-bg, 10%);
|
||||
|
||||
@select-item-border-radius: 2px;
|
||||
@select-item-gutter: 5px;
|
||||
|
||||
@select-item-padding-horizontal: 5px;
|
||||
@select-item-padding-vertical: 2px;
|
||||
|
||||
// imports
|
||||
// @mistercrunch: these were altered to point to react-select/less
|
||||
@import "../../node_modules/react-select/less/control.less";
|
||||
@import "../../node_modules/react-select/less/menu.less";
|
||||
@import "../../node_modules/react-select/less/mixins.less";
|
||||
@import "../../node_modules/react-select/less/multi.less";
|
||||
@import "../../node_modules/react-select/less/spinner.less";
|
||||
@@ -4,7 +4,7 @@ var d3 = window.d3 || require('d3');
|
||||
// CSS
|
||||
require('./big_number.css');
|
||||
|
||||
var px = require('../javascripts/modules/caravel.js');
|
||||
import { formatDate } from '../javascripts/modules/dates'
|
||||
|
||||
function bigNumberVis(slice) {
|
||||
var div = d3.select(slice.selector);
|
||||
@@ -140,7 +140,7 @@ function bigNumberVis(slice) {
|
||||
.scale(scale_x)
|
||||
.orient('bottom')
|
||||
.ticks(4)
|
||||
.tickFormat(px.formatDate);
|
||||
.tickFormat(formatDate);
|
||||
g.call(x_axis);
|
||||
g.attr('transform', 'translate(0,' + (height - margin) + ')');
|
||||
|
||||
|
||||
@@ -4,19 +4,26 @@
|
||||
}
|
||||
|
||||
.dashboard .filter_box .slice_container > div {
|
||||
padding-top: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
ul.select2-results li.select2-highlighted div.filter_box{
|
||||
color: black;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-color: #666;
|
||||
color: black;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-color: #666;
|
||||
}
|
||||
|
||||
ul.select2-results div.filter_box{
|
||||
color: black;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-color: transparent;
|
||||
color: black;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-color: transparent;
|
||||
}
|
||||
.filter_box .slice_container {
|
||||
padding: 10px;
|
||||
overflow: visible !important;
|
||||
}
|
||||
.filter_box:hover {
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
// JS
|
||||
var $ = window.$ = require('jquery');
|
||||
var jQuery = window.jQuery = $;
|
||||
var d3 = window.d3 || require('d3');
|
||||
|
||||
// CSS
|
||||
require('./filter_box.css');
|
||||
require('../javascripts/caravel-select2.js');
|
||||
|
||||
function filterBox(slice) {
|
||||
var filtersObj = {};
|
||||
var d3token = d3.select(slice.selector);
|
||||
|
||||
var fltChanged = function () {
|
||||
var val = $(this).val();
|
||||
var vals = [];
|
||||
if (val !== '') {
|
||||
vals = val.split(',');
|
||||
}
|
||||
slice.setFilter($(this).attr('name'), vals);
|
||||
};
|
||||
|
||||
var refresh = function () {
|
||||
d3token.selectAll("*").remove();
|
||||
var container = d3token
|
||||
.append('div')
|
||||
.classed('padded', true);
|
||||
|
||||
var preSelectDict = slice.getFilters() || {};
|
||||
$.getJSON(slice.jsonEndpoint({
|
||||
// filter box should ignore the filters
|
||||
// otherwise there will be only a few options in the dropdown menu
|
||||
extraFilters: false,
|
||||
}), 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;
|
||||
});
|
||||
var id = 'fltbox__' + filter;
|
||||
|
||||
var div = container.append('div');
|
||||
|
||||
div.append("label").text(filter);
|
||||
|
||||
div.append('div')
|
||||
.attr('name', filter)
|
||||
.classed('form-control', true)
|
||||
.attr('multiple', '')
|
||||
.attr('id', id);
|
||||
|
||||
filtersObj[filter] = $('#' + id).select2({
|
||||
placeholder: "Select [" + filter + ']',
|
||||
containment: 'parent',
|
||||
dropdownAutoWidth: true,
|
||||
data: data,
|
||||
multiple: true,
|
||||
formatResult: select2Formatter,
|
||||
})
|
||||
.on('change', fltChanged);
|
||||
|
||||
var preSelect = preSelectDict[filter];
|
||||
if (preSelect !== undefined) {
|
||||
filtersObj[filter].select2('val', preSelect);
|
||||
}
|
||||
}
|
||||
slice.done(payload);
|
||||
|
||||
function select2Formatter(result, container /*, query, escapeMarkup*/) {
|
||||
var perc = Math.round((result.metric / maxes[result.filter]) * 100);
|
||||
var style = 'padding: 2px 5px;';
|
||||
style += "background-image: ";
|
||||
style += "linear-gradient(to right, lightgrey, lightgrey " + perc + "%, rgba(0,0,0,0) " + perc + "%";
|
||||
|
||||
$(container).attr('style', 'padding: 0px; background: white;');
|
||||
$(container).addClass('filter_box');
|
||||
return '<div style="' + style + '"><span>' + result.text + '</span></div>';
|
||||
}
|
||||
})
|
||||
.fail(function (xhr) {
|
||||
slice.error(xhr.responseText, xhr);
|
||||
});
|
||||
};
|
||||
return {
|
||||
render: refresh,
|
||||
resize: refresh,
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = filterBox;
|
||||
122
caravel/assets/visualizations/filter_box.jsx
Normal file
122
caravel/assets/visualizations/filter_box.jsx
Normal file
@@ -0,0 +1,122 @@
|
||||
// JS
|
||||
const $ = window.$ = require('jquery');
|
||||
const d3 = window.d3 || require('d3');
|
||||
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
import Select from 'react-select';
|
||||
import '../stylesheets/react-select/select.less';
|
||||
|
||||
import './filter_box.css';
|
||||
|
||||
class FilterBox extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
selectedValues: props.origSelectedValues,
|
||||
};
|
||||
}
|
||||
render() {
|
||||
const filters = Object.keys(this.props.filtersChoices).map((filter) => {
|
||||
const data = this.props.filtersChoices[filter];
|
||||
const id = 'fltbox__' + filter;
|
||||
const maxes = {};
|
||||
maxes[filter] = d3.max(data, function (d) {
|
||||
return d.metric;
|
||||
});
|
||||
return (
|
||||
<div>
|
||||
{filter}
|
||||
<Select
|
||||
placeholder={`Select [${filter}]`}
|
||||
key={filter}
|
||||
multi={true}
|
||||
value={this.state.selectedValues[filter]}
|
||||
options={data.map((opt) => {
|
||||
const perc = Math.round((opt.metric / maxes[opt.filter]) * 100);
|
||||
const backgroundImage = (
|
||||
'linear-gradient(to right, lightgrey, ' +
|
||||
`lightgrey ${perc}%, rgba(0,0,0,0) ${perc}%`
|
||||
);
|
||||
const style = {
|
||||
backgroundImage,
|
||||
padding:'2px 5px',
|
||||
};
|
||||
return { value: opt.id, label: opt.id, style };
|
||||
})}
|
||||
onChange={(selectedOptions) => {
|
||||
let vals;
|
||||
if (selectedOptions) {
|
||||
vals = selectedOptions.map((opt) => opt.value);
|
||||
} else {
|
||||
vals = null;
|
||||
}
|
||||
const selectedValues = this.state.selectedValues;
|
||||
selectedValues[filter] = vals;
|
||||
this.setState({ selectedValues });
|
||||
this.props.onChange(filter, vals);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
const preSelect = preSelectDict[filter];
|
||||
if (preSelect !== undefined) {
|
||||
filtersObj[filter].select2('val', preSelect);
|
||||
}
|
||||
});
|
||||
return (
|
||||
<div>
|
||||
{filters}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
FilterBox.propTypes = {
|
||||
origSelectedValues: React.PropTypes.objectOf(React.PropTypes.array),
|
||||
filtersChoices: React.PropTypes.objectOf(React.PropTypes.array),
|
||||
onChange: React.PropTypes.function,
|
||||
};
|
||||
FilterBox.defaultProps = {
|
||||
origSelectedValues: {},
|
||||
onChange: function () {},
|
||||
};
|
||||
|
||||
function filterBox(slice) {
|
||||
const filtersObj = {};
|
||||
const d3token = d3.select(slice.selector);
|
||||
|
||||
const refresh = function () {
|
||||
d3token.selectAll('*').remove();
|
||||
const container = d3token
|
||||
.append('div')
|
||||
.classed('padded', true);
|
||||
const preSelectDict = slice.getFilters() || {};
|
||||
|
||||
// filter box should ignore the dashboard's filters
|
||||
const url = slice.jsonEndpoint({ extraFilters: false});
|
||||
$.getJSON(url, (payload) => {
|
||||
ReactDOM.render(
|
||||
(
|
||||
<FilterBox
|
||||
filtersChoices={payload.data}
|
||||
onChange={slice.setFilter}
|
||||
origSelectedValues={slice.getFilters() || {}}
|
||||
/>
|
||||
),
|
||||
document.getElementById(slice.containerId)
|
||||
);
|
||||
slice.done(payload);
|
||||
})
|
||||
.fail(function (xhr) {
|
||||
slice.error(xhr.responseText, xhr);
|
||||
});
|
||||
};
|
||||
return {
|
||||
render: refresh,
|
||||
resize: () => {},
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = filterBox;
|
||||
@@ -1,7 +1,7 @@
|
||||
// JS
|
||||
var $ = window.$ || require('jquery');
|
||||
var px = window.px || require('../javascripts/modules/caravel.js');
|
||||
var d3 = require('d3');
|
||||
import { colorScalerFactory } from '../javascripts/modules/colors'
|
||||
|
||||
d3.tip = require('d3-tip'); //using window.d3 doesn't capture events properly bc of multiple instances
|
||||
|
||||
@@ -84,7 +84,7 @@ function heatmapVis(slice) {
|
||||
Y = 1;
|
||||
var heatmapDim = [xRbScale.domain().length, yRbScale.domain().length];
|
||||
|
||||
var color = px.color.colorScalerFactory(fd.linear_color_scheme);
|
||||
var color = colorScalerFactory(fd.linear_color_scheme);
|
||||
|
||||
var scale = [
|
||||
d3.scale.linear()
|
||||
|
||||
31
caravel/assets/visualizations/main.js
Normal file
31
caravel/assets/visualizations/main.js
Normal file
@@ -0,0 +1,31 @@
|
||||
const vizMap = {
|
||||
filter_box: require('./filter_box.jsx'),
|
||||
area: require('./nvd3_vis.js'),
|
||||
bar: require('./nvd3_vis.js'),
|
||||
big_number: require('./big_number.js'),
|
||||
big_number_total: require('./big_number.js'),
|
||||
box_plot: require('./nvd3_vis.js'),
|
||||
bubble: require('./nvd3_vis.js'),
|
||||
cal_heatmap: require('./cal_heatmap.js'),
|
||||
compare: require('./nvd3_vis.js'),
|
||||
directed_force: require('./directed_force.js'),
|
||||
dist_bar: require('./nvd3_vis.js'),
|
||||
heatmap: require('./heatmap.js'),
|
||||
histogram: require('./histogram.js'),
|
||||
horizon: require('./horizon.js'),
|
||||
iframe: require('./iframe.js'),
|
||||
line: require('./nvd3_vis.js'),
|
||||
mapbox: require('./mapbox.jsx'),
|
||||
markup: require('./markup.js'),
|
||||
para: require('./parallel_coordinates.js'),
|
||||
pie: require('./nvd3_vis.js'),
|
||||
pivot_table: require('./pivot_table.js'),
|
||||
sankey: require('./sankey.js'),
|
||||
separator: require('./markup.js'),
|
||||
sunburst: require('./sunburst.js'),
|
||||
table: require('./table.js'),
|
||||
treemap: require('./treemap.js'),
|
||||
word_cloud: require('./word_cloud.js'),
|
||||
world_map: require('./world_map.js'),
|
||||
};
|
||||
export default vizMap;
|
||||
@@ -1,6 +1,7 @@
|
||||
// JS
|
||||
var d3 = window.d3 || require('d3');
|
||||
var px = window.px || require('../javascripts/modules/caravel.js');
|
||||
import { category21 } from '../javascripts/modules/colors'
|
||||
import { timeFormatFactory, formatDate } from '../javascripts/modules/dates'
|
||||
var nv = require('nvd3');
|
||||
|
||||
// CSS
|
||||
@@ -203,14 +204,14 @@ function nvd3Vis(slice) {
|
||||
if (fd.x_log_scale) {
|
||||
chart.xScale(d3.scale.log());
|
||||
}
|
||||
var xAxisFormatter = null;
|
||||
var xAxisFormatter;
|
||||
if (viz_type === 'bubble') {
|
||||
xAxisFormatter = d3.format('.3s');
|
||||
} else if (fd.x_axis_format === 'smart_date') {
|
||||
xAxisFormatter = px.formatDate;
|
||||
xAxisFormatter = formatDate;
|
||||
chart.xAxis.tickFormat(xAxisFormatter);
|
||||
} else if (fd.x_axis_format !== undefined) {
|
||||
xAxisFormatter = px.timeFormatFactory(fd.x_axis_format);
|
||||
xAxisFormatter = timeFormatFactory(fd.x_axis_format);
|
||||
chart.xAxis.tickFormat(xAxisFormatter);
|
||||
}
|
||||
|
||||
@@ -222,9 +223,9 @@ function nvd3Vis(slice) {
|
||||
if (viz_type === 'bubble') {
|
||||
chart.xAxis.tickFormat(d3.format('.3s'));
|
||||
} else if (fd.x_axis_format === 'smart_date') {
|
||||
chart.xAxis.tickFormat(px.formatDate);
|
||||
chart.xAxis.tickFormat(formatDate);
|
||||
} else if (fd.x_axis_format !== undefined) {
|
||||
chart.xAxis.tickFormat(px.timeFormatFactory(fd.x_axis_format));
|
||||
chart.xAxis.tickFormat(timeFormatFactory(fd.x_axis_format));
|
||||
}
|
||||
if (chart.yAxis !== undefined) {
|
||||
chart.yAxis.tickFormat(d3.format('.3s'));
|
||||
@@ -238,7 +239,7 @@ function nvd3Vis(slice) {
|
||||
}
|
||||
}
|
||||
chart.color(function (d, i) {
|
||||
return px.color.category21(d[colorKey]);
|
||||
return category21(d[colorKey]);
|
||||
});
|
||||
|
||||
if (fd.x_axis_label && fd.x_axis_label !== '' && chart.xAxis) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// CSS
|
||||
require('./sankey.css');
|
||||
// JS
|
||||
var px = window.px || require('../javascripts/modules/caravel.js');
|
||||
import { category21 } from '../javascripts/modules/colors'
|
||||
var d3 = window.d3 || require('d3');
|
||||
d3.sankey = require('d3-sankey').sankey;
|
||||
|
||||
@@ -94,7 +94,7 @@ function sankeyVis(slice) {
|
||||
})
|
||||
.attr("width", sankey.nodeWidth())
|
||||
.style("fill", function (d) {
|
||||
d.color = px.color.category21(d.name.replace(/ .*/, ""));
|
||||
d.color = category21(d.name.replace(/ .*/, ""));
|
||||
return d.color;
|
||||
})
|
||||
.style("stroke", function (d) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
var d3 = window.d3 || require('d3');
|
||||
var px = require('../javascripts/modules/caravel.js');
|
||||
var wrapSvgText = require('../javascripts/modules/utils.js').wrapSvgText;
|
||||
import { category21 } from '../javascripts/modules/colors'
|
||||
import { wrapSvgText } from '../javascripts/modules/utils'
|
||||
|
||||
require('./sunburst.css');
|
||||
|
||||
@@ -132,7 +132,7 @@ function sunburstVis(slice) {
|
||||
.attr("d", arc)
|
||||
.attr("fill-rule", "evenodd")
|
||||
.style("fill", function (d) {
|
||||
return colorByCategory ? px.color.category21(d.name) : colorScale(d.m2 / d.m1);
|
||||
return colorByCategory ? category21(d.name) : colorScale(d.m2 / d.m1);
|
||||
})
|
||||
.style("opacity", 1)
|
||||
.on("mouseenter", mouseenter);
|
||||
@@ -263,7 +263,7 @@ function sunburstVis(slice) {
|
||||
entering.append("svg:polygon")
|
||||
.attr("points", breadcrumbPoints)
|
||||
.style("fill", function (d) {
|
||||
return colorByCategory ? px.color.category21(d.name) : colorScale(d.m2 / d.m1);
|
||||
return colorByCategory ? category21(d.name) : colorScale(d.m2 / d.m1);
|
||||
});
|
||||
|
||||
entering.append("svg:text")
|
||||
@@ -272,7 +272,7 @@ function sunburstVis(slice) {
|
||||
.attr("dy", "0.35em")
|
||||
.style("fill", function (d) {
|
||||
// Make text white or black based on the lightness of the background
|
||||
var col = d3.hsl(colorByCategory ? px.color.category21(d.name) : colorScale(d.m2 / d.m1));
|
||||
var col = d3.hsl(colorByCategory ? category21(d.name) : colorScale(d.m2 / d.m1));
|
||||
return col.l < 0.5 ? 'white' : 'black';
|
||||
})
|
||||
.attr("class", "step-label")
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
var $ = window.$ = require('jquery');
|
||||
var jQuery = window.jQuery = $;
|
||||
var d3 = require('d3');
|
||||
var px = window.px || require('../javascripts/modules/caravel.js');
|
||||
var utils = require('../javascripts/modules/utils.js');
|
||||
import { fixDataTableBodyHeight } from '../javascripts/modules/utils'
|
||||
import { timeFormatFactory, formatDate } from '../javascripts/modules/dates'
|
||||
|
||||
require('./table.css');
|
||||
require('datatables.net-bs');
|
||||
require('../node_modules/datatables-bootstrap3-plugin/media/css/datatables-bootstrap3.css');
|
||||
require('datatables-bootstrap3-plugin/media/css/datatables-bootstrap3.css');
|
||||
|
||||
function tableVis(slice) {
|
||||
var fC = d3.format('0,000');
|
||||
@@ -46,9 +45,9 @@ function tableVis(slice) {
|
||||
}
|
||||
|
||||
if (json.form_data.table_timestamp_format === 'smart_date') {
|
||||
timestampFormatter = px.formatDate;
|
||||
timestampFormatter = formatDate;
|
||||
} else if (json.form_data.table_timestamp_format !== undefined) {
|
||||
timestampFormatter = px.timeFormatFactory(json.form_data.table_timestamp_format);
|
||||
timestampFormatter = timeFormatFactory(json.form_data.table_timestamp_format);
|
||||
}
|
||||
|
||||
var div = d3.select(slice.selector);
|
||||
@@ -134,7 +133,7 @@ function tableVis(slice) {
|
||||
scrollCollapse: true,
|
||||
scrollX: true,
|
||||
});
|
||||
utils.fixDataTableBodyHeight(
|
||||
fixDataTableBodyHeight(
|
||||
slice.container.find('.dataTables_wrapper'), height);
|
||||
// Sorting table by main column
|
||||
if (form_data.metrics.length > 0) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// JS
|
||||
var d3 = window.d3 || require('d3');
|
||||
var px = window.px || require('../javascripts/modules/caravel.js');
|
||||
import { category21 } from '../javascripts/modules/colors'
|
||||
|
||||
// CSS
|
||||
require('./treemap.css');
|
||||
@@ -185,9 +185,8 @@ function treemap(slice) {
|
||||
.attr("dy", "1.0em")
|
||||
.text(function (d) { return formatNumber(d.value); });
|
||||
t.call(text);
|
||||
|
||||
g.selectAll("rect")
|
||||
.style("fill", function (d) { return px.color.category21(d.name); });
|
||||
.style("fill", function (d) { return category21(d.name); });
|
||||
|
||||
return g;
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
var px = window.px || require('../javascripts/modules/caravel.js');
|
||||
var d3 = window.d3 || require('d3');
|
||||
var cloudLayout = require('d3-cloud');
|
||||
import cloudLayout from 'd3-cloud'
|
||||
import { category21 } from '../javascripts/modules/colors'
|
||||
|
||||
function wordCloudChart(slice) {
|
||||
var chart = d3.select(slice.selector);
|
||||
@@ -68,7 +68,7 @@ function wordCloudChart(slice) {
|
||||
})
|
||||
.style("font-family", "Impact")
|
||||
.style("fill", function (d) {
|
||||
return px.color.category21(d.text);
|
||||
return category21(d.text);
|
||||
})
|
||||
.attr("text-anchor", "middle")
|
||||
.attr("transform", function (d) {
|
||||
|
||||
Reference in New Issue
Block a user