<template>
	<view class="ly-map-wrapper">
		<view style="background: transparent;position: absolute;z-index:1998;top:10px;left: 10px;right:10px;display: flex;align-items: center;justify-content: space-between;">
			<uni-icons type="left" size="26" color="#333" @click="back"></uni-icons>
			<u-button 
				@click="confirm" 
				type="primary" 
				v-if="type == 'chooselocation'"
				style="font-size: 15px;width: 100rpx;margin: 0;">确定</u-button>
		</view>
		<!-- <uni-nav-bar 
			left-icon="back" 
			@clickLeft="back"
			backgroundColor="transparent"
			:border="false"
			fixed
			statusBar
			>
			<template slot="right" v-if="type == 'chooselocation'">
				<u-button 
					type="primary" 
					size="mini" 
					:customStyle="{
						fontSize: '26rpx',
						padding: '16rpx auto'
					}"
					@click="confirm">确定</u-button>
			</template>
		</uni-nav-bar> -->
		<!-- 地图展示 -->
		<view :id="mapId" :config="config" :change:config="LyMap.init" :call="option" :change:call="LyMap.call"
			class="ly-map" />
		<!-- 中心图标 -->
		<image v-if="showCenterIcon" :src="centerIcon||defCenterIcon" class="ly-center-icon" />
		<!-- 定位图标 -->
		<view v-if="showLocationIcon" class="ly-location-icon" @click="onLocation">
			<image :src="locationIcon" class="icon" />
		</view>
	</view>
</template>

<script>
	import centerIcon from '../../static/ly-map/center.png';
	import locationIcon from '../../static/ly-map/location.png';

	export default {
		// 接口参数
		props: {
			// 地图key
			mapKey: {
				type: String,
				default: ''
			},
			// 经纬度
			lonlat: {
				type: Array,
				default: () => ([111.668097, 40.825417]),
			},
			// 缩放
			zoom: {
				type: Number,
				default: 16,
			},
			// 是否显示中心定位图标
			showCenterIcon: {
				type: Boolean,
				default: false,
			},
			// 中心点图标
			centerIcon: {
				type: String,
				default: "",
			},
			// 是否显示用户定位图标
			showLocationIcon: {
				type: Boolean,
				default: false,
			},
			type:String
		},
		// 数据定义
		data() {
			return {
				// 地图容器id
				mapId: this.genId(),
				// 调用渲染层
				option: {},
				// 地图配置（传递到render中的数据）
				config: {},
				// 调用渲染层队列
				event: [],
				// 事件处理定时器
				timer: null,
				// 中心图标
				defCenterIcon: centerIcon,
				// 定位图标
				locationIcon: locationIcon,
			}
		},
		// 挂载完成后
		mounted() {
			// 设置渲染数据
			this.config = {
				mapId: this.mapId,
				mapKey: this.mapKey,
				lonlat: this.lonlat,
				zoom: this.zoom,
			};
		},
		// 通用方法
		methods: {
			confirm(){
				this.$emit('onUserEvent',{type:'confirm'});
			},
			back(){
				this.$emit('onUserEvent',{type:'back'});
			},
			// 生成唯一ID
			genId() {
				let result = '';
				const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
				const charactersLength = characters.length;
				for (let i = 0; i < 30; i++) {
					result += characters.charAt(Math.floor(Math.random() * charactersLength));
				}
				return Date.now() + result;
			},
			// 调用
			call() {
				if (this.timer) return;
				// 消费事件队列（生产者/消费者机制）
				this.timer = setInterval(() => {
					if (this.event.length) {
						this.option = this.event.shift();
					} else {
						clearInterval(this.timer);
						this.timer = null;
					}
				}, 10);
			},
			// 添加事件队列
			addEvent(name, data) {
				// #ifdef APP-PLUS
				// tips:由于采用监听option改变来调用方法，
				// 如果连续变化两次option，渲染层只会则监听到最后一次
				// 导致调用丢失，所以采用事件队列形式解决，稍微延时10ms
				// 等待渲染进程监听到option变化，在进行更改option
				// 从性能上，几乎无感可以放心使用
				const option = {
					id: this.genId(),
					name: `_${name}`,
					data
				};
				this.event.push(option);
				this.call();
				// #endif

				// #ifndef APP-PLUS
				this[`_${name}`] && this[`_${name}`](data);
				// #endif
			},
			// 设置
			setOption(option) {
				this.addEvent("setOption", option);
			},
			// 设置类型 0矢量地图 1卫星地图
			geoCoder(lng,lat,uuid) {
				this.addEvent("geoCoder", {
					lng,lat,uuid
				});
			},
			// 设置位置
			setCenter(lon, lat, zoom) {
				this.addEvent("setCenter", {
					lon,
					lat,
					zoom
				});
			},
			// 设置类型 0矢量地图 1卫星地图
			setType(type) {
				this.addEvent("setType", {
					type
				});
			},
			// 设置标注 marks:[{url, width, height, lon, lat}]
			setMarkers(markers = []) {
				this.addEvent("setMarkers", {
					markers
				});
			},
			// 在原有的情况下添加覆盖物
			addOvers(overs) {
				this.addEvent("addOvers", overs);
			},
			// 清除原有同类型的覆盖物，并重新创建
			setOvers(overs) {
				this.addEvent("setOvers", overs);
			},
			// 移除指定属性的覆盖物
			removeOvers(prop, value) {
				this.addEvent("removeOvers", {
					prop,
					value
				});
			},
			// 清除指定类型的覆盖物，不指定则清除所有
			clearOvers(type = "") {
				this.addEvent("clearOvers", type);
			},
			// 设置缩放
			setZoom(zoom) {
				this.addEvent("setZoom", {
					zoom
				});
			},
			// 设置是使能
			setEnable(option) {
				this.addEvent("setEnable", option);
			},
			// 重置地图
			resize() {
				this.addEvent("resize");
			},
			// 开始拖拽地图
			UserEvent(data) {
				this.$emit('onUserEvent',data);
			}
		},
	}
