01 【ArcGIS JS API + eCharts系列】实现地图上二维图表的绘制

概述

ArcGIS API for JavaScript目前提供的图表绘制接口十分有限,而且样式也并不美观,当我们在地图上添加相应的图表的时候,还是需要结合目前市面上其他的图表可视化插件来做。本文就介绍下如何使用ArcGIS API for JavaScript 4.14版本和eCharts 4.7.0来实现这个需求。文章实现参考【GIS之家】的博客内容。首先来看下最终的效果:

实现思路

此需求的实现完全是纯前端的解决方法,接下来简要介绍下实现思路:

  • 先实现一张基础的二维地图;
  • 在地图上添加eCharts图表;
  • 监听地图的视图变化事件,重绘图表大小,实现图表跟随地图的伪缩放。

具体实现过程

1、先用ArcGIS API for JavaScript初始化一张二维地图,代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>echarts和ArcGIS JS API结合</title>

    <link rel="stylesheet" href="https://js.arcgis.com/4.14/esri/themes/light/main.css" />
    <style>
        body {
            margin: 0 !important;
        }
        #mapview {
            position: absolute;
            width: 100%;
            height: 100%;
        }
    </style>
</head>
<body>
    <div id="mapview"></div>

    <script src="https://js.arcgis.com/4.14/"></script>
    <script>
        require(["esri/Map", "esri/views/MapView","esri/Basemap", "esri/layers/TileLayer"], function(Map, MapView, Basemap, TileLayer) {

            var basemap = new Basemap({      //此处自定义一张暗夜色的底图,并没有用JS API自带的底图
                baseLayers: [
                    new TileLayer({
                        url: "http://map.geoq.cn/arcgis/rest/services/ChinaOnlineStreetPurplishBlue/MapServer",
                        title: "Basemap"
                    })
                ],
                title: "basemap",
                id: "basemap"
            });

            var map = new Map({
                basemap: basemap
            });
            var view = new MapView({
                container: "mapview", 
                map: map, 
                zoom: 8, 
                center: [104.072043,30.663724]     //地图中心点为成都
            });
      });
    </script>
</body>
</html>

2、然后在地图上绘制eCharts图表。说白了就是在mapview这个DOM元素内添加存放图表的div元素,并设置初始大小,这就意味着页面中要求引入eCharts和相应的jQuery开发包,我们只需要去官网下载即可,代码如下:

引入开发包:

    <script src="./libs/jquery-3.4.1.min.js"></script>
    <script src="./libs/echarts.js"></script>

