博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ArcGIS JS 学习笔记3 实现百度风格的BubblePopup
阅读量:5166 次
发布时间:2019-06-13

本文共 16898 字,大约阅读时间需要 56 分钟。

原文:

1. 开篇

模仿是最好的学习,这次我们继续山寨百度,通过自定义Infowindow来实现百度风格的BubblePopup

 

2.准备

2.1 Copy模板

先打开百度地图,按下f12吧BubblePopup的HTML代码和CSS代码拷贝下来,这里我无耻的把类名改了,大家不要在意细节。

HTML模板

1 
2
4
5
6
7
8
9
10
11
View Code

CSS代码

1   2 .dextra-bubble-pop {  3     position: absolute;  4     z-index: 100;  5     box-sizing: border-box;  6     box-shadow: 1px 2px 1px rgba(0, 0, 0, .15);  7     background-color: #FFF;  8 }  9  10 .dextra-poi-info-window { 11     padding: 4px 0; 12 } 13  14 .dextra-poi-info-window .left { 15     padding-left: 10px; 16     padding-right: 10px; 17     height: 40px; 18     line-height: 40px; 19     display: table; 20     table-layout: fixed; 21     width: 140px; 22     text-align: center; 23 } 24  25 .dextra-poi-info-window .name-wrap .name { 26     vertical-align: middle; 27     font-size: 14px; 28     font-weight: 700; 29     white-space: nowrap; 30     overflow: hidden; 31     text-overflow: ellipsis; 32     display: block; 33 } 34  35 .dextra-bubble-pop-bottom span { 36     position: absolute; 37     left:72px; 38     width: 16px; 39     height: 10px; 40     background-image: url("../images/tail_shadow.png"); 41 }
View Code

2.2 编写BubblePopup

    要实现BubblePopup,实际上就是自定义一个InfoWindow,我们可以通过继承InfoWindowBase来实现。要实现自定义的InfoWindow。我们可以先参考一下官方的例子,注意,这个例子是有缺陷的,如果当infowindow超出当前视图边界就会出现滚动条。下载官方的实例,我们打开infoWindow.js文件。

1 define([  2     "dojo/Evented",  3     "dojo/parser",  4     "dojo/on",  5     "dojo/_base/declare",  6     "dojo/dom-construct",  7     "dojo/_base/array",  8     "dojo/dom-style",  9     "dojo/_base/lang", 10     "dojo/dom-class", 11     "dojo/fx/Toggler", 12     "dojo/fx", 13     "dojo/Deferred", 14     "esri/domUtils", 15     "esri/InfoWindowBase" 16  17 ], 18 function( 19     Evented, 20     parser, 21     on, 22     declare, 23     domConstruct, 24     array, 25     domStyle, 26     lang, 27     domClass, 28     Toggler, 29     coreFx, 30     Deferred, 31     domUtils, 32     InfoWindowBase 33 ) { 34     return declare([InfoWindowBase, Evented], { 35  36         isContentShowing :false, 37  38         constructor: function(parameters) { 39  40  41           lang.mixin(this, parameters); 42  43  44           domClass.add(this.domNode, "myInfoWindow"); 45  46           this._closeButton = domConstruct.create("div",{"class": "close", "title": "Close"}, this.domNode); 47           this._title = domConstruct.create("div",{"class": "title"}, this.domNode); 48           this._content = domConstruct.create("div",{"class": "content"}, this.domNode); 49  50           this._toggleButton = domConstruct.create("div",{"class": "toggleOpen", "title": "Toggle"}, this.domNode); 51  52           var toggler = new  Toggler({ 53             "node": this._content, 54             showFunc: coreFx.wipeIn, 55             hideFunc: coreFx.wipeOut 56           }); 57           toggler.hide(); 58  59           on(this._closeButton, "click", lang.hitch(this, function(){ 60             //hide the content when the info window is toggled close. 61             this.hide(); 62             if(this.isContentShowing){ 63               toggler.hide(); 64               this.isContentShowing = false; 65               domClass.remove(this._toggleButton); 66               domClass.add(this._toggleButton, "toggleOpen"); 67             } 68           })); 69           on(this._toggleButton, "click", lang.hitch(this, function(){ 70             //animate the content display  71               if(this.isContentShowing){ 72  73                 toggler.hide(); 74                 this.isContentShowing = false; 75                 domClass.remove(this._toggleButton); 76                 domClass.add(this._toggleButton,"toggleOpen"); 77  78               }else{ 79                 toggler.show(); 80                 this.isContentShowing=true; 81                 domClass.remove(this._toggleButton); 82                 domClass.add(this._toggleButton,"toggleClose"); 83               } 84  85           })); 86           //hide initial display  87           domUtils.hide(this.domNode); 88           this.isShowing = false; 89  90         }, 91         setMap: function(map){ 92           this.inherited(arguments); 93           map.on("pan-start", lang.hitch(this, function(){ 94             this.hide(); 95           })); 96           map.on("zoom-start", lang.hitch(this, function(){ 97             this.hide(); 98           })); 99          // map.on("zoom-start", //this, this.hide);100 101         },102         setTitle: function(title){103           this.place(title, this._title);104 105         },106         setContent: function(content){107           this.place(content, this._content);108         },109         show: function(location){110           if(location.spatialReference){111             location = this.map.toScreen(location);112           }113 114           //Position 10x10 pixels away from the specified location115           domStyle.set(this.domNode,{116             "left": (location.x + 10) + "px",117             "top": (location.y + 10) + "px"118           });119 120           //display the info window121           domUtils.show(this.domNode);122           this.isShowing = true;123           this.onShow();124         },125         hide: function(){126           domUtils.hide(this.domNode);127           this.isShowing = false;128           this.onHide();129 130         },131         resize: function(width, height){132           domStyle.set(this._content,{133             "width": width + "px",134             "height": height + "px"135           });136           domStyle.set(this._title,{137             "width": width + "px"138           });139 140         },141         destroy: function(){142           domConstruct.destroy(this.domNode);143           this._closeButton = this._title = this._content = null;144 145         }146 147 148       });149 150 });
View Code

我们就在此基础上进行改造,不但要实现需求还要解决缺陷。infoWindowBase是继承自_WidgetBase的,我们先来看一下infoWindowBase的官方描述.

我们可以重写infoWindowBase的一些方法,来实现自己的infoWindow。

首先我们先引入我们要用到的模块

1 define([  2         "dojo/Evented",  3         "dojo/on",  4         "dojo/query",  5         "dojo/_base/declare",  6         "dojo/dom-construct",  7         "dojo/dom-attr",  8         "dojo/_base/array",  9         "dojo/dom-style", 10         "dojo/_base/lang", 11         "dojo/dom-class", 12         "dijit/_TemplatedMixin", 13         "esri/domUtils", 14         "esri/InfoWindowBase", 15         "esri/geometry/ScreenPoint", 16         "esri/geometry/screenUtils", 17         "esri/geometry/webMercatorUtils", 18         "dojo/text!./templates/dextraPopup.html" 19     ], 20     function (Evented, 21               on, 22               query, 23               declare, 24               domConstruct, 25               domAttr, 26               array, 27               domStyle, 28               lang, 29               domClass, 30               _TemplatedMixin, 31               domUtils, 32               InfoWindowBase, ScreenPoint, screenUtils, webMercatorUtils, template) { 33         var showMapPoint = null; 34         return declare([InfoWindowBase, Evented, _TemplatedMixin], { 35             isContentShowing: false, 36             templateString: template, 37             _events: [], 38             constructor: function (parameters) { 39                 lang.mixin(this, parameters); 40             }, 41                 ... 42               });
View Code

      对比官方的例子,我去掉了部分模块(coreFx,Toggler),加入了dijit/_TemplateMixin,esri/geometry/webMecratorUtils,

esri/geomtry/srcreenUtils模块。_TemplateMixin是为了使用我在第一步拷贝下来的HTML模板,关于编写基于模板的widget可以到

dojo的官网进行查看;webMecratorUtils和srcreenUtils则是为了实现地理坐标和屏幕坐标的准确转换。

showMapPoint是一个全局的变量,用来记录popup的地理坐标位置。

templateString是_TemplateMixin模块的一个属性,用来保存HTML模板。

_events:是一个数组,用来存储相关的事件,在popup被释放时释放注册的事件。

 

      先用一个私有方法来进行初始化。应为InfoWindowBase是继承自_WidgetBase的,domNode是_WidgetBase的一个属性,用于表示生成Widget的dom节点,可以通过在构造函数里用第二个参数来进行传入,或者在内部自己定义。

1   _createInfoWindowInstance: function (map) {  2                 this.domNode = domConstruct.create("div", null, map.id + "_root");  3                 domClass.add(this.domNode, "dextra-bubble-pop");  4                 domStyle.set(this.domNode, {  5                     width: "160px",  6                 });  7   8                 this.domNode.innerHTML = this.templateString;  9  10                 this._content = query("div.name-wrap span.name"); 11                 this._title=query("div.name-wrap"); 12                 //hide initial display 13                 domUtils.hide(this.domNode); 14                 this.isShowing = false; 15             },
View Code

     注意,我在这里创建了一个div节点,并把它添加到一个id为{map.id}_root({map.id}占位符,用于表示地图的id)的dom节点中,这一步就是解决当infowindow超出当前视图范围时会出现滚动条。我们可以先用arcgis提供的infowindow来试一试,在浏览器中按

f12,我们看一看infowindow是放在哪的。

     利用arcgis自带的infowindow,我们可以看到这个infowindow的dom节点被添加到一个id为map_root的div中。在这里,我的map控件的id为“map”,所以它会生成一个id为“map_root”({map.id}_root)的div。所以我们只要把自定生成的popup放到这个节点中,当popup超出当前视图时,会被裁减了,而不是出现滚动条。这里最关键的部分已经完成了,接下来的操作就是如何在地图上展现这个popup。

1   _showInfoWindow: function (extent) {  2                 if (showMapPoint == null)return;  3                 var showScreenPoint = screenUtils.toScreenGeometry(extent, this.map.width, this.map.height, showMapPoint);  4                 domStyle.set(this.domNode, {  5                     "left": (showScreenPoint.x - 80) + "px",  6                     "top": (showScreenPoint.y - 76 ) + "px"  7                 });  8   9                 domUtils.show(this.domNode); 10                 this.isShowing = true; 11                 this.onShow(); 12             }, 13  14             show: function (location) { 15                 showMapPoint = location; 16                 if (webMercatorUtils.canProject(location, this.map)) { 17                     showMapPoint = webMercatorUtils.project(location, this.map); 18                 } 19                 if (showMapPoint.spatialReference) { 20                     var screenPoint = this.map.toScreen(showMapPoint); 21                     domStyle.set(this.domNode, { 22                         "left": (screenPoint.x - 80) + "px", 23                         "top": (screenPoint.y - 76) + "px" 24                     }); 25                 } 26  27                 //display the info window 28                 domUtils.show(this.domNode); 29                 this.isShowing = true; 30                 this.onShow(); 31             },
View Code

      _showInfoWindow方法是一个私有方法,用于在地图事件触发时调用。当地图平移,缩放时根据地理坐标从新计算BubblePopup的屏幕坐标。用screenUtils.toScreenGeometry(extent, width, height, mapGeometry)根据地图的范围,宽度,高度,和点计算出相应的屏幕坐标。

     show方法是一个公有方法,用于在外部进行调用。在这里利用了arcgis js 提供webMercatorUtils模块,来进行坐标的转换。一般而言,我们都会用经纬度坐标,但是当地图是webMercator投影时,就需要先把经纬度坐标转化成米制坐标,才能在正确的位置显示出来来。

关键的部分已经完成,下面贴出全部代码

1 define([  2         "dojo/Evented",  3         "dojo/on",  4         "dojo/query",  5         "dojo/_base/declare",  6         "dojo/dom-construct",  7         "dojo/dom-attr",  8         "dojo/_base/array",  9         "dojo/dom-style", 10         "dojo/_base/lang", 11         "dojo/dom-class", 12         "dijit/_TemplatedMixin", 13         "esri/domUtils", 14         "esri/InfoWindowBase", 15         "esri/geometry/ScreenPoint", 16         "esri/geometry/screenUtils", 17         "esri/geometry/webMercatorUtils", 18         "dojo/text!./templates/dextraPopup.html" 19     ], 20     function (Evented, 21               on, 22               query, 23               declare, 24               domConstruct, 25               domAttr, 26               array, 27               domStyle, 28               lang, 29               domClass, 30               _TemplatedMixin, 31               domUtils, 32               InfoWindowBase, ScreenPoint, screenUtils, webMercatorUtils, template) { 33         var showMapPoint = null; 34         return declare([InfoWindowBase, Evented, _TemplatedMixin], { 35  36             templateString: template, 37             _events: [], 38             constructor: function (parameters) { 39                 lang.mixin(this, parameters); 40             }, 41             _createInfoWindowInstance: function (map) { 42                 this.domNode = domConstruct.create("div", null, map.id + "_root"); 43                 domClass.add(this.domNode, "dextra-bubble-pop"); 44                 domStyle.set(this.domNode, { 45                     width: "160px", 46                 }); 47  48                 this.domNode.innerHTML = this.templateString; 49  50                 this._content = query("div.name-wrap span.name"); 51                 this._title=query("div.name-wrap"); 52                 //hide initial display 53                 domUtils.hide(this.domNode); 54                 this.isShowing = false; 55             }, 56  57             setMap: function (map) { 58                 this.inherited(arguments); 59                 this._events = []; 60                 this._createInfoWindowInstance(map); 61                 this._events.push(map.on("pan", lang.hitch(this, function (evt) { 62                     if (this.isShowing) { 63                         this._showInfoWindow(evt.extent); 64                     } 65                 }))); 66  67                 this._events.push(map.on("zoom-start", lang.hitch(this, function (evt) { 68                     this.hide(); 69                 }))); 70  71                 this._events.push(map.on("zoom-end", lang.hitch(this, function (evt) { 72                     this._showInfoWindow(evt.extent); 73                 }))); 74             }, 75  76             unsetMap: function (map) { 77                 this.inherited(arguments); 78                 array.forEach(this._events, function (event) { 79                     event.remove(); 80                 }); 81             }, 82             setTitle: function (title) { 83                 this._title.forEach(function (node) { 84                     domAttr.set(node, "title", title); 85                 }); 86             }, 87  88             setContent: function (content) { 89                 this._content.forEach(function (node) { 90                     node.innerHTML = content; 91                 }); 92             }, 93  94             _showInfoWindow: function (extent) { 95                 if (showMapPoint == null)return; 96                 var showScreenPoint = screenUtils.toScreenGeometry(extent, this.map.width, this.map.height, showMapPoint); 97                 domStyle.set(this.domNode, { 98                     "left": (showScreenPoint.x - 80) + "px", 99                     "top": (showScreenPoint.y - 76 ) + "px"100                 });101 102                 domUtils.show(this.domNode);103                 this.isShowing = true;104                 this.onShow();105             },106 107             show: function (location) {108                 showMapPoint = location;109                 if (webMercatorUtils.canProject(location, this.map)) {110                     showMapPoint = webMercatorUtils.project(location, this.map);111                 }112                 if (showMapPoint.spatialReference) {113                     var screenPoint = this.map.toScreen(showMapPoint);114                     domStyle.set(this.domNode, {115                         "left": (screenPoint.x - 80) + "px",116                         "top": (screenPoint.y - 76) + "px"117                     });118                 }119 120                 //display the info window121                 domUtils.show(this.domNode);122                 this.isShowing = true;123                 this.onShow();124             },125             hide: function () {126                 if (this.isShowing) {127                     domUtils.hide(this.domNode);128                     this.isShowing = false;129                     this.onHide();130                 }131             },132             resize: function (width, height) {133                 domStyle.set(this._content, {134                     "width": width + "px",135                     "height": height + "px"136                 });137             },138             remove: function () {139                 this.hide();140                 showMapPoint = null;141             },142             destroy: function () {143                 domConstruct.destroy(this.domNode);144             }145         });146     });147
View Code

DEMO:

1   2   3   4     
5 DExtra-BubublPoopup 6
7
8
9 22 23 81 89 90 91
92
93
94 95
96 97
View Code
 

效果截图:

3.1 小结

    可以看到,通过继承InfoWindowBase我们完全可以实现自己的的infoWindow,编写更具个性化的插件。最后像新手玩家推荐一下

esri的github,这里有很多有用的东西,非常值得学习。

    本文参考了 谢谢的分享。

    欢迎转载 http://www.cnblogs.com/deliciousExtra/p/5565787.html

posted on
2016-08-18 18:40 阅读(
...) 评论(
...)

转载于:https://www.cnblogs.com/lonelyxmas/p/5785033.html

你可能感兴趣的文章
从.Net版本演变看String和StringBuilder性能之争
查看>>
Excel操作 Microsoft.Office.Interop.Excel.dll的使用
查看>>
解决Ubuntu下博通网卡驱动问题
查看>>
【bzoj2788】Festival
查看>>
执行gem install dryrun错误
查看>>
HTML5简单入门系列(四)
查看>>
实现字符串反转
查看>>
转载:《TypeScript 中文入门教程》 5、命名空间和模块
查看>>
苹果开发中常用英语单词
查看>>
[USACO 1.4.3]等差数列
查看>>
Shader Overview
查看>>
Reveal 配置与使用
查看>>
Java中反射的学习与理解(一)
查看>>
C语言初学 俩数相除问题
查看>>
B/S和C/S架构的区别
查看>>
[Java] Java record
查看>>
jQuery - 控制元素显示、隐藏、切换、滑动的方法
查看>>
postgresql学习文档
查看>>
Struts2返回JSON数据的具体应用范例
查看>>
socket阻塞与非阻塞,同步与异步
查看>>