Skip to content
This repository has been archived by the owner on Nov 3, 2023. It is now read-only.

Commit

Permalink
[SIP-5] Refactor calendar chart (apache#5760)
Browse files Browse the repository at this point in the history
* remove stroke

* update style and annotate data type

* update prop type

* bring back utc code

* add comments
  • Loading branch information
kristw authored and williaster committed Sep 5, 2018
1 parent 0c33f80 commit 2811498
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 30 deletions.
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

0 comments on commit 2811498

Please sign in to comment.