最近做项目,有个需求使用到高德地图JS API,现写博客总结一下。
需求要求大概是这样的:
- 使用地图高德或百度或谷歌都可以(这里吐槽一下,百度地图的jsAPI帮助文档写的太。。。谷歌你懂的。。。高德目前感觉非常nice)
- 需要根据用户定位获取周边片区相关数据统计,并展示
- 头部根据用户点击poi点信息而变更
- 点击左上列表任意一列,地图中心自动切换并展示出信息框
- 效果图如下:
紧接着带着需求我就去高德地图JSAPI寻找解决办法,很惊喜发现有相关解决办法,高德地图JSAPI-UI组件事例中,标注列表-完整事例 比较接近,只要稍微改造一下即可。
具体代码如下:
map_house.js
/**
* 使用高德地图 1、先定位获取用户位置 2、定位成功后获取区域统计数据
*/
$("#panel").hide();
// 创建地图
var map = new AMap.Map('container', {
zoom: 15
});
var options = {
'showButton' : true,// 是否显示定位按钮
'buttonPosition' : 'LB',// 定位按钮的位置
/* LT LB RT RB */
'buttonOffset' : new AMap.Pixel(10, 20),// 定位按钮距离对应角落的距离
'showMarker' : true,// 是否显示定位点
'markerOptions' : {// 自定义定位点样式,同Marker的Options
'offset' : new AMap.Pixel(-18, -36),
'content' : '<img src="https://a.amap.com/jsapi_demos/static/resource/img/user.png" style="width:36px;height:36px"/>'
},
'convert':true,//是否使用坐标偏移,取值true:为高德地图坐标,取值false:为浏览器定位坐标默认值:true
'timeout':1000,// 定位超时
'GeoLocationFirst':true,//默认为false,设置为true的时候可以调整PC端为优先使用浏览器定位,失败后使用IP定位
'zoomToAccuracy':true,// 定位成功后调整地图视野范围使定位位置及精度范围视野内可见,默认:false
'showCircle' : true,// 是否显示定位精度圈
'circleOptions' : {// 定位精度圈的样式
'strokeColor' : '#0093FF',
'noSelect' : true,
'strokeOpacity' : 0.5,
'strokeWeight' : 1,
'fillColor' : '#02B0FF',
'fillOpacity' : 0.25
}
}
AMap.plugin([ "AMap.Geolocation" ], function() {
// 定位 -开始
var geolocation = new AMap.Geolocation(options);
map.addControl(geolocation);
geolocation.getCurrentPosition();
// 返回定位信息
AMap.event.addListener(geolocation, 'complete', onComplete);
// 返回定位错误信息
AMap.event.addListener(geolocation, 'error', onError);
});
// 定位成功
function onComplete(data) {
}
// 定位失败
function onError(data) {
var str = '';
str += '错误信息:'
switch (data.info) {
case 'PERMISSION_DENIED':
str += '浏览器阻止了定位操作';
break;
case 'POSITION_UNAVAILBLE':
str += '无法获得当前位置';
break;
case 'TIMEOUT':
str += '定位超时';
break;
default:
str += '未知错误';
break;
}
alert(str);
}
// 加载数据
oninstall();
function oninstall(){
AMapUI.loadUI(['misc/MarkerList', 'overlay/SimpleMarker', 'overlay/SimpleInfoWindow'],
function(MarkerList, SimpleMarker, SimpleInfoWindow) {
// 即jQuery/Zepto
var $ = MarkerList.utils.$;
var defaultIconStyle = 'red', // 默认的图标样式
hoverIconStyle = 'green', // 鼠标hover时的样式
selectedIconStyle = 'purple' // 选中时的图标样式
;
var markerList = new MarkerList({
map: map,
// ListElement对应的父节点或者ID
listContainer: "myList", // document.getElementById("myList"),
// 选中后显示
// 从数据中读取位置, 返回lngLat
getPosition: function(item) {
return [item.arealongitude, item.arealatitude];
},
// 数据ID,如果不提供,默认使用数组索引,即index
getDataId: function(item, index) {
return item.id;
},
getInfoWindow: function(data, context, recycledInfoWindow) {
// 排除统计为0的数据
if(data.totalNum!=0){
if (recycledInfoWindow) {
recycledInfoWindow.setInfoTitle(data.areaName);
recycledInfoWindow.setInfoBody("剩余:"+data.totalNum+" 套");
return recycledInfoWindow;
}
return new SimpleInfoWindow({
infoTitle: data.areaName,
infoBody: "剩余:"+data.totalNum+" 套",
offset: new AMap.Pixel(0, -37)
});
}return;
},
// 构造marker用的options对象,
// content和title支持模板,也可以是函数,返回marker实例,或者返回options对象
getMarker: function(data, context, recycledMarker) {
// 排除统计为0的数据
if(data.totalNum!=0){
if($("#panel").is(':hidden')){
$("#panel").show();
}
var label = String.fromCharCode('A'.charCodeAt(0) + context.index);
if (recycledMarker) {
recycledMarker.setIconLabel(label);
return;
}
return new SimpleMarker({
containerClassNames: 'my-marker',
iconStyle: defaultIconStyle,
iconLabel: label
});
}return;
},
// 构造列表元素,与getMarker类似,可以是函数,返回一个dom元素,或者模板 html string
getListElement: function(data, context, recycledListElement) {
if(data.totalNum!=0){
var label = String.fromCharCode('A'.charCodeAt(0) + context.index);
// 使用模板创建
var innerHTML = MarkerList.utils.template(
'<div class="poi-info-left">' +
' <h3 class="poi-title">' +
label +'.'+data.areaName +
' </h3>' +
' <div class="poi-info">' +
' <p class="poi-addr">剩余:'+data.totalNum+' 套</p>' +
' </div>' +
'</div>' +
'<div class="clear"></div>', {
data: data,
label: label
});
if (recycledListElement) {
recycledListElement.innerHTML = innerHTML;
return recycledListElement;
}
return '<li class="poibox">' +
innerHTML +
'</li>';
}
},
// 列表节点上监听的事件
listElementEvents: ['click', 'mouseenter', 'mouseleave'],
// marker上监听的事件
markerEvents: ['click', 'mouseover', 'mouseout'],
// makeSelectedEvents:false,
selectedClassNames: 'selected',
autoSetFitView: true
});
window.markerList = markerList;
markerList.on('selectedChanged', function(event, info) {
// checkBtnStats();
if (info.selected) {
// 切换页面标题
$("#titleId").html("广西-南宁市-"+info.selected.data.areaName+" 房源数:"+info.selected.data.totalNum+" 套");
console.log(info);
if (info.selected.marker) {
// 更新为选中样式
info.selected.marker.setIconStyle(selectedIconStyle);
}
// 选中并非由列表节点上的事件触发,将关联的列表节点移动到视野内
if (!info.sourceEventInfo.isListElementEvent) {
if (info.selected.listElement) {
scrollListElementIntoView($(info.selected.listElement));
}
}
}
if (info.unSelected && info.unSelected.marker) {
// 更新为默认样式
info.unSelected.marker.setIconStyle(defaultIconStyle);
}
});
markerList.on('listElementMouseenter markerMouseover', function(event, record) {
if (record && record.marker) {
forcusMarker(record.marker);
// this.openInfoWindowOnRecord(record);
// 非选中的id
if (!this.isSelectedDataId(record.id)) {
// 设置为hover样式
record.marker.setIconStyle(hoverIconStyle);
// this.closeInfoWindow();
}
}
});
markerList.on('listElementMouseleave markerMouseout', function(event, record) {
if (record && record.marker) {
if (!this.isSelectedDataId(record.id)) {
// 恢复默认样式
record.marker.setIconStyle(defaultIconStyle);
}
}
});
// 数据输出完成
markerList.on('renderComplete', function(event, records) {
// checkBtnStats();
console.log(event);
console.log(records);
var typeStatus=0;
$.each(records, function(i,val){
if(val.data.totalNum!=0){
// 更新页面头部提示
$("#titleId").html("请点击标注或左上列表选项,进行房源数量查看");
typeStatus=1;
}
});
if(typeStatus==0){
$("#titleId").html("暂无相关数据");
}
});
// 加载数据
function loadData(src, callback) {
$.getJSON(src, function(data) {
if(data.data==null){$("#titleId").html("暂无相关数据");$("#panel").hide();return;}
console.log(data.data);
markerList._dataSrc = src;
// 渲染数据
markerList.render(data.data);
if (callback) {
callback(null, data.data);
}
});
}
var $btns = $('#btmlod');
/**
* 检测各个button的状态
*/
// function checkBtnStats() {
// $('#btnList input[data-enable]').each(function() {
//
// var $input = $(this),
// codeEval = $input.attr('data-enable');
//
// $input.prop({
// disabled: !eval(codeEval)
// });
// });
// }
// 初始化
loadData($btns.attr('data-path'));
function forcusMarker(marker) {
marker.setTop(true);
// 不在地图视野内
if (!(map.getBounds().contains(marker.getPosition()))) {
// 移动到中心
map.setCenter(marker.getPosition());
}
}
function isElementInViewport(el) {
var rect = el.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /*
* or
* $(window).height()
*/
rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*
* or
* $(window).width()
*/
);
}
function scrollListElementIntoView($listEle) {
if (!isElementInViewport($listEle.get(0))) {
$('#panel').scrollTop($listEle.offset().top - $listEle.parent().offset().top);
}
// 闪动一下
$listEle
.one('webkitAnimationEnd oanimationend msAnimationEnd animationend',
function(e) {
$(this).removeClass('flash animated');
}).addClass('flash animated');
}
});
}
html
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ include file="/WEB-INF/views/include/mobile/taglib.jsp"%>
<title>${fns:getConfig('productName')}</title>
<link rel="stylesheet" type="text/css" href="${ctxStatic}/rent/css/map_css.css">
</head>
<body>
<div id="outer-box">
<div class="popup" id="titleId">正在加载...</div>
<div id="container" tabindex="0"></div>
<!-- 列表 -->
<div id="panel" class="scrollbar1">
<ul id="myList">
</ul>
</div>
</div>
<!-- 数据地址,ajax,需返回json -->
<input type="hidden" id="btmlod" data-path="${conPathRennt}/mobile/rentHouse/mapJson">
</body>
<script type="text/javascript"
src="${ctxStatic}/rent/js/jquery-1.8.3.min.js"></script>
<script type="text/javascript"
src="https://webapi.amap.com/maps?v=1.4.7&key=你的key"></script>
<!-- UI组件库 1.0 -->
<script src="https://webapi.amap.com/ui/1.0/main.js?v=1.0.11"></script>
<script src="${ctxStaticRent }/js/map_house.js" type="text/javascript"></script>
</html>
css
html,
body{
width:100%;
height:100%;
margin:0px;
padding:0;
font-size:13px;
}
ul,
li{
padding:0;
margin:0;
list-style:none;
}
#outer-box{
/* height:100%; */
/* padding-right:100px; */
}
#container{
height:100%;
width:100%;
}
#panel{
position:absolute;
top:60;
/* bottom:0; */
left:0;
height:300px;
overflow:auto;
width:100px;
z-index:999;
border-left:1px solid #eaeaea;
background:#fff;
}
#btnList{
position:absolute;
right:300px;
top:0;
padding:0;
margin:0;
z-index:999;
}
#btnList li{
padding:5px;
}
#btnList input{
padding:3px 10px;
min-width:120px;
}
li.poibox{
border-bottom:1px solid #eaeaea;
border-left:2px solid rgba(0,0,0,0);
padding:10px 3px;
cursor:pointer;
}
li.poibox.selected{
border-left-color:#f00;
background:#f6f6f6;
}
li.poibox:hover{
background:#f6f6f6;
}
li.poibox:last-child{
border-bottom:none;
}
h3.poi-title{
margin:3px 0;
font-size:13px;
}
.poibox .poi-info-left{
padding-left:8px
}
.poi-addr{
margin:7px 0 0;
}
.poibox .poi-imgbox{
width:100px;
height:74px;
vertical-align:top;
float:right;
margin:0 8px;
overflow:hidden
}
.poibox .poi-img{
display:inline-block;
width:100%;
height:100%;
background-size:cover;
background-position:50% 50%;
}
.amap-simple-marker.my-marker .amap-simple-marker-label{
font-size:12px;
color:#eee;
font-family:sans-serif;
}
.selected .amap-simple-marker.my-marker .amap-simple-marker-label{
font-size:14px;
color:orange;
font-weight:700;
}
@-webkit-keyframes flash{
from,
50%,
to{
opacity:1;
}
25%,
75%{
opacity:0;
}
}
@keyframes flash{
from,
50%,
to{
opacity:1;
}
25%,
75%{
opacity:0;
}
}
.flash{
-webkit-animation-name:flash;
animation-name:flash;
}
.animated{
-webkit-animation-duration:1s;
animation-duration:1s;
-webkit-animation-fill-mode:both;
animation-fill-mode:both;
}
.scrollbar1::-webkit-scrollbar-track{
-webkit-box-shadow:inset 0 0 6px rgba(0,0,0,0.3);
background-color:#fff;
}
.scrollbar1::-webkit-scrollbar{
width:6px;
background-color:#fff;
}
.scrollbar1::-webkit-scrollbar-thumb{
background-color:#aaa;
}
.clear{
clear:both;
}
/* body, html {
width: 100%;
height: 100%;
margin: 0;
font-family: "微软雅黑";
}
#container {
width: 100%;
height: 600px;
} */
p {
margin-left: 15px;
font-size: 14px;
/* padding: 20px 0px 0px 0px; */
}
.popup {
z-index: 99999;
position: absolute;
text-align: center;
border: none;
text-align: center;
width: 100%;
height: 60px;
font: 16px/60px Tahoma, Verdana, sans-serif;
box-shadow: 0 10px 14px rgba(0, 0, 0, 0.4);
color: #fefefe;
background: #1e90ff;
}
.content-window-card {
z-index: 99999;
position: relative;
box-shadow: none;
bottom: 0;
left: 0;
width: auto;
padding: 0;
}
.content-window-card p {
height: 2rem;
}
.custom-info {
border: solid 1px silver;
}
div.info-top {
position: relative;
background: none repeat scroll 0 0 #F9F9F9;
border-bottom: 1px solid #CCC;
border-radius: 5px 5px 0 0;
}
div.info-top div {
display: inline-block;
color: #333333;
font-size: 14px;
font-weight: bold;
line-height: 31px;
padding: 0 10px;
}
div.info-top img {
position: absolute;
top: 10px;
right: 10px;
transition-duration: 0.25s;
}
div.info-top img:hover {
box-shadow: 0px 0px 5px #000;
}
div.info-middle {
font-size: 12px;
padding: 10px 6px;
line-height: 20px;
}
div.info-bottom {
height: 0px;
width: 100%;
clear: both;
text-align: center;
}
div.info-bottom img {
position: relative;
z-index: 104;
}
span {
margin-left: 5px;
font-size: 11px;
}
.info-middle img {
float: left;
margin-right: 6px;
}
参考链接:
事例:https://lbs.amap.com/api/amap-ui/demos/amap-ui-markerlist/index