Superset 0.34集成Echarts地图并下钻(0.36可参考)

Superset 地图(下钻)开发

在这里插入图片描述

1, 左侧控制栏开发

新增 assets/src/explore/controlPanels/EchartsMap.js

import { t } from '@superset-ui/translation';

export default {
    controlPanelSections: [
        {
            label: t('GROUP BY'),
            expanded: true,
            controlSetRows: [
                ['groupby'],
                ['metrics'],
                ['percent_metrics'],
                ['include_time'],
                ['timeseries_limit_metric', 'order_desc'],
            ],
        },
        {
            label: t('NOT GROUPED BY'),
            description: t('Use this section if you want to query atomic rows'),
            controlSetRows: [
                ['all_columns'],
                ['order_by_cols'],
            ],
        },
        {
            label: t('Options'),
            controlSetRows: [
                ['table_timestamp_format'],
                ['row_limit', 'page_length'],
                ['include_search', 'table_filter'],
            ],
        }
    ],
    controlOverrides: {
        metrics: {
            validators: [],
        },
        time_grain_sqla: {
            default: null,
        },
    }

};

2, 左侧栏注册

assets/src/explore/controlPanels/index.js

参照案例即可

3, 右侧渲染层开发

在这里插入图片描述

EchartsMap.js (主要渲染文件)

import echarts from 'echarts';
import d3 from 'd3';
import PropTypes from 'prop-types';
import china from 'echarts/map/js/china'
import {city_json, province_json} from './map'


// 数据类型检查
const propTypes = {
    width: PropTypes.number,
    height: PropTypes.number,
};

function EchartsMap(element, props) {

    const {
        width,
        height,
        data,
        formData
    } = props; // transformProps.js 返回的数据


    const div = d3.select(element);
    const sliceId = 'echarts-map-' + 10;
    const html = '<div id="' + sliceId + '" style="height:' + height + 'px; width:' + width + 'px;border:1px"></div>';
    div.html(html);

    let myChart = echarts.init(document.getElementById(sliceId), 'light');
    document.oncontextmenu = function () {
        return false;
    }; // 取消浏览器的邮件点击事件


    let groupbys = formData['groupby'];
    let metrics = formData['metrics'];
    let lab = 1;

    let data_value = data[groupbys[0]];

    let data_name = new Set();

    let option = {
        title: {
            subtext: '点击进入下一级,右键返回中国地图',
            x: 'center',
            bottom: '5%'
        },
        tooltip: {
            trigger: 'item',
            formatter: function (params) {
                let res = params.name + '<br/>';
                let myseries = option.series;
                for (let i = 0; i < myseries.length; i++) {
                    for (let j = 0; j < myseries[i].data.length; j++) {
                        if (myseries[i].data[j].name == params.name) {
                            res += myseries[i].name + ' : ' + myseries[i].data[j].value + '</br>';
                        }
                    }
                }
                return res;
            }
        },
        toolbox: {
            show: true,
            orient: 'vertical',
            left: 'right',
            top: 'center',
            feature: {
                dataView: {readOnly: false},
                restore: {},
                saveAsImage: {}
            }
        },
        visualMap: {
            //type: 'continuous',
            min: 0,
            max: data['max'],
            text: ['高', '低'],
            realtime: false,
            calculable: true,
            //right:'-15%',
            inRange: {
                color: ['#d0f4fc',
                    '#a9dbf6',
                    '#9cd3f4',
                    '#93cdf3',
                    '#83c2f0',
                    '#6eb5ed',
                    'yellow']
            }
        },
        series: getSeries('china')
    };


    // 使用刚指定的配置项和数据显示图表。
    myChart.setOption(option);

    // 异步加载其余地图
    province_json.map(item => {
        $.getJSON('http://' + window.document.location.host + '/static/assets/spec/echarts/province/' + item['value'] + '.json', function (res) {
            echarts.registerMap(item['name'], res);
        })
    });


    //用点击事件来切换地图实现下钻功能,该省份有值时才可以下钻
    myChart.on('click', function (chinaParam) {
        if (data_name.has(chinaParam.name) && lab === 1 && groupbys.length > 1) {
            lab = 2;
            data_value = data[groupbys[1]];
            let result_value = [];
            data_value.map(item => {
                let midValue = [];
                item['data'].map(opt => {
                    if (opt['key'] === chinaParam.name) {
                        midValue.push({'name': opt['name'], 'value': opt['value']})
                    }
                });
                result_value.push({'name': item['name'], 'data': midValue})
            });

            data_value = result_value;
            option = myChart.getOption();
            option.series = getSeries(chinaParam.name);
            myChart.setOption(option);

            city_json.map(item => {
                if (item['dep'] === chinaParam.name) {
                    $.getJSON('http://' + window.document.location.host + '/static/assets/spec/echarts/citys/' + item['value'] + '.json', function (res) {
                        echarts.registerMap(item['name'], res);
                    })
                }
            })
        }

        if (data_name.has(chinaParam.name) && lab === 2 && groupbys.length > 2) {
            lab = 3;
            data_value = data[groupbys[2]];
            let result_value = [];
            data_value.map(item => {
                let midValue = [];
                item['data'].map(opt => {
                    if (opt['key'] === chinaParam.name) {
                        midValue.push({'name': opt['name'], 'value': opt['value']})
                    }
                });
                result_value.push({'name': item['name'], 'data': midValue})
            });

            data_value = result_value;
            option = myChart.getOption();
            option.series = getSeries(chinaParam.name);
            myChart.setOption(option);


        }
    });


    //用双击事件来返回最上层的中国地图,当不在中国地图时生效
    myChart.on('contextmenu', function (chinaParam) {
        if (myChart.getOption().series[0].map !== 'china') {
            lab = 1;
            data_value = data[groupbys[0]];
            option = myChart.getOption();
            option.series = getSeries('china');
            myChart.setOption(option);
        }
    });


    function getSeries(type) {
        let result = [];
        data_name.clear();
        metrics.map(opt => {
            data_value.map(datax => {
                if (datax['name'] === opt) {
                    datax['data'].map(item => {
                        data_name.add(item['name']);
                    });

                    let midx = {
                        name: datax['name'],
                        type: 'map',
                        map: type,
                        selectedMode: 'single',
                        roam: 'scale',
                        data: datax['data'],
                        label: {
                            normal: {
                                show: true,
                                textStyle: {color: "#b6a38a"}
                            },
                            emphasis: {
                                show: true,
                                textStyle: {color: "#ff6347"}
                            }
                        },
                        itemStyle: {
                            emphasis: {
                                areaColor: "#2e4783",
                                borderWidth: 0
                            }
                        }
                    };
                    result.push(midx);
                }
            })
        });

        return result;

    }

}

