diff --git a/superset/assets/src/visualizations/parallel_coordinates.js b/superset/assets/src/visualizations/parallel_coordinates.js index 8e4ff5e6ccbd7..7d454e10e8568 100644 --- a/superset/assets/src/visualizations/parallel_coordinates.js +++ b/superset/assets/src/visualizations/parallel_coordinates.js @@ -1,89 +1,130 @@ import d3 from 'd3'; +import PropTypes from 'prop-types'; +import { colorScalerFactory } from '../modules/colors'; +import parcoords from '../../vendor/parallel_coordinates/d3.parcoords'; +import divgrid from '../../vendor/parallel_coordinates/divgrid'; import '../../vendor/parallel_coordinates/d3.parcoords.css'; import './parallel_coordinates.css'; -import { colorScalerFactory } from '../modules/colors'; -d3.parcoords = require('../../vendor/parallel_coordinates/d3.parcoords.js'); -d3.divgrid = require('../../vendor/parallel_coordinates/divgrid.js'); +const propTypes = { + // Standard tabular data [{ fieldName1: value1, fieldName2: value2 }] + data: PropTypes.arrayOf(PropTypes.object), + width: PropTypes.number, + height: PropTypes.number, + colorMetric: PropTypes.string, + includeSeries: PropTypes.bool, + linearColorScheme: PropTypes.string, + metrics: PropTypes.arrayOf(PropTypes.string), + series: PropTypes.string, + showDatatable: PropTypes.bool, +}; -const $ = require('jquery'); +function ParallelCoordinates(element, props) { + PropTypes.checkPropTypes(propTypes, props, 'prop', 'ParallelCoordinates'); -function parallelCoordVis(slice, payload) { - $('#code').attr('rows', '15'); - const fd = slice.formData; - const data = payload.data; + const { + data, + width, + height, + colorMetric, + includeSeries, + linearColorScheme, + metrics, + series, + showDatatable, + } = props; - const metrics = fd.metrics.map(m => m.label || m); - - let cols = metrics; - if (fd.include_series) { - cols = [fd.series].concat(metrics); - } + const cols = includeSeries ? [series].concat(metrics) : metrics; const ttypes = {}; - ttypes[fd.series] = 'string'; - metrics.forEach(function (v) { - ttypes[v] = 'number'; - }); + ttypes[series] = 'string'; + metrics.forEach((v) => { ttypes[v] = 'number'; }); - const secondaryMetric = fd.secondary_metric ? fd.secondary_metric.label : fd.secondary_metric; - const colorScaler = fd.secondary_metric ? - colorScalerFactory(fd.linear_color_scheme, data, d => d[secondaryMetric]) : - () => 'grey'; - const color = d => colorScaler(d[secondaryMetric]); - const container = d3.select(slice.selector); + const colorScaler = colorMetric + ? colorScalerFactory(linearColorScheme, data, d => d[colorMetric]) + : () => 'grey'; + const color = d => colorScaler(d[colorMetric]); + const container = d3.select(element); container.selectAll('*').remove(); - const effHeight = fd.show_datatable ? (slice.height() / 2) : slice.height(); + const effHeight = showDatatable ? (height / 2) : height; - container.append('div') - .attr('id', 'parcoords_' + slice.container_id) - .style('height', effHeight + 'px') - .classed('parcoords', true); + const div = container.append('div') + .style('height', effHeight + 'px') + .classed('parcoords', true); - const parcoords = d3.parcoords()('#parcoords_' + slice.container_id) - .width(slice.width()) - .color(color) - .alpha(0.5) - .composite('darken') - .height(effHeight) - .data(data) - .dimensions(cols) - .types(ttypes) - .render() - .createAxes() - .shadows() - .reorderable() - .brushMode('1D-axes'); + const chart = parcoords()(div.node()) + .width(width) + .color(color) + .alpha(0.5) + .composite('darken') + .height(effHeight) + .data(data) + .dimensions(cols) + .types(ttypes) + .render() + .createAxes() + .shadows() + .reorderable() + .brushMode('1D-axes'); - if (fd.show_datatable) { + if (showDatatable) { // create data table, row hover highlighting - const grid = d3.divgrid(); + const grid = divgrid(); container.append('div') - .style('height', effHeight + 'px') - .datum(data) - .call(grid) - .classed('parcoords grid', true) - .selectAll('.row') - .on({ - mouseover(d) { - parcoords.highlight([d]); - }, - mouseout: parcoords.unhighlight, - }); + .style('height', effHeight + 'px') + .datum(data) + .call(grid) + .classed('parcoords grid', true) + .selectAll('.row') + .on({ + mouseover(d) { + chart.highlight([d]); + }, + mouseout: chart.unhighlight, + }); // update data table on brush event - parcoords.on('brush', function (d) { + chart.on('brush', function (d) { d3.select('.grid') .datum(d) .call(grid) .selectAll('.row') .on({ mouseover(dd) { - parcoords.highlight([dd]); + chart.highlight([dd]); }, - mouseout: parcoords.unhighlight, + mouseout: chart.unhighlight, }); }); } } -module.exports = parallelCoordVis; +ParallelCoordinates.propTypes = propTypes; + +function adaptor(slice, payload) { + const { selector, formData } = slice; + const { + include_series: includeSeries, + linear_color_scheme: linearColorScheme, + metrics, + secondary_metric: secondaryMetric, + series, + show_datatable: showDatatable, + } = formData; + const element = document.querySelector(selector); + + return ParallelCoordinates(element, { + data: payload.data, + width: slice.width(), + height: slice.height(), + includeSeries, + linearColorScheme, + metrics: metrics.map(m => m.label || m), + colorMetric: secondaryMetric && secondaryMetric.label + ? secondaryMetric.label + : secondaryMetric, + series, + showDatatable, + }); +} + +export default adaptor;