mirror of
https://github.com/apache/superset.git
synced 2026-06-01 13:49:21 +00:00
feat(plugin): add plugin-chart-cartodiagram (#25869)
Co-authored-by: Jakob Miksch <jakob@meggsimum.de>
This commit is contained in:
@@ -0,0 +1,183 @@
|
||||
/**
|
||||
* 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/core';
|
||||
import * as echarts from 'echarts';
|
||||
import { createRef, FC, useEffect } from 'react';
|
||||
import { ZoomConfigsChartProps } from './types';
|
||||
import {
|
||||
createDragGraphicOptions,
|
||||
dataToZoomConfigs,
|
||||
MAX_ZOOM_LEVEL,
|
||||
MIN_ZOOM_LEVEL,
|
||||
zoomConfigsToData,
|
||||
} from './zoomUtil';
|
||||
|
||||
export const ZoomConfigsChart: FC<ZoomConfigsChartProps> = ({
|
||||
value,
|
||||
onChange = () => {},
|
||||
}) => {
|
||||
const ref = createRef<HTMLDivElement>();
|
||||
|
||||
useEffect(() => {
|
||||
if (!ref.current) {
|
||||
return undefined;
|
||||
}
|
||||
// TODO check if this can be applied here
|
||||
if (value === null || value === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let timer: number;
|
||||
|
||||
const barWidth = 15;
|
||||
const data = zoomConfigsToData(value.values);
|
||||
|
||||
const chart = echarts.init(ref.current);
|
||||
|
||||
const option = {
|
||||
xAxis: {
|
||||
min: 0,
|
||||
name: t('Size in pixels'),
|
||||
nameLocation: 'center',
|
||||
nameGap: 25,
|
||||
},
|
||||
yAxis: {
|
||||
type: 'category',
|
||||
min: MIN_ZOOM_LEVEL,
|
||||
max: MAX_ZOOM_LEVEL,
|
||||
name: t('Zoom level'),
|
||||
nameLocation: 'center',
|
||||
nameRotate: 90,
|
||||
nameGap: 25,
|
||||
},
|
||||
dataset: {
|
||||
dimensions: ['width', 'height', 'zoom'],
|
||||
source: data,
|
||||
},
|
||||
grid: {
|
||||
top: 12,
|
||||
left: 40,
|
||||
},
|
||||
series: [
|
||||
{
|
||||
id: 'width',
|
||||
name: 'width',
|
||||
type: 'bar',
|
||||
animation: false,
|
||||
showBackground: true,
|
||||
barWidth,
|
||||
barGap: '0%',
|
||||
label: {
|
||||
show: true,
|
||||
formatter: '{a}: {@width}',
|
||||
},
|
||||
encode: {
|
||||
x: 'width',
|
||||
y: 'zoom',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'height',
|
||||
name: 'height',
|
||||
type: 'bar',
|
||||
animation: false,
|
||||
showBackground: true,
|
||||
barWidth,
|
||||
barGap: '0%',
|
||||
label: {
|
||||
show: true,
|
||||
formatter: '{a}: {@height}',
|
||||
},
|
||||
encode: {
|
||||
x: 'height',
|
||||
y: 'zoom',
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
chart.setOption(option);
|
||||
|
||||
const onDrag = function (
|
||||
this: any,
|
||||
dataIndex: number | undefined,
|
||||
itemIndex: number,
|
||||
) {
|
||||
if (dataIndex === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line react/no-this-in-sfc
|
||||
const newPosition = chart.convertFromPixel('grid', [this.x, this.y]);
|
||||
if (typeof newPosition === 'number') {
|
||||
return;
|
||||
}
|
||||
|
||||
const roundedPosition = Math.round(newPosition[0]);
|
||||
const newRoundedPosition = roundedPosition < 0 ? 0 : roundedPosition;
|
||||
data[dataIndex][itemIndex] = newRoundedPosition;
|
||||
chart.setOption({
|
||||
dataset: {
|
||||
source: data,
|
||||
},
|
||||
});
|
||||
if (timer !== undefined) {
|
||||
clearTimeout(timer);
|
||||
}
|
||||
timer = window.setTimeout(() => {
|
||||
const newValues = dataToZoomConfigs(data);
|
||||
onChange({ ...value, values: newValues });
|
||||
}, 200);
|
||||
};
|
||||
|
||||
const onWidthDrag = function (this: any, dataIndex: number | undefined) {
|
||||
onDrag.call(this, dataIndex, 0);
|
||||
};
|
||||
const onHeightDrag = function (this: any, dataIndex: number | undefined) {
|
||||
onDrag.call(this, dataIndex, 1);
|
||||
};
|
||||
|
||||
// TODO listen to resize event and redraw chart
|
||||
// TODO rearrange the draghandlers when the chart range changes
|
||||
chart.setOption({
|
||||
graphic: createDragGraphicOptions({
|
||||
data,
|
||||
onWidthDrag,
|
||||
onHeightDrag,
|
||||
barWidth,
|
||||
chart,
|
||||
}),
|
||||
});
|
||||
// chart.on('click', 'series', (params) => {
|
||||
// const clickedData: number[] = params.data as number[];
|
||||
// const zoomLevel: number = clickedData[2];
|
||||
// // TODO we have to set a flag on value that indicates, which zoomLevel should be active
|
||||
// // TODO maybe it's better to add a callback to the map that triggers when the zoom
|
||||
// // in the map changes. This can then be displayed on the zoom chart.
|
||||
// });
|
||||
|
||||
return () => {
|
||||
clearTimeout(timer);
|
||||
};
|
||||
}, [value]);
|
||||
|
||||
return <div ref={ref} style={{ height: '1300px', width: '100%' }} />;
|
||||
};
|
||||
|
||||
export default ZoomConfigsChart;
|
||||
Reference in New Issue
Block a user