EchartsMap.displayName = 'Echarts Map';
EchartsMap.propTypes = propTypes;

export default EchartsMap;

**EchartsMapChartPlugin.js ** 插件文件

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({
    name: t('Echarts Map'),
    description: '',
    credits: ['https://www.echartsjs.com/examples/en/editor.html?c=mix-line-bar'],
    thumbnail,
});

export default class MixLineBarChartPlugin extends ChartPlugin {
    constructor() {
        super({
            metadata,
            transformProps,
            loadChart: () => import('./ReactEchartsMap.js'), // 前端渲染逻辑
        });
    }
}

map.js 地图文件

const province_json = [
    {"name": '北京', value: 110000},
    {"name": '天津', value: 120000},
    .......
    {"name": '香港', value: 810000},
    {"name": '澳门', value: 820000},
];
const city_json = [
    {'name': '石家庄市', 'value': 130100, 'dep': '河北'},
    {'name': '唐山市', 'value': 130200, 'dep': '河北'},
    {'name': '秦皇岛市', 'value': 130300, 'dep': '河北'},
    .....
    {'name': '可克达拉市', 'value': 659008, 'dep': '新疆'},
    {'name': '昆玉市', 'value': 659009, 'dep': '新疆'}
];

export {city_json, province_json}

ReactEchartsMap.js

import reactify from '@superset-ui/chart/esm/components/reactify';
import Component from './EchartsMap';

export default reactify(Component);

transformProps.js 数据传递的js

export default function transformProps(chartProps) {

    const {width, height, payload, formData} = chartProps;
    // formData 前端页面的数据
    // queryData  后端返回的数据


    return {
        data: payload.data,
        width,
        height,
        formData,
    };

}

4, 右侧模块注册

assets/src/visualizations/presets/MainPreset.js 参照其它案例即可完成

5, 修改package.json

"echarts": "^4.7.0",

6, 后端开发

viz.py 添加如下内容

class EchartsMap(NVD3Viz):
    """ echarts map viz """
    viz_type = 'echarts_map'  # 对应前端名字
    verbose_name = _('echarts_map')
    credits = 'a <a href="https://github.com/airbnb/superset">Superset</a> original'
    is_timeseries = False

    def run_extra_queries(self):
        qry = super().query_obj()
        metrics = qry['metrics']
        groupbys = qry['groupby']
        by = []
        self.dataframes = {}
        for groupby in groupbys:
            by.append(groupby)
            for metric in metrics:
                qry.update({'metrics': [metric],'groupby':by})
                df = self.get_df_payload(query_obj=qry).get("df")
                self.dataframes[groupby+ '_' +metric] = df

    def get_data(self, df):
        metrics = self.form_data.get("metrics") or []
        groupbys = self.form_data.get("groupby") or []
        d = {}
        max_num = 0
        index = 0
        for groupby in groupbys:
            index = index + 1
            midlist = []
            for metric in metrics:
                df = self.dataframes.get(groupby+ '_' +metric)
                list = df.itertuples(index=False)
                if index == 1:
                    data = [
                        {'name': row[0], 'value': row[1]} for row in list
                    ]
                    mid_max = max([data[i].get('value') for i in range(len(data))])
                    if mid_max > max_num:
                        max_num = mid_max
                else:
                    data = [
                        {'name': row[index-1], 'value': row[index],'key':row[index-2]} for row in list
                    ]
                midlist.append({'name': metric, 'data': data})
            d.update({groupby: midlist})
        d.update({'max': max_num})
        return d

7, Q&A

实现echarts三级下钻,里面使用了动态加载地图数据,文件中没有提供,后续提供到下载

数据是一次加载,会有些问题,可以使用ajax异步,后面开发表格下钻时,已经实现过ajax加载数据,可以查看

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值