</script>

<script module="LyMap" lang="renderjs">
	// 天地图接口
	const TDT_API = "https://api.tianditu.gov.cn/api?v=4.0&tk=";

	export default {
		data() {
			return {
				// 初始化配置数据
				_config: {},
				// 地图实例
				_mapInstance: {},
				// 注记
				_markerList: [],
				// 覆盖物
				_overs: {},
				// 地图事件
				_event: {},
			};
		},
		methods: {
			// 初始化
			init(newValue, oldValue, ownerInstance, instance) {
				// 防止重复渲染
				if (!Object.keys(newValue).length) {
					return;
				}
				this._config = newValue;
				// 初始化地图
				if (typeof window.LyMap === 'function') {
					this._createMap();
				} else {
					const script = document.createElement('script');
					script.src = TDT_API + newValue.mapKey;
					script.onload = this._createMap;
					document.head.appendChild(script);
				}
			},
			// 通过监听call来调用渲染层方法
			call(newValue, oldValue, ownerInstance, instance) {
				if (this[newValue.name] && typeof this[newValue.name] === "function") {
					this[newValue.name](newValue.data);
				}
			},
			// 创建地图
			_createMap() {
				// 创建地图实例
				try {
					this._mapInstance = new T.Map(this._config.mapId);
					this._mapInstance.addEventListener('load', () => {
                        this.$ownerInstance.callMethod('UserEvent',{type:'onMapLoad'});
                    });
					
                    setTimeout(() => {
                        this._setCenter({
                            lon: this._config.lonlat[0],
                            lat: this._config.lonlat[1],
                            zoom: this._config.zoom
                        });
                    }, 100);
					this._bindEvent();
				} catch (err) {
					console.error(err);
				}
			},
            _geoCoder(lng,lat, uuid) { 
                //创建对象
                const geocode = new T.Geocoder();
                geocode.getLocation(new T.LngLat(lng,lat), (res)=>{
                    console.log(res.getStatus ());
                    console.log(res.getMsg ());
                    console.log(res.getAddress ());
                    console.log(res.getAddressComponent ());
                    console.log(res.getLocationLevel ());
                });
                return geocode;
            },
			// 绑定事件
			_bindEvent() {
				try {
					// 绑定开始移动事件
					this._event = {};
                    var fn = ({type})=>{
                        if(this._mapInstance==null)return;
						const center = this._mapInstance.getCenter();
						this.$ownerInstance.callMethod('UserEvent', {
                            type,
							lng: center.getLng(),
							lat: center.getLat()
						});
                    }
                    //this._mapInstance.addEventListener('movestart', fn);
                    this._mapInstance.addEventListener('move', fn);
                    this._mapInstance.addEventListener('moveend', fn);
                    this._mapInstance.addEventListener('zoomstart', fn);
                    this._mapInstance.addEventListener('zoomend', fn);
                    this._mapInstance.addEventListener('dragstart', fn);
                    this._mapInstance.addEventListener('drag', fn);
                    this._mapInstance.addEventListener('dragend', fn);
                    this._mapInstance.addEventListener('touchstart', fn);
                    this._mapInstance.addEventListener('touchmove', fn);
                    this._mapInstance.addEventListener('touchend', fn);
                    this._mapInstance.addEventListener('longpress', fn);
				} catch (err) {
					console.error(err);
				}
			},
			// 卸载事件
			_unbindEvent() {
				const eventsKey = Object.keys(this._event);
				eventsKey.forEach(key => this._mapInstance.removeEventListener(key));
				this._event = null;
			},
			// 重置地图尺寸
			_resize() {
				try {
					this._mapInstance.checkResize && this._mapInstance.checkResize();
				} catch (err) {
					console.error(err);
				}
			},
			// 设置选项
			_setOption(data) {
				data.type && this._setType(data);
				data.center && this._setCenter({
					...data.center,
					zoom: data.zoom
				});
				if (!data.center && data.zoom) this._setZoom(data);
				data.markers && this._setMarkers(data);
				data.overs && this.setOvers(data.overs);
			},
			// 设置中心点
			_setCenter(data) {
				try {
					this._resize();
					this._mapInstance.panTo(new T.LngLat(Number(data.lon), Number(data.lat)), data.zoom || this._mapInstance.getZoom());
				} catch (err) {
					console.error(err);
				}
			},
			// 设置地图显示类型
			_setType(data) {
				try {
					this._mapInstance.setMapType(data.type === 1 ? TMAP_SATELLITE_MAP : TMAP_NORMAL_MAP);
				} catch (err) {
					console.error(err);
				}
			},
			// 设置地图缩放
			_setZoom(data) {
				try {
					this._mapInstance.setZoom(data.zoom);
				} catch (err) {
					console.error(err);
				}
			},
			// 设置注记
			_setMarkers(data) {
				try {
					// 清空当前所有注记
					//if (!this._markerList) this._markerList = [];
					//this._markerList.forEach(marker => this._mapInstance.removeOverLay(marker));
					this._markerList = [];
                    this._mapInstance.clearOverLays();
					// 创建新注记
					data.markers && data.markers.forEach(item => {
						const option = {};
						if (item.icon) {
							option.icon = new T.Icon({
								iconUrl: item.icon,
								iconSize: new T.Point(item.width || 24, item.height || 24),
								iconAnchor: new T.Point(item.offsetX || item.width / 2, item.offsetY ||
									item.height)
							});
						}
						const marker = new T.Marker(new T.LngLat(item.lon, item.lat), option);
						item.click && marker.addEventListener("click", () => this._setEvent('click', item));
						this._markerList.push(marker);
						this._mapInstance.addOverLay(marker);
					});
				} catch (err) {
					console.error(err);
				}
			},
			// 设置使能
			_setEnable(data) {
				// 允许地图拖拽
				if (data.hasOwnProperty("drag")) {
					!!data["drag"] ? this._mapInstance.enableDrag() : this._mapInstance.disableDrag();
				}
				// 允许双击放大，默认启用。
				if (data.hasOwnProperty("doubleClickZoom")) {
					!!data["doubleClickZoom"] ? this._mapInstance.enableDoubleClickZoom() : this._mapInstance
						.disableDoubleClickZoom();
				}
				// 允许地图惯性拖拽
				if (data.hasOwnProperty("inertia")) {
					!!data["inertia"] ? this._mapInstance.enableInertia() : this._mapInstance.disableInertia();
				}
				// 允许双指操作缩放
				if (data.hasOwnProperty("pinchToZoom")) {
					!!data["pinchToZoom"] ? this._mapInstance.enablePinchToZoom() : this._mapInstance.disablePinchToZoom();
				}
			},
			// 添加覆盖物
			_addOvers(data = []) {
				if (!this._overs) this._overs = {};
				data.forEach(item => {
					switch (item.type) {
						// 信息窗口
						case "infowindow":
							this._createOverInfoWindow(item);
							break;
							// 文本
						case "label":
							this._createOverLabel(item);
							break;
							// 创建圆
						case "circle":
							this._createOverCircle(item);
							break;
							// 创建折线
						case "polyline":
							this._createOverPolyLine(item);
							break;
							// 创建多边形
						case "polygon":
							this._createOverPolygon(item);
							break;
							// 创建矩形
						case "rect":
							this._createOverRectangle(item);
							break;
							// 创建带箭头的折线
						case "polylineArrow":
							// 创建不带箭头的三次样条曲线
						case "cardinalCurve":
							// 创建带箭头的三次样条曲线
						case "cardinalCurveArrow":
							this._createOverSymbol(item);
							break;
						default:
							console.warn(
								`'${item.type}'未知的覆盖物类型，有效值为 circle,polyline,polygon,rect,polylineArrow,cardinalCurve,cardinalCurveArrow`
							);
					}
				});
			},
			// 设置覆盖物
			_setOvers(data = []) {
				if (!this._overs) this._overs = {};
				// 移除现有同类型（时间复杂度On^2，不影响使用，暂时不优化了）
				data.forEach(item => this._clearOvers(item.type));
				// 添加
				this._addOvers(data);
			},
			// 清除覆盖物
			_clearOvers(type = "") {
				if (!this._overs) this._overs = {};
				// 清除
				for (const id in this._overs) {
					if (this._overs[id].options.type === type || !type) {
						this._mapInstance.removeOverLay(this._overs[id]);
						delete this._overs[id];
					}
				}
			},
			// 移除指定属性的覆盖物
			_removeOvers(data = {}) {
				if (!this._overs) this._overs = {};
				for (const id in this._overs) {
					if (this._overs[id].options[data.prop] === data.value) {
						this._mapInstance.removeOverLay(this._overs[id]);
						delete this._overs[id];
					}
				}
			},
			// 创建覆盖物
			_createOver(over) {
				// 添加到覆盖物层
				this._mapInstance.addOverLay(over);
				this._overs[this._genKey()] = over;
				// 绑定点击事件
				if (over.options.click) {
					over.addEventListener("click", () => this._setEvent('click', over.options));
				}
			},
			// 创建信息窗口
			_createOverInfoWindow(option) {
				try {
					// 格式化参数
					const param = {
						...option
					};
					// 弹出窗口位置的补偿值。在同一图层中打开弹出窗口时对于控制锚点比较有用。
					if (option.offsetX !== undefined || option.offsetY !== undefined) {
						param.offset = new T.Point(option.offsetX || 0, option.offsetY || 0);
					}
					// 在地图视图自动平移产生后弹出窗口和地图视图之间的边缘。
					if (option.autoPanPaddingX !== undefined || option.autoPanPaddingY !== undefined) {
						param.autoPanPadding = new T.Point(option.autoPanPaddingX || 0, option.autoPanPaddingY || 0);
					}
					const infoWin = new T.InfoWindow(option.content, param);
					// 设置或改变信息浮窗所指向的地理位置坐标
					if (option.lon && option.lat) {
						infoWin.setLngLat(new T.LngLat(option.lon, option.lat));
					}
					this._createOver(infoWin);
				} catch (err) {
					console.error(err);
				}
			},
			// 创建文本覆盖物
			_createOverLabel(option) {
				try {
					// 格式化参数
					const param = {
						...option
					};
					if (option.lon && option.lat) param.position = new T.LngLat(option.lon, option.lat);
					param.offset = new T.Point(option.offsetX || 0, option.offsetY || 0);
					const label = new T.Label(param);
					this._createOver(label);
				} catch (err) {
					console.error(err);
				}
			},
			// 创建圆覆盖物
			_createOverCircle(option) {
				try {
					const circle = new T.Circle(new T.LngLat(option.lon, option.lat), option.rad, option);
					this._createOver(circle);
				} catch (err) {
					console.error(err);
				}
			},
			// 创建折线覆盖物
			_createOverPolyLine(option) {
				try {
					const points = option.points.map(point => new T.LngLat(point[0], point[1]));
					const line = new T.Polyline(points, option);
					this._createOver(line);
				} catch (err) {
					console.error(err);
				}
			},
			// 创建多边形覆盖物
			_createOverPolygon(option) {
				try {
					const points = option.points.map(point => new T.LngLat(point[0], point[1]));
					const polygon = new T.Polygon(points, option);
					this._createOver(polygon);
				} catch (err) {
					console.error(err);
				}
			},
			// 创建矩形覆盖物
			_createOverRectangle(option) {
				try {
					const lt = option.leftTop;
					const rb = option.rightBottom;
					const bounds = new T.LngLatBounds(new T.LngLat(lt[0], lt[1]), new T.LngLat(rb[0], rb[1]));
					const rect = new T.Rectangle(bounds, option);
					this._createOver(rect);
				} catch (err) {
					console.error(err);
				}
			},
			// 创建符号覆盖物
			_createOverSymbol(option) {
				try {
					let over = null;
					const points = option.points.map(point => new T.LngLat(point[0], point[1]));
					switch (option.type) {
						case "polylineArrow":
							over = new T.PolylineArrow(points, option);
							break;
						case "cardinalCurve":
							over = new T.CardinalCurve(points, option);
							break;
						case "cardinalCurveArrow":
							over = new T.CardinalCurveArrow(points, option);
							break;
						default:
							break;
					}
					if (over) this._createOver(over);
				} catch (err) {
					console.error(err);
				}
			},
			// 设置事件
			_setEvent(type, target) {
				this.$ownerInstance.callMethod('UserEvent', {
                    type:'onMapListen',
					type, // 事件类型UserEvent
					target, // 事件目标
				});
			},
			// 释放地图
			_dispose() {
				delete this._mapInstance;
				this._mapInstance = null;
				this._unbindEvent();
			},
			// 生成唯一ID
			_genKey() {
				let result = '';
				const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
				const charactersLength = characters.length;
				for (let i = 0; i < 30; i++) {
					result += characters.charAt(Math.floor(Math.random() * charactersLength));
				}
				return Date.now() + result;
			},
		},
	};
</script>

<style lang="scss" scoped>
	.ly-map-wrapper {
		width: 100%;
		height: 100%;
		position: relative;
		overflow: hidden;
		background: transparent;

		.ly-map {
			width: 100%;
			height: 100%;
		}

		.ly-center-icon {
			position: absolute;
			z-index: 401;
			left: 50%;
			top: 50%;
			transform: translateX(-50%) translateY(-100%);
			width: 64rpx;
			height: 64rpx;
		}

		.ly-location-icon {
			position: absolute;
			z-index: 401;
			right: 24rpx;
			bottom: 24rpx;
			width: 72rpx;
			height: 72rpx;
			background: #ffffff;
			border-radius: 12rpx;
			display: flex;
			align-items: center;
			justify-content: center;
			box-shadow: 0 0 8rpx rgba(0, 0, 0, .15);

			.icon {
				width: 44rpx;
				height: 44rpx;
			}
		}
	}
</style>