1132 lines
46 KiB
TypeScript
1132 lines
46 KiB
TypeScript
namespace APPMAP {
|
||
// 对城市信息初始化
|
||
// 对inpout初始化
|
||
class base {
|
||
// 当前地图经纬度
|
||
protected mapLng: string = '116.395645'
|
||
protected mapLat: string = '39.929986'
|
||
// 当前地图的经纬度对象
|
||
protected mapPoints: object = {}
|
||
|
||
// input值
|
||
protected inputLng: string = ''
|
||
protected inputLat: string = ''
|
||
// input值对象
|
||
protected inputPoints: object = {}
|
||
// input生成标注点对象,跟模态框同步的对象标注点
|
||
protected cacheMarker: object = {}
|
||
|
||
// 城市信息
|
||
protected allCity: string = ''
|
||
protected selectProv: string = ''
|
||
protected selectCity: string = ''
|
||
protected selectDist: string = ''
|
||
protected address: string = ''
|
||
// 场所
|
||
protected placeName: string = ''
|
||
|
||
// dom
|
||
private lngDom: any = {}
|
||
private latDom: any = {}
|
||
|
||
constructor() {
|
||
|
||
this.mapLng = CL.c.maplng || this.mapLng
|
||
this.mapLat = CL.c.maplat || this.mapLat
|
||
|
||
// 若是inputLng值变化同步到input输入框
|
||
this.watch(this, 'inputLng', () => {
|
||
this.setInputLng()
|
||
})
|
||
// 若是inputLat值变化同步到input输入框
|
||
this.watch(this, 'inputLat', () => {
|
||
this.setInputLat()
|
||
})
|
||
|
||
this.initHtmlDom()
|
||
// 进行初始化
|
||
this.getInputLngLat()
|
||
// 判断input是否有值,有的话直接传递给默认值
|
||
this.syncMapLngLat()
|
||
// 获取城市信息
|
||
this.getCity()
|
||
|
||
// 城市信息
|
||
$(document).on('change keyup', '.city-js select', () => {
|
||
// 清空详细地址
|
||
if ($(".city-mapjs-address").length) $(".city-mapjs-address").val('')
|
||
});
|
||
// 包含详细地址的变化
|
||
$(document).on('change keyup', '.city-js select, .city-mapjs-address', () => {
|
||
this.getCity()
|
||
});
|
||
}
|
||
|
||
// 全局dom
|
||
initHtmlDom() {
|
||
// 经纬度
|
||
this.lngDom = $(".city-mapjs-lng")
|
||
this.latDom = $(".city-mapjs-lat")
|
||
}
|
||
|
||
// 判断是否为空
|
||
isEmpty(val: any) {
|
||
switch (val) {
|
||
case ',':
|
||
return true
|
||
case '请选择':
|
||
return true
|
||
case '请选择所在地区':
|
||
return true
|
||
}
|
||
return APPFUN.isEmpty(val)
|
||
}
|
||
|
||
// 获取经纬度
|
||
getInputLngLat() {
|
||
this.inputLng = this.lngDom.val()
|
||
this.inputLat = this.latDom.val()
|
||
}
|
||
|
||
// 同步到地图经纬度
|
||
syncMapLngLat() {
|
||
if (!this.isEmpty(this.inputLng) && !this.isEmpty(this.inputLat)) {
|
||
this.mapLng = this.inputLng
|
||
this.mapLat = this.inputLat
|
||
}
|
||
}
|
||
|
||
// 对input赋值
|
||
setInputLngLat() {
|
||
this.setInputLng()
|
||
this.setInputLat()
|
||
}
|
||
|
||
setInputLng() {
|
||
this.lngDom.val(this.inputLng)
|
||
this.lngDom.trigger('input')
|
||
}
|
||
|
||
setInputLat() {
|
||
this.latDom.val(this.inputLat)
|
||
this.latDom.trigger('input')
|
||
}
|
||
|
||
// 获取地址信息
|
||
getCity() {
|
||
//获取城市信息
|
||
this.selectProv = this.isCity($(".city-js select.prov").find("option:selected").val())
|
||
this.selectCity = this.isCity($(".city-js select.city").find("option:selected").val())
|
||
this.selectDist = this.isCity($(".city-js select.dist").find("option:selected").val())
|
||
this.address = this.isCity($(".city-mapjs-address").val())
|
||
// 拼装一个除了省信息以外的地址字符串
|
||
this.allCity = this.selectCity + this.selectDist + this.address;
|
||
}
|
||
|
||
// 判断城市信息是否为空
|
||
isCity(string: string) {
|
||
return !this.isEmpty(string) ? string : ''
|
||
}
|
||
|
||
// 根据城市信息判断地图级别
|
||
level() {
|
||
let level = 12
|
||
// 省份 20km
|
||
if (!this.isEmpty(this.selectProv)) level = 11
|
||
// 市区 5km
|
||
if (!this.isEmpty(this.selectCity)) level = 13
|
||
// 县市区 500M
|
||
if (!this.isEmpty(this.selectDist)) level = 15
|
||
// 详细地址 200M
|
||
if (!this.isEmpty(this.selectDist) && !this.isEmpty(this.address)) level = 18
|
||
return level;
|
||
}
|
||
|
||
// 对参数进行监听,做出对应的操作
|
||
watch(JsonObj: any, key: string, closure?: any) {
|
||
// 缓存值
|
||
let cacheData: any = {};
|
||
cacheData[key] = JsonObj[key];
|
||
Object.defineProperty(JsonObj, key, {
|
||
enumerable: true, // 该属性可被枚举
|
||
configurable: true, // 该属性可以被删除以及属性描述符可以被改变
|
||
get() {
|
||
// 需要从缓存值获取,不能直接obj获取
|
||
return cacheData[key]
|
||
},
|
||
set(newValue) {
|
||
const oldValue = cacheData[key];
|
||
// 改变原来的值,也就是修改JsonObj的值
|
||
cacheData[key] = newValue;
|
||
if (typeof closure === 'function' && oldValue !== newValue) closure(newValue, oldValue)
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
// 初始一个地图并返回本地图对象
|
||
class initialMap extends base {
|
||
// 展示类型的地图对象缓存
|
||
protected showMap: any = {}
|
||
// 模态框地图对象缓存
|
||
protected modalMap: any = {}
|
||
// 地图模式
|
||
protected mapType: boolean = false
|
||
protected myGeos: any = {}
|
||
|
||
// 缓存ajax查询结果
|
||
protected mapLngLatList: any = {}
|
||
protected mapCacheMarker: any = {}
|
||
|
||
constructor() {
|
||
super()
|
||
this.myGeos = new BMapGL.Geocoder();
|
||
// 将input信息转为对象,若是input有值 直接初始化后传递给地图
|
||
if (!this.isEmpty(this.inputLng) && !this.isEmpty(this.inputLat)) {
|
||
this.inputPoints = this.mapPoints = this.lnglatToPoints(this.inputLng, this.inputLat)
|
||
} else {
|
||
// 若是经纬度不存在,则城市信息存在则以城市信息为准,但是城市信息获取对象有延迟,则需要调整到后面
|
||
// 使用默认值对地图的经纬度转成对象
|
||
this.mapPoints = this.lnglatToPoints(this.mapLng, this.mapLat)
|
||
}
|
||
}
|
||
|
||
// 将字符串经纬度转换成经纬度对象
|
||
lnglatToPoints(lng: string, lat: string) {
|
||
let point = {}
|
||
if (!this.isEmpty(lng) && !this.isEmpty(lat)) point = new BMapGL.Point(lng, lat)
|
||
return point
|
||
}
|
||
|
||
// 初始化一个地图
|
||
initMap(domId: string, level?: any) {
|
||
const map = new BMapGL.Map(domId, {enableMapClick: false});
|
||
// 初始化地图,设置中心点坐标和地图级别
|
||
console.log(this.level())
|
||
map.centerAndZoom(this.mapPoints, level || this.level());
|
||
// 开启鼠标滚轮缩放
|
||
map.enableScrollWheelZoom(true);
|
||
// 地图配置
|
||
map.setDisplayOptions({
|
||
// 隐藏POI文字
|
||
// poiText: false,
|
||
// 隐藏POI的Icon
|
||
poiIcon: false
|
||
})
|
||
return map
|
||
}
|
||
|
||
// 旋转地图角度
|
||
setHeadingTilt(map: any) {
|
||
// 地图当前旋转角度
|
||
// map.setHeading(64.5);
|
||
// 地图当前状态倾斜角度
|
||
map.setTilt(65);
|
||
}
|
||
|
||
// 将城市信息转化为经纬度,并根据经纬度调整地图
|
||
citySyncMap(mapOjb: any, level?: number) {
|
||
// 异步执行建议在地图加载完成(tilesloaded)后再进行地图调整,否则无效
|
||
this.myGeos.getPoint(this.allCity || this.selectProv, (point: any) => {
|
||
if (point) {
|
||
this.mapPoints = point
|
||
this.mapLng = point.lng
|
||
this.mapLat = point.lat
|
||
mapOjb.panTo(point);
|
||
// 让他自动调整地图
|
||
if (level && level > 0) mapOjb.setZoom(level);
|
||
} else {
|
||
console.log("您选择地址没有解析到结果!")
|
||
}
|
||
}, this.selectProv);
|
||
}
|
||
|
||
// 根据小区名称调整地图
|
||
placeNameMap(map, callbackQuery, callbackPolygon) {
|
||
// this.mapPoints this.selectCity
|
||
const local = new BMapGL.LocalSearch(this.selectCity, {
|
||
renderOptions: {
|
||
map: map
|
||
// panel:"r-result" 查询得到的信息列表
|
||
},
|
||
pageCapacity: 1,
|
||
|
||
});
|
||
// local.disableAutoViewport()
|
||
// forceLocal限定在区域内
|
||
local.search(this.placeName, {forceLocal: true});
|
||
// 自动标注后回调
|
||
local.setMarkersSetCallback((e) => {
|
||
// 获取数组第一个值
|
||
let city = e.pop()
|
||
// address: "山东省泰安市岱岳区杏林路"
|
||
// city: "泰安市"
|
||
// detailUrl: "https://api.map.baidu.com/place/detail?uid=7df64328bc0d8e4788f15d0a&output=html&source=jsapi"
|
||
// isAccurate: true
|
||
// marker: az {latLng: cZ, hashCode: "mz_2h", _type: "overlay", _visible: true, _visibleInternal: true, …}
|
||
// phoneNumber: undefined
|
||
// point: cZ {lng: 117.07973971764177, lat: 36.18540716406726}
|
||
// postcode: undefined
|
||
// province: "山东省"
|
||
// tags: (2) ["地产小区", "小区/楼盘"]
|
||
// title: "东瑞·长城一品"
|
||
// type: 0
|
||
// uid: "7df64328bc0d8e4788f15d0a"
|
||
// url: "https://map.baidu.com?s=inf%26uid%3D7df64328bc0d8e4788f15d0a%26c%3D325&i=0&sr=1"
|
||
// 目前只调整位置,然后删除标记,目前因为需求只是获取地图显示位置,不需要他进行标注
|
||
map.removeOverlay(city.marker)
|
||
// isAccurate 为true 精确定位 false 模糊定位
|
||
setTimeout(() => {
|
||
if (city.isAccurate === true) {
|
||
// 精准查询则按小区名
|
||
map.panTo(city.point)
|
||
map.setZoom(18)
|
||
// 对小区画线
|
||
callbackQuery(city.uid, callbackPolygon)
|
||
} else {
|
||
// 模糊查询则按地址查询
|
||
this.citySyncMap(map)
|
||
}
|
||
}, 50)
|
||
});
|
||
|
||
}
|
||
|
||
// 获取经纬度列表
|
||
ajaxlnglatList(map: any, formJson: object, clickEvent: boolean = false, closure?: any) {
|
||
$.getJSON(M.url.own_name + "c=ajax&a=doallmap", formJson, (listJson: any) => {
|
||
this.mapLngLatList = listJson
|
||
$.each(listJson, (i: number, val: any) => {
|
||
// 值的转换为了后面统一使用,对应后期数据库的值
|
||
val.maplng = val.v_maplng
|
||
val.maplat = val.v_maplat
|
||
// 根据clickEvent 判断是否要启用标注点的信息提示
|
||
const clickClosure = clickEvent ? this.addOpenInfo(map, val) : ''
|
||
if (!this.isEmpty(val.maplng) && !this.isEmpty(val.maplat)) this.addMapOverlay(map, val.maplng, val.maplat, false, val.id, clickClosure);
|
||
// 暂时考虑加入一个回调
|
||
// if (typeof closure === 'function') closure(val);
|
||
})
|
||
})
|
||
}
|
||
|
||
// 标注图标样式
|
||
myIcon() {
|
||
return new BMapGL.Icon(
|
||
// 图片地址
|
||
M.url.own_tem + "/img/markers.png",
|
||
// 标注的大小,跟图片上的标注图样大小一致
|
||
new BMapGL.Size(21, 25),
|
||
// 其他参数
|
||
{
|
||
// 图片的大小
|
||
imageSize: new BMapGL.Size(42, 325),
|
||
// 指定定位位置。
|
||
// 当标注显示在地图上时,其所指向的地理位置距离图标左上
|
||
// 角各偏移10像素和25像素。您可以看到在本例中该位置即是
|
||
// 图标中央下端的尖角位置。
|
||
anchor: new BMapGL.Size(10, 25),
|
||
// 设置图片偏移。
|
||
// 当您需要从一幅较大的图片中截取某部分作为标注图标时,您
|
||
// 需要指定大图的偏移位置,此做法与css sprites技术类似。
|
||
// 设置图片偏移
|
||
// imageOffset: new BMapGL.Size(0, 0)
|
||
imageOffset: new BMapGL.Size(0, 300)
|
||
}
|
||
);
|
||
}
|
||
|
||
// 地图点的标注
|
||
addMapOverlay(appmapl: any, lng: string, lat: string, icons: boolean = false, listId?, clickClosure?: any) {
|
||
if (this.isEmpty(lng)) return false;
|
||
// 获取经纬度 创建标注
|
||
const points = this.lnglatToPoints(lng, lat)
|
||
const marker = new BMapGL.Marker(points);
|
||
// 给标注点添加点击回调
|
||
if (typeof clickClosure === 'function') {
|
||
marker.addEventListener("click", (e: any) => {
|
||
clickClosure(e)
|
||
})
|
||
// 因为marker不会直接存在dom,地图打开后才会生成dom
|
||
// 将所有的标注点缓存,方便手动触发标注点的点击事件
|
||
this.watch(marker, 'domElement', () => {
|
||
this.mapCacheMarker[listId] = $(marker.domElement)
|
||
})
|
||
}
|
||
// 标注图标,需要单独标注的颜色,则进行缓存
|
||
if (icons) {
|
||
// 缓存一下
|
||
this.cacheMarker = marker
|
||
marker.setIcon(this.myIcon());
|
||
}
|
||
|
||
// 添加到地图
|
||
appmapl.addOverlay(marker);
|
||
return points
|
||
}
|
||
|
||
// 添加标注信息窗口
|
||
addOpenInfo(map: any, value: any) {
|
||
const opts = {
|
||
// width: 250, // 信息窗口宽度
|
||
// height: 80, // 信息窗口高度
|
||
maxWidth: 350,
|
||
enableAutoPan: true,
|
||
title: value.v_name // 信息窗口标题,设置为小区名称
|
||
};
|
||
// 组织内容
|
||
// let content = `<p>类型:${value.}</p>`
|
||
let content = `<p>${value.v_province}${value.v_city}${value.v_district}${value.v_address}</p>`
|
||
// 返回一个函数方便点击事件二次调用
|
||
return (e: any) => {
|
||
const p = e.target;
|
||
const point = this.lnglatToPoints(p.getPosition().lng, p.getPosition().lat);
|
||
const infoWindow = new BMapGL.InfoWindow(content, opts); // 创建信息窗口对象
|
||
map.openInfoWindow(infoWindow, point); //开启信息窗口
|
||
}
|
||
}
|
||
}
|
||
|
||
// 展示型的地图动作操作
|
||
class showMap extends initialMap {
|
||
constructor() {
|
||
super();
|
||
// 获取地图状态
|
||
this.getMapType()
|
||
// 初始化
|
||
this.showInitMap()
|
||
// 启动城市信息监听
|
||
this.watchCity()
|
||
}
|
||
|
||
showInitMap() {
|
||
// 初始化地图
|
||
this.showMap = this.initMap("showmap")
|
||
// 旋转地图角度
|
||
this.setHeadingTilt(this.showMap)
|
||
// 地图初始化完成后,若是没有input的值,且又存在城市信息则按照城市信息调整地图
|
||
if (this.isEmpty(this.inputLng) && this.isEmpty(this.inputLat) && !this.isEmpty(this.allCity)) this.citySyncMap(this.showMap)
|
||
// 根据地图状态处理标记
|
||
if (this.mapType) this.addMapOverlay(this.showMap, this.inputLng, this.inputLat, true)
|
||
}
|
||
|
||
getMapType() {
|
||
// true 则进行标记
|
||
// false 不进行地图标记
|
||
return this.mapType = $('#showmap').data('type') === 'showmap' ? false : true;
|
||
}
|
||
|
||
watchCity() {
|
||
const $fun = () => {
|
||
this.citySyncMap(this.showMap)
|
||
}
|
||
// 监听指定的参数
|
||
this.watch(this, 'selectProv', $fun)
|
||
this.watch(this, 'allCity', $fun)
|
||
// 只是针对纯展示型地图,不带标记的
|
||
if (!this.mapType) {
|
||
// 禁止拖拽
|
||
// this.showMap.disableDragging()
|
||
// 若是地图经纬度变化时,是否同步给input
|
||
this.watch(this, 'mapLng', () => {
|
||
this.inputLng = this.mapLng
|
||
})
|
||
this.watch(this, 'mapLat', () => {
|
||
this.inputLat = this.mapLat
|
||
})
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
// 模态框地图动作操作
|
||
class modalMap extends showMap {
|
||
// 模态框的缓存信息
|
||
protected modalLng: string = ''
|
||
protected modalLat: string = ''
|
||
// input值对象
|
||
protected modalPoints: object = {}
|
||
|
||
constructor() {
|
||
super();
|
||
|
||
//验证信息
|
||
$('#mapmodal').on('click', () => {
|
||
// 获取城市信息
|
||
// this.getCity()
|
||
if (this.isEmpty(this.selectCity)) {
|
||
$.include(M['url']['static2_vendor'] + 'alertify/alertify.js', function () {
|
||
alertify.logPosition("右下角");
|
||
alertify.error("请选择城市。");
|
||
})
|
||
} else {
|
||
// 获取小区名称
|
||
this.placeName = $('select[name="v_name"]').find("option:selected").val()
|
||
let html = '范围:' + this.selectProv + '<small style="padding-left:15px;">' + this.allCity + '</small>';
|
||
html += '<span class="tag tag-sm tag-outline tag-danger font-size-16 m-l-5">' + this.placeName + '</span>';
|
||
$('h4.modal-title').html(html)
|
||
// 打开模态框
|
||
$('#appmaps').modal('show')
|
||
}
|
||
});
|
||
|
||
//模态框
|
||
$('#appmaps').on('shown.bs.modal', () => {
|
||
// 延迟效果可以让模态框加载时看起来没有卡的感觉
|
||
setTimeout(() => {
|
||
// 解决因页面产品滚动条导致的点击地图获取的经纬度不准确问题
|
||
// 让滚动条回滚到顶部
|
||
document.body.scrollTop = document.documentElement.scrollTop = 0
|
||
// 初始化模态框
|
||
this.modalInitMap()
|
||
// 主要是用来排除掉当前小区的标记
|
||
const mapId = $('#modalmap').data('mapid') || '';
|
||
// // ajax查找 当前地区点的标注并添加在地图上
|
||
this.ajaxlnglatList(this.modalMap, {
|
||
id: mapId,
|
||
province: this.selectProv,
|
||
city: this.selectCity,
|
||
district: this.selectDist
|
||
})
|
||
|
||
// 根据小区名称 且经纬度为空 调整地图核心
|
||
if (this.placeName && this.isEmpty(this.inputLng) && this.isEmpty(this.inputLat)) {
|
||
this.placeNameMap(this.modalMap, this.queryHouseOutline, this.showPolygon(this.modalMap))
|
||
}
|
||
|
||
//点击百度地图时触发
|
||
this.modalMap.addEventListener("click", (e: any) => {
|
||
//清除单个标注
|
||
this.modalMap.removeOverlay(this.cacheMarker);
|
||
//赋值给输入框
|
||
this.modalLng = e.latlng.lng
|
||
this.modalLat = e.latlng.lat;
|
||
// 他变化时要同时针对多个地图直接变化
|
||
this.modalPoints = this.addMapOverlay(this.modalMap, this.modalLng, this.modalLat, true)
|
||
});
|
||
}, 200)
|
||
|
||
});
|
||
|
||
// 保存
|
||
$('#appmaps .button-save').on('click', () => {
|
||
//判断是否同步信息到展示地图
|
||
if (!this.isEmpty(this.modalLng) && !this.isEmpty(this.modalLat)) {
|
||
//返回值
|
||
this.inputLng = this.modalLng
|
||
this.inputLat = this.modalLat
|
||
//展示图的操作
|
||
if (!this.isEmpty(this.showMap)) {
|
||
//清除展示地图的标注
|
||
this.showMap.clearOverlays();
|
||
//地图显示
|
||
this.mapPoints = this.inputPoints = this.modalPoints
|
||
this.showMap.panTo(this.mapPoints)
|
||
//对地图一进行标注
|
||
this.addMapOverlay(this.showMap, this.inputLng, this.inputLat, true);
|
||
}
|
||
}
|
||
//关闭对话框
|
||
$('#appmaps').modal('hide');
|
||
});
|
||
|
||
// 关闭
|
||
$('#appmaps').on('hidden.bs.modal', () => {
|
||
//清除标注
|
||
this.modalMap.clearOverlays()
|
||
// 还原信息
|
||
this.modalLng = this.modalLat = ''
|
||
this.modalPoints = {}
|
||
//清除模态框数据
|
||
$('#appmaps').removeData("bs.modal")
|
||
// 销毁地图
|
||
this.modalMap.destroy()
|
||
});
|
||
}
|
||
|
||
// 初始化
|
||
modalInitMap() {
|
||
// 初始化地图
|
||
this.modalMap = this.initMap("modalmap")
|
||
// 添加当前经纬度标记
|
||
if (!this.isEmpty(this.inputLng) && !this.isEmpty(this.inputLat)) this.addMapOverlay(this.modalMap, this.inputLng, this.inputLat, true);
|
||
|
||
}
|
||
|
||
// 本接口采集于百度地图,并非官方文档提供,稳定性有待考究
|
||
// 获取指定小区的边界经纬度
|
||
queryHouseOutline(uid: number, callback: any) {
|
||
let baseURL = 'https://map.baidu.com/?reqflag=pcmap&coord_type=3&from=webmap&qt=ext&ext_ver=new&l=18';
|
||
let url = baseURL + "&uid=" + uid;
|
||
callback && (window['queryHouseOutlineCallback'] = callback);
|
||
$.ajax({
|
||
type: "get",
|
||
async: false,
|
||
url: url,
|
||
dataType: "jsonp",
|
||
jsonpCallback: "queryHouseOutlineCallback",
|
||
success: function (datas) {
|
||
}
|
||
});
|
||
}
|
||
|
||
// 墨卡托坐标解析
|
||
parseGeo(mocator: string) {
|
||
if (typeof mocator != 'string') return {}
|
||
const t = mocator.split("|");
|
||
let n = parseInt(t[0]);
|
||
let i = t[1];
|
||
let r = t[2];
|
||
let o: any = r.split(";");
|
||
if (n === 4) {
|
||
let a = []
|
||
for (let s = 0; s < o.length - 1; s++) {
|
||
// @ts-ignore
|
||
"1" === o[s].split("-")[0] && a.push(o[s].split("-")[1]);
|
||
}
|
||
o = a;
|
||
o.push("");
|
||
}
|
||
let u = [];
|
||
switch (n) {
|
||
case 1:
|
||
// @ts-ignore
|
||
u.push(o[0]);
|
||
break;
|
||
case 2:
|
||
case 3:
|
||
case 4:
|
||
for (let s = 0; s < o.length - 1; s++) {
|
||
let l = o[s];
|
||
if (l.length > 100) {
|
||
l = l.replace(/(-?[1-9]\d*\.\d*|-?0\.\d*[1-9]\d*|-?0?\.0+|0|-?[1-9]\d*),(-?[1-9]\d*\.\d*|-?0\.\d*[1-9]\d*|-?0?\.0+|0|-?[1-9]\d*)(,)/g,
|
||
"$1,$2;");
|
||
// @ts-ignore
|
||
u.push(l);
|
||
} else {
|
||
let c = []
|
||
for (let d = l.split(","), f = 0; f < d.length; f += 2) {
|
||
let p = d[f], h = d[f + 1];
|
||
// @ts-ignore
|
||
c.push(p + "," + h);
|
||
}
|
||
// @ts-ignore
|
||
u.push(c.join(";"))
|
||
}
|
||
}
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
// @ts-ignore
|
||
if (u.length <= 1) u = u.toString();
|
||
return {
|
||
type: n,
|
||
bound: i,
|
||
points: u
|
||
}
|
||
}
|
||
|
||
// 墨卡托坐标转百度坐标
|
||
coordinateToPoints(map, coordinate) {
|
||
let points = [];
|
||
if (coordinate) {
|
||
const arr = coordinate.split(";");
|
||
if (arr) {
|
||
for (let i = 0; i < arr.length; i++) {
|
||
const coord = arr[i].split(",");
|
||
if (coord && coord.length == 2) {
|
||
// coord 墨卡托平面坐标转换为经纬度球体坐标
|
||
const point = map.mercatorToLnglat(coord[0], coord[1]);
|
||
// @ts-ignore
|
||
points.push(new BMapGL.Point(point[0], point[1]));
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return points;
|
||
}
|
||
|
||
// 显示多边形
|
||
showPolygon(map) {
|
||
return (datas) => {
|
||
let geo = datas.content.geo
|
||
if (geo) {
|
||
// 存在geo 则标记边界
|
||
// map.clearOverlays();
|
||
const geoObj = this.parseGeo(geo);
|
||
//边界点
|
||
const points = this.coordinateToPoints(map, geoObj.points);
|
||
//建立多边形覆盖物
|
||
const ply = new BMapGL.Polygon(points, {
|
||
// 蓝色:#3e8ef7、浅蓝色:#0bb2d4、绿色:#17b3a3
|
||
// 橘色:#eb6709、红色:#ff4c52、紫色:#9463f7
|
||
strokeColor: "#ff4c52",
|
||
strokeWeight: 2,
|
||
strokeOpacity: 1,
|
||
strokeStyle: 'dashed', // solid(默认)、dashed
|
||
fillColor: "transparent",
|
||
fillOpacity: 0
|
||
});
|
||
map.addOverlay(ply); //添加覆盖物
|
||
map.setViewport(ply.getPath()); //调整视野
|
||
}
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
// 通过地图选择
|
||
class selectMap extends initialMap {
|
||
// 目前的形式地图只初始化一次,模态框关闭不影响二次打开继续之前的操作
|
||
protected selectMapInitType = false
|
||
// 地图实例对象
|
||
public selectMap: any = {}
|
||
// 地图工具对象
|
||
protected drawingManager: any = {}
|
||
|
||
//本次覆盖物对象缓存
|
||
protected overlaysCache = {
|
||
overlays: {},
|
||
hashCode: '',
|
||
drawingMode: ''
|
||
}
|
||
// 绘制覆盖物缓存 hashCode = 覆盖物对象
|
||
protected overlays = {}
|
||
// 绘制覆盖物类型对照 hashCode = 类型
|
||
// Marker 点 || Circle 圆 || Polyline 线 || Polygon 多边 || rectangle 矩形
|
||
protected hashCode = {}
|
||
// 绘制覆盖物选中的小区对照 hashCode = 小区ID
|
||
protected markerID = {
|
||
marker: [],
|
||
polyline: [],
|
||
circle: [],
|
||
rectangle: [],
|
||
polygon: []
|
||
}
|
||
// 选中小区缓存过渡 初次筛选
|
||
protected villageFilterList = {}
|
||
// 选中的小区数组 id = 小区对象
|
||
protected villageList = {}
|
||
|
||
constructor() {
|
||
super();
|
||
|
||
// 在地图弹窗内进行小区条件筛选
|
||
$(document).on('change', 'select[name="vtype"]', () => {
|
||
this.filter()
|
||
})
|
||
this.watch(this, 'selectProv', () => {
|
||
this.filter()
|
||
})
|
||
this.watch(this, 'allCity', () => {
|
||
this.filter()
|
||
})
|
||
|
||
//模态框
|
||
$('#selectMapId').on('shown.bs.modal', () => {
|
||
if (this.selectMapInitType) return false
|
||
// 设置地图高度,达到满屏效果
|
||
this.setHeight()
|
||
// 延迟效果可以让模态框加载时看起来没有卡的感觉
|
||
setTimeout(() => {
|
||
// 解决因页面产品滚动条导致的点击地图获取的经纬度不准确问题
|
||
// 让滚动条回滚到顶部
|
||
document.body.scrollTop = document.documentElement.scrollTop = 0
|
||
// 初始化模态框
|
||
this.selectInitMap()
|
||
// ajax查找 当前地区点的标注并添加在地图上
|
||
this.ajaxlnglatList(this.selectMap, {
|
||
id: '',
|
||
province: this.selectProv,
|
||
city: this.selectCity,
|
||
district: this.selectDist,
|
||
allinfo: 'all'
|
||
}, true)
|
||
// 初始化绘制工具
|
||
this.drawingManagerInit()
|
||
// 绘制结束后的回调
|
||
this.drawingManager.addEventListener("overlaycomplete", (e) => {
|
||
let overlay = e.overlay
|
||
let hashCode = overlay.hashCode
|
||
let drawingMode = e.drawingMode
|
||
this.overlays[hashCode] = overlay
|
||
this.hashCode[hashCode] = drawingMode
|
||
// 本次操作的值缓存
|
||
this.overlaysCache = {
|
||
overlays: overlay,
|
||
hashCode: hashCode,
|
||
drawingMode: drawingMode
|
||
}
|
||
|
||
// 筛选选中的小区
|
||
let latLngNum = 0
|
||
// 初始化
|
||
this.villageFilterList = {}
|
||
$.each(this.mapLngLatList, (i: number, val: any) => {
|
||
latLngNum++
|
||
// 值的转换为了后面统一使用,对应后期数据库的值
|
||
let points = this.lnglatToPoints(val.v_maplng, val.v_maplat)
|
||
let result = false
|
||
// 只有矩形需要获取覆盖物的范围,其他的直接将覆盖物对象传入即可
|
||
switch (drawingMode) {
|
||
case 'polyline':
|
||
// 折线
|
||
result = BMapGLLib.GeoUtils.isPointOnPolyline(points, overlay)
|
||
break;
|
||
case 'circle':
|
||
// 圆
|
||
result = BMapGLLib.GeoUtils.isPointInCircle(points, overlay)
|
||
break;
|
||
case 'rectangle':
|
||
// 矩形
|
||
let bounds = overlay.getBounds()
|
||
result = BMapGLLib.GeoUtils.isPointInRect(points, bounds)
|
||
break;
|
||
case 'polygon':
|
||
// 多边形
|
||
result = BMapGLLib.GeoUtils.isPointInPolygon(points, overlay)
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
|
||
if (result == true) {
|
||
if (!this.markerID[drawingMode][hashCode]) this.markerID[drawingMode][hashCode] = []
|
||
this.markerID[drawingMode][hashCode].push(val.id)
|
||
// 缓存本次的值
|
||
this.villageFilterList[val.id] = val
|
||
}
|
||
|
||
// 打开弹窗 选中小区缓存筛选
|
||
if (latLngNum === Object.keys(this.mapLngLatList).length) this.confirmOperate()
|
||
})
|
||
});
|
||
// 标记为已经初始化过
|
||
if (this.selectMapInitType === false) this.selectMapInitType = true
|
||
}, 100)
|
||
});
|
||
|
||
// 清空
|
||
$('#selectMapId .mapreset').on('click', (e: any) => {
|
||
// 重置
|
||
this.mapreset()
|
||
this.listNum('selectMapId')
|
||
this.input()
|
||
})
|
||
// 删除指定小区
|
||
$('#selectMapId').on('click', 'li button', (e) => {
|
||
const domLi = $(e.target).parents('li')
|
||
this.delFilterList(domLi.data('id'))
|
||
domLi.remove()
|
||
})
|
||
|
||
// 保存
|
||
$('#selectMapId .button-save').on('click', () => {
|
||
// 将ID写入某个input
|
||
let keysArr = Object.keys(this.villageList)
|
||
let keysStr = keysArr.toString()
|
||
this.input(keysStr)
|
||
//关闭对话框
|
||
$('#selectMapId').modal('hide');
|
||
});
|
||
|
||
// 关闭
|
||
$('#selectMapId').on('hidden.bs.modal', () => {
|
||
//清除标注
|
||
// this.modalMap.clearOverlays()
|
||
//清除模态框数据
|
||
// $('#selectMapId').removeData("bs.modal")
|
||
// 销毁地图
|
||
// this.selectMap.destroy()
|
||
});
|
||
|
||
// 点击LI地图上打开对应的标注
|
||
$('.villageList ul').on('click', 'li[data-id] h5', (e) => {
|
||
let id = $(e.target).parents('li').data('id')
|
||
let listInfo = this.villageList[id]
|
||
// 转移地图核心为标注点
|
||
let point: any = this.lnglatToPoints(listInfo.maplng, listInfo.maplat)
|
||
this.selectMap.panTo(point);
|
||
// 触发标注点的点击事件
|
||
this.mapCacheMarker[id].trigger('click')
|
||
})
|
||
}
|
||
|
||
// 设置同步地图和选中列表展示的高度
|
||
// outerHeight 包含padding margin border
|
||
// height 不含padding margin border
|
||
setHeight() {
|
||
const headerHeight = $("#selectMapId .modal-header").outerHeight(true)
|
||
// const footerHeight = $("#selectMapId .modal-footer").height()
|
||
const wHeight = $(document.body).height()
|
||
const mapHeight = wHeight - headerHeight - 15
|
||
// 设置高度
|
||
$(".selectMapHeight").height(mapHeight)
|
||
// 选中内容高度
|
||
const panelHeading = $(".selectMapHeight .panel-heading").outerHeight(true)
|
||
const panelFooter = $(".selectMapHeight .panel-footer").outerHeight(true)
|
||
const panelBody = $(".selectMapHeight .panel-body").outerHeight(true) - $(".selectMapHeight .panel-body").height()
|
||
$(".selectMapHeight .panel-body").height(mapHeight - panelHeading - panelFooter - panelBody)
|
||
}
|
||
|
||
// 设置首次筛选列表内容高度
|
||
setFilterModalBodyHeight() {
|
||
// 首次筛选的内容高度
|
||
const filterListmodalHeight = $("#filterListmodal").outerHeight(true)
|
||
const modalHeader = $("#filterListmodal .modal-header").outerHeight(true)
|
||
const modalFooter = $("#filterListmodal .modal-footer").outerHeight(true)
|
||
const modalBody = $("#filterListmodal .modal-body").outerHeight(true) - $("#filterListmodal .modal-body").height()
|
||
$("#filterListmodal .filterList").height(filterListmodalHeight - modalHeader - modalBody - modalFooter)
|
||
}
|
||
|
||
// 初始化地图
|
||
selectInitMap() {
|
||
this.selectMap = this.initMap("selectMap")
|
||
}
|
||
|
||
// 实例化鼠标绘制工具
|
||
drawingManagerInit() {
|
||
// 源码:https://github.com/huiyan-fe/BMapGLLib/blob/master/DrawingManager/src/DrawingManager.js#L44
|
||
const styleOptions = {
|
||
strokeColor: '#5E87DB', // 边线颜色
|
||
fillColor: '#5E87DB', // 填充颜色。当参数为空时,圆形没有填充颜色
|
||
strokeWeight: 2, // 边线宽度,以像素为单位
|
||
strokeOpacity: 1, // 边线透明度,取值范围0-1
|
||
fillOpacity: 0.2 // 填充透明度,取值范围0-1
|
||
};
|
||
const labelOptions = {
|
||
borderRadius: '2px',
|
||
background: '#FFFBCC',
|
||
border: '1px solid #E1E1E1',
|
||
color: '#703A04',
|
||
fontSize: '12px',
|
||
letterSpacing: '0',
|
||
padding: '5px'
|
||
};
|
||
|
||
this.drawingManager = new BMapGLLib.DrawingManager(this.selectMap, {
|
||
// isOpen: true, //是否开启绘制模式
|
||
enableDrawingTool: true, // 是否显示工具栏
|
||
enableCalculate: true, // 绘制是否进行测距(画线时候)、测面(画圆、多边形、矩形)
|
||
drawingToolOptions: {
|
||
enableTips: true,
|
||
customContainer: 'selectbox_Drawing',
|
||
hasCustomStyle: true,
|
||
anchor: BMAP_ANCHOR_TOP_RIGHT,
|
||
offset: new BMapGL.Size(25, 15), // 偏离值,调整工具的位置
|
||
scale: 1, // 工具栏缩放比例
|
||
drawingModes: [
|
||
// BMAP_DRAWING_MARKER,
|
||
BMAP_DRAWING_POLYLINE,
|
||
BMAP_DRAWING_RECTANGLE,
|
||
BMAP_DRAWING_POLYGON,
|
||
BMAP_DRAWING_CIRCLE,
|
||
]
|
||
},
|
||
enableSorption: true, // 是否开启边界吸附功能
|
||
sorptionDistance: 20, // 边界吸附距离
|
||
enableGpc: true, // 是否开启延边裁剪功能
|
||
circleOptions: styleOptions, // 圆的样式
|
||
polylineOptions: styleOptions, // 线的样式
|
||
polygonOptions: styleOptions, // 多边形的样式
|
||
rectangleOptions: styleOptions, // 矩形的样式
|
||
labelOptions: labelOptions // label的样式
|
||
});
|
||
}
|
||
|
||
// 选中区域确定后的处理
|
||
confirmOperate() {
|
||
// 执行循环结果后的内容
|
||
this.addHtmlShow('filterList')
|
||
// 打开筛选模态框
|
||
$('#filterListmodal').modal('show')
|
||
$('#filterListmodal').on('shown.bs.modal', () => {
|
||
this.listNum('filterListmodal')
|
||
// 处理列表
|
||
this.setFilterModalBodyHeight()
|
||
})
|
||
|
||
// 筛选中时重选
|
||
$('#filterListmodal .mapreset').on('click', (e: any) => {
|
||
//关闭对话框
|
||
$('#filterListmodal').modal('hide');
|
||
// 主要是取消选中区域覆盖物
|
||
this.mapresetClose()
|
||
})
|
||
|
||
// 保存
|
||
$('#filterListmodal .button-save').on('click', () => {
|
||
//关闭对话框
|
||
$('#filterListmodal').modal('hide');
|
||
// 并将保存的结果插入到选中小区表
|
||
this.addHtmlShow('villageList')
|
||
})
|
||
|
||
// 删除指定小区
|
||
$('#filterListmodal').on('click', 'li button', (e) => {
|
||
const domLi = $(e.target).parents('li')
|
||
this.delFilterList(domLi.data('id'), 'filterList')
|
||
domLi.remove()
|
||
})
|
||
|
||
// 关闭
|
||
$('#selectMapId').on('hidden.bs.modal', () => {
|
||
//清除模态框数据
|
||
$('#selectMapId').removeData("bs.modal")
|
||
})
|
||
}
|
||
|
||
// 选中区域HTML输出
|
||
// 判断输出到哪个dom
|
||
addHtmlShow(domclass?) {
|
||
let dom = $(`.${domclass}`).find('ul')
|
||
// 暂时直接输出,不考虑分页问题
|
||
let listNum = domclass === 'filterList' ? 0 : (Object.keys(this.villageList).length || 0)
|
||
let initListNum = 0
|
||
$.each(this.villageFilterList, (i: number, val: any) => {
|
||
// 组织HTML结构
|
||
if (domclass !== 'filterList') {
|
||
if (this.villageList[i] && Object.keys(this.villageList[i]).length > 0) return true
|
||
// 赋值给最终结果
|
||
this.villageList[i] = val
|
||
}
|
||
// 输出html
|
||
let li = this.htmlLi(i, val)
|
||
listNum === 0 ? dom.html(li) : dom.prepend(li)
|
||
listNum++
|
||
initListNum++
|
||
if (initListNum === Object.keys(this.villageFilterList).length) {
|
||
this.listNum('selectMapId')
|
||
}
|
||
})
|
||
}
|
||
|
||
// 组织HTML结构
|
||
htmlLi(key, val) {
|
||
// 组织HTML结构
|
||
let address = val.v_city + val.v_district + val.v_address
|
||
return `<li class="list-group-item village-list-item" data-id="${key}">
|
||
<h5>${val.v_name}</h5>
|
||
<button type="button" class="float-right close">
|
||
<i class="icon wb-close m-0 font-danger" aria-hidden="true"></i>
|
||
</button>
|
||
<p>地址:${address}</p>
|
||
</li>`
|
||
}
|
||
|
||
// 重选,或者取消
|
||
mapresetClose() {
|
||
// 主要是取消选中区域覆盖物
|
||
let hashCode = this.overlaysCache.hashCode
|
||
let drawingMode = this.overlaysCache.drawingMode
|
||
delete this.overlays[hashCode]
|
||
delete this.hashCode[hashCode]
|
||
delete this.markerID[drawingMode][hashCode]
|
||
this.selectMap.removeOverlay(this.overlaysCache.overlays)
|
||
}
|
||
|
||
// 清空选中的所有内容操作
|
||
mapreset() {
|
||
// 无法禁止在removeOverlay删除小区标注点,换成单个删除
|
||
$.each(this.overlays, (i, val: any) => {
|
||
this.selectMap.removeOverlay(val)
|
||
delete this.overlays[i]
|
||
// 后期若是要达到精准需要单独处理
|
||
delete this.hashCode[i]
|
||
})
|
||
// 全部还原
|
||
this.markerID = {
|
||
marker: [],
|
||
polyline: [],
|
||
circle: [],
|
||
rectangle: [],
|
||
polygon: []
|
||
}
|
||
// 全部还原
|
||
this.villageList = {}
|
||
$('.villageList ul').html(`<li class="list-group-item">没有选中小区</li>`)
|
||
}
|
||
|
||
// 删除指定的数据
|
||
delFilterList(id, domclass?) {
|
||
if (domclass === 'filterList') {
|
||
delete this.villageFilterList[id]
|
||
this.listNum('filterListmodal', 'del')
|
||
} else {
|
||
delete this.villageList[id]
|
||
this.listNum('selectMapId', 'del')
|
||
}
|
||
}
|
||
|
||
// 计算选中个数
|
||
listNum(domclass?, type?) {
|
||
if (domclass === 'filterListmodal') {
|
||
let listNum = this.villageFilterList ? Object.keys(this.villageFilterList).length : 0
|
||
$('#filterListmodal .listNum').html(listNum)
|
||
if (listNum === 0 && type === 'del') {
|
||
this.mapresetClose()
|
||
//关闭对话框
|
||
$('#filterListmodal').modal('hide');
|
||
}
|
||
} else {
|
||
let listNums = this.villageList ? Object.keys(this.villageList).length : 0
|
||
$('#selectMapId .listNum').html(listNums)
|
||
$('button[data-target="#selectMapId"] .listNum').html(listNums > 0 ? listNums : '')
|
||
if (listNums === 0 && type === 'del') this.mapreset()
|
||
}
|
||
}
|
||
|
||
// 将指传递到input
|
||
input(keysStr?) {
|
||
const inputVid = $('input[name="v_id"]')
|
||
inputVid.val(keysStr)
|
||
inputVid.trigger('change')
|
||
}
|
||
|
||
// 根据条件筛选小区
|
||
filter() {
|
||
// 获取指定的值
|
||
let vtype: any
|
||
if ($('select[name="vtype"]').length) {
|
||
vtype = $('select[name="vtype"]').val()
|
||
vtype = vtype ? vtype.join(',') : ''
|
||
}
|
||
|
||
// 需要将缓存全部删除掉
|
||
$('#selectMapId .mapreset').trigger('click')
|
||
//清除标注
|
||
this.selectMap.clearOverlays()
|
||
// 提交后端
|
||
this.ajaxlnglatList(this.selectMap, {
|
||
id: '',
|
||
province: this.selectProv,
|
||
city: this.selectCity,
|
||
district: this.selectDist,
|
||
vtype: vtype,
|
||
allinfo: 'all'
|
||
}, true)
|
||
// 调整地图核心位置
|
||
this.citySyncMap(this.selectMap, this.level())
|
||
}
|
||
|
||
}
|
||
|
||
// @ts-ignore
|
||
export function bmaps() {
|
||
// 模态框
|
||
if ($('#modalmap').length) {
|
||
new modalMap()
|
||
} else if ($('#showmap').length) {
|
||
// 展示形式
|
||
new showMap()
|
||
} else if ($('#selectMap').length) {
|
||
// 地图选择形式
|
||
// $('button[data-target="#selectMapId"]').on('click', () => {})
|
||
// 目前的形式地图只初始化一次,模态框关闭不影响二次打开继续之前的操作
|
||
new selectMap()
|
||
// 测试时自动启动模态框
|
||
// $('button[data-target="#selectMapId"]').click()
|
||
|
||
}
|
||
}
|
||
} |