mirror of
https://github.com/apache/superset.git
synced 2024-09-19 12:09:42 -04:00
add calendar
This commit is contained in:
parent
b72e17ee94
commit
1d3e3c5c27
@ -0,0 +1,34 @@
|
||||
## @superset-ui/legacy-plugin-chart-calendar
|
||||
|
||||
[![Version](https://img.shields.io/npm/v/@superset-ui/legacy-plugin-chart-calendar.svg?style=flat-square)](https://img.shields.io/npm/v/@superset-ui/legacy-plugin-chart-calendar.svg?style=flat-square)
|
||||
[![David (path)](https://img.shields.io/david/apache-superset/superset-ui.svg?path=packages%2Fsuperset-ui-legacy-plugin-chart-calendar&style=flat-square)](https://david-dm.org/apache-superset/superset-ui?path=packages/superset-ui-legacy-plugin-chart-calendar)
|
||||
|
||||
This plugin provides Calendar Heatmap for Superset.
|
||||
|
||||
### Usage
|
||||
|
||||
Configure `key`, which can be any `string`, and register the plugin. This `key` will be used to lookup this chart throughout the app.
|
||||
|
||||
```js
|
||||
import CalendarChartPlugin from '@superset-ui/legacy-plugin-chart-calendar';
|
||||
|
||||
new CalendarChartPlugin()
|
||||
.configure({ key: 'calendar' })
|
||||
.register();
|
||||
```
|
||||
|
||||
Then use it via `SuperChart`. See [storybook](https://apache-superset.github.io/superset-ui-legacy/?selectedKind=plugin-chart-calendar) for more details.
|
||||
|
||||
```js
|
||||
<SuperChart
|
||||
chartType="calendar"
|
||||
chartProps={{
|
||||
width: 600,
|
||||
height: 600,
|
||||
formData: {...},
|
||||
payload: {
|
||||
data: {...},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
```
|
@ -0,0 +1,48 @@
|
||||
{
|
||||
"name": "@superset-ui/legacy-plugin-chart-calendar",
|
||||
"version": "0.0.0",
|
||||
"description": "Superset Legacy Chart - Calendar Heatmap",
|
||||
"sideEffects": false,
|
||||
"main": "lib/index.js",
|
||||
"module": "esm/index.js",
|
||||
"files": [
|
||||
"esm",
|
||||
"lib"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/apache-superset/superset-ui-legacy.git"
|
||||
},
|
||||
"keywords": [
|
||||
"superset"
|
||||
],
|
||||
"author": "Superset",
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/apache-superset/superset-ui-legacy/issues"
|
||||
},
|
||||
"homepage": "https://github.com/apache-superset/superset-ui-legacy#readme",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"dependencies": {
|
||||
"@superset-ui/core": "^0.9.x",
|
||||
"d3-array": "^2.0.3",
|
||||
"d3-selection": "^1.4.0",
|
||||
"prop-types": "^15.6.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@superset-ui/chart": "^0.9.x",
|
||||
"@superset-ui/color": "^0.9.x",
|
||||
"@superset-ui/number-format": "^0.9.x",
|
||||
"@superset-ui/time-format": "^0.9.x",
|
||||
"@superset-ui/translation": "^0.9.x"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@superset-ui/chart": "^0.9.x",
|
||||
"@superset-ui/color": "^0.9.x",
|
||||
"@superset-ui/number-format": "^0.9.x",
|
||||
"@superset-ui/time-format": "^0.9.x",
|
||||
"@superset-ui/translation": "^0.9.x"
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
.cal_heatmap {
|
||||
padding: 10px;
|
||||
position: static !important;
|
||||
overflow: auto !important;
|
||||
}
|
||||
|
||||
.cal_heatmap .ch-tooltip {
|
||||
margin-left: 20px;
|
||||
margin-top: 5px;
|
||||
}
|
@ -0,0 +1,159 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
/* eslint-disable sort-keys, no-magic-numbers, react/forbid-prop-types */
|
||||
import PropTypes from 'prop-types';
|
||||
import { extent as d3Extent, range as d3Range } from 'd3-array';
|
||||
import { select as d3Select } from 'd3-selection';
|
||||
import { getSequentialSchemeRegistry } from '@superset-ui/color';
|
||||
import { getNumberFormatter } from '@superset-ui/number-format';
|
||||
import { getTimeFormatter } from '@superset-ui/time-format';
|
||||
import CalHeatMap from './vendor/cal-heatmap';
|
||||
import './vendor/cal-heatmap.css';
|
||||
import './Calendar.css';
|
||||
|
||||
function convertUTC(dttm) {
|
||||
return new Date(
|
||||
dttm.getUTCFullYear(),
|
||||
dttm.getUTCMonth(),
|
||||
dttm.getUTCDate(),
|
||||
dttm.getUTCHours(),
|
||||
dttm.getUTCMinutes(),
|
||||
dttm.getUTCSeconds(),
|
||||
);
|
||||
}
|
||||
|
||||
const convertUTCTS = uts => convertUTC(new Date(uts)).getTime();
|
||||
|
||||
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) {
|
||||
const {
|
||||
data,
|
||||
height,
|
||||
cellPadding = 3,
|
||||
cellRadius = 0,
|
||||
cellSize = 10,
|
||||
linearColorScheme,
|
||||
showLegend,
|
||||
showMetricName,
|
||||
showValues,
|
||||
steps,
|
||||
timeFormat,
|
||||
valueFormat,
|
||||
verboseMap,
|
||||
} = props;
|
||||
|
||||
const valueFormatter = getNumberFormatter(valueFormat);
|
||||
const timeFormatter = getTimeFormatter(timeFormat);
|
||||
|
||||
const container = d3Select(element).style('height', height);
|
||||
container.selectAll('*').remove();
|
||||
const div = container.append('div');
|
||||
|
||||
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] = {};
|
||||
Object.keys(data.data[metric]).forEach(ts => {
|
||||
metricsData[metric][convertUTCTS(ts * 1000) / 1000] = data.data[metric][ts];
|
||||
});
|
||||
});
|
||||
|
||||
Object.keys(metricsData).forEach(metric => {
|
||||
const calContainer = div.append('div');
|
||||
if (showMetricName) {
|
||||
calContainer.text(`Metric: ${verboseMap[metric] || metric}`);
|
||||
}
|
||||
const timestamps = metricsData[metric];
|
||||
const extents = d3Extent(Object.keys(timestamps), key => timestamps[key]);
|
||||
const step = (extents[1] - extents[0]) / (steps - 1);
|
||||
const colorScale = getSequentialSchemeRegistry()
|
||||
.get(linearColorScheme)
|
||||
.createLinearScale(extents);
|
||||
|
||||
const legend = d3Range(steps).map(i => extents[0] + step * i);
|
||||
const legendColors = legend.map(colorScale);
|
||||
|
||||
const cal = new CalHeatMap();
|
||||
|
||||
cal.init({
|
||||
start: convertUTCTS(data.start),
|
||||
data: timestamps,
|
||||
itemSelector: calContainer.node(),
|
||||
legendVerticalPosition: 'top',
|
||||
cellSize,
|
||||
cellPadding,
|
||||
cellRadius,
|
||||
legendCellSize: cellSize,
|
||||
legendCellPadding: 2,
|
||||
legendCellRadius: cellRadius,
|
||||
tooltip: true,
|
||||
domain: data.domain,
|
||||
subDomain: data.subdomain,
|
||||
range: data.range,
|
||||
browsing: true,
|
||||
legend,
|
||||
legendColors: {
|
||||
colorScale,
|
||||
min: legendColors[0],
|
||||
max: legendColors[legendColors.length - 1],
|
||||
empty: 'white',
|
||||
},
|
||||
displayLegend: showLegend,
|
||||
itemName: '',
|
||||
valueFormatter,
|
||||
timeFormatter,
|
||||
subDomainTextFormat,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Calendar.displayName = 'Calendar';
|
||||
Calendar.propTypes = propTypes;
|
||||
|
||||
export default Calendar;
|
@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { reactify } from '@superset-ui/chart';
|
||||
import Component from './Calendar';
|
||||
|
||||
export default reactify(Component);
|
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
Binary file not shown.
After Width: | Height: | Size: 31 KiB |
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { t } from '@superset-ui/translation';
|
||||
import { ChartMetadata, ChartPlugin } from '@superset-ui/chart';
|
||||
import transformProps from './transformProps';
|
||||
import thumbnail from './images/thumbnail.png';
|
||||
|
||||
const metadata = new ChartMetadata({
|
||||
credits: ['https://github.com/wa0x6e/cal-heatmap'],
|
||||
description: '',
|
||||
name: t('Calendar Heatmap'),
|
||||
thumbnail,
|
||||
});
|
||||
|
||||
export default class ChordChartPlugin extends ChartPlugin {
|
||||
constructor() {
|
||||
super({
|
||||
loadChart: () => import('./ReactCalendar'),
|
||||
metadata,
|
||||
transformProps,
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
/* eslint-disable sort-keys */
|
||||
export default function transformProps(chartProps) {
|
||||
const { height, formData, payload, datasource } = chartProps;
|
||||
const {
|
||||
cellPadding,
|
||||
cellRadius,
|
||||
cellSize,
|
||||
linearColorScheme,
|
||||
showLegend,
|
||||
showMetricName,
|
||||
showValues,
|
||||
steps,
|
||||
xAxisTimeFormat,
|
||||
yAxisFormat,
|
||||
} = formData;
|
||||
|
||||
const { verboseMap } = datasource;
|
||||
|
||||
return {
|
||||
height,
|
||||
data: payload.data,
|
||||
cellPadding,
|
||||
cellRadius,
|
||||
cellSize,
|
||||
linearColorScheme,
|
||||
showLegend,
|
||||
showMetricName,
|
||||
showValues,
|
||||
steps,
|
||||
timeFormat: xAxisTimeFormat,
|
||||
valueFormat: yAxisFormat,
|
||||
verboseMap,
|
||||
};
|
||||
}
|
@ -0,0 +1,141 @@
|
||||
/* [LICENSE TBD] */
|
||||
/* Cal-HeatMap CSS */
|
||||
|
||||
.cal-heatmap-container {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.cal-heatmap-container .graph-label
|
||||
{
|
||||
fill: #999;
|
||||
font-size: 10px
|
||||
}
|
||||
|
||||
.cal-heatmap-container .graph, .cal-heatmap-container .graph-legend rect {
|
||||
shape-rendering: crispedges
|
||||
}
|
||||
|
||||
.cal-heatmap-container .graph-rect
|
||||
{
|
||||
fill: #ededed
|
||||
}
|
||||
|
||||
.cal-heatmap-container .graph-subdomain-group rect:hover
|
||||
{
|
||||
stroke: #000;
|
||||
stroke-width: 1px
|
||||
}
|
||||
|
||||
.cal-heatmap-container .subdomain-text {
|
||||
font-size: 8px;
|
||||
fill: #999;
|
||||
pointer-events: none
|
||||
}
|
||||
|
||||
.cal-heatmap-container .hover_cursor:hover {
|
||||
cursor: pointer
|
||||
}
|
||||
|
||||
.cal-heatmap-container .qi {
|
||||
background-color: #999;
|
||||
fill: #999
|
||||
}
|
||||
|
||||
/*
|
||||
Remove comment to apply this style to date with value equal to 0
|
||||
.q0
|
||||
{
|
||||
background-color: #fff;
|
||||
fill: #fff;
|
||||
stroke: #ededed
|
||||
}
|
||||
*/
|
||||
|
||||
.cal-heatmap-container .q1
|
||||
{
|
||||
background-color: #dae289;
|
||||
fill: #dae289
|
||||
}
|
||||
|
||||
.cal-heatmap-container .q2
|
||||
{
|
||||
background-color: #cedb9c;
|
||||
fill: #9cc069
|
||||
}
|
||||
|
||||
.cal-heatmap-container .q3
|
||||
{
|
||||
background-color: #b5cf6b;
|
||||
fill: #669d45
|
||||
}
|
||||
|
||||
.cal-heatmap-container .q4
|
||||
{
|
||||
background-color: #637939;
|
||||
fill: #637939
|
||||
}
|
||||
|
||||
.cal-heatmap-container .q5
|
||||
{
|
||||
background-color: #3b6427;
|
||||
fill: #3b6427
|
||||
}
|
||||
|
||||
.cal-heatmap-container rect.highlight
|
||||
{
|
||||
stroke:#444;
|
||||
stroke-width:1
|
||||
}
|
||||
|
||||
.cal-heatmap-container text.highlight
|
||||
{
|
||||
fill: #444
|
||||
}
|
||||
|
||||
.cal-heatmap-container rect.highlight-now
|
||||
{
|
||||
stroke: red
|
||||
}
|
||||
|
||||
.cal-heatmap-container text.highlight-now
|
||||
{
|
||||
fill: red;
|
||||
font-weight: 800
|
||||
}
|
||||
|
||||
.cal-heatmap-container .domain-background {
|
||||
fill: none;
|
||||
shape-rendering: crispedges
|
||||
}
|
||||
|
||||
.ch-tooltip {
|
||||
padding: 10px;
|
||||
background: #222;
|
||||
color: #bbb;
|
||||
font-size: 12px;
|
||||
line-height: 1.4;
|
||||
width: 140px;
|
||||
position: absolute;
|
||||
z-index: 99999;
|
||||
text-align: center;
|
||||
border-radius: 2px;
|
||||
box-shadow: 2px 2px 2px rgba(0,0,0,0.2);
|
||||
display: none;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.ch-tooltip::after{
|
||||
position: absolute;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-color: transparent;
|
||||
border-style: solid;
|
||||
content: "";
|
||||
padding: 0;
|
||||
display: block;
|
||||
bottom: -6px;
|
||||
left: 50%;
|
||||
margin-left: -6px;
|
||||
border-width: 6px 6px 0;
|
||||
border-top-color: #222;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user