地图上绘制图表:

            //初始化图表信息函数
			function echartsMapInit() {
                echartsInfos = [];      //绘制函数里定义一个存放图表配置的全局数组
                echartsInfos.push({
                    x: 104.072043,      //图表在地图上绘制的位置
                    y: 30.663724,
                    content: '<div id="info1" style="height:150px;width:300px;position:absolute;"></div>',      //存放图表的DOM元素
                    id:"info1",
                    echartsObj:null,
                    option:{                   //图表的配置信息,具体参数可到eCharts官网查看
                        color: ['#3398DB'],
                        tooltip : {
                            trigger: 'axis',
                            axisPointer : {            
                                type : 'shadow'        
                            }
                        },
                        grid: {
                            left: '3%',
                            right: '4%',
                            bottom: '3%',
                            top: '3%',
                            containLabel: true,
                        },
                        xAxis : [
                            {
                                type : 'category',
                                data : ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
                                axisTick: {
                                    alignWithLabel: true
                                },              
                                axisLabel:{  
                                    interval:0,
                                    rotate:-30,
                                },  
                                axisLine:{  
                                    lineStyle:{  
                                        color:'#FFFFFF',  
                                        width:1,
                                    }  
                                }
                            }
                        ],
                        yAxis : [
                            {
                                type : 'value',
                                splitLine: {  
                                    lineStyle: {  
                                        color: ['#0087ED']  
                                    }  
                                },  
                                nameTextStyle: {  
                                    color: ['#FFFFFF']  
                                    },  
                                axisLine:{  
                                    lineStyle:{  
                                        color:'#FFFFFF',  
                                        width:1,
                                    }  
                                }
                            }
                        ],
                        series : [
                            {
                                name:'直接访问',
                                type:'bar',
                                barWidth: '60%',
                                data:[10, 52, 200, 334, 390, 330, 220]
                            }
                        ]
                    }
                });

                echartsInfos.push({       //需要绘制的第二个图表的相关信息
                    x: 106.492447,
                    y: 29.608168,
                    content: '<div id="info2" style="height:150px;width:300px;position:absolute;"></div>',
                    id:"info2",
                    echartsObj:null,
                    option:{
                        title: {
                            text: ''
                        },
                        tooltip : {
                            trigger: 'axis',
                            axisPointer: {
                                type: 'cross',
                                label: {
                                    backgroundColor: '#6a7985'
                                }
                            }
                        },
                        legend: {
                            data:['视频广告','直接访问','搜索引擎'],
                            textStyle:{  
                                color: ['#FFFFFF']  
                            },  
                        },
                        toolbox: {
                            feature: {
                                saveAsImage: {}
                            }
                        },
                        grid: {
                            left: '3%',
                            right: '4%',
                            bottom: '3%',
                            top: '10%',
                            containLabel: true
                        },
                        xAxis : [
                            {
                                type : 'category',
                                boundaryGap : false,
                                data : ['周一','周二','周三','周四','周五','周六','周日'],
                                nameTextStyle: {  
                                    color: ['#FFFFFF']  
                                },  
                                axisLine:{  
                                    lineStyle:{  
                                        color:'#FFFFFF',  
                                        width:1,
                                    }  
                                }
                            }
                        ],
                        yAxis : [
                            {
                                type : 'value',
                                nameTextStyle: {  
                                    color: ['#FFFFFF']  
                                },  
                                axisLine:{  
                                    lineStyle:{  
                                        color:'#FFFFFF',  
                                        width:1,
                                    }  
                                }
                            }
                        ],
                        series : [
                            {
                                name:'视频广告',
                                type:'line',
                                stack: '总量',
                                areaStyle: {},
                                data:[150, 232, 201, 154, 190, 330, 410]
                            },
                            {
                                name:'直接访问',
                                type:'line',
                                stack: '总量',
                                areaStyle: {normal: {}},
                                data:[320, 332, 301, 334, 390, 330, 320]
                            },
                            {
                                name:'搜索引擎',
                                type:'line',
                                stack: '总量',
                                label: {
                                    normal: {
                                        show: true,
                                        position: 'top'
                                    }
                                },
                                areaStyle: {normal: {}},
                                data:[820, 932, 901, 934, 1290, 1330, 1320]
                            }
                        ]
                    }
                });

                for (var i = 0; i < echartsInfos.length; i++) {
                        var echartsInfo = echartsInfos[i];
                        
                        var mapPoint = {             //坐标转换,将地理坐标转为屏幕坐标
                            x: echartsInfo.x,
                            y: echartsInfo.y,
                            // spatialReference: {
                            //     wkid: view.spatialReference.wkid
                            // }
                            spatialReference: {
                                wkid: 4326
                            }
                        };
                        var screenPoint = view.toScreen(mapPoint);
                        var obj = {};            //重新定义一个图表配置信息的对象
                        obj.x =screenPoint.x;
                        obj.y =screenPoint.y;
                        obj.content = echartsInfo.content;
                        obj.id = echartsInfo.id;
                        obj.option = echartsInfo.option;
                        obj.echartsObj  = echartsInfo.echartsObj;
                        echartsInfos[i].echartsObj = loadEchartsMap(obj);
                }
            };

			//绘制图表函数
            function loadEchartsMap(obj) {
                $("#mapview").append(obj.content);           //往mapview追加存放图表的DOM元素
                
                var dom = document.getElementById(obj.id);     //绘制图表
                var myChart = echarts.init(dom);
                myChart.setOption(obj.option);

                positionEchartsMap(obj);        //调整图表位置及大小
                return myChart;
            }

3、图表信息初始化完成之后,要重新调整图表的位置和大小,此处图表的大小要跟随地图实现缩放,所以要获取地图视图的层级,根据层级来调整图表大小,代码如下:

            //统计图窗口位置
            function relocatePopup() {
                for (var i = 0; i < echartsInfos.length; i++) {
                    var echartsInfo = echartsInfos[i];
                    //坐标转换
                    var mapPoint = {
                    	x: echartsInfo.x,
                    	y: echartsInfo.y,
                    	//spatialReference: view.spatialReference
                    	spatialReference: {
                        	wkid: 4326
                    	}
                    };
                    var screenPoint = view.toScreen(mapPoint);
                    var obj = {};
                    obj.x =screenPoint.x;
                    obj.y =screenPoint.y;
                    obj.option = echartsInfo.option;
                    obj.id = echartsInfo.id;
                    obj.echartsObj  = echartsInfo.echartsObj;
                    
                    positionEchartsMap(obj);
            }
            };

			//调整图表位置及大小函数
            function positionEchartsMap(obj) {
                $('#' + obj.id).css('transform', 'translate3d(' + obj.x + 'px, ' + obj.y + 'px, 0)');

                switch(view.zoom) {
                    case 0:
                    case 1:
                    case 2:
                    case 3:
                    case 4:
                    case 5:
                        $('#'+obj.id).css('height', '50px');
                        $('#'+obj.id).css('width', '100px');
                        break;
                    case 6:
                    case 7:
                    case 8:
                        $('#'+obj.id).css('height', '120px');
                        $('#'+obj.id).css('width', '200px');
                        break;
                    case 9:
                    case 10:
                        $('#'+obj.id).css('height', '150px');
                        $('#'+obj.id).css('width', '300px');
                        break;
                    case 11:
                    case 12:
                        $('#'+obj.id).css('height', '200px');
                        $('#'+obj.id).css('width', '350px');
                        break;
                    default:
                        $('#'+obj.id).css('height', '250px');
                        $('#'+obj.id).css('width', '400px');

                }
                if(obj.echartsObj) {
                    obj.echartsObj.resize(); 
                } 
            };

