平台地址:http://lbs.amap.com/api/javascript-api/example/amap-ui-districtcluster/custom-cluster-marker
在做之前得科普一下,百度和高德,谷歌的经纬度是有偏差的。
了解经纬度偏差原因(pc测试可先不考虑,高德地图api定位在移动端显示定位失败,故采用百度地图获取经纬度,然后传给高德api转化坐标):
高德地图坐标转换API
适用场景
为了使用高德服务,用户需要将非高德坐标转换为高德坐标。
地址:http://lbs.amap.com/api/webservice/guide/api/convert/
不同地图经纬度差异在线测试
地址:http://www.gpsspg.com/maps.htm
高德地图使用参考:
1.ul组件库:http://lbs.amap.com/api/javascript-api/reference-amap-ui/overlay/simplemarker
2.示例中心:http://lbs.amap.com/api/javascript-api/example/amap-ui-simplemarker/index
以下为demo:
map_demo.html代码
<!doctype html>
<html lang="zh-CN">
<head>
<!-- 原始地址://webapi.amap.com/ui/1.0/ui/geo/DistrictCluster/examples/plus-point-simplifier.html -->
<!--<base href="//webapi.amap.com/ui/1.0/ui/geo/DistrictCluster/examples/" />-->
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=0.8, user-scalable=yes, width=device-width">
<title>区划聚合+海量点展示+定位+自定义标记</title>
<link rel="stylesheet" href="http://cache.amap.com/lbs/static/main1119.css"/>
<!--调整容器大小和一些目标地点样式大小,一级隐藏,需要使用-->
<link rel="stylesheet" href="css/map_common.css">
<!--定位坐标的css样式,带一些水波效果,可以不加,在updateMarker生成标记的地方,用img的url链接即可-->
<link rel="stylesheet" href="css/ico_position.css">
<!--一些样式修改和遮罩弹框样式,可以不加,默认是显示的,通过js触发显示和关闭-->
<link rel="stylesheet" href="css/map_plus.css">
<!--高德自带,需要使用-->
<script type="text/javascript" src='//webapi.amap.com/maps?v=1.4.3&key=d59a0ae0dd2a9b17cbbc480bea2f2033'></script>
<!-- UI组件库 1.0 -->
<script src="//webapi.amap.com/ui/1.0/main.js?v=1.0.11"></script>
<!--以下为工具使用,比如公交,和高德自身定位,以下代码暂不使用-->
<!--<script type="text/javascript"-->
<!--src="http://webapi.amap.com/maps?v=1.4.3&key=你的高德地图秘钥&plugin=AMap.Transfer"></script>-->
<!--<script type="text/javascript" src="http://cache.amap.com/lbs/static/addToolbar.js"></script>-->
</head>
<body id="body">
<div id="container"></div>
<script type="text/javascript">
//创建地图
var map = new AMap.Map('container', {
resizeEnable: true,
expandZoomRange: true,
zoom: 10,
zooms: [10, 16],
cursor: 'default',
center: [122.947398, 34.351598]/*中心确定暂时用不上*/
});
// 地图初始化
function initPage(DistrictCluster, PointSimplifier, $) {
// 1.具体坐标点设置
var pointSimplifierIns = new PointSimplifier({
map: map, //所属的地图实例
autoSetFitView: false, //禁止自动更新地图视野
zIndex: 110,
getPosition: function (item) {
if (!item) {
return null;
}
var parts = item.split(',');
//返回经纬度
return [parseFloat(parts[0]), parseFloat(parts[1]), parts[2]];
},
getHoverTitle: function (dataItem) {
var parts1 = dataItem.split(',');
return parts1[2];
},
renderOptions: {
//点的样式
pointStyle: {
width: 20,
height: 20,
fillStyle: 'rgba(55, 175, 55, 0.8)',
},
// hover层级大小
pointHoverStyle: {
width: 20,
height: 20,
fillStyle: 'rgba(255, 175, 55, 0.8)',
},
// 点击范围大小
pointHardcoreStyle: {
width: 50,
height: 50,
lineWidth: 3,
},
//鼠标hover时的title信息
hoverTitleStyle: {
position: 'left',
offset: [3, 0],
},
}
});
// 2.地区块设置
var distCluster = new DistrictCluster({
zIndex: 102,
map: map, //所属的地图实例
getPosition: function (item) {
if (!item) {
return null;
}
var parts = item.split(',');
//返回经纬度
return [parseFloat(parts[0]), parseFloat(parts[1]), parts[2]];
},
renderOptions: {
featureStyle: {
fillStyle: 'rgba(0, 0, 0, 1)',
lineWidth: 1,
strokeStyle: 'rgba(55, 175, 55, 0.8)',
hoverOptions: {
fillStyle: 'rgba(255, 0, 0, 0.2)',
lineWidth: 2,
strokeStyle: 'rgba(255, 0, 0, 0.8)'
}
},
//直接定义某写区划面的样式
getFeatureStyle: function(feature, dataItems) {
if (dataItems.length > 2) {
return {
fillStyle: 'rgba(0, 0, 0, 0.6)'
};
} else if (dataItems.length > 1) {
return {
fillStyle: 'rgba(0, 0, 0, 0.6)'
};
}
return {};
},
featureEventSupport: true,
clusterMarkerEventSupport: true,
clusterMarkerEventNames: ['click', 'rightclick', 'mouseover', 'mouseout'],
//显示在所辖数据点的平均位置
getClusterMarkerPosition: DistrictCluster.ClusterMarkerPositionStrategy.AVERAGE_POINTS_POSITION,
getClusterMarker: function (feature, dataItems, recycledMarker) {
//label内容
var name3 = feature.properties.name.length < 4 ? feature.properties.name : (feature.properties.name[0] + feature.properties.name[1])
var content = name3 + '<br />' + dataItems.length + '个';
var label = {
offset: new AMap.Pixel(0, 0), //修改label相对于marker的位置
//----------要改等级---------
// content: map.getZoom() > 13 ? content : null
content: content
};
if (dataItems.length > 0) {
//存在可回收利用的marker
if (recycledMarker) {
//直接更新内容返回
recycledMarker.setLabel(label);
return recycledMarker;
}
//返回一个新的Marker
return new AMap.Marker({
//----------要改等级---------
// label: map.getZoom() > 13 ? label : null,
label: label,
});
}
}
}
});
window.distCluster = distCluster;
//根据当前zoom调整点的尺寸,大小
// 3.自定义定位
function selfPosition() {
addMarker();
// 实例化点标记
function addMarker() {
marker = new AMap.Marker({});
marker.setMap(map);
}
function updateMarker() {
// 自定义点标记内容
var markerContent = document.createElement("div");
// 点标记中的图标
var ico_position = document.createElement("div");
ico_position.className = 'ico_position';
var pin = document.createElement("div");
pin.className = 'pin';
var pulse = document.createElement("div");
pulse.className = 'pulse';
markerContent.appendChild(ico_position);
ico_position.appendChild(pin);
ico_position.appendChild(pulse);
// 点标记中的文本
var markerSpan = document.createElement("span");
markerSpan.className = 'marker';
markerSpan.innerHTML = "我在这";
markerContent.appendChild(markerSpan);
以下为默认图片展示
点标记中的图标
//var markerImg = document.createElement("img");
//markerImg.className = "markerlnglat";
//markerImg.src = "http://webapi.amap.com/theme/v1.3/markers/n/mark_r.png";
//markerContent.appendChild(markerImg);
点标记中的文本
//var markerSpan = document.createElement("span");
//markerSpan.className = 'marker';
//markerSpan.innerHTML = "Hi,我换新装备啦!";
//markerContent.appendChild(markerSpan);
marker.setContent(markerContent); //更新点标记内容
marker.setPosition([108.992398, 34.256198]); //更新点标记位置,如果是固定的这么写下面不用转化坐标了
//百度坐标转化高德坐标,使用高德api坐标(以下为php程序调用发送{$xpoint}, {$ypoint}坐标点)
// htmlobj = $.ajax({
// url: "http://restapi.amap.com/v3/assistant/coordinate/convert?key=c67d73f88613f4f574df092a93602c43&locations={$xpoint},{$ypoint}&coordsys=baidu",
// async: false
// });
// var obj = JSON.parse(htmlobj.responseText);
// var parts1 = obj.locations.split(',');
// console.log('精度:',parts1[0],'纬度:',parts1[1])
// marker.setPosition([parts1[0], parts1[1]]); //更新点标记位置
// console.log('x坐标:', {$xpoint}, 'y坐标:', {$ypoint});
}
updateMarker();
}
selfPosition();
// 4.刷新显示
function refresh() {
var zoom = map.getZoom();
if (zoom < 13) {
$('.amap-marker-label').show()//区县显示内容
pointSimplifierIns.hide();//具体坐标点显示
} else if (zoom > 16) {
map.setZoom(12);
} else {
$('.amap-marker-label').hide();//区县显示内容
pointSimplifierIns.show();//具体坐标点显示
}
}
// 5.监听事件
map.on('zoomend', function () {
refresh();
console.log('zoom1', map.getZoom())
});
pointSimplifierIns.on('pointClick', function (e, record) {
var parts1 = record.data.split(',');
$('#showMsg').html(parts1[2]);
$('.mask').show(500)
// $('.mask').fadeIn(500)/*注意:渐显的效果只能pc显示,移动端不反应*/
});
distCluster.on('featureClick', function (e, feature) {
if (map.getZoom() == 16) {
map.setZoom(16);
} else {
map.setZoom(map.getZoom() + 1);
}
// 设置点击点为视图坐标
map.setCenter([e.originalEvent.lnglat.getLng(), e.originalEvent.lnglat.getLat()])
console.log(e, feature.properties.name)
});
distCluster.on('clusterMarkerClick clusterMarkerRightclick', function (e, record) {
if (map.getZoom() == 16) {
map.setZoom(16);
} else {
map.setZoom(map.getZoom() + 1);
}
map.setCenter([e.originalEvent.lnglat.getLng(), e.originalEvent.lnglat.getLat()])
console.log(e, record.feature.properties.name)
});
$('.mask').on('click', function () {
$('.mask').hide(500);
// $('.mask').fadeOut(500);/*注意:渐隐的效果只能pc显示,移动端不反应*/
});
$('#showMsg').on('click', function (e) {
// 阻止事件冒泡
e.stopPropagation()
});
$('<div id="loadingTip">加载数据,请稍候...</div>').appendTo(document.body);
$.get('http://localhost:63342/map/10w1.txt', function (csv) {
// 本地同级目录的数据文件,除官方数据已有的经纬度之外,添加了第三个自定义信息
$('#loadingTip').remove();
var data = csv.split('\n');
distCluster.setData(data);
pointSimplifierIns.setData(data);
});
}
//加载相关组件
AMapUI.load(['ui/geo/DistrictCluster', 'ui/misc/PointSimplifier', 'lib/$'], function (DistrictCluster, PointSimplifier, $) {
// 创建点击具体坐标点后弹框样式
function creatMask() {
var bodyin = document.getElementById('body');
var new_obj1 = document.createElement("div");
new_obj1.setAttribute("class", "mask");
var new_obj2 = document.createElement("div");
new_obj2.setAttribute("id", "showMsg");
bodyin.appendChild(new_obj1);
new_obj1.appendChild(new_obj2);
}
creatMask();
$('.mask').hide();
//启动页面
initPage(DistrictCluster, PointSimplifier, $);
});
</script>
</body>
</html>
10w1.txt文件:
108.935398,34.256598,西安市1
108.926398,34.316598,西安市2
108.947398,34.351598,西安市3
108.868398,34.253598,西安市4
108.879398,34.246598,西安市5
108.981398,34.354598,西安市6
108.992398,34.256198,西安市7
map_common.css代码:
html,
body,
#container {
width: 100%;
height: 100%;
margin: 0px;
}
#loadingTip {
position: absolute;
z-index: 9999;
top: 50%;
left: -50%;
padding: 3px 3px;
background: red;
color: #fff;
font-size: 14px;
border: none;
}
.amap-marker-label {
text-align: center;
padding:1rem;
width: 42px;
height: 42px;
background: rgba(55, 175, 55, 0.8);
color: #fff;
border-radius: 50%;
line-height:1.5rem;
border: 1px solid #fff;
font-size: 1rem;
}
.amap-icon {
width: 42px !important;
top: 0;
display: none;
}
.amap-icon img {
width: 42px !important;
height: 42px !important;
left: 0 !important;
visibility: hidden;
cursor: pointer;
}
.amap-toolbar {
display: none
}
展示效果如上图
注意:
1.高德地图示例也有聚合显示个数的,但是为网格聚合,按照面积计算,不适合用其为基础模板,应当选用带有海量展示点和的行政区域聚合
2.由于电脑和移动端屏幕可视区域不同,由缩放逻辑控制的显示情况可能会出现差异,可以通过meta标签里的
initial-scale=0.8
这个来修改
3.注意提供数据格式的拆分
var data = csv.split('\n');
data.split(',');
4.本示例通过隐藏样例的定位图标,将定位点的样式放大而写,你也可以通过重新书写标签样式来改变
以下为主要研究示例:
demo2-使用高德定位+公交规划:
map_demo2.html
<!doctype html>
<html lang="zh-CN">
<head>
<!-- 原始地址://webapi.amap.com/ui/1.0/ui/geo/DistrictCluster/examples/plus-point-simplifier.html -->
<!--<base href="//webapi.amap.com/ui/1.0/ui/geo/DistrictCluster/examples/" />-->
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1.0, user-scalable=yes, width=device-width">
<title>区划聚合+海量点展示+定位+最近公交路线</title>
<!--调整容器大小和一些目标地点样式大小,一级隐藏,需要使用-->
<link rel="stylesheet" href="css/map_common.css">
<!--一些样式修改和遮罩弹框样式,可以不加,需要使用-->
<link rel="stylesheet" href="css/map_plus.css">
<link rel="stylesheet" href="http://cache.amap.com/lbs/static/main1119.css"/>
<script type="text/javascript" src='//webapi.amap.com/maps?v=1.4.3&key=d59a0ae0dd2a9b17cbbc480bea2f2033'></script>
<!-- UI组件库 1.0 -->
<script src="//webapi.amap.com/ui/1.0/main.js?v=1.0.11"></script>
<script type="text/javascript"
src="http://webapi.amap.com/maps?v=1.4.3&key=你的高德地图秘钥&plugin=AMap.Transfer"></script>
<script type="text/javascript" src="http://cache.amap.com/lbs/static/addToolbar.js"></script>
</head>
<body>
<div id="container"></div>
<div id="panel"></div>
<div id="tip"></div>
<div id="btn_minRoad" class="btn_road">点击查看最近公交路线</div>
<script type="text/javascript">
//创建地图
var map = new AMap.Map('container', {
resizeEnable: true,
expandZoomRange: true,
zoom: 10,
zooms: [10, 15],
cursor: 'default',
center:[112.947398,34.351598]
});
// 地图初始化
function initPage(DistrictCluster, PointSimplifier, $) {
var pointSimplifierIns = new PointSimplifier({
map: map, //所属的地图实例
autoSetFitView: false, //禁止自动更新地图视野
zIndex: 110,
getPosition: function (item) {
if (!item) {
return null;
}
var parts = item.split(',');
//返回经纬度
return [parseFloat(parts[0]), parseFloat(parts[1]), parts[2]];
},
getHoverTitle: function (dataItem) {
var parts1 = dataItem.split(',');
return parts1[2];
},
renderOptions: {
//点的样式
pointStyle: {
width: 20,
height: 20,
fillStyle: 'rgba(255, 0, 0, 1)',
},
// hover层级大小
pointHoverStyle: {
width: 20,
height: 20,
},
// 点击范围大小
pointHardcoreStyle: {
width: 20,
height: 20,
lineWidth: 3,
},
//鼠标hover时的title信息
hoverTitleStyle: {
position: 'left',
offset: [3, 0],
},
}
});
var distCluster = new DistrictCluster({
zIndex: 102,
map: map, //所属的地图实例
getPosition: function (item) {
if (!item) {
return null;
}
var parts = item.split(',');
//返回经纬度
return [parseFloat(parts[0]), parseFloat(parts[1]), parts[2]];
},
renderOptions: {
//显示在所辖数据点的平均位置
getClusterMarkerPosition: DistrictCluster.ClusterMarkerPositionStrategy.AVERAGE_POINTS_POSITION,
getClusterMarker: function (feature, dataItems, recycledMarker) {
//label内容
var name3 = feature.properties.name.length < 4 ? feature.properties.name : (feature.properties.name[0] + feature.properties.name[1])
var content = name3 + '<br />' + dataItems.length+'个';
var label = {
offset: new AMap.Pixel(-20, 0), //修改label相对于marker的位置
//----------要改等级---------
// content: map.getZoom() < 13 ? content : null
content: content
};
if (dataItems.length > 0) {
//存在可回收利用的marker
if (recycledMarker) {
//直接更新内容返回
recycledMarker.setLabel(label);
return recycledMarker;
}
//返回一个新的Marker
return new AMap.Marker({
//----------要改等级---------
// label: map.getZoom() < 13 ? label : null,
label: label,
});
}
}
}
});
window.distCluster = distCluster;
//根据当前zoom调整点的尺寸,大小
var pointStyle = pointSimplifierIns.getRenderOptions().pointStyle;
pointStyle.width = pointStyle.height = 8 * Math.pow(1.2, map.getZoom() - 3);
function refresh() {
var zoom = map.getZoom();
if (zoom == 10) {
$('.amap-marker-label').show()//区县显示内容
pointSimplifierIns.hide();//具体坐标点显示
} else if (zoom == 11) {
map.setZoom(12);
} else if (zoom == 12) {
map.setZoom(12);
$('.amap-marker-label').hide();//区县显示内容
pointSimplifierIns.show();//具体坐标点显示
} else if (zoom == 13) {
map.setZoom(13);
$('.amap-marker-label').hide();//区县显示内容
pointSimplifierIns.show();//具体坐标点显示
}else if (zoom == 14) {
map.setZoom(14);
$('.amap-marker-label').hide();//区县显示内容
pointSimplifierIns.show();//具体坐标点显示
}else {
map.setZoom(10);
}
}
//监听事件
map.on('zoomend', function () {
refresh();
console.log('zoom1', map.getZoom())
});
map.on('click', function (e) {
map.setZoom(map.getZoom() + 1);
map.setCenter([e.lnglat.getLng(), e.lnglat.getLat()])
refresh();
// alert('您在[ ' + e.lnglat.getLng() + ',' + e.lnglat.getLat() + ' ]的位置点击了地图!');
});
pointSimplifierIns.on('pointClick', function (e, record) {
var parts1 = record.data.split(',');
map.setZoom(10);
alert(parts1[2])
});
//------------------公交路线规划----------------------
function road_planning(data_Geolocation) {
btn_minRoad.onclick = function () {
var transOptions = {
map: map,
city: '西安市',
panel: 'panel',
//cityd:'乌鲁木齐',
policy: AMap.TransferPolicy.LEAST_TIME
};
//构造公交换乘类
var transfer = new AMap.Transfer(transOptions);
//根据起、终点坐标查询公交换乘路线
var min_road = Number.POSITIVE_INFINITY;
var min_roads = [];
var postion_now_j = data_Geolocation.position.getLng();
var postion_now_w = data_Geolocation.position.getLat();
function minRoad(data_Geolocation) {
for (var i = 0; i < pointSimplifierIns._data.source.length; i++) {
// console.log(pointSimplifierIns._data.source[i])
if (!pointSimplifierIns._data.source[i]) {
return null;
}
var parts = pointSimplifierIns._data.source[i].split(',');
postion_target_j = parseFloat(parts[0]);
postion_target_w = parseFloat(parts[1]);
Math.pow(postion_target_j - postion_now_j, 2);
Math.pow(postion_now_w - postion_target_w, 2);
if ((Math.pow(postion_target_j - postion_now_j, 2) + Math.pow(postion_now_w - postion_target_w, 2)) < min_road) {
min_road = Math.pow(postion_target_j - postion_now_j, 2) + Math.pow(postion_now_w - postion_target_w, 2)
min_roads = [postion_target_j, postion_target_w];
console.log('min_roads', min_roads[0], min_roads[1])
console.log('min_road', (Math.pow(postion_target_j - postion_now_j, 2) + Math.pow(postion_now_w - postion_target_w, 2)))
}
//返回经纬度
return min_roads
}
};
transfer.search(new AMap.LngLat(postion_now_j, postion_now_w), new AMap.LngLat(minRoad()[0], minRoad()[1]));
}
}
//------------------定位功能----------------------
var geolocation;
//加载地图,调用浏览器定位服务
map.plugin('AMap.Geolocation', function () {
geolocation = new AMap.Geolocation({
enableHighAccuracy: true,//是否使用高精度定位,默认:true
timeout: 10000, //超过10秒后停止定位,默认:无穷大
buttonOffset: new AMap.Pixel(10, 20),//定位按钮与设置的停靠位置的偏移量,默认:Pixel(10, 20)
zoomToAccuracy: true, //定位成功后调整地图视野范围使定位位置及精度范围视野内可见,默认:false
buttonPosition: 'RB',
});
map.addControl(geolocation);
geolocation.getCurrentPosition();
AMap.event.addListener(geolocation, 'complete', complete_zoom);//返回定位信息
AMap.event.addListener(geolocation, 'error', onError); //返回定位出错信息
});
var zoom2 = map.getZoom();
console.log('zoom2:',zoom2);
//解析定位结果
function complete_zoom(data_Geolocation) {
var zoom = map.getZoom();
console.log('zoom3:',zoom);
map.setZoom(zoom);
// var str = ['定位成功'];
// str.push('经度:' + data_Geolocation.position.getLng());
// str.push('纬度:' + data_Geolocation.position.getLat());
// if (data_Geolocation.accuracy) {
// str.push('精度:' + data_Geolocation.accuracy + ' 米');
// }//如为IP精确定位结果则没有精度信息
// str.push('是否经过偏移:' + (data_Geolocation.isConverted ? '是' : '否'));
// document.getElementById('tip').innerHTML = str.join('<br>');
var btn_minRoad = $('#btn_minRoad');
road_planning(data_Geolocation)
}
//解析定位错误信息
function onError(data_Geolocation) {
document.getElementById('tip').innerHTML = '定位失败';
}
//------------打开设备判断----------------
if (/Android|webOS|iPhone|iPod|BlackBerry/i.test(navigator.userAgent)) {
$('#panel').css('display', 'none');
$('.amap-toolbar').hide();
} else {
$('#panel').css('display', 'block')
}
$('<div id="loadingTip">加载数据,请稍候...</div>').appendTo(document.body);
$.get('http://localhost:63342/map/10w1.txt', function (csv) {
// 本地同级目录的数据文件,除官方数据已有的经纬度之外,添加了第三个自定义信息
$('#loadingTip').remove();
var data = csv.split('\n');
distCluster.setData(data);
pointSimplifierIns.setData(data);
});
}
//加载相关组件
AMapUI.load(['ui/geo/DistrictCluster', 'ui/misc/PointSimplifier', 'lib/$'], function (DistrictCluster, PointSimplifier, $) {
//启动页面
initPage(DistrictCluster, PointSimplifier, $);
});
</script>
</body>
</html>
css,txt文件同,可本地环境打开显示
未解决疑问:
1.高德地图定位失败的原因
在高德地图-浏览器定位的官方文档上有这样的一句注释“/***************************************
由于Chrome、IOS10等已不再支持非安全域的浏览器定位请求,为保证定位成功率和精度,请尽快升级您的站点到HTTPS。
***************************************/”,不知道是不是和定位失败有关
另外,发现浏览器定位的时候,会有弹框提示问是否允许,只有点击确定才能定位,但有的浏览器没有提示弹框,或者用户第一次点击取消,之后怎么刷新都没有弹框确认定位,定位也就失败了。js中如何写定位提醒的弹框呢?