[SIP-5] Refactor rose (#5763)

* refactor rose

* update proptypes
This commit is contained in:
Krist Wongsuphasawat 2018-08-29 14:56:28 -07:00 committed by Chris Williams
parent 00cc6e981e
commit 86f99b0e1e

View File

@ -1,11 +1,27 @@
/* eslint no-use-before-define: ["error", { "functions": false }] */ /* eslint no-use-before-define: ["error", { "functions": false }] */
import d3 from 'd3'; import d3 from 'd3';
import PropTypes from 'prop-types';
import nv from 'nvd3'; import nv from 'nvd3';
import { d3TimeFormatPreset } from '../modules/utils'; import { d3TimeFormatPreset } from '../modules/utils';
import { getColorFromScheme } from '../modules/colors'; import { getColorFromScheme } from '../modules/colors';
import './rose.css'; import './rose.css';
const propTypes = {
// Data is an object hashed by numeric value, perhaps timestamp
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) { function copyArc(d) {
return { return {
startAngle: d.startAngle, startAngle: d.startAngle,
@ -22,10 +38,21 @@ function sortValues(a, b) {
return b.value - a.value; return b.value - a.value;
} }
function roseVis(slice, payload) { function Rose(element, props) {
const data = payload.data; PropTypes.checkPropTypes(propTypes, props, 'prop', 'Rose');
const fd = slice.formData;
const div = d3.select(slice.selector); const {
data,
width,
height,
colorScheme,
dateTimeFormat,
numberFormat,
useRichTooltip,
useAreaProportions,
} = props;
const div = d3.select(element);
const datum = data; const datum = data;
const times = Object.keys(datum) const times = Object.keys(datum)
@ -33,8 +60,8 @@ function roseVis(slice, payload) {
.sort((a, b) => a - b); .sort((a, b) => a - b);
const numGrains = times.length; const numGrains = times.length;
const numGroups = datum[times[0]].length; const numGroups = datum[times[0]].length;
const format = d3.format(fd.number_format); const format = d3.format(numberFormat);
const timeFormat = d3TimeFormatPreset(fd.date_time_format); const timeFormat = d3TimeFormatPreset(dateTimeFormat);
d3.select('.nvtooltip').remove(); d3.select('.nvtooltip').remove();
div.selectAll('*').remove(); div.selectAll('*').remove();
@ -43,12 +70,12 @@ function roseVis(slice, payload) {
const legend = nv.models.legend(); const legend = nv.models.legend();
const tooltip = nv.models.tooltip(); const tooltip = nv.models.tooltip();
const state = { disabled: datum[times[0]].map(() => false) }; 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 const svg = div
.append('svg') .append('svg')
.attr('width', slice.width()) .attr('width', width)
.attr('height', slice.height()); .attr('height', height);
const g = svg const g = svg
.append('g') .append('g')
@ -68,7 +95,7 @@ function roseVis(slice, payload) {
function tooltipData(d, i, adatum) { function tooltipData(d, i, adatum) {
const timeIndex = Math.floor(d.arcId / numGroups); const timeIndex = Math.floor(d.arcId / numGroups);
const series = fd.rich_tooltip ? const series = useRichTooltip ?
adatum[times[timeIndex]] adatum[times[timeIndex]]
.filter(v => !state.disabled[v.id % numGroups]) .filter(v => !state.disabled[v.id % numGroups])
.map(v => ({ .map(v => ({
@ -85,8 +112,8 @@ function roseVis(slice, payload) {
} }
legend legend
.width(slice.width()) .width(width)
.color(d => getColorFromScheme(d.key, fd.color_scheme)); .color(d => getColorFromScheme(d.key, colorScheme));
legendWrap legendWrap
.datum(legendData(datum)) .datum(legendData(datum))
.call(legend); .call(legend);
@ -96,16 +123,15 @@ function roseVis(slice, payload) {
.valueFormatter(format); .valueFormatter(format);
// Compute max radius, which the largest value will occupy // Compute max radius, which the largest value will occupy
const width = slice.width(); const roseHeight = height - legend.height();
const height = slice.height() - legend.height();
const margin = { top: legend.height() }; const margin = { top: legend.height() };
const edgeMargin = 35; // space between outermost radius and slice edge 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 labelThreshold = 0.05;
const gro = 8; // mouseover radius growth in pixels const gro = 8; // mouseover radius growth in pixels
const mini = 0.075; 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 const roseWrap = g
.append('g') .append('g')
.attr('transform', centerTranslate) .attr('transform', centerTranslate)
@ -146,7 +172,7 @@ function roseVis(slice, payload) {
// Compute proportion // Compute proportion
const P = maxRadius / maxSum; const P = maxRadius / maxSum;
const Q = P * maxRadius; const Q = P * maxRadius;
const computeOuterRadius = (value, innerRadius) => fd.rose_area_proportion ? const computeOuterRadius = (value, innerRadius) => useAreaProportions ?
Math.sqrt(Q * value + innerRadius * innerRadius) : Math.sqrt(Q * value + innerRadius * innerRadius) :
P * value + innerRadius; P * value + innerRadius;
@ -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;