<template>
|
<div :id="id" ref="contentRef" style="height: 100%; width: 100%">
|
<div
|
v-if="isShowControl"
|
:class="controlPosition"
|
class="control-container bottom-right"
|
>
|
<div
|
v-for="item in controlMapping"
|
:key="item.id"
|
class="control-content"
|
>
|
<template v-if="item.children">
|
<div
|
v-for="child in item.children"
|
:key="child.id"
|
class="control-item"
|
@click="child.event"
|
>
|
<img :src="child.img" />
|
</div>
|
</template>
|
<template v-else>
|
<div class="control-item" @click="item.event">
|
<img :src="item.img" />
|
</div>
|
</template>
|
</div>
|
</div>
|
</div>
|
</template>
|
<script>
|
import Location from "@/assets/images/location.png";
|
import FileImg from "@/assets/images/file1.png";
|
import MinusImg from "@/assets/images/minus.png";
|
import PlusImg from "@/assets/images/plus.png";
|
import FullScreenImg from "@/assets/images/fullScreen.png";
|
import PositionImg from "@/assets/images/position.png";
|
var infoWin;
|
export default {
|
data() {
|
return {
|
zoom: 15,
|
map: null,
|
contentRef: {},
|
infoWin: {},
|
defaultMaskInfo: {},
|
mapKey: "ffb871cd7ca48883db3b04cfd00d469f",
|
controlMapping: [
|
{
|
id: "定位",
|
img: PositionImg,
|
event: this.getCurrentPosition,
|
},
|
{
|
id: "缩放",
|
children: [
|
{
|
id: "放大",
|
img: PlusImg,
|
event: this.zoomIn,
|
},
|
{
|
id: "缩小",
|
img: MinusImg,
|
event: this.zoomOut,
|
},
|
],
|
},
|
{
|
id: "全屏",
|
img: FullScreenImg,
|
event: this.fullScreen,
|
},
|
],
|
};
|
},
|
props: {
|
id: String,
|
mapList: Array,
|
listType: Boolean,
|
isShowControl: Boolean,
|
controlPosition: Object,
|
isImmediateLoad: { type: Boolean, default: true },
|
mapType: Boolean,
|
},
|
|
created() {
|
this.defaultMaskInfo = {
|
lon: this.$props.mapList[0]?.lon
|
? this.$props.mapList[0].lon
|
: "105.37281",
|
lat: this.$props.mapList[0]?.lat
|
? this.$props.mapList[0].lat
|
: "30.87145",
|
name: this.$props.mapList[0]?.name ? this.$props.mapList[0].name : "创建",
|
};
|
if (this.$props.isImmediateLoad) this.onLoad();
|
},
|
methods: {
|
async onLoad() {
|
const scripts = document.body.querySelectorAll("script");
|
if (!this.mapKey) {
|
// const res = await getDicts('map_key')
|
// mapKey = res[0].dictLabel
|
this.mapKey = "ffb871cd7ca48883db3b04cfd00d469f";
|
}
|
|
const scriptSrc = `http://api.tianditu.gov.cn/api?v=4.0&tk=${this.mapKey}`;
|
const mapScript = Array.from(scripts).find((item) => {
|
return item.getAttribute("src") === scriptSrc;
|
});
|
|
if (!mapScript) {
|
// 创建script标签
|
const script = document.createElement("script");
|
// 设置API的URL
|
script.src = scriptSrc;
|
script.type = "text/javascript";
|
// 将script标签添加到HTML中
|
document.body.appendChild(script);
|
script.onload = () => {
|
this.initTianMap();
|
};
|
} else {
|
this.initTianMap();
|
}
|
},
|
|
initTianMap() {
|
var T = window.T;
|
setTimeout(async () => {
|
// this.map = new T.Map(this.id, {
|
// projection: "EPSG:4326",
|
// });
|
this.map = new T.Map(this.id);
|
this.map.centerAndZoom(
|
new T.LngLat(this.defaultMaskInfo.lon, this.defaultMaskInfo.lat),
|
this.zoom
|
);
|
if (!this.$props.listType) {
|
// 清除之前的标记
|
// map && map.clearOverLays()
|
//form表单中是否有坐标,有则定位到对应位置,没有则使用默认的
|
// 104.65417 28.75572 测试数据
|
// 四川省宜宾市翠屏区大观楼街道外南街71
|
if (this.$props.mapList[0].addr) {
|
const { lng: lon, lat } = await this.getGeocode(
|
this.$props.mapList[0].addr
|
);
|
this.defaultMaskInfo.lon = String(lon);
|
this.defaultMaskInfo.lat = String(lat);
|
}
|
|
this.map && this.makeDefaultMask(this.defaultMaskInfo);
|
this.addEvent(this.map, "click", (e) => this.mapClick(e));
|
} else {
|
this.$props.mapList.length && this.makeAllMask(this.$props.mapList);
|
}
|
}, 1500);
|
},
|
|
zoomIn() {
|
this.map && this.map.zoomIn();
|
},
|
|
zoomOut() {
|
this.map && this.map.zoomOut();
|
},
|
|
fullScreen() {
|
this.map && this.contentRef?.requestFullscreen();
|
},
|
|
getCurrentPosition() {
|
// if (navigator.geolocation) {
|
// ElMessage.warning("该功能暂未开发");
|
// // TODO 地图定位
|
// // navigator.geolocation.getCurrentPosition(function (position) {
|
// // var latitude = position.coords.latitude
|
// // var longitude = position.coords.longitude
|
// //
|
// // moveTo(String(longitude), String(latitude))
|
// // })
|
// } else {
|
// ElMessage.warning("当前浏览器不支持定位功能");
|
// }
|
},
|
|
moveTo(lon, lat) {
|
this.map && this.map.panTo(new T.LngLat(lon, lat));
|
},
|
// 默认的点标记
|
makeDefaultMask(mapInfo) {
|
const { name, lon, lat } = mapInfo;
|
const option = {
|
text: name,
|
offset: [-35, -45],
|
labelBg: "#3369FF",
|
labelColor: "#fff",
|
labelClick: this.labelClick,
|
};
|
// 清除之前的标记
|
this.map && this.map.clearOverLays();
|
this.map.panTo(new T.LngLat(lon, lat));
|
this.makeMask(lon, lat, { labelOptions: option });
|
},
|
|
// 地图点击事件
|
mapClick(e) {
|
e.originalEvent.stopPropagation();
|
|
const { lat, lng: lon } = e.lnglat;
|
|
this.makeDefaultMask({
|
...this.defaultMaskInfo,
|
lon: String(lon),
|
lat: String(lat),
|
});
|
this.getReverseGeocode(e).then((addr) => {
|
this.$emit("mapClick", {
|
e,
|
addr,
|
});
|
});
|
console.log("点击事件", e);
|
},
|
|
// 逆地理编码 获取地址
|
getReverseGeocode(e) {
|
return new Promise((resolve) => {
|
const geocode = new T.Geocoder();
|
geocode.getLocation(e.lnglat, (result) => {
|
if (result.status === "0") {
|
resolve(result.getAddress());
|
}
|
});
|
});
|
},
|
|
// 地理编码
|
getGeocode(addr) {
|
return new Promise((resolve) => {
|
const geocoder = new T.Geocoder();
|
geocoder.getPoint(addr, (result) => {
|
if (result.status === "0") {
|
resolve(result.getLocationPoint());
|
}
|
});
|
});
|
},
|
|
// 生成点位内容
|
// 生成点位内容
|
generateContent(row, random) {
|
if (row) {
|
return `
|
<div class="map-window-info">
|
<div class='title-block'>
|
<div class="title truncate-content">
|
${row.projectName ?? "暂无数据"}
|
</div>
|
<div class='close-btn close-btn-${random}'>
|
</div>
|
</div>
|
<div class="detail-info">
|
<span class="truncate-content">总投资:${row.totalMoney || ""}</span>
|
<span class="truncate-content">
|
项目状态:${this.showProjectStatusStr(row.projectStatus)}
|
</span>
|
<span class="truncate-content">
|
项目地址:${row.projectAddr ?? "暂无数据"}
|
</span>
|
</div>
|
</div>`;
|
} else {
|
return `<div style="display: flex; justify-content:center; align-items:center; opacity: 0;">
|
|
</div>`;
|
}
|
},
|
showProjectStatusStr(status) {
|
switch (status) {
|
case "1":
|
return "储备项目";
|
case "2":
|
return "前期项目";
|
case "3":
|
return "实施项目";
|
case "4":
|
return "竣工项目";
|
case "5":
|
return "异常项目";
|
|
default:
|
return "异常项目";
|
}
|
},
|
// 唯一标识
|
getUniqueId() {
|
return Math.random().toString(36).substr(2) + Date.now();
|
},
|
|
markerMouseover(_e, info, random, markerOptions) {
|
if (infoWin) this.map.removeOverLay(infoWin);
|
// 点位标记移入显示不同内容
|
if (this.$props.isShowControl) {
|
infoWin = new T.InfoWindow();
|
infoWin.setContent(this.generateContent(info, random));
|
infoWin.setLngLat(_e.lnglat);
|
// 向地图上添加信息窗口
|
// if (this.$props.mapType) {
|
this.map && this.map.addOverLay(infoWin);
|
// }
|
|
// const contentWrapper = document.querySelector(
|
// ".tdt-infowindow-content-wrapper"
|
// );
|
// if (contentWrapper) {
|
// contentWrapper.style.opacity = "1";
|
// }
|
// 查找到那个info 界面
|
// const allCloseBtn = document.querySelectorAll(`.close-btn-${random}`);
|
// allCloseBtn[allCloseBtn.length - 1].onclick = (_e) => {
|
// infoWin.setContent(generateContent());
|
// };
|
}
|
},
|
|
markerMouseout(_e) {
|
// infoWin.setContent(this.generateContent());
|
// const contentWrapper = document.querySelector(
|
// ".tdt-infowindow-content-wrapper"
|
// );
|
// if (contentWrapper) {
|
// contentWrapper.style.opacity = "0";
|
// }
|
// this.map.removeOverLay(infoWin);
|
},
|
|
// 打标记
|
makeMask(lon, lat, options) {
|
if (lon && lat) {
|
const { markerOptions, labelOptions } = options;
|
|
const icon = new T.Icon({
|
iconUrl: Location,
|
iconSize: new T.Point(19, 27),
|
iconAnchor: new T.Point(10, 25),
|
});
|
|
var marker = new T.Marker(new T.LngLat(lon, lat), {
|
icon,
|
id: markerOptions?.id,
|
});
|
|
this.map && this.map.addOverLay(marker);
|
const label = new T.Label({
|
text: labelOptions.text,
|
position: new T.LngLat(lon, lat),
|
offset: new T.Point(...labelOptions.offset),
|
id: labelOptions?.id,
|
});
|
|
labelOptions.labelBg && label.setBackgroundColor(labelOptions.labelBg);
|
labelOptions.labelColor && label.setFontColor(labelOptions.labelColor);
|
//创建地图文本对象
|
if (!this.$props.mapType) {
|
this.map && this.map.addOverLay(label);
|
}
|
markerOptions?.markerClick &&
|
this.addEvent(marker, "click", (e) =>
|
markerOptions.markerClick(label, e)
|
);
|
labelOptions?.labelClick &&
|
this.addEvent(label, "click", (e) =>
|
labelOptions.labelClick(label, e)
|
);
|
|
this.addEvent(marker, "mouseover", (e) =>
|
this.markerMouseover(e, options, this.getUniqueId(), markerOptions)
|
);
|
this.addEvent(marker, "mouseout", (e) => this.markerMouseout(e));
|
}
|
},
|
|
// 标记所有点
|
makeAllMask(mapList) {
|
// 清除之前的标记
|
this.map && this.map.clearOverLays();
|
var minX = mapList[0].longitude;
|
var maxX = mapList[0].longitude;
|
var minY = mapList[0].latitude;
|
var maxY = mapList[0].latitude;
|
var _this = this;
|
mapList.map((item) => {
|
const config = {
|
markerOptions: {
|
id: item.id,
|
// markerClick: _this.markerClick,
|
},
|
labelOptions: {
|
text: item.projectName,
|
offset: [-45, -45],
|
id: item.id,
|
// markerClick: _this.labelClick,
|
},
|
projectName: item.projectName,
|
totalMoney: item.yearInvestAmount
|
? item.yearInvestAmount + "元"
|
: "暂无数据",
|
projectAddr: item.projectAddress,
|
projectStatus: item.usedStatus,
|
};
|
_this.makeMask(item.longitude, item.latitude, config);
|
if (item.longitude && item.longitude > maxX) {
|
maxX = item.longitude;
|
}
|
if (item.longitude && item.longitude < minX) {
|
minX = item.longitude;
|
}
|
if (item.latitude && item.latitude > maxY) {
|
maxY = item.latitude;
|
}
|
if (item.latitude && item.latitude < minY) {
|
minY = item.latitude;
|
}
|
});
|
this.moveTo(
|
(parseFloat(maxX) + parseFloat(minX)) / 2,
|
(parseFloat(maxY) + parseFloat(minY)) / 2
|
);
|
},
|
|
// 通用添加事件的方法
|
addEvent(component, name, func) {
|
// 移出事件
|
this.removeEvent(component, name, func);
|
// 添加事件
|
component.addEventListener(name, func);
|
},
|
|
// 通用移出事件的方法
|
removeEvent(component, name, func) {
|
component.removeEventListener(name, func);
|
},
|
|
//标记点击事件
|
markerClick(currentLabel, e) {
|
const id = e.target.options.id;
|
this.currentLabelStyleChange(currentLabel);
|
console.log("点击事件", e, currentLabel);
|
this.getReverseGeocode(e).then((addr) => {
|
this.$emit(
|
"markClick",
|
id
|
? this.$props.mapList?.find((item) => item.id === id)
|
: { e, addr: addr }
|
);
|
});
|
},
|
|
// label点击事件
|
labelClick(currentLabel, e) {
|
console.log("触发点击事件");
|
const id = e.target.options.id;
|
this.currentLabelStyleChange(currentLabel);
|
this.getReverseGeocode(e).then((addr) => {
|
this.$emit(
|
"labelClick",
|
id
|
? this.$props.mapList?.find((item) => {
|
return String(item.id) === String(id);
|
})
|
: { e, addr: addr }
|
);
|
});
|
},
|
|
currentLabelStyleChange(currentLabel) {
|
this.$emit("currentLabelStyleChange", currentLabel);
|
},
|
|
resizeMap() {
|
this.map.checkResize();
|
},
|
},
|
watch: {
|
listType: {
|
handler(val) {
|
if (val) {
|
this.map && this.map.clearOverLays();
|
if (this.$props.mapList.length && T) {
|
this.makeAllMask(this.$props.mapList);
|
}
|
}
|
},
|
},
|
},
|
beforeDestroy() {
|
this.map = null;
|
},
|
};
|
|
// const emits = defineEmits<{
|
// (e: 'labelClick', value: any): void;
|
// (e: 'markClick', value: any): void;
|
// (e: 'mapClick', value: any): void;
|
// (e: 'currentLabelStyleChange', value: any): void;
|
// }>();
|
</script>
|
<style lang="scss" scoped>
|
:deep(.tdt-label) {
|
border-radius: 15px;
|
color: var(--el-color-primary);
|
cursor: pointer;
|
}
|
|
// #53547f
|
:deep(.tdt-bar a, .tdt-bar a:hover) {
|
border-bottom: 0;
|
color: #53547f;
|
}
|
|
:deep(.tdt-touch .tdt-control-zoom-in) {
|
font-size: 18px;
|
}
|
|
:deep(.tdt-bar) {
|
border-radius: 3px;
|
box-shadow: 5px 0px 12px 0px rgb(0 0 0 / 0.03);
|
}
|
|
.tdt-bar a.tdt-disabled,
|
.tdt-bar a:hover {
|
background-color: #f4f4f4;
|
}
|
|
.control-container {
|
position: absolute;
|
display: flex;
|
flex-direction: column;
|
gap: 10px;
|
z-index: 999;
|
}
|
|
.top-left {
|
top: 10px;
|
left: 10px;
|
}
|
|
.top-right {
|
top: 10px;
|
right: 10px;
|
}
|
|
.bottom-left {
|
bottom: 10px;
|
left: 10px;
|
}
|
|
.bottom-right {
|
bottom: 10px;
|
right: 10px;
|
}
|
|
.control-content {
|
border-radius: 3px;
|
box-shadow: 5px 0px 12px 0px rgb(0 0 0 / 0.03);
|
background-color: #fff;
|
}
|
|
.control-item {
|
box-sizing: border-box;
|
width: 30px;
|
height: 30px;
|
line-height: 28px;
|
padding: 0 9px;
|
|
img {
|
display: inline-block;
|
}
|
}
|
|
.control-item:hover {
|
background-color: #f4f4f4;
|
}
|
</style>
|
<style lang="scss">
|
.map-window-info {
|
padding: 0 20px;
|
width: 300px;
|
cursor: default;
|
|
.title {
|
color: #3369ff;
|
font-size: 18px;
|
margin-bottom: 13px;
|
}
|
|
.detail-info {
|
display: flex;
|
flex-direction: column;
|
color: #7e809c;
|
font-size: 12px;
|
gap: 8px;
|
}
|
}
|
|
.title-block {
|
display: flex;
|
justify-content: space-between;
|
|
.close-btn {
|
font-size: 18px;
|
color: #d8dde6;
|
cursor: pointer;
|
z-index: 999999;
|
}
|
}
|
|
//.tdt-control-copyright {
|
// display: none;
|
//}
|
|
.tdt-infowindow-tip-container {
|
opacity: 1;
|
}
|
|
.tdt-infowindow-content-wrapper {
|
opacity: 1;
|
}
|
</style>
|