4、最后监听地图视图大小改变事件来调用relocatePopup方法重绘图表,如下:

            view.when(function() {
                //监听地图变化事件,刷新统计图位置
                view.watch("extent", function() {
                    relocatePopup();
                });
                view.watch("rotation", function() {
                    relocatePopup();
                });

                //地图加载完,初始化统计图
                echartsMapInit();
            });

5、完成以上步骤之后,就用纯前端技术实现了ArcGIS JS API和eCharts的结合来绘制二维图表的功能。

附全部代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>echarts和ArcGIS JS API结合</title>

    <link rel="stylesheet" href="https://js.arcgis.com/4.14/esri/themes/light/main.css" />
    <style>
        body {
            margin: 0 !important;
        }
        #mapview {
            position: absolute;
            width: 100%;
            height: 100%;
        }
    </style>
</head>
<body>
    <div id="mapview"></div>

    <script src="./libs/jquery-3.4.1.min.js"></script>
    <script src="./libs/echarts.js"></script>
    <script src="https://js.arcgis.com/4.14/"></script>
    <script>
        require(["esri/Map", "esri/views/MapView","esri/Basemap", "esri/layers/TileLayer"], function(Map, MapView, Basemap, TileLayer) {

            var basemap = new Basemap({
                baseLayers: [
                    new TileLayer({
                        url: "http://map.geoq.cn/arcgis/rest/services/ChinaOnlineStreetPurplishBlue/MapServer",
                        title: "Basemap"
                    })
                ],
                title: "basemap",
                id: "basemap"
            });

            var map = new Map({
                basemap: basemap
            });
            var view = new MapView({
                container: "mapview", 
                map: map, 
                zoom: 8, 
                center: [104.072043,30.663724] 
            });

            view.when(function() {
                view.watch("extent", function() {
                    relocatePopup();
                });
                view.watch("rotation", function() {
                    relocatePopup();
                });

                echartsMapInit();
            });

            function relocatePopup(e) {
                for (var i = 0; i < echartsInfos.length; i++) {
                    var echartsInfo = echartsInfos[i];

                    var mapPoint = {
                    x: echartsInfo.x,
                    y: echartsInfo.y,
                    //spatialReference: view.spatialReference
                    spatialReference: {
                        wkid: 4326
                    }
                    };
                    var screenPoint = view.toScreen(mapPoint);
                    var obj = {};
                    obj.x =screenPoint.x;
                    obj.y =screenPoint.y;
                    obj.option = echartsInfo.option;
                    obj.id = echartsInfo.id;
                    obj.echartsObj  = echartsInfo.echartsObj;

                    positionEchartsMap(obj);
            }
            };

            function positionEchartsMap(obj) {
                $('#' + obj.id).css('transform', 'translate3d(' + obj.x + 'px, ' + obj.y + 'px, 0)');

                switch(view.zoom) {
                    case 0:
                    case 1:
                    case 2:
                    case 3:
                    case 4:
                    case 5:
                        $('#'+obj.id).css('height', '50px');
                        $('#'+obj.id).css('width', '100px');
                        break;
                    case 6:
                    case 7:
                    case 8:
                        $('#'+obj.id).css('height', '120px');
                        $('#'+obj.id).css('width', '200px');
                        break;
                    case 9:
                    case 10:
                        $('#'+obj.id).css('height', '150px');
                        $('#'+obj.id).css('width', '300px');
                        break;
                    case 11:
                    case 12:
                        $('#'+obj.id).css('height', '200px');
                        $('#'+obj.id).css('width', '350px');
                        break;
                    default:
                        $('#'+obj.id).css('height', '250px');
                        $('#'+obj.id).css('width', '400px');

                }
                if(obj.echartsObj) {
                    obj.echartsObj.resize(); 
                } 
            };

            function echartsMapInit() {
                echartsInfos = [];
                echartsInfos.push({
                    x: 104.072043,
                    y: 30.663724,
                    content: '<div id="info1" style="height:150px;width:300px;position:absolute;"></div>',
                    id:"info1",
                    echartsObj:null,
                    option:{
                        color: ['#3398DB'],
                        tooltip : {
                            trigger: 'axis',
                            axisPointer : {            
                                type : 'shadow'        
                            }
                        },
                        grid: {
                            left: '3%',
                            right: '4%',
                            bottom: '3%',
                            top: '3%',
                            containLabel: true,
                            //y2: 140
                        },
                        xAxis : [
                            {
                                type : 'category',
                                data : ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
                                axisTick: {
                                    alignWithLabel: true
                                },              
                                axisLabel:{  
                                    interval:0,
                                    rotate:-30,
                                },  
                                axisLine:{  
                                    lineStyle:{  
                                        color:'#FFFFFF',  
                                        width:1,
                                    }  
                                }
                            }
                        ],
                        yAxis : [
                            {
                                type : 'value',
                                splitLine: {  
                                    lineStyle: {  
                                        color: ['#0087ED']  
                                    }  
                                },  
                                nameTextStyle: {  
                                    color: ['#FFFFFF']  
                                    },  
                                axisLine:{  
                                    lineStyle:{  
                                        color:'#FFFFFF',  
                                        width:1,
                                    }  
                                }
                            }
                        ],
                        series : [
                            {
                                name:'直接访问',
                                type:'bar',
                                barWidth: '60%',
                                data:[10, 52, 200, 334, 390, 330, 220]
                            }
                        ]
                    }
                });

                echartsInfos.push({
                    x: 106.492447,
                    y: 29.608168,
                    content: '<div id="info2" style="height:150px;width:300px;position:absolute;"></div>',
                    id:"info2",
                    echartsObj:null,
                    option:{
                        title: {
                            text: ''
                        },
                        tooltip : {
                            trigger: 'axis',
                            axisPointer: {
                                type: 'cross',
                                label: {
                                    backgroundColor: '#6a7985'
                                }
                            }
                        },
                        legend: {
                            data:['视频广告','直接访问','搜索引擎'],
                            textStyle:{  
                                color: ['#FFFFFF']  
                            },  
                        },
                        toolbox: {
                            feature: {
                                saveAsImage: {}
                            }
                        },
                        grid: {
                            left: '3%',
                            right: '4%',
                            bottom: '3%',
                            top: '10%',
                            containLabel: true
                        },
                        xAxis : [
                            {
                                type : 'category',
                                boundaryGap : false,
                                data : ['周一','周二','周三','周四','周五','周六','周日'],
                                nameTextStyle: {  
                                    color: ['#FFFFFF']  
                                },  
                                axisLine:{  
                                    lineStyle:{  
                                        color:'#FFFFFF',  
                                        width:1,
                                    }  
                                }
                            }
                        ],
                        yAxis : [
                            {
                                type : 'value',
                                nameTextStyle: {  
                                    color: ['#FFFFFF']  
                                },  
                                axisLine:{  
                                    lineStyle:{  
                                        color:'#FFFFFF',  
                                        width:1,
                                    }  
                                }
                            }
                        ],
                        series : [
                            {
                                name:'视频广告',
                                type:'line',
                                stack: '总量',
                                areaStyle: {},
                                data:[150, 232, 201, 154, 190, 330, 410]
                            },
                            {
                                name:'直接访问',
                                type:'line',
                                stack: '总量',
                                areaStyle: {normal: {}},
                                data:[320, 332, 301, 334, 390, 330, 320]
                            },
                            {
                                name:'搜索引擎',
                                type:'line',
                                stack: '总量',
                                label: {
                                    normal: {
                                        show: true,
                                        position: 'top'
                                    }
                                },
                                areaStyle: {normal: {}},
                                data:[820, 932, 901, 934, 1290, 1330, 1320]
                            }
                        ]
                    }
                });

                for (var i = 0; i < echartsInfos.length; i++) {
                        var echartsInfo = echartsInfos[i];

                        var mapPoint = {
                            x: echartsInfo.x,
                            y: echartsInfo.y,
                            // spatialReference: {
                            //     wkid: view.spatialReference.wkid
                            // }
                            spatialReference: {
                                wkid: 4326
                            }
                        };
                        var screenPoint = view.toScreen(mapPoint);
                        var obj = {};
                        obj.x =screenPoint.x;
                        obj.y =screenPoint.y;
                        obj.content = echartsInfo.content;
                        obj.id = echartsInfo.id;
                        obj.option = echartsInfo.option;
                        obj.echartsObj  = echartsInfo.echartsObj;
                        echartsInfos[i].echartsObj = loadEchartsMap(obj);
                }
            };

            function loadEchartsMap(obj) {

                $("#mapview").append(obj.content);

                var dom = document.getElementById(obj.id);
                var myChart = echarts.init(dom);
                myChart.setOption(obj.option);

                positionEchartsMap(obj);
                return myChart;
            }
      });
    </script>
</body>
</html>
发布了138 篇原创文章 · 获赞 201 · 访问量 28万+

猜你喜欢

转载自blog.csdn.net/qq_35117024/article/details/105058536