基于Echarts插件的省市区多级地图下钻和返回功能实现

Echarts3的离线地图组件,比echart2更容易实现省市区多级离线地图的展示。

当然echart2也是可以实现,由于echarts是基于canvas,加载一个地图无非就是加载一张图。而这张图,则是利用每张地图边界的经纬度,组成的一个面。理论上,只要给出一张地图边缘点的集合,用echarts,准确还说用canvas技术就能画出任何我们想要展示的地图形状。

实现思路:为了实现多级(省市区)地图的相互切换,本文采用单击鼠标事件触发页面进行下一级地图(如:从全国地图到湖南省的地图),采用双击鼠标事件返回上一级地图(如:从湖南省地图返回全国地图)。返回的上一级地图的实现方式也可以采用鼠标右键事件实现。鼠标右键可能比双击返回更好,因为双击容易跟单击冲突。

实现工具:echarts插件、地图json文件。
全国省市区的离线json文件,已上传到github:

主要要两种实现方法:区别主要在于如何返回上一级。
方法1:双击地图返回上一级地图;
方法2:右键点击“返回上一级”按钮进行返回。
以具体的代码,来介绍两种方法,先介绍它们公用的函数:loadMap。该函数主要用于加载地图。$.getJSON为jquery插件的ajax函数。

/**
   加载地图:根据地图所在省市的行政编号,
   获取对应的json地图数据,然后向echarts注册该区域的地图
   最后加载地图信息
   @params {String} mapCode:地图行政编号,for example['中国':'100000', '湖南': '430000']
   @params {String} mapName: 地图名称
*/
function loadMap(mapCode, mapName) {
    $.getJSON('china-main-city/' + mapCode + '.json', function (data) {
         if (data) {
             //向echarts插件注册地图
             echarts.registerMap(mapName, data);
             var option = {
                tooltip: {
                    trigger: 'item',
                    formatter: '{b}'
                },
                series: [
                    {
                        name: '',
                        type: 'map',
                        mapType: mapName,
                        selectedMode : 'multiple',
                        label: {
                            normal: {
                                show: true
                            },
                            emphasis: {
                                show: true
                            }
                        },
                        data:[
                        ]
                    }
                ]
             };
             myChart.setOption(option);
             curMap = {
                mapCode: mapCode,
                mapName: mapName
             };     
         } else {
             alert('无法加载该地图');
         }       
    });
}

方法1:采用用户单击下钻地图到下级地图;双击地图返回上级地图。由于双击受单击影响,故双击事件的响应方法延迟了250毫秒。这样就可以一旦检测到了双击事件,就立刻解除单击的回调事件。这样图表就只会响应双击事件。当用户单击时,如果可以下钻,则将当前地图信息存储到栈(利用栈先进后出的特性)便于获取返回的地图信息。如下代码所示:

/**
   绑定用户切换地图区域事件
   cityMap对象存储着地图区域名称和区域的信息(name-code)
   当mapCode有值,说明可以切换到下级地图
   同时保存上级地图的编号和名称  
*/
myChart.on('mapselectchanged', function(params) {
    clearTimeout(timeFn);
    //由于单击事件和双击事件冲突,故单击的响应事件延迟250毫秒执行
    timeFn = setTimeout(function(){
        var name = params.batch[0].name;
        var mapCode = cityMap[name];
        if (!mapCode) {
            alert('无此区域地图显示');
            return;
        }
        loadMap(mapCode, name); 
        //将上一级地图信息压入mapStack
        mapStack.push({
            mapCode: curMap.mapCode,
            mapName: curMap.mapName
        }); 
    }, 250);   
});
/**
   绑定双击事件,并加载上一级地图
*/
myChart.on('dblclick', function(params) {
    //当双击事件发生时,清除单击事件,仅响应双击事件
    clearTimeout(timeFn);
    var map = mapStack.pop();
    if (!mapStack.length && !map) {
        alert('已经到达最上一级地图了');
        return;
    }
    loadMap(map.mapCode, map.mapName);
});

方法2:采用图表的右键事件,再点击“返回上一级”按钮进行返回。方法一相比方法二的优点就是无需采用定时器进行延迟,即单击的回调事件可以立刻响应,无需延迟250毫秒。如下代码所示:

