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>

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章