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,
|
isInt: true,
|
||||||
validators: [v.integer],
|
validators: [v.integer],
|
||||||
renderTrigger: true,
|
renderTrigger: true,
|
||||||
default: 0,
|
default: 2,
|
||||||
label: t('Cell Padding'),
|
label: t('Cell Padding'),
|
||||||
description: t('The distance between cells, in pixels'),
|
description: t('The distance between cells, in pixels'),
|
||||||
},
|
},
|
||||||
|
|
|
@ -8,7 +8,3 @@
|
||||||
margin-left: 20px;
|
margin-left: 20px;
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
}
|
}
|
||||||
.graph-legend rect {
|
|
||||||
stroke: #aaa;
|
|
||||||
stroke-location: inside;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,31 +1,73 @@
|
||||||
import d3 from 'd3';
|
import d3 from 'd3';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
import { colorScalerFactory } from '../modules/colors';
|
import { colorScalerFactory } from '../modules/colors';
|
||||||
import CalHeatMap from '../../vendor/cal-heatmap/cal-heatmap';
|
import CalHeatMap from '../../vendor/cal-heatmap/cal-heatmap';
|
||||||
import '../../vendor/cal-heatmap/cal-heatmap.css';
|
|
||||||
import { d3TimeFormatPreset, d3FormatPreset } from '../modules/utils';
|
import { d3TimeFormatPreset, d3FormatPreset } from '../modules/utils';
|
||||||
import './cal_heatmap.css';
|
|
||||||
import { UTC } from '../modules/dates';
|
import { UTC } from '../modules/dates';
|
||||||
|
import '../../vendor/cal-heatmap/cal-heatmap.css';
|
||||||
|
import './cal_heatmap.css';
|
||||||
|
|
||||||
const UTCTS = uts => UTC(new Date(uts)).getTime();
|
const UTCTS = uts => UTC(new Date(uts)).getTime();
|
||||||
|
|
||||||
function calHeatmap(slice, payload) {
|
const propTypes = {
|
||||||
const fd = slice.formData;
|
data: PropTypes.shape({
|
||||||
const steps = fd.steps;
|
// Object hashed by metric name,
|
||||||
const valueFormatter = d3FormatPreset(fd.y_axis_format);
|
// then hashed by timestamp (in seconds, not milliseconds) as float
|
||||||
const timeFormatter = d3TimeFormatPreset(fd.x_axis_time_format);
|
// 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();
|
container.selectAll('*').remove();
|
||||||
const div = container.append('div');
|
const div = container.append('div');
|
||||||
const data = payload.data;
|
|
||||||
|
|
||||||
const subDomainTextFormat = fd.show_values ? (date, value) => valueFormatter(value) : null;
|
const subDomainTextFormat = showValues ? (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;
|
|
||||||
|
|
||||||
// Trick to convert all timestamps to UTC
|
// 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 = {};
|
const metricsData = {};
|
||||||
Object.keys(data.data).forEach((metric) => {
|
Object.keys(data.data).forEach((metric) => {
|
||||||
metricsData[metric] = {};
|
metricsData[metric] = {};
|
||||||
|
@ -36,15 +78,16 @@ function calHeatmap(slice, payload) {
|
||||||
|
|
||||||
Object.keys(metricsData).forEach((metric) => {
|
Object.keys(metricsData).forEach((metric) => {
|
||||||
const calContainer = div.append('div');
|
const calContainer = div.append('div');
|
||||||
if (fd.show_metric_name) {
|
if (showMetricName) {
|
||||||
calContainer.append('h4').text(slice.verboseMetricName(metric));
|
calContainer.text(`Metric: ${verboseMap[metric] || metric}`);
|
||||||
}
|
}
|
||||||
const timestamps = metricsData[metric];
|
const timestamps = metricsData[metric];
|
||||||
const extents = d3.extent(Object.keys(timestamps), key => timestamps[key]);
|
const extents = d3.extent(Object.keys(timestamps), key => timestamps[key]);
|
||||||
const step = (extents[1] - extents[0]) / (steps - 1);
|
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 legendColors = legend.map(colorScale);
|
||||||
|
|
||||||
const cal = new CalHeatMap();
|
const cal = new CalHeatMap();
|
||||||
|
@ -72,7 +115,7 @@ function calHeatmap(slice, payload) {
|
||||||
max: legendColors[legendColors.length - 1],
|
max: legendColors[legendColors.length - 1],
|
||||||
empty: 'white',
|
empty: 'white',
|
||||||
},
|
},
|
||||||
displayLegend: fd.show_legend,
|
displayLegend: showLegend,
|
||||||
itemName: '',
|
itemName: '',
|
||||||
valueFormatter,
|
valueFormatter,
|
||||||
timeFormatter,
|
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;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cal-heatmap-container .graph
|
|
||||||
{
|
|
||||||
font-family: "Lucida Grande", Lucida, Verdana, sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cal-heatmap-container .graph-label
|
.cal-heatmap-container .graph-label
|
||||||
{
|
{
|
||||||
fill: #999;
|
fill: #999;
|
||||||
|
|
Loading…
Reference in New Issue