/**
   绑定用户切换地图区域事件
   cityMap对象存储着地图区域名称和区域的信息(name-code)
   当mapCode有值说明可以切换到下级地图
   此时保存上级地图的编号和名称
*/
myChart.on('mapselectchanged', function(params) {   
    var name = params.batch[0].name;
    var mapCode = cityMap[name];
    if (!mapCode) {
        alert('无此区域地图显示');
        return;
    }
    loadMap(mapCode, name); 
    //将上一级地图信息压入mapStack
    mapStack.push({
        mapCode: curMap.mapCode,
        mapName: curMap.mapName
    }); 
});
/**
   绑定右键事件
*/
myChart.on('contextmenu', function(params) {
   $('#contextMenu').css({
       left: params.event.offsetX,
       top: params.event.offsetY
   }).show();
});
/**
   响应图表的右键事件,返回上一级地图
*/
$('#contextMenu').on('click', function () {
    $(this).hide();
    //获取上一级地图信息
    var map = mapStack.pop();
    if (!mapStack.length && !map) {
        alert('已经到达最上一级地图了');
        return;
    }
    loadMap(map.mapCode, map.mapName);  
});

单击下钻,双击返回整个代码如下:

<!DOCTYPE html>
<html>
  <head >
  <meta charset="utf-8">
    <script type="text/javascript" src="echarts.js"></script>
    <script type="text/javascript" src="jquery.js"></script>
    <script type="text/javascript" src="china-main-city-map.js" charset="utf-8"></script>
  </head>

 <body>
    <div id= "main" style="width:1350px;height:600px;"></div>
    <script type="text/javascript">

    var myChart = echarts.init(document.getElementById('main'));
    //存储切换的每一级地图信息
    var mapStack = [];
    var timeFn = null;
    var curMap = {};
    //初始化为中国地图
    loadMap('100000', 'china');
    /**
       绑定用户切换地图区域事件
       cityMap对象存储着地图区域名称和区域的信息(name-code)
       当mapCode有值,说明可以切换到下级地图
       同时保存上级地图的编号和名称  
    */
    myChart.on('mapselectchanged', function(params) {
        clearTimeout(timeFn);
        //由于单击事件和双击事件冲突,故单击的响应事件延迟250毫秒执行
        timeFn = setTimeout(function(){
            var name = params.batch[0].name;
            var mapCode = cityMap[name];
            if (!mapCode) {
                alert('无此区域地图显示');
                return;
            }
            loadMap(mapCode, name); 
            //将上一级地图信息压入mapStack
            mapStack.push({
                mapCode: curMap.mapCode,
                mapName: curMap.mapName
            }); 
        }, 250);   
    });
    /**
       绑定双击事件,并加载上一级地图
    */
    myChart.on('dblclick', function(params) {
        //当双击事件发生时,清除单击事件,仅响应双击事件
        clearTimeout(timeFn);
        var map = mapStack.pop();
        if (!mapStack.length && !map) {
            alert('已经到达最上一级地图了');
            return;
        }
        loadMap(map.mapCode, map.mapName);
    });
    /**
       加载地图:根据地图所在省市的行政编号,
       获取对应的json地图数据,然后向echarts注册该区域的地图
       最后加载地图信息
       @params {String} mapCode:地图行政编号,for example['中国':'100000', '湖南': '430000']
       @params {String} mapName: 地图名称
    */
    function loadMap(mapCode, mapName) {
        $.getJSON('china-main-city/' + mapCode + '.json', function (data) {
             if (data) {
                 echarts.registerMap(mapName, data);
                 var option = {
                    tooltip: {
                        trigger: 'item',
                        formatter: '{b}'
                    },
                    series: [
                        {
                            name: '',
                            type: 'map',
                            mapType: mapName,
                            selectedMode : 'multiple',
                            label: {
                                normal: {
                                    show: true
                                },
                                emphasis: {
                                    show: true
                                }
                            },
                            data:[
                            ]
                        }
                    ]
                 };
                 myChart.setOption(option);
                 curMap = {
                    mapCode: mapCode,
                    mapName: mapName
                 };     
             } else {
                 alert('无法加载该地图');
             }       
        });
    }
    </script> 
</body>
</html>

