Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SIP-5] Refactor rose #5763

Merged
merged 2 commits into from
Aug 29, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 70 additions & 19 deletions superset/assets/src/visualizations/rose.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,27 @@
/* eslint no-use-before-define: ["error", { "functions": false }] */
import d3 from 'd3';
import PropTypes from 'prop-types';
import nv from 'nvd3';
import { d3TimeFormatPreset } from '../modules/utils';
import { getColorFromScheme } from '../modules/colors';

import './rose.css';

const propTypes = {
// Data is an object hashed by numeric value, perhaps timestamp
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it work do specify this like this?

data: PropTypes.objectOf(
  PropTypes.arrayOf(PropTypes.shape({ ... }),
),

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call. Will update

data: PropTypes.objectOf(PropTypes.arrayOf(PropTypes.shape({
key: PropTypes.arrayOf(PropTypes.string),
name: PropTypes.arrayOf(PropTypes.string),
time: PropTypes.number,
value: PropTypes.number,
}))),
width: PropTypes.number,
height: PropTypes.number,
dateTimeFormat: PropTypes.string,
numberFormat: PropTypes.string,
useRichTooltip: PropTypes.bool,
useAreaProportions: PropTypes.bool,
};

function copyArc(d) {
return {
startAngle: d.startAngle,
Expand All @@ -22,19 +38,30 @@ function sortValues(a, b) {
return b.value - a.value;
}

function roseVis(slice, payload) {
const data = payload.data;
const fd = slice.formData;
const div = d3.select(slice.selector);
function Rose(element, props) {
PropTypes.checkPropTypes(propTypes, props, 'prop', 'Rose');

const {
data,
width,
height,
colorScheme,
dateTimeFormat,
numberFormat,
useRichTooltip,
useAreaProportions,
} = props;

const div = d3.select(element);

const datum = data;
const times = Object.keys(datum)
.map(t => parseInt(t, 10))
.sort((a, b) => a - b);
const numGrains = times.length;
const numGroups = datum[times[0]].length;
const format = d3.format(fd.number_format);
const timeFormat = d3TimeFormatPreset(fd.date_time_format);
const format = d3.format(numberFormat);
const timeFormat = d3TimeFormatPreset(dateTimeFormat);

d3.select('.nvtooltip').remove();
div.selectAll('*').remove();
Expand All @@ -43,12 +70,12 @@ function roseVis(slice, payload) {
const legend = nv.models.legend();
const tooltip = nv.models.tooltip();
const state = { disabled: datum[times[0]].map(() => false) };
const color = name => getColorFromScheme(name, fd.color_scheme);
const color = name => getColorFromScheme(name, colorScheme);

const svg = div
.append('svg')
.attr('width', slice.width())
.attr('height', slice.height());
.attr('width', width)
.attr('height', height);

const g = svg
.append('g')
Expand All @@ -68,7 +95,7 @@ function roseVis(slice, payload) {

function tooltipData(d, i, adatum) {
const timeIndex = Math.floor(d.arcId / numGroups);
const series = fd.rich_tooltip ?
const series = useRichTooltip ?
adatum[times[timeIndex]]
.filter(v => !state.disabled[v.id % numGroups])
.map(v => ({
Expand All @@ -85,8 +112,8 @@ function roseVis(slice, payload) {
}

legend
.width(slice.width())
.color(d => getColorFromScheme(d.key, fd.color_scheme));
.width(width)
.color(d => getColorFromScheme(d.key, colorScheme));
legendWrap
.datum(legendData(datum))
.call(legend);
Expand All @@ -96,16 +123,15 @@ function roseVis(slice, payload) {
.valueFormatter(format);

// Compute max radius, which the largest value will occupy
const width = slice.width();
const height = slice.height() - legend.height();
const roseHeight = height - legend.height();
const margin = { top: legend.height() };
const edgeMargin = 35; // space between outermost radius and slice edge
const maxRadius = Math.min(width, height) / 2 - edgeMargin;
const maxRadius = Math.min(width, roseHeight) / 2 - edgeMargin;
const labelThreshold = 0.05;
const gro = 8; // mouseover radius growth in pixels
const mini = 0.075;

const centerTranslate = `translate(${width / 2},${height / 2 + margin.top})`;
const centerTranslate = `translate(${width / 2},${roseHeight / 2 + margin.top})`;
const roseWrap = g
.append('g')
.attr('transform', centerTranslate)
Expand Down Expand Up @@ -146,7 +172,7 @@ function roseVis(slice, payload) {
// Compute proportion
const P = maxRadius / maxSum;
const Q = P * maxRadius;
const computeOuterRadius = (value, innerRadius) => fd.rose_area_proportion ?
const computeOuterRadius = (value, innerRadius) => useAreaProportions ?
Math.sqrt(Q * value + innerRadius * innerRadius) :
P * value + innerRadius;

Expand Down Expand Up @@ -537,4 +563,29 @@ function roseVis(slice, payload) {
});
}

module.exports = roseVis;
Rose.propTypes = propTypes;

function adaptor(slice, payload) {
const { selector, formData } = slice;
const {
color_scheme: colorScheme,
date_time_format: dateTimeFormat,
number_format: numberFormat,
rich_tooltip: useRichTooltip,
rose_area_proportion: useAreaProportions,
} = formData;
const element = document.querySelector(selector);

return Rose(element, {
data: payload.data,
width: slice.width(),
height: slice.height(),
colorScheme,
dateTimeFormat,
numberFormat,
useRichTooltip,
useAreaProportions,
});
}

export default adaptor;