mirror of https://github.com/apache/superset.git
[SIP-5] Refactor calendar chart (#5760)
* remove stroke * update style and annotate data type * update prop type * bring back utc code * add comments
This commit is contained in:
parent
0c33f80c1d
commit
2811498ec9
|
@ -1078,7 +1078,7 @@ export const controls = {
|
|||
isInt: true,
|
||||
validators: [v.integer],
|
||||
renderTrigger: true,
|
||||
default: 0,
|
||||
default: 2,
|
||||
label: t('Cell Padding'),
|
||||
description: t('The distance between cells, in pixels'),
|
||||
},
|
||||
|
|
|
@ -8,7 +8,3 @@
|
|||
margin-left: 20px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
.graph-legend rect {
|
||||
stroke: #aaa;
|
||||
stroke-location: inside;
|
||||
}
|
||||
|
|
|
@ -1,31 +1,73 @@
|
|||
import d3 from 'd3';
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
import { colorScalerFactory } from '../modules/colors';
|
||||
import CalHeatMap from '../../vendor/cal-heatmap/cal-heatmap';
|
||||
import '../../vendor/cal-heatmap/cal-heatmap.css';
|
||||
import { d3TimeFormatPreset, d3FormatPreset } from '../modules/utils';
|
||||
import './cal_heatmap.css';
|
||||
import { UTC } from '../modules/dates';
|
||||
import '../../vendor/cal-heatmap/cal-heatmap.css';
|
||||
import './cal_heatmap.css';
|
||||
|
||||
const UTCTS = uts => UTC(new Date(uts)).getTime();
|
||||
|
||||
function calHeatmap(slice, payload) {
|
||||
const fd = slice.formData;
|
||||
const steps = fd.steps;
|
||||
const valueFormatter = d3FormatPreset(fd.y_axis_format);
|
||||
const timeFormatter = d3TimeFormatPreset(fd.x_axis_time_format);
|
||||
const propTypes = {
|
||||
data: PropTypes.shape({
|
||||
// Object hashed by metric name,
|
||||
// then hashed by timestamp (in seconds, not milliseconds) as float
|
||||
// the innermost value is count
|
||||
// e.g. { count_distinct_something: { 1535034236.0: 3 } }
|
||||
data: PropTypes.object,
|
||||
domain: PropTypes.string,
|
||||
range: PropTypes.number,
|
||||
// timestamp in milliseconds
|
||||
start: PropTypes.number,
|
||||
subdomain: PropTypes.string,
|
||||
}),
|
||||
height: PropTypes.number,
|
||||
cellPadding: PropTypes.number,
|
||||
cellRadius: PropTypes.number,
|
||||
cellSize: PropTypes.number,
|
||||
linearColorScheme: PropTypes.string,
|
||||
showLegend: PropTypes.bool,
|
||||
showMetricName: PropTypes.bool,
|
||||
showValues: PropTypes.bool,
|
||||
steps: PropTypes.number,
|
||||
timeFormat: PropTypes.string,
|
||||
valueFormat: PropTypes.string,
|
||||
verboseMap: PropTypes.object,
|
||||
};
|
||||
|
||||
const container = d3.select(slice.selector).style('height', slice.height());
|
||||
function Calendar(element, props) {
|
||||
PropTypes.checkPropTypes(propTypes, props, 'prop', 'Calendar');
|
||||
|
||||
const {
|
||||
data,
|
||||
height,
|
||||
cellPadding = 3,
|
||||
cellRadius = 0,
|
||||
cellSize = 10,
|
||||
linearColorScheme,
|
||||
showLegend,
|
||||
showMetricName,
|
||||
showValues,
|
||||
steps,
|
||||
timeFormat,
|
||||
valueFormat,
|
||||
verboseMap,
|
||||
} = props;
|
||||
|
||||
const valueFormatter = d3FormatPreset(valueFormat);
|
||||
const timeFormatter = d3TimeFormatPreset(timeFormat);
|
||||
|
||||
const container = d3.select(element)
|
||||
.style('height', height);
|
||||
container.selectAll('*').remove();
|
||||
const div = container.append('div');
|
||||
const data = payload.data;
|
||||
|
||||
const subDomainTextFormat = fd.show_values ? (date, value) => valueFormatter(value) : null;
|
||||
const cellPadding = fd.cell_padding !== '' ? fd.cell_padding : 2;
|
||||
const cellRadius = fd.cell_radius || 0;
|
||||
const cellSize = fd.cell_size || 10;
|
||||
const subDomainTextFormat = showValues ? (date, value) => valueFormatter(value) : null;
|
||||
|
||||
// Trick to convert all timestamps to UTC
|
||||
// TODO: Verify if this conversion is really necessary
|
||||
// since all timestamps should always be in UTC.
|
||||
const metricsData = {};
|
||||
Object.keys(data.data).forEach((metric) => {
|
||||
metricsData[metric] = {};
|
||||
|
@ -36,15 +78,16 @@ function calHeatmap(slice, payload) {
|
|||
|
||||
Object.keys(metricsData).forEach((metric) => {
|
||||
const calContainer = div.append('div');
|
||||
if (fd.show_metric_name) {
|
||||
calContainer.append('h4').text(slice.verboseMetricName(metric));
|
||||
if (showMetricName) {
|
||||
calContainer.text(`Metric: ${verboseMap[metric] || metric}`);
|
||||
}
|
||||
const timestamps = metricsData[metric];
|
||||
const extents = d3.extent(Object.keys(timestamps), key => timestamps[key]);
|
||||
const step = (extents[1] - extents[0]) / (steps - 1);
|
||||
const colorScale = colorScalerFactory(fd.linear_color_scheme, null, null, extents);
|
||||
const colorScale = colorScalerFactory(linearColorScheme, null, null, extents);
|
||||
|
||||
const legend = d3.range(steps).map(i => extents[0] + (step * i));
|
||||
const legend = d3.range(steps)
|
||||
.map(i => extents[0] + (step * i));
|
||||
const legendColors = legend.map(colorScale);
|
||||
|
||||
const cal = new CalHeatMap();
|
||||
|
@ -72,7 +115,7 @@ function calHeatmap(slice, payload) {
|
|||
max: legendColors[legendColors.length - 1],
|
||||
empty: 'white',
|
||||
},
|
||||
displayLegend: fd.show_legend,
|
||||
displayLegend: showLegend,
|
||||
itemName: '',
|
||||
valueFormatter,
|
||||
timeFormatter,
|
||||
|
@ -80,4 +123,41 @@ function calHeatmap(slice, payload) {
|
|||
});
|
||||
});
|
||||
}
|
||||
module.exports = calHeatmap;
|
||||
|
||||
Calendar.propTypes = propTypes;
|
||||
|
||||
function adaptor(slice, payload) {
|
||||
const { selector, formData, datasource } = slice;
|
||||
const {
|
||||
cell_padding: cellPadding,
|
||||
cell_radius: cellRadius,
|
||||
cell_size: cellSize,
|
||||
linear_color_scheme: linearColorScheme,
|
||||
show_legend: showLegend,
|
||||
show_metric_name: showMetricName,
|
||||
show_values: showValues,
|
||||
steps,
|
||||
x_axis_time_format: timeFormat,
|
||||
y_axis_format: valueFormat,
|
||||
} = formData;
|
||||
const { verbose_map: verboseMap } = datasource;
|
||||
const element = document.querySelector(selector);
|
||||
|
||||
return Calendar(element, {
|
||||
data: payload.data,
|
||||
height: slice.height(),
|
||||
cellPadding,
|
||||
cellRadius,
|
||||
cellSize,
|
||||
linearColorScheme,
|
||||
showLegend,
|
||||
showMetricName,
|
||||
showValues,
|
||||
steps,
|
||||
timeFormat,
|
||||
valueFormat,
|
||||
verboseMap,
|
||||
});
|
||||
}
|
||||
|
||||
export default adaptor;
|
||||
|
|
|
@ -4,11 +4,6 @@
|
|||
display: block;
|
||||
}
|
||||
|
||||
.cal-heatmap-container .graph
|
||||
{
|
||||
font-family: "Lucida Grande", Lucida, Verdana, sans-serif;
|
||||
}
|
||||
|
||||
.cal-heatmap-container .graph-label
|
||||
{
|
||||
fill: #999;
|
||||
|
|
Loading…
Reference in New Issue