一,zoom要是小数,需要3d地图模式
const Map = new AMap.Map(that.idHash, {
mask: mask, //只显示包裹起来的区域
resizeEnable: true, //是否监控地图容器尺寸变化
showIndoorMap: false, //关闭室内地图
center: [96.01906121185537, 35.874643454131984],
viewMode: "3D",
dragEnable: false, //初始状态下不可移动
pitch: 0,
zoom: that.zoom - 0.1,
features: that.depFeatures, //初始色块模式下,不显示标注等信息
mapStyle: "amap://styles/021981e1781074e215441507a954df4b" //设置地图的显示样式
});
主要是这两个3d模式打开:
viewMode: "3D",
pitch: 0,
但是呢,使用setFitView,根据覆盖物自动调整地图的大小,以适应容器,还是使用的整数。例如,要正好完美地显示地图在容器中,需要地缩放zoom是6.66时,setFitView只会使用zoom=6进行处理,这就导致,所渲染的地图只有少部分情况下是正常满足要求的缩放级别。大部分情况是偏小的。
如下图所示:
二,采取的解决方案
现在,我们的主要问题是,setFitView是以整数来处理zoom的,从而导致有的时候,地图偏小。
1,取到容器边界的经度值:
//获取当前缩放级别下,左侧容器的经纬度(左上角的点在当前地图中的经纬度)
getLnglat() {
let pixel = new AMap.Pixel(0, 0);
let lnglat = this.map.containerToLngLat(pixel);
return lnglat;
},
2,通过官网的获取我们要展示地图的最左侧点的经纬度(实际上只要经度即可)
https://lbs.amap.com/demo/jsapi-v2/example/event/map-click-event
右侧点也先取到,后续用:
所以,现在,我们知道了我们要显示的地图的最左侧和最右侧的经度:
89.84339和103.123006,
于是,我们要显示的地图跨度:
103.123006-89.84339=13.279616
并且第一步可以取到容器最左侧的经度。
3,计算地图最左侧到容器最左侧的经度差距
这样一来,2中得到的目标地图跨度,加上这里计算的经度差距的2倍,就是容器能够容纳的经度跨度了,如下图所示:
4,自己给定合适的上图黄绿色的经纬度值
Map.setFitView();
that.zoom = Map.getZoom() + 0.5;
Map.setZoomAndCenter(that.zoom, [
96.01906121185537,
35.874643454131984
]);
console.log("当前放大级别", Map.getZoom());
let leftValue;
setTimeout(() => {
leftValue = that.getLnglat();
console.log("左侧容器的经纬度", leftValue.lng);
console.log(
"目标地图距离容器最左侧的经度:",
89.84339 - leftValue.lng
); //青海省地图经度范围89.84339和103.123006
// that.zoom = Map.getZoom() + 0.66;
// Map.setZoomAndCenter(that.zoom, [
// 96.01906121185537,
// 35.874643454131984
// ]);
console.log("当前级别", Map.getZoom());
}, 0);
所以,我的目标是无论浏览器大小怎么变,只要这个黄绿色的经度跨度是1.196642左右,就可以满足我的需求。
但是,问题是,目前这个效果,是我手动调试出来的,也就是上面的代码:
Map.setFitView();
that.zoom = Map.getZoom() + 0.5;
Map.setZoomAndCenter(that.zoom, [
96.01906121185537,
35.874643454131984
]);
先是自适应后,手动加了这个0.5,才达到的效果。因为之前已经说过,这个setFitView是按整数来的,所以加的值必然在0-1之间。那要怎样才能得到比较准确的值呢?
我也不知道哈哈,这个源码没看过,但是给个大概的倒是没问题。
我的尝试方法是,每次Map.setFitView();之后,不再手动添加数值,直接计算出来这个值,然后和1.196642比对,多比对几次,得出比较靠谱的系数。我自己用的是0.148.
于是代码:
Map.setFitView();//在初始设置zoom后自适应一次(此时可能有地图偏小的情况发生)
console.log("当前放大级别", Map.getZoom());
setTimeout(() => {//这里为了获取左侧的经度值需要在第一次自适应之后获取,所以settimeout
let leftValue = that.getLnglat();
console.log("左侧容器的经纬度", leftValue.lng);
console.log(
"目标地图距离容器最左侧的经度:",
89.84339 - leftValue.lng
); //青海省地图经度范围89.84339和103.123006
const leftLngRange = ((89.84339 - leftValue.lng) / 1.196642) * 0.148;
console.log("需要调整的系数:", leftLngRange);
that.zoom = Map.getZoom() + leftLngRange;
Map.setZoomAndCenter(that.zoom, [
96.01906121185537,
35.874643454131984
]);//处理好系数之后,再次变换地图
console.log("当前级别", Map.getZoom());
}, 0);
三,实现的效果
四,完整的vue组件代码
要实现自适应的,看上面的代码即可,下面这个代码,有很多是其他功能的,填充色块,描边,行政区高亮,点聚合等等一大堆。
<template>
<div
:id="idHash"
class="container"
style="z-index:1"
/>
</template>
<script>
import pin1 from "../assets/images/pin1.png";
import pin2 from "../assets/images/pin2.png";
import pin3 from "../assets/images/pin3.png";
import pin4 from "../assets/images/pin4.png";
import pin5 from "../assets/images/pin5.png";
import axios from "axios";
export default {
name: "MapChart",
props: {
year: { type: String, default: "2021" },
// zoom: { type: Number, default: 4 },
showData: { type: Boolean, default: false },
locationList: Array, //产业数据-面店分布的地图显示传入数据
getLocation: { type: Boolean, default: false } //首页-面店分布的图片显示
},
data: () => ({
loading: false,
idHash: "MapContainer" + new Date().getTime(),
disProvinces: " ",
map: {}, //地图对象
depFeatures: [], //地图标注内容
lineArr: [],
zoom: 7
}),
watch: {
year() {
this.refresh();
},
locationList() {
this.refresh();
}
},
mounted() {
// eslint-disable-next-line no-undefined
if (window.AMap == undefined) {
const script = document.createElement("script");
script.src =
"https://webapi.amap.com/maps?v=1.4.15&plugin=AMap.MarkerClusterer,Map3D,AMap.DistrictLayer,AMap.DistrictSearch&callback=initAMap&key=de45c1a0e7ea44bea49388cea9cca2f7";
document.head.appendChild(script);
window.initAMap = () => {
this.refresh();
};
} else {
this.refresh();
}
},
methods: {
refresh() {
let that = this;
if (!window.AMap) {
return;
}
const opts = {
subdistrict: 0,
extensions: "all",
level: "province"
};
//直接通过经纬度构建mask路径
// eslint-disable-next-line no-undef
const district = new AMap.DistrictSearch(opts);
district.search("青海省", function(status, result) {
const bounds = result.districtList[0].boundaries;
const mask = [];
for (let i = 0; i < bounds.length; i += 1) {
mask.push([bounds[i]]);
}
// eslint-disable-next-line no-undef
const Map = new AMap.Map(that.idHash, {
mask: mask, //只显示包裹起来的区域
resizeEnable: true, //是否监控地图容器尺寸变化
showIndoorMap: false, //关闭室内地图
center: [96.01906121185537, 35.874643454131984],
viewMode: "3D",
dragEnable: false, //初始状态下不可移动
pitch: 0,
zoom: that.zoom - 0.1,
features: that.depFeatures, //初始色块模式下,不显示标注等信息
mapStyle: "amap://styles/021981e1781074e215441507a954df4b" //设置地图的显示样式
});
that.map = Map; //把这里面创建的地图对象存起来,让这个指针指向它,后续要使用
//青海省描边--(原因是黄南中间有块地方,是属于海南自治区的。)
for (let i = 0; i < bounds.length; i += 1) {
// eslint-disable-next-line no-undef
new AMap.Polyline({
path: bounds[i],
strokeColor: "#1a77aa",
strokeWeight: 10,
map: Map
});
}
//点聚合数据处理
if (that.showData) {
// 地图的数据由父组件传入
that.updateMark(Map, that.locationList);
} else if (that.getLocation) {
// 首页-面店分布的图片显示
axios({
url: "diagram/getShopDistribute2",
method: "get", // default
baseURL: "http://47.115.140.114:5001/api/report/",
headers: {
"x-user-token":
"eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJiYW5rZm9ydGVzdDAwMSIsInN1YiI6ImxvZ2luLmxvZ2luIiwiaWF0IjoxNjI0OTU2NjQ0LCJhdXRob3JpemF0aW9uIjp7fSwiZGVwdE5hbWUiOiLpnZLmtbfmi4npnaLkuqfkuJrnu7zlkIjmnI3liqHlubPlj7AiLCJsb2dpblRpbWUiOiIyMDIxLTA2LTI5IDE2OjUwOjQ0IiwidW5pdE5hbWUiOiLpnZLmtbfmi4npnaLkuqfkuJrnu7zlkIjmnI3liqHlubPlj7AiLCJwcm92aW5jZSI6IjQ0MDAwMCIsImNpdHkiOiI0NDAxMDAiLCJ1bml0Q29kZSI6ImxhbWlhbiIsInJlZGlzVG9rZW4iOiJkNTdmNDExOC0zYTVkLTQ2OWYtYTcxZC02MDY3NjIwNzg2ODMiLCJ0ZW5hbnRJZCI6ImxhbWlhbiIsInN0YWZmVHlwZTIiOiI0IiwiZGVwdENvZGUiOiJsYW1pYW4iLCJleHAiOjE2MjQ5NTg0NDQsInVzZXJuYW1lIjoiYmFua2ZvcnRlc3QwMDEifQ.WqCfDi6iSQnn8MYOSwnvNwy6oixiZPFdE4mEUSr0H0M"
}
}).then(res => {
that.updateMark(Map, res.data.locationList);
});
}
//按行政区填充色块
that.initPro(Map);
//也可以改用覆盖物填充的方式填充行政区
// that.alldrawBounds(Map);
//按行政区描边
that.allborderLine(Map);
Map.setFitView();
console.log("当前放大级别", Map.getZoom());
setTimeout(() => {
let leftValue = that.getLnglat();
console.log("左侧容器的经纬度", leftValue.lng);
console.log(
"目标地图距离容器最左侧的经度:",
89.84339 - leftValue.lng
); //青海省地图经度范围89.84339和103.123006
const leftLngRange = ((89.84339 - leftValue.lng) / 1.196642) * 0.148;
console.log("目前跨度是目标值的倍数", leftLngRange);
that.zoom = Map.getZoom() + leftLngRange;
Map.setZoomAndCenter(that.zoom, [
96.01906121185537,
35.874643454131984
]);
console.log("当前级别", Map.getZoom());
//监听地图的缩放事件
Map.on("zoomstart", function() {
console.log("放大级别:", Map.getZoom());
if (Map.getZoom() >= that.zoom) {
that.zoomChange();
} else {
//重新显示行政区色块
that.disProvinces.show();
//且需要关闭街景模式
that.depFeatures = [];
that.setFeature(that.map);
//重新显示描边
for (let i = 0; i < that.lineArr.length; i++) {
that.lineArr[i].show();
}
}
});
}, 0);
});
},
//所有行政区填充色块-(注释掉不用)
alldrawBounds(Map) {
const that = this;
that.drawBounds("西宁市", Map, "#2c54cf");
that.drawBounds("海西蒙古族藏族自治州", Map, "#17307c");
that.drawBounds("海东市", Map, "#17307c");
that.drawBounds("海南藏族自治州", Map, "#2b47ac");
that.drawBounds("海北藏族自治州", Map, "#204699");
that.drawBounds("果洛藏族自治州", Map, "#17307c");
that.drawBounds("黄南藏族自治州", Map, "#1c3077");
that.drawBounds("玉树藏族自治州", Map, "#204699");
},
//使用覆盖物的方法,按行政区填充色块-(注释掉不用)
drawBounds(city, Map, color) {
//实例化DistrictSearch
let opts = {
subdistrict: 0, //获取边界不需要返回下级行政区
extensions: "all", //返回行政区边界坐标组等具体信息
level: "city" //查询行政级别为市
};
// eslint-disable-next-line no-undef
const district = new AMap.DistrictSearch(opts);
//行政区查询
district.search(city, function(status, result) {
const polygons = [];
const bounds = result.districtList[0].boundaries;
console.log(city, bounds);
if (bounds) {
for (let i = 0, l = bounds.length; i < l; i++) {
//生成行政区划polygon
// eslint-disable-next-line no-undef
let polygon = new AMap.Polygon({
strokeWeight: 0, //线宽
path: bounds[i], //多边形边界路径
fillOpacity: 0.7, //填充透明度
fillColor: color, //填充颜色
strokeColor: "#1a77aa" //线颜色
});
// 创建覆盖物的监听事件
// polygon.on('mouseover', function(e) {
// polygon.setOptions({
// fillColor: '#114af8',//填充颜色
// })
// });
// polygon.on('mouseout', function(e) {
// console.log(e.lnglat);
// polygon.setOptions({
// fillColor: color,//填充颜色
// })
// });
polygons.push(polygon);
}
}
Map.add(polygons);
});
},
// 创建市区的颜色块
initPro(map) {
const that = this;
const code = 630000; //青海省代码
const dep = 1; //按市区划分
let disProvince;
disProvince && disProvince.setMap(null);
// eslint-disable-next-line no-undef
disProvince = new AMap.DistrictLayer.Province({
zIndex: 12,
adcode: [code],
depth: dep,
styles: {
fill: function(properties) {
// properties为可用于做样式映射的字段,包含
// NAME_CHN:中文名称
// adcode_pro
// adcode_cit
// adcode
let adcode = properties.adcode;
return that.getColorByAdcode(adcode);
},
// 'province-stroke': 'cornflowerblue',
"city-stroke": "#3078AC" // 中国地级市边界
// 'county-stroke': 'rgba(255,255,255,0.5)' // 中国区县边界
}
});
disProvince.setMap(map);
that.disProvinces = disProvince;
},
// 颜色辅助方法
getColorByAdcode(adcode) {
const colors = {
630100: "#2c54cf", //西宁
630200: "#17307c", //海东
632200: "#204699", //海北
632300: "#1c3077", //黄南
632500: "#2b47ac", //海南
632600: "#17307c", //果洛
632700: "#204699", //玉树
632800: "#17307c" //海西
};
return colors[adcode];
},
//更新标记点
updateMark(Map, points) {
// 位置标记
const Markers = [];
for (let i = 0; i < points.length; i += 1) {
if (points[i]) {
Markers.push(
// eslint-disable-next-line no-undef
new AMap.Marker({
position: points[i].split(","),
// eslint-disable-next-line no-undef
offset: new AMap.Pixel(-15, -15)
})
);
}
}
let str = [
{
url: pin5,
// eslint-disable-next-line no-undef
size: new AMap.Size(100, 100),
// eslint-disable-next-line no-undef
offset: new AMap.Pixel(-100, -100),
textSize: 40,
textColor: "#353535"
},
{
url: pin4,
// eslint-disable-next-line no-undef
size: new AMap.Size(100, 100),
// eslint-disable-next-line no-undef
offset: new AMap.Pixel(-100, -100),
textSize: 40,
textColor: "#353535"
},
{
url: pin3,
// eslint-disable-next-line no-undef
size: new AMap.Size(100, 100),
// eslint-disable-next-line no-undef
offset: new AMap.Pixel(-100, -100),
textSize: 40,
textColor: "#353535"
},
{
url: pin2,
// eslint-disable-next-line no-undef
size: new AMap.Size(100, 100),
// eslint-disable-next-line no-undef
offset: new AMap.Pixel(-100, -100),
textSize: 40,
textColor: "#353535"
},
{
url: pin1,
// eslint-disable-next-line no-undef
size: new AMap.Size(100, 100),
// eslint-disable-next-line no-undef
offset: new AMap.Pixel(-100, -100),
textSize: 40,
textColor: "#353535"
}
];
// eslint-disable-next-line no-undef
new AMap.MarkerClusterer(Map, Markers, {
styles: str,
gridSize: 60,
minClusterSize: 1
});
},
//所有行政区描边
allborderLine(Map) {
const that = this;
that.borderLine("海西蒙古族藏族自治州", Map);
that.borderLine("海东市", Map);
that.borderLine("海南藏族自治州", Map);
that.borderLine("海北藏族自治州", Map);
that.borderLine("果洛藏族自治州", Map);
// that.borderLine('黄南藏族自治州',Map)//黄南中间有块地皮是海南自治区的,不能描边,采用省描边加邻区描边来作为它的边
that.borderLine("玉树藏族自治州", Map);
that.borderLine("西宁市", Map);
},
//行政区描边的功能
borderLine(city, Map) {
const that = this;
const opts = {
subdistrict: 0,
extensions: "all",
level: "city"
};
//直接通过经纬度构建mask路径
// eslint-disable-next-line no-undef
const district = new AMap.DistrictSearch(opts);
district.search(city, function(status, result) {
const bounds = result.districtList[0].boundaries;
//添加描边
for (let i = 0; i < bounds.length; i += 1) {
// eslint-disable-next-line no-undef
const myLine = new AMap.Polyline({
path: bounds[i],
strokeColor: "#1a77aa",
strokeWeight: 5,
strokeOpacity: 0.9,
map: Map
});
// 创建线条的监听事件
myLine.on("mouseover", function() {
myLine.setOptions({
strokeColor: "#114af8",
strokeWeight: 10
});
});
myLine.on("mouseout", function() {
myLine.setOptions({
strokeColor: "#1a77aa",
strokeWeight: 5
});
});
that.lineArr.push(myLine); //把行政区描边通过闭包给拿出来,后续需要显示和隐藏切换
}
});
},
//重新给地图增加标注信息
setFeature(Map) {
const _that = this;
Map.setFeatures(_that.depFeatures);
},
//监听鼠标滚轮事件,一旦用户放大地图则切换成街景模式
zoomChange() {
if (this.depFeatures.length > 0) {
console.log("已经开启街景地图,不做处理");
return;
} else {
this.depFeatures = ["bg", "road", "building", "point"];
this.map.setStatus({
dragEnable: true //切换成街景模式需要开启可拖拽模式
});
this.setFeature(this.map);
// this.map.clearMap(); //清除所有覆盖物
// this.removePoly("polygon"); //清除选定的覆盖物
// this.removePoly("polyline"); //清除选定的行政区边界
this.disProvinces.hide(); //隐藏行政区色块图层
//隐藏行政区描边
for (let i = 0; i < this.lineArr.length; i++) {
this.lineArr[i].hide();
}
console.log("开启街景地图");
}
},
//清除行政区色块和边界线条--(已经注释掉采用隐藏的方案替代)
removePoly(target) {
let mapPolyArr = this.map.getAllOverlays(target);
let arr = [];
for (let i = 0; i < mapPolyArr.length; i++) {
arr.push(mapPolyArr[i]);
}
this.map.remove(arr);
},
//获取当前缩放级别下,左侧容器的经度
getLnglat() {
// eslint-disable-next-line no-undef
let pixel = new AMap.Pixel(0, 0);
let lnglat = this.map.containerToLngLat(pixel);
return lnglat;
}
}
};
</script>
<style lang="scss" scoped>
.container {
height: 100%;
background: #0e204f !important;
}
::v-deep .amap-logo {
display: none !important;
}
::v-deep .amap-maps {
background: #0e204f;
}
::v-deep .amap-drags {
background: #0e204f;
}
::v-deep .amap-layers {
background: #0e204f;
}
</style>