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 calendar chart #5760

Merged
merged 5 commits into from
Sep 5, 2018
Merged
Show file tree
Hide file tree
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
2 changes: 1 addition & 1 deletion superset/assets/src/explore/controls.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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'),
},
Expand Down
4 changes: 0 additions & 4 deletions superset/assets/src/visualizations/cal_heatmap.css
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,3 @@
margin-left: 20px;
margin-top: 5px;
}
.graph-legend rect {
stroke: #aaa;
stroke-location: inside;
}
120 changes: 100 additions & 20 deletions superset/assets/src/visualizations/cal_heatmap.js
Original file line number Diff line number Diff line change
@@ -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,
};

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 container = d3.select(slice.selector).style('height', slice.height());
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] = {};
Expand All @@ -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();
Expand Down Expand Up @@ -72,12 +115,49 @@ function calHeatmap(slice, payload) {
max: legendColors[legendColors.length - 1],
empty: 'white',
},
displayLegend: fd.show_legend,
displayLegend: showLegend,
itemName: '',
valueFormatter,
timeFormatter,
subDomainTextFormat,
});
});
}
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;
5 changes: 0 additions & 5 deletions superset/assets/vendor/cal-heatmap/cal-heatmap.css
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down