add pivot table

This commit is contained in:
Krist Wongsuphasawat 2019-01-31 11:37:11 -08:00 committed by Yongjie Zhao
parent 7586951f16
commit ca4d2747d2
11 changed files with 296 additions and 2 deletions

View File

@ -0,0 +1,34 @@
## @superset-ui/legacy-plugin-chart-pivot-table
[![Version](https://img.shields.io/npm/v/@superset-ui/legacy-plugin-chart-pivot-table.svg?style=flat-square)](https://img.shields.io/npm/v/@superset-ui/legacy-plugin-chart-pivot-table.svg?style=flat-square)
[![David (path)](https://img.shields.io/david/apache-superset/superset-ui.svg?path=packages%2Fsuperset-ui-legacy-plugin-chart-pivot-table&style=flat-square)](https://david-dm.org/apache-superset/superset-ui?path=packages/superset-ui-legacy-plugin-chart-pivot-table)
This plugin provides Pivot Table 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 PivottableChartPlugin from '@superset-ui/legacy-plugin-chart-pivot-table';
new PivottableChartPlugin()
.configure({ key: 'pivot-table' })
.register();
```
Then use it via `SuperChart`. See [storybook](https://apache-superset.github.io/superset-ui-legacy/?selectedKind=plugin-chart-pivot-table) for more details.
```js
<SuperChart
chartType="pivot-table"
chartProps={{
width: 600,
height: 600,
formData: {...},
payload: {
data: {...},
},
}}
/>
```

View File

@ -0,0 +1,44 @@
{
"name": "@superset-ui/legacy-plugin-chart-pivot-table",
"version": "0.0.0",
"description": "Superset Legacy Chart - Pivot Table",
"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": "^3.5.17",
"datatables.net-bs": "^1.10.15",
"prop-types": "^15.6.2"
},
"devDependencies": {
"@superset-ui/chart": "^0.9.x",
"@superset-ui/number-format": "^0.9.x",
"@superset-ui/translation": "^0.9.x"
},
"peerDependencies": {
"@superset-ui/chart": "^0.9.x",
"@superset-ui/number-format": "^0.9.x",
"@superset-ui/translation": "^0.9.x"
}
}

View File

@ -0,0 +1,109 @@
/**
* 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, babel/no-invalid-this, babel/new-cap */
import dt from 'datatables.net-bs';
import PropTypes from 'prop-types';
import { formatNumber } from '@superset-ui/number-format';
import fixTableHeight from './utils/fixTableHeight';
import 'datatables.net-bs/css/dataTables.bootstrap.css';
const { $ } = dt;
const propTypes = {
data: PropTypes.shape({
// TODO: replace this with raw data in SIP-6
html: PropTypes.string,
columns: PropTypes.arrayOf(
PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]),
),
}),
height: PropTypes.number,
columnFormats: PropTypes.objectOf(PropTypes.string),
numberFormat: PropTypes.string,
numGroups: PropTypes.number,
verboseMap: PropTypes.objectOf(PropTypes.string),
};
function PivotTable(element, props) {
const { data, height, columnFormats, numberFormat, numGroups, verboseMap } = props;
const { html, columns } = data;
const container = element;
const $container = $(element);
// payload data is a string of html with a single table element
container.innerHTML = html;
const cols = Array.isArray(columns[0]) ? columns.map(col => col[0]) : columns;
// jQuery hack to set verbose names in headers
const replaceCell = function replace() {
const s = $(this)[0].textContent;
$(this)[0].textContent = verboseMap[s] || s;
};
$container.find('thead tr:first th').each(replaceCell);
$container.find('thead tr th:first-child').each(replaceCell);
// jQuery hack to format number
$container.find('tbody tr').each(function eachRow() {
$(this)
.find('td')
.each(function each(i) {
const metric = cols[i];
const format = columnFormats[metric] || numberFormat || '.3s';
const tdText = $(this)[0].textContent;
if (!Number.isNaN(tdText) && tdText !== '') {
$(this)[0].textContent = formatNumber(format, tdText);
$(this).attr('data-sort', tdText);
}
});
});
if (numGroups === 1) {
// When there is only 1 group by column,
// we use the DataTable plugin to make the header fixed.
// The plugin takes care of the scrolling so we don't need
// overflow: 'auto' on the table.
container.style.overflow = 'hidden';
const table = $container.find('table').DataTable({
paging: false,
searching: false,
bInfo: false,
scrollY: `${height}px`,
scrollCollapse: true,
scrollX: true,
});
table
.column('-1')
.order('desc')
.draw();
fixTableHeight($container.find('.dataTables_wrapper'), height);
} else {
// When there is more than 1 group by column we just render the table, without using
// the DataTable plugin, so we need to handle the scrolling ourselves.
// In this case the header is not fixed.
container.style.overflow = 'auto';
container.style.height = `${height + 10}px`;
}
}
PivotTable.displayName = 'PivotTable';
PivotTable.propTypes = propTypes;
export default PivotTable;

View File

@ -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 './PivotTable';
export default reactify(Component);

View File

@ -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({
description: '',
name: t('Pivot Table'),
thumbnail,
useLegacyApi: true,
});
export default class PivotTableChartPlugin extends ChartPlugin {
constructor() {
super({
loadChart: () => import('./ReactPivotTable.js'),
metadata,
transformProps,
});
}
}

View File

@ -0,0 +1,33 @@
/**
* 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, datasource, formData, payload } = chartProps;
const { groupby, numberFormat } = formData;
const { columnFormats, verboseMap } = datasource;
return {
height,
data: payload.data,
columnFormats,
numGroups: groupby.length,
numberFormat,
verboseMap,
};
}

View File

@ -0,0 +1,13 @@
/**
* Fix the height of the table body of a DataTable with scrollY set
*/
export default function fixTableHeight($tableDom, height) {
const headHeight = $tableDom.find('.dataTables_scrollHead').height();
const filterHeight = $tableDom.find('.dataTables_filter').height() || 0;
const pageLengthHeight = $tableDom.find('.dataTables_length').height() || 0;
const paginationHeight = $tableDom.find('.dataTables_paginate').height() || 0;
const controlsHeight = pageLengthHeight > filterHeight ? pageLengthHeight : filterHeight;
$tableDom
.find('.dataTables_scrollBody')
.css('max-height', height - headHeight - controlsHeight - paginationHeight);
}

View File

@ -279,7 +279,7 @@ function Rose(element, props) {
let arcSt = computeArcStates(datum);
function tween(target, resFunc) {
return function(d) {
return function doTween(d) {
const interpolate = d3.interpolate(copyArc(d), copyArc(target));
return t => resFunc(Object.assign(d, interpolate(t)));

View File

@ -279,7 +279,7 @@ function Sunburst(element, props) {
.style('opacity', 1)
.style('stroke', null)
.style('stroke-width', null)
.each('end', function() {
.each('end', function end() {
d3.select(this).on('mouseenter', mouseenter);
});
}