diff --git a/caravel/assets/.eslintignore b/caravel/assets/.eslintignore index 613212ecc7d0..8999d0d1c171 100644 --- a/caravel/assets/.eslintignore +++ b/caravel/assets/.eslintignore @@ -1,6 +1,5 @@ node_modules/* vendor/* javascripts/dist/* -visualizations/* stylesheets/* spec/* diff --git a/caravel/assets/javascripts/dashboard/Dashboard.jsx b/caravel/assets/javascripts/dashboard/Dashboard.jsx index 99c2a1bd3825..1f2137c70592 100644 --- a/caravel/assets/javascripts/dashboard/Dashboard.jsx +++ b/caravel/assets/javascripts/dashboard/Dashboard.jsx @@ -1,5 +1,5 @@ const $ = window.$ = require('jquery'); -const jQuery = window.jQuery = $; +const jQuery = window.jQuery = require('jquery'); // eslint-disable-line const px = require('../modules/caravel.js'); const d3 = require('d3'); const urlLib = require('url'); diff --git a/caravel/assets/javascripts/dashboard/components/GridLayout.jsx b/caravel/assets/javascripts/dashboard/components/GridLayout.jsx index 3388ee062c79..7dbac5fe1522 100644 --- a/caravel/assets/javascripts/dashboard/components/GridLayout.jsx +++ b/caravel/assets/javascripts/dashboard/components/GridLayout.jsx @@ -90,7 +90,7 @@ class GridLayout extends React.Component { rowHeight={100} autoSize margin={[20, 20]} - useCSSTransforms={true} + useCSSTransforms draggableHandle=".drag" > { diff --git a/caravel/assets/javascripts/dashboard/components/SliceAdder.jsx b/caravel/assets/javascripts/dashboard/components/SliceAdder.jsx index 10caa33693d4..75b11a7dcdc0 100644 --- a/caravel/assets/javascripts/dashboard/components/SliceAdder.jsx +++ b/caravel/assets/javascripts/dashboard/components/SliceAdder.jsx @@ -3,7 +3,7 @@ import React, { PropTypes } from 'react'; import update from 'immutability-helper'; import { BootstrapTable, TableHeaderColumn } from 'react-bootstrap-table'; import Modal from './Modal.jsx'; -require('../../../node_modules/react-bootstrap-table/css/react-bootstrap-table.css'); +require('react-bootstrap-table/css/react-bootstrap-table.css'); const propTypes = { dashboard: PropTypes.object.isRequired, @@ -129,7 +129,8 @@ class SliceAdder extends React.Component { render() { const hideLoad = this.slicesLoaded || this.errored; - const enableAddSlice = this.state.selectionMap && Object.keys(this.state.selectionMap).some(function (key) { + let enableAddSlice = this.state.selectionMap && Object.keys(this.state.selectionMap); + enableAddSlice = enableAddSlice.some(function (key) { return this.state.selectionMap[key]; }, this); const modalContent = ( diff --git a/caravel/assets/javascripts/explore/explore.jsx b/caravel/assets/javascripts/explore/explore.jsx index 233df2dec495..76c548aa750e 100644 --- a/caravel/assets/javascripts/explore/explore.jsx +++ b/caravel/assets/javascripts/explore/explore.jsx @@ -4,9 +4,9 @@ // // js const $ = window.$ = require('jquery'); -const jQuery = window.jQuery = $; const px = require('./../modules/caravel.js'); const showModal = require('./../modules/utils.js').showModal; +const jQuery = window.jQuery = require('jquery'); // eslint-disable-line import React from 'react'; import ReactDOM from 'react-dom'; @@ -76,23 +76,55 @@ function query(forceUpdate, pushState) { slice.render(force); } +function saveSlice() { + const action = $('input[name=rdo_save]:checked').val(); + if (action === 'saveas') { + const sliceName = $('input[name=new_slice_name]').val(); + if (sliceName === '') { + showModal({ + title: 'Error', + body: 'You must pick a name for the new slice', + }); + return; + } + document.getElementById('slice_name').value = sliceName; + } + const addToDash = $('input[name=addToDash]:checked').val(); + if (addToDash === 'existing' && $('#save_to_dashboard_id').val() === '') { + showModal({ + title: 'Error', + body: 'You must pick an existing dashboard', + }); + return; + } else if (addToDash === 'new' && $('input[name=new_dashboard_name]').val() === '') { + showModal({ + title: 'Error', + body: 'Please enter a name for the new dashboard', + }); + return; + } + $('#action').val(action); + prepForm(); + $('#query').submit(); +} + function initExploreView() { - function get_collapsed_fieldsets() { - var collapsed_fieldsets = $('#collapsed_fieldsets').val(); + function getCollapsedFieldsets() { + let collapsedFieldsets = $('#collapsedFieldsets').val(); - if (collapsed_fieldsets !== undefined && collapsed_fieldsets !== '') { - collapsed_fieldsets = collapsed_fieldsets.split('||'); + if (collapsedFieldsets !== undefined && collapsedFieldsets !== '') { + collapsedFieldsets = collapsedFieldsets.split('||'); } else { - collapsed_fieldsets = []; + collapsedFieldsets = []; } - return collapsed_fieldsets; + return collapsedFieldsets; } - function toggle_fieldset(legend, animation) { - var parent = legend.parent(); - var fieldset = parent.find('.legend_label').text(); - var collapsed_fieldsets = get_collapsed_fieldsets(); - var index; + function toggleFieldset(legend, animation) { + const parent = legend.parent(); + const fieldset = parent.find('.legend_label').text(); + const collapsedFieldsets = getCollapsedFieldsets(); + let index; if (parent.hasClass('collapsed')) { if (animation) { @@ -104,9 +136,9 @@ function initExploreView() { parent.find('span.collapser').text('[-]'); // removing from array, js is overcomplicated - index = collapsed_fieldsets.indexOf(fieldset); + index = collapsedFieldsets.indexOf(fieldset); if (index !== -1) { - collapsed_fieldsets.splice(index, 1); + collapsedFieldsets.splice(index, 1); } } else { // not collapsed if (animation) { @@ -117,33 +149,33 @@ function initExploreView() { parent.addClass('collapsed'); parent.find('span.collapser').text('[+]'); - index = collapsed_fieldsets.indexOf(fieldset); + index = collapsedFieldsets.indexOf(fieldset); if (index === -1 && fieldset !== '' && fieldset !== undefined) { - collapsed_fieldsets.push(fieldset); + collapsedFieldsets.push(fieldset); } } - $('#collapsed_fieldsets').val(collapsed_fieldsets.join('||')); + $('#collapsedFieldsets').val(collapsedFieldsets.join('||')); } px.initFavStars(); function copyURLToClipboard(url) { - var textArea = document.createElement('textarea'); + const textArea = document.createElement('textarea'); textArea.style.position = 'fixed'; textArea.style.left = '-1000px'; textArea.value = url; document.body.appendChild(textArea); textArea.select(); - + let successful; try { - var successful = document.execCommand('copy'); + successful = document.execCommand('copy'); if (!successful) { throw new Error('Not successful'); } } catch (err) { - window.alert('Sorry, your browser does not support copying. Use Ctrl / Cmd + C!'); + window.alert('Sorry, your browser does not support copying. Use Ctrl / Cmd + C!'); // eslint-disable-line } document.body.removeChild(textArea); return successful; @@ -157,12 +189,20 @@ function initExploreView() { data: '/' + window.location.pathname + slice.querystring(), }, success(data) { - var close = ''; - var copy = ''; - var spaces = '   '; - var popover = data + spaces + copy + spaces + close; - - var $shortner = $('#shortner') + const close = ( + '' + + '' + + '' + ); + const copy = ( + '' + + '' + + '' + ); + const spaces = '   '; + const popover = data + spaces + copy + spaces + close; + + const $shortner = $('#shortner') .popover({ content: popover, placement: 'left', @@ -170,42 +210,57 @@ function initExploreView() { trigger: 'manual', }) .popover('show'); + function destroyPopover() { + $shortner.popover('destroy'); + } - $('#copy_url').tooltip().click(function () { - var success = copyURLToClipboard(data); + $('#copy_url') + .tooltip() + .click(function () { + const success = copyURLToClipboard(data); if (success) { - $(this).attr('data-original-title', 'Copied!').tooltip('fixTitle').tooltip('show'); + $(this).attr('data-original-title', 'Copied!') + .tooltip('fixTitle') + .tooltip('show'); window.setTimeout(destroyPopover, 1200); } }); $('#close_shortner').click(destroyPopover); - - function destroyPopover() { - $shortner.popover('destroy'); - } }, error(error) { showModal({ title: 'Error', body: 'Sorry, an error occurred during this operation:
' + error, }); - console.warn('Short URL error', error); }, }); }); $('#standalone').click(function () { - var src_link = window.location.origin + slice.data.standalone_endpoint; - var dataToCopy = ''; - var close = ''; - var copy = ''; - var spaces = '   '; - var widthInput = ''; - var heightInput = ''; - var popover = ""; + const srcLink = window.location.origin + slice.data.standalone_endpoint; + const close = ( + '' + + '' + + '' + ); + const copy = ( + '' + + '' + + '' + ); + const spaces = '   '; + const widthInput = ''; + const heightInput = ''; + let popover = ""; popover = popover + spaces + copy + spaces + close + spaces + widthInput + spaces + heightInput; + let dataToCopy = ''; + + const $standalone = $(this); + + function destroyPopover() { + $standalone.popover('destroy'); + } - var $standalone = $(this); $standalone.popover({ content: popover, title: 'embed html', @@ -215,37 +270,36 @@ function initExploreView() { }) .popover('show'); $('#copy_embed').tooltip().click(function () { - var success = copyURLToClipboard(dataToCopy); + const success = copyURLToClipboard(dataToCopy); if (success) { - $(this).attr('data-original-title', 'Copied!').tooltip('fixTitle').tooltip('show'); + $(this).attr('data-original-title', 'Copied!') + .tooltip('fixTitle') + .tooltip('show'); window.setTimeout(destroyPopover, 1200); } }); $('#close_standalone').click(destroyPopover); - function destroyPopover() { - $standalone.popover('destroy'); - } + const $standaloneWidth = $('#standalone_width'); + const $standaloneHeight = $('#standalone_height'); + const $standaloneText = $('#standalone_text'); - var $standalone_width = $('#standalone_width'); - var $standalone_height = $('#standalone_height'); - var $standalone_text = $('#standalone_text'); + function generateEmbedHTML() { + const width = $standaloneWidth.val(); + const height = $standaloneHeight.val(); + dataToCopy = `'; + $standaloneText.val(dataToCopy); + } - $standalone_height.change(function () { + $standaloneHeight.change(function () { generateEmbedHTML(); }); - $standalone_width.change(function () { + $standaloneWidth.change(function () { generateEmbedHTML(); }); generateEmbedHTML(); - function generateEmbedHTML() { - var width = $standalone_width.val(); - var height = $standalone_height.val(); - dataToCopy = ''; - $standalone_text.val(dataToCopy); - } }); $('#viz_type').change(function () { @@ -253,20 +307,19 @@ function initExploreView() { }); $('#datasource_id').change(function () { - var url = $(this).find('option:selected').attr('url'); - window.location = url; + window.location = $(this).find('option:selected').attr('url'); }); - var collapsed_fieldsets = get_collapsed_fieldsets(); - for (var i = 0; i < collapsed_fieldsets.length; i++) { - toggle_fieldset($('legend:contains("' + collapsed_fieldsets[i] + '")'), false); + const collapsedFieldsets = getCollapsedFieldsets(); + for (let i = 0; i < collapsedFieldsets.length; i++) { + toggleFieldset($('legend:contains("' + collapsedFieldsets[i] + '")'), false); } function formatViz(viz) { - var url = '/static/assets/images/viz_thumbnails/' + viz.id + '.png'; - var no_img = '/static/assets/images/noimg.png'; + const url = `/static/assets/images/viz_thumbnails/${viz.id}.png`; + const noImg = '/static/assets/images/noimg.png'; return $( - '' + - '' + viz.text + '' + `` + + `${viz.text}` ); } @@ -288,20 +341,8 @@ function initExploreView() { $('[data-toggle="tooltip"]').tooltip({ container: 'body' }); $('.ui-helper-hidden-accessible').remove(); // jQuery-ui 1.11+ creates a div for every tooltip - function set_filters() { - ['flt', 'having'].forEach(function (prefix) { - for (var i = 1; i < 10; i++) { - var col = px.getParam(prefix + '_col_' + i); - if (col !== '') { - add_filter(i, prefix); - } - } - }); - } - set_filters(); - - function add_filter(i, fieldPrefix) { - var cp = $('#' + fieldPrefix + '0').clone(); + function addFilter(i, fieldPrefix) { + const cp = $('#' + fieldPrefix + '0').clone(); $(cp).appendTo('#' + getPanelClass(fieldPrefix) + ' #filters'); $(cp).show(); if (i !== undefined) { @@ -311,23 +352,38 @@ function initExploreView() { } $(cp).find('select').select2(); $(cp).find('.remove').click(function () { - $(this).parent().parent().remove(); + $(this) + .parent() + .parent() + .remove(); }); } - $(window).bind('popstate', function (event) { + function setFilters() { + ['flt', 'having'].forEach(function (prefix) { + for (let i = 1; i < 10; i++) { + const col = px.getParam(prefix + '_col_' + i); + if (col !== '') { + addFilter(i, prefix); + } + } + }); + } + setFilters(); + + $(window).bind('popstate', function () { // Browser back button - var returnLocation = history.location || document.location; + const returnLocation = history.location || document.location; // Could do something more lightweight here, but we're not optimizing // for the use of the back button anyways returnLocation.reload(); }); $('#filter_panel #plus').click(function () { - add_filter(undefined, 'flt'); + addFilter(undefined, 'flt'); }); $('#having_panel #plus').click(function () { - add_filter(undefined, 'having'); + addFilter(undefined, 'having'); }); const queryAndSaveBtnsEl = document.getElementById('js-query-and-save-btns'); @@ -339,8 +395,8 @@ function initExploreView() { queryAndSaveBtnsEl ); - function create_choices(term, data) { - var filtered = $(data).filter(function () { + function createChoices(term, data) { + const filtered = $(data).filter(function () { return this.text.localeCompare(term) === 0; }); if (filtered.length === 0) { @@ -349,6 +405,7 @@ function initExploreView() { text: term, }; } + return {}; } function initSelectionToValue(element, callback) { @@ -359,11 +416,11 @@ function initExploreView() { } $('.select2_freeform').each(function () { - var parent = $(this).parent(); - var name = $(this).attr('name'); - var l = []; - var selected = ''; - for (var i = 0; i < this.options.length; i++) { + const parent = $(this).parent(); + const name = $(this).attr('name'); + const l = []; + let selected = ''; + for (let i = 0; i < this.options.length; i++) { l.push({ id: this.options[i].value, text: this.options[i].text, @@ -373,10 +430,11 @@ function initExploreView() { } } parent.append( - '' + `` ); - $("input[name='" + name + "']").select2({ - createSearchChoice: create_choices, + $(`input[name='${name}']`).select2({ + createSearchChoice: createChoices, initSelection: initSelectionToValue, dropdownAutoWidth: true, multiple: false, @@ -386,31 +444,30 @@ function initExploreView() { }); function prepSaveDialog() { - var setButtonsState = function () { - var add_to_dash = $('input[name=add_to_dash]:checked').val(); - if (add_to_dash === 'existing' || add_to_dash === 'new') { + const setButtonsState = function () { + const addToDash = $('input[name=addToDash]:checked').val(); + if (addToDash === 'existing' || addToDash === 'new') { $('.gotodash').removeAttr('disabled'); } else { $('.gotodash').prop('disabled', true); } }; - var url = '/dashboardmodelviewasync/api/read'; - url += '?_flt_0_owners=' + $('#userid').val(); + const url = '/dashboardmodelviewasync/api/read?_flt_0_owners=' + $('#userid').val(); $.get(url, function (data) { - var choices = []; - for (var i = 0; i < data.pks.length; i++) { + const choices = []; + for (let i = 0; i < data.pks.length; i++) { choices.push({ id: data.pks[i], text: data.result[i].dashboard_title }); } $('#save_to_dashboard_id').select2({ data: choices, dropdownAutoWidth: true, }).on('select2-selecting', function () { - $('#add_to_dash_existing').prop('checked', true); + $('#addToDash_existing').prop('checked', true); setButtonsState(); }); }); - $('input[name=add_to_dash]').change(setButtonsState); + $('input[name=addToDash]').change(setButtonsState); $("input[name='new_dashboard_name']").on('focus', function () { $('#add_to_new_dash').prop('checked', true); setButtonsState(); @@ -430,38 +487,6 @@ function initExploreView() { prepSaveDialog(); } -function saveSlice() { - var action = $('input[name=rdo_save]:checked').val(); - if (action === 'saveas') { - var slice_name = $('input[name=new_slice_name]').val(); - if (slice_name === '') { - showModal({ - title: 'Error', - body: 'You must pick a name for the new slice', - }); - return; - } - document.getElementById('slice_name').value = slice_name; - } - var add_to_dash = $('input[name=add_to_dash]:checked').val(); - if (add_to_dash === 'existing' && $('#save_to_dashboard_id').val() === '') { - showModal({ - title: 'Error', - body: 'You must pick an existing dashboard', - }); - return; - } else if (add_to_dash === 'new' && $('input[name=new_dashboard_name]').val() === '') { - showModal({ - title: 'Error', - body: 'Please enter a name for the new dashboard', - }); - return; - } - $('#action').val(action); - prepForm(); - $('#query').submit(); -} - $(document).ready(function () { const data = $('.slice').data('slice'); diff --git a/caravel/assets/package.json b/caravel/assets/package.json index d9d9f8b1d396..97e23d071c9e 100644 --- a/caravel/assets/package.json +++ b/caravel/assets/package.json @@ -11,7 +11,7 @@ "dev": "NODE_ENV=dev webpack -d --watch --colors", "prod": "NODE_ENV=production webpack -p --colors --progress", "lint": "npm run --silent lint:js", - "lint:js": "eslint --ignore-path=.eslintignore --ext .js ." + "lint:js": "eslint --ignore-path=.eslintignore --ext .js,.jsx ." }, "repository": { "type": "git", diff --git a/caravel/assets/visualizations/big_number.js b/caravel/assets/visualizations/big_number.js index b4777ca99ff4..aa1b9b6fe4c6 100644 --- a/caravel/assets/visualizations/big_number.js +++ b/caravel/assets/visualizations/big_number.js @@ -1,78 +1,69 @@ -// JS -var d3 = window.d3 || require('d3'); +import d3 from 'd3'; +import { formatDate } from '../javascripts/modules/dates'; -// CSS require('./big_number.css'); -import { formatDate } from '../javascripts/modules/dates' - function bigNumberVis(slice) { - var div = d3.select(slice.selector); + const div = d3.select(slice.selector); function render() { d3.json(slice.jsonEndpoint(), function (error, payload) { - //Define the percentage bounds that define color from red to green + // Define the percentage bounds that define color from red to green if (error !== null) { slice.error(error.responseText, error); - return ''; + return; } - div.html(''); //reset - - var fd = payload.form_data; - var json = payload.data; - var color_range = [-1, 1]; - - var f = d3.format(fd.y_axis_format); - var fp = d3.format('+.1%'); - var width = slice.width(); - var height = slice.height(); - div.selectAll("*").remove(); - var svg = div.append('svg'); - svg.attr("width", width); - svg.attr("height", height); - var data = json.data; - var compare_suffix = ' ' + json.compare_suffix; - var v_compare = null; - var v = null; + div.html(''); // reset + + const fd = payload.form_data; + const json = payload.data; + + const f = d3.format(fd.y_axis_format); + const fp = d3.format('+.1%'); + const width = slice.width(); + const height = slice.height(); + const svg = div.append('svg'); + svg.attr('width', width); + svg.attr('height', height); + const data = json.data; + let vCompare; + let v; if (fd.viz_type === 'big_number') { v = data[data.length - 1][1]; } else { v = data[0][0]; } if (json.compare_lag > 0) { - var pos = data.length - (json.compare_lag + 1); + const pos = data.length - (json.compare_lag + 1); if (pos >= 0) { - v_compare = (v / data[pos][1]) - 1; + vCompare = (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 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) + const dateExt = d3.extent(data, (d) => d[0]); + const valueExt = d3.extent(data, (d) => d[1]); + + const margin = 20; + const scaleX = d3.time.scale.utc().domain(dateExt).range([margin, width - margin]); + const scaleY = d3.scale.linear().domain(valueExt).range([height - (margin), margin]); + const colorRange = [d3.hsl(0, 1, 0.3), d3.hsl(120, 1, 0.3)]; + const scaleColor = d3.scale + .linear().domain([-1, 1]) .interpolate(d3.interpolateHsl) - .range(colorRange).clamp(true); - var line = d3.svg.line() + .range(colorRange) + .clamp(true); + const line = d3.svg.line() .x(function (d) { - return scale_x(d[0]); + return scaleX(d[0]); }) .y(function (d) { - return scale_y(d[1]); + return scaleY(d[1]); }) - .interpolate("basis"); + .interpolate('basis'); - var g = svg.append('g'); - var y = height / 2; - //Printing big number - g.append("g").attr("class", "digits") + let y = height / 2; + let g = svg.append('g'); + // Printing big number + g.append('g').attr('class', 'digits') .attr('opacity', 1) .append('text') .attr('x', width / 2) @@ -87,27 +78,29 @@ function bigNumberVis(slice) { .attr('fill', 'white'); if (fd.viz_type === 'big_number') { - //Drawing trend line + // Drawing trend line g.append('path') - .attr('d', function (d) { + .attr('d', function () { return line(data); }) .attr('stroke-width', 5) .attr('opacity', 0.5) - .attr('fill', "none") - .attr('stroke-linecap', "round") - .attr('stroke', "grey"); + .attr('fill', 'none') + .attr('stroke-linecap', 'round') + .attr('stroke', 'grey'); g = svg.append('g') .attr('class', 'digits') .attr('opacity', 1); - if (v_compare !== null) { + if (vCompare !== null) { y = (height / 8) * 3; } - //Printing big number subheader text + const c = scaleColor(vCompare); + + // Printing big number subheader text if (json.subheader !== null) { g.append('text') .attr('x', width / 2) @@ -120,58 +113,74 @@ function bigNumberVis(slice) { .attr('stroke', c); } - var c = scale_color(v_compare); - - //Printing compare % - if (v_compare !== null) { + // Printing compare % + if (vCompare !== null) { g.append('text') .attr('x', width / 2) .attr('y', (height / 16) * 12) - .text(fp(v_compare) + compare_suffix) + .text(fp(vCompare) + json.compare_suffix) .style('font-size', d3.min([height, width]) / 8) .style('text-anchor', 'middle') .attr('fill', c) .attr('stroke', c); } - var g_axis = svg.append('g').attr('class', 'axis').attr('opacity', 0); - g = g_axis.append('g'); - var x_axis = d3.svg.axis() - .scale(scale_x) + const gAxis = svg.append('g').attr('class', 'axis').attr('opacity', 0); + g = gAxis.append('g'); + const xAxis = d3.svg.axis() + .scale(scaleX) .orient('bottom') .ticks(4) .tickFormat(formatDate); - g.call(x_axis); + g.call(xAxis); g.attr('transform', 'translate(0,' + (height - margin) + ')'); - g = g_axis.append('g').attr('transform', 'translate(' + (width - margin) + ',0)'); - var y_axis = d3.svg.axis() - .scale(scale_y) + g = gAxis.append('g').attr('transform', 'translate(' + (width - margin) + ',0)'); + const yAxis = d3.svg.axis() + .scale(scaleY) .orient('left') .tickFormat(d3.format(fd.y_axis_format)) - .tickValues(value_ext); - g.call(y_axis); + .tickValues(valueExt); + g.call(yAxis); g.selectAll('text') .style('text-anchor', 'end') .attr('y', '-7') .attr('x', '-4'); - g.selectAll("text") + g.selectAll('text') .style('font-size', '10px'); - div.on('mouseover', function (d) { - var div = d3.select(this); - div.selectAll('path').transition().duration(500).attr('opacity', 1) + div.on('mouseover', function () { + const el = d3.select(this); + el.selectAll('path') + .transition() + .duration(500) + .attr('opacity', 1) .style('stroke-width', '2px'); - div.selectAll('g.digits').transition().duration(500).attr('opacity', 0.1); - div.selectAll('g.axis').transition().duration(500).attr('opacity', 1); + el.selectAll('g.digits') + .transition() + .duration(500) + .attr('opacity', 0.1); + el.selectAll('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) + .on('mouseout', function () { + const el = d3.select(this); + el.select('path') + .transition() + .duration(500) + .attr('opacity', 0.5) .style('stroke-width', '5px'); - div.selectAll('g.digits').transition().duration(500).attr('opacity', 1); - div.selectAll('g.axis').transition().duration(500).attr('opacity', 0); + el.selectAll('g.digits') + .transition() + .duration(500) + .attr('opacity', 1); + el.selectAll('g.axis') + .transition() + .duration(500) + .attr('opacity', 0); }); } slice.done(payload); @@ -179,7 +188,7 @@ function bigNumberVis(slice) { } return { - render: render, + render, resize: render, }; } diff --git a/caravel/assets/visualizations/cal_heatmap.js b/caravel/assets/visualizations/cal_heatmap.js index 5ce2cd760a78..5e5a6b21b87e 100644 --- a/caravel/assets/visualizations/cal_heatmap.js +++ b/caravel/assets/visualizations/cal_heatmap.js @@ -1,45 +1,41 @@ // JS -var d3 = window.d3 || require('d3'); +import d3 from 'd3'; // CSS require('./cal_heatmap.css'); require('../node_modules/cal-heatmap/cal-heatmap.css'); -var CalHeatMap = require('cal-heatmap'); +const CalHeatMap = require('cal-heatmap'); function calHeatmap(slice) { + const div = d3.select(slice.selector); - var div = d3.select(slice.selector); - var cal = new CalHeatMap(); - - var render = function () { + const render = function () { d3.json(slice.jsonEndpoint(), function (error, json) { - + const data = json.data; if (error !== null) { slice.error(error.responseText, error); - return ''; + return; } - div.selectAll("*").remove(); - cal = new CalHeatMap(); + div.selectAll('*').remove(); + const cal = new CalHeatMap(); - var timestamps = json.data["timestamps"], - extents = d3.extent(Object.keys(timestamps), function (key) { - return timestamps[key]; - }), - step = (extents[1] - extents[0]) / 5; + const timestamps = data.timestamps; + const extents = d3.extent(Object.keys(timestamps), (key) => timestamps[key]); + const step = (extents[1] - extents[0]) / 5; try { cal.init({ - start: json.data["start"], + start: data.start, data: timestamps, itemSelector: slice.selector, tooltip: true, - domain: json.data["domain"], - subDomain: json.data["subdomain"], - range: json.data["range"], + domain: data.domain, + subDomain: data.subdomain, + range: data.range, browsing: true, - legend: [extents[0], extents[0]+step, extents[0]+step*2, extents[0]+step*3], + legend: [extents[0], extents[0] + step, extents[0] + step * 2, extents[0] + step * 3], }); } catch (e) { slice.error(e); @@ -50,7 +46,7 @@ function calHeatmap(slice) { }; return { - render: render, + render, resize: render, }; } diff --git a/caravel/assets/visualizations/directed_force.js b/caravel/assets/visualizations/directed_force.js index 62359a768d60..3aa63b591071 100644 --- a/caravel/assets/visualizations/directed_force.js +++ b/caravel/assets/visualizations/directed_force.js @@ -1,26 +1,25 @@ -// JS -var d3 = window.d3 || require('d3'); +/* eslint-disable no-param-reassign */ +import d3 from 'd3'; -// CSS require('./directed_force.css'); /* Modified from http://bl.ocks.org/d3noob/5141278 */ function directedForceVis(slice) { - var div = d3.select(slice.selector); + const div = d3.select(slice.selector); - var render = function () { - var width = slice.width(); - var height = slice.height() - 25; + const render = function () { + const width = slice.width(); + const height = slice.height() - 25; d3.json(slice.jsonEndpoint(), function (error, json) { - var link_length = json.form_data.link_length || 200; - var charge = json.form_data.charge || -500; + const linkLength = json.form_data.link_length || 200; + const charge = json.form_data.charge || -500; if (error !== null) { slice.error(error.responseText, error); - return ''; + return; } - var links = json.data; - var nodes = {}; + const links = json.data; + const nodes = {}; // Compute the distinct nodes from the links. links.forEach(function (link) { link.source = nodes[link.source] || (nodes[link.source] = { @@ -31,143 +30,151 @@ function directedForceVis(slice) { }); link.value = Number(link.value); - var target_name = link.target.name; - var source_name = link.source.name; + const targetName = link.target.name; + const sourceName = link.source.name; - if (nodes[target_name].total === undefined) { - nodes[target_name].total = link.value; + if (nodes[targetName].total === undefined) { + nodes[targetName].total = link.value; } - if (nodes[source_name].total === undefined) { - nodes[source_name].total = 0; + if (nodes[sourceName].total === undefined) { + nodes[sourceName].total = 0; } - if (nodes[target_name].max === undefined) { - nodes[target_name].max = 0; + if (nodes[targetName].max === undefined) { + nodes[targetName].max = 0; } - if (link.value > nodes[target_name].max) { - nodes[target_name].max = link.value; + if (link.value > nodes[targetName].max) { + nodes[targetName].max = link.value; } - if (nodes[target_name].min === undefined) { - nodes[target_name].min = 0; + if (nodes[targetName].min === undefined) { + nodes[targetName].min = 0; } - if (link.value > nodes[target_name].min) { - nodes[target_name].min = link.value; + if (link.value > nodes[targetName].min) { + nodes[targetName].min = link.value; } - nodes[target_name].total += link.value; + nodes[targetName].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(); + /* eslint-disable no-use-before-define */ + // add the curvy lines + function tick() { + path.attr('d', function (d) { + const dx = d.target.x - d.source.x; + const dy = d.target.y - d.source.y; + const 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 + ); + }); - var svg = div.append("svg") - .attr("width", width) - .attr("height", height); + node.attr('transform', function (d) { + return 'translate(' + d.x + ',' + d.y + ')'; + }); + } + /* eslint-enable no-use-before-define */ + + const force = d3.layout.force() + .nodes(d3.values(nodes)) + .links(links) + .size([width, height]) + .linkDistance(linkLength) + .charge(charge) + .on('tick', tick) + .start(); + + const svg = div.append('svg') + .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") - .append("svg:path") - .attr("d", "M0,-5L10,0L0,5"); - - var edgeScale = d3.scale.linear() - .range([0.1, 0.5]); + 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') + .append('svg:path') + .attr('d', 'M0,-5L10,0L0,5'); + + const edgeScale = d3.scale.linear() + .range([0.1, 0.5]); // add the links and the arrows - var path = svg.append("svg:g").selectAll("path") - .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)"); + const path = svg.append('svg:g').selectAll('path') + .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)'); // define the nodes - var node = svg.selectAll(".node") - .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); + const node = svg.selectAll('.node') + .data(force.nodes()) + .enter() + .append('g') + .attr('class', 'node') + .on('mouseenter', function () { + d3.select(this) + .select('circle') + .transition() + .style('stroke-width', 5); + + d3.select(this) + .select('text') + .transition() + .style('font-size', 25); + }) + .on('mouseleave', function () { + 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) { + const ext = d3.extent(d3.values(nodes), function (d) { return Math.sqrt(d.total); }); - var circleScale = d3.scale.linear() - .domain(ext) - .range([3, 30]); + const circleScale = d3.scale.linear() + .domain(ext) + .range([3, 30]); - node.append("circle") - .attr("r", function (d) { - return circleScale(Math.sqrt(d.total)); - }); + node.append('circle') + .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; - }); - - // 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.append('text') + .attr('x', 6) + .attr('dy', '.35em') + .text(function (d) { + return d.name; + }); - node.attr("transform", function (d) { - return "translate(" + d.x + "," + d.y + ")"; - }); - } slice.done(json); }); }; return { - render: render, + render, resize: render, }; } diff --git a/caravel/assets/visualizations/filter_box.jsx b/caravel/assets/visualizations/filter_box.jsx index 34fb14e52d18..f50e52eba926 100644 --- a/caravel/assets/visualizations/filter_box.jsx +++ b/caravel/assets/visualizations/filter_box.jsx @@ -1,6 +1,6 @@ // JS -const $ = window.$ = require('jquery'); -const d3 = window.d3 || require('d3'); +const $ = require('jquery'); +import d3 from 'd3'; import React from 'react'; import ReactDOM from 'react-dom'; @@ -20,7 +20,6 @@ class FilterBox extends React.Component { 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; @@ -31,7 +30,7 @@ class FilterBox extends React.Component {