单击下钻,右键菜单返回,全部代码如下:

<!DOCTYPE html>
<html>
  <head >
  <meta charset="utf-8">
    <script type="text/javascript" src="echarts.js"></script>
    <script type="text/javascript" src="jquery.js"></script>
    <script type="text/javascript" src="china-main-city-map.js" charset="utf-8"></script>
  </head>

 <body>
     <div id= "main" style="width:1350px;height:600px;"></div>
     <div id = "contextMenu" style = "position: absolute;background:#000;opacity:0.8;cursor: pointer;border-radius: 2px;padding:8px 30px;display:none;color: #fff;font-size:14px;">返回上一级</div>
     <script type="text/javascript">

    var myChart = echarts.init(document.getElementById('main'));
    //存储切换的每一级地图信息
    var mapStack = [];
    var curMap = {};
    //初始化地图
    loadMap('100000', 'china');
    /**
       绑定用户切换地图区域事件
       cityMap对象存储着地图区域名称和区域的信息(name-code)
       当mapCode有值说明可以切换到下级地图
       此时保存上级地图的编号和名称
    */
    myChart.on('mapselectchanged', function(params) {   
        var name = params.batch[0].name;
        var mapCode = cityMap[name];
        if (!mapCode) {
            alert('无此区域地图显示');
            return;
        }
        loadMap(mapCode, name); 
        //将上一级地图信息压入mapStack
        mapStack.push({
            mapCode: curMap.mapCode,
            mapName: curMap.mapName
        }); 
    });
    /**
       绑定右键事件
    */
    myChart.on('contextmenu', function(params) {
       $('#contextMenu').css({
           left: params.event.offsetX,
           top: params.event.offsetY
       }).show();
    });
    /**
       响应图表的右键事件,返回上一级地图
    */
    $('#contextMenu').on('click', function () {
        $(this).hide();
        //获取上一级地图信息
        var map = mapStack.pop();
        if (!mapStack.length && !map) {
            alert('已经到达最上一级地图了');
            return;
        }
        loadMap(map.mapCode, map.mapName);  
    });
    /**
       加载地图:根据地图所在省市的行政编号,
       获取对应的json地图数据,然后向echarts注册该区域的地图
       最后加载地图信息
       @params {String} mapCode:地图行政编号,for example['中国':'100000', '湖南': '430000']
       @params {String} mapName: 地图名称
    */
    function loadMap(mapCode, mapName) {
        $.getJSON('china-main-city/' + mapCode + '.json', function (data) {
             if (data) {
                 echarts.registerMap(mapName, data);
                 var option = {
                    tooltip: {
                        trigger: 'item',
                        formatter: '{b}'
                    },
                    series: [
                        {
                            name: '',
                            type: 'map',
                            mapType: mapName,
                            selectedMode : 'multiple',
                            label: {
                                normal: {
                                    show: true
                                },
                                emphasis: {
                                    show: true
                                }
                            },
                            data:[
                            ]
                        }
                    ]
                 };
                 myChart.setOption(option);
                 //存储当前地图的信息
                 curMap = {
                    mapCode: mapCode,
                    mapName: mapName
                 };     
             } else {
                 alert('无法加载该地图');
             }       
        });
    }
    </script>

  </body>
</html>

总结:两种方法都有各自的优缺点,方法一相比二,操作更方便,但容易误操作;方法二,需要额外的右键操作,绑定dom进行回调处理。如果需要进一步对地图显示效果进行处理,可直接对loadMap函数的option对象进行操作,传入相应参数即可。其实,只要有展示地区的json轮廓数据,然后在china-main-city-map.js配置相应参数,这个设计和实现方法,完全可以实现多级(最多没有限制)地图的切换。
实际效果,如下图所示:
(1) 初始化为全国地图

全国地图

(2)单击进入下级地图(如湖南地图)

湖南地图

(3)再单击进入下级地图(如湖南下面的长沙市地图)

长沙地图

(4)双击返回或者右键返回上一级地图

右键返回湖南省

双击返回湖南省

(5)双击返回或者右键返回上一级地图

返回到全国地图

下载地址:详细源码已经上传到了csdn,地址为:http://download.csdn.net/download/mulumeng981/9962651

©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页