Bladeren bron

1、修正房屋绘制后无法修改属性及修改属性异常的BUG
2、修改完善瓦片数据叠加实景三维的瓦片移除机制,尚需进一步修复

不会爬树的猴 2 jaren geleden
bovenliggende
commit
8bb1657dfd

+ 419 - 117
src/components/CrMap/CrImageServerLayer.js

@@ -25,41 +25,113 @@ Date.prototype.Format = function(fmt) { // author: meizz
 
 /* 引入Cesium */
 import * as Cesium from 'cesium';
-// import Worker from '../../../public/worker/download.js?worker';
+
+/* 扩展primivite方法 */
+
+/**
+ * 设置Id
+ * @param {String} id
+ */
+Cesium.GroundPrimitive.prototype.setId = function(id) {
+	this._id = id;
+}
+
+/**
+ * 获取Id
+ */
+Cesium.GroundPrimitive.prototype.getId = function() {
+	return this._id;
+}
+
+/**
+ * 根据Id进行查询
+ * @param {String} id
+ * @return {Cesium.GroundPrimitive} 返回查询到的Primivite 未查询到 则返回undefined
+ */
+Cesium.PrimitiveCollection.prototype.getById = function(id) {
+	let findPrimivite = this._primitives.find(obj => {
+		if (obj._id === id) return obj;
+	})
+	return findPrimivite;
+}
+
+/**
+ * 根据Id进行移除操作
+ * @param {String} id
+ */
+Cesium.PrimitiveCollection.prototype.removeById = function(id) {
+	let findPrimitive = this.getById(id);
+	if (findPrimitive !== undefined) {
+		return this.remove(findPrimitive);
+	} else {
+		return false;
+	}
+}
+
 
 /* 创建类 */
 class CrImageServerLayer {
 	/**
 	 * 构造函数
 	 * @param {Cesium.Viewer} options.viewer 地图视图容器
-	 * @param {String} options.url 服务地址
+	 * @param {CrImageServerLayer.ProviderType} options.providerType 数据提供器类型
+	 * @param {JSON} options.config 对应该提供器的配置参数
 	 * @param {Number} options.opacity 图层透明度[0.0~1.0] [默认0.3]    
 	 */
 	constructor({
 		viewer,
-		url,
+		providerType = CrImageServerLayer.ArcGisMapServerImageryProvider,
+		config = {},
 		opacity = 0.75,
 		show = true,
 	} = {}) {
+		let _self = this;
 		/* 地图视图 外部传入 必须参数 */
 		this._viewer = viewer;
-		/* 服务地址 外部传入 */
-		this._url = url;
+		/* 服务提供者配置参数 */
+		this._providerType = providerType;
+		/* 服务提供者 */
+		this._provider = undefined;
+		/* 服务提供者切片方案 */
+		this._tilingScheme = undefined;
+		/* 服务的切片的最大/最小层级 */
+		this._maximumLevel = 0;
+		this._minimumLevel = 20;
+		/* 切片大小 */
+		this._tileWidth = 0;
+		this._tileHeight = 0;
+		/* 服务数据范围 */
+		this._rectangle = undefined;
+		/* 服务提供者的配置参数 */
+		this._config = config;
 		/* 透明度 外部传入 */
 		this._opacity = opacity;
 		/* 图层随机标识 */
 		this._renderName = this._guid();
-		/* 实体集合 */
-		/* 用DataSource 方式 以便进行多图层管理 */
-		let dataSource = new Cesium.CustomDataSource(this._renderName);
-		this._viewer.dataSources.add(dataSource);
-		this._entities = dataSource.entities;
+		/* 当前图层的渲染集合 */
+		this._primitives = new Cesium.PrimitiveCollection();
+		this._viewer.scene.primitives.add(this._primitives);
 		/* 渲染集合 */
-		this._renderEntities = new Map();
+		this._renderPrimitives = new Map();
+		/* 移除渲染集合 */
+		this._removePrimitives = new Map();
 		/* 是否渲染标志 */
 		this._isUpdateTile = show;
 		/* 是否输出测试信息 */
-		this._isDebug = false;
+		this._isDebug = true;
+		/* 创建一个线程 用于处理移除任务 */
+		this._sendTask = true;
+		let workerBlob = new Blob([`(${downloadWorker.toString ()})()`]); // 把函数转成一个自执行函数
+		this._worker = new Worker(URL.createObjectURL(workerBlob));
+		/* 接收反馈 */
+		this._worker.onmessage = function(event) {
+			for (let key of event.data) {
+				_self._primitives.removeById(key);
+				_self._removePrimitives.delete(key);
+				_self._renderPrimitives.delete(key);
+			}
+			_self._sendTask = true;
+		}
 		/* 初始化 */
 		this._init();
 	}
@@ -70,13 +142,30 @@ class CrImageServerLayer {
 	_init() {
 		let _self = this;
 		/* 创建服务提供者 */
-		this._provider = new Cesium.ArcGisMapServerImageryProvider({
-			url: _self._url,
-		})
+		switch (this._providerType) {
+			case CrImageServerLayer.ProviderType.ArcGisMapServerImageryProvider:
+				this._provider = new Cesium.ArcGisMapServerImageryProvider(this._config);
+				break;
+			case CrImageServerLayer.ProviderType.UrlTemplateImageryProvider:
+				this._provider = new Cesium.UrlTemplateImageryProvider(this._config);
+				break;
+		}
+		/* 服务提供者判断 */
+		if (this._provider === undefined) {
+			this._console('没有服务提供者,无法初始化!');
+			return;
+		}
 		/* 激活服务提供者 注册刷帧事件 */
 		this._provider.readyPromise.then(function(result) {
-			/* 服务提供者的数据范围 */
+			/* 初始化参数 */
 			_self._rectangle = _self._provider.rectangle;
+			_self._tilingScheme = _self._provider.tilingScheme;
+			_self._maximumLevel = _self._provider.maximumLevel === undefined ? 22 : _self._provider
+				.maximumLevel;
+			_self._minimumLevel = _self._provider.minimumLevel === undefined ? 0 : _self._provider
+				.minimumLevel;
+			_self._tileWidth = _self._provider.tileWidth;
+			_self._tileHeight = _self._provider.tileHeight;
 			/* 输出调试信息 */
 			if (_self._isDebug) _self._printDebug();
 			/* 注册事件 */
@@ -113,17 +202,6 @@ class CrImageServerLayer {
 		this._drawDebugRectangle(this._rectangle, Cesium.Color.GREEN);
 		/* 根据行列号和等级创建调试矩形 */
 		let rect = tiling84.tileXYToRectangle(1696, 312, 10);
-		/* 绘制调试矩形 */
-		// this._drawDebugRectangle(rect, Cesium.Color.YELLOW);
-
-		// let rect11 = Cesium.Rectangle.subsection(rect, 0, 0, 0.5, 0.5);
-		// let rect12 = Cesium.Rectangle.subsection(rect, 0.5, 0, 1.0, 0.5);
-		// let rect21 = Cesium.Rectangle.subsection(rect, 0, 0.5, 0.5, 1.0);
-		// let rect22 = Cesium.Rectangle.subsection(rect, 0.5, 0.5, 1.0, 1.0);
-		// this._drawDebugRectangle(rect11, Cesium.Color.RED);
-		// this._drawDebugRectangle(rect12, Cesium.Color.GREEN);
-		// this._drawDebugRectangle(rect21, Cesium.Color.BLUE);
-		// this._drawDebugRectangle(rect22, Cesium.Color.WHITE);
 	}
 
 	/**
@@ -134,18 +212,59 @@ class CrImageServerLayer {
 	_drawDebugRectangle(rectangle, color) {
 		/* 计算矩形的外包范围 */
 		let positions = this._calculateRectangleOutlineCoordinates(rectangle);
-		/* 创建矩形实体 */
-		let rectEntity = new Cesium.Entity({
-			name: this._renderName,
-			polyline: {
+		/* 创建矩形图元 */
+		let rectangleInstance = new Cesium.GeometryInstance({
+			geometry: new Cesium.GroundPolylineGeometry({
 				positions: positions,
-				material: color,
-				width: 10,
-				clampToGround: true, //开启贴地 如果有模型则贴模型
+				width: 8,
+			})
+		})
+		/* 创建对象 */
+		let primivite = new Cesium.GroundPolylinePrimitive({
+			geometryInstances: rectangleInstance,
+			appearance: this._createMaterialColorAppearance('rgba(0,255,0,1)'),
+			classificationType: Cesium.ClassificationType.BOTH,
+		})
+		/* 加入数据集 */
+		this._primitives.add(primivite);
+	}
+
+	/**
+	 * 创建颜色着色器
+	 * @param {String} color rgba(r,g,b,a)
+	 */
+	_createMaterialColorAppearance(color) {
+		/* 创建材质 */
+		let material = new Cesium.Material({
+			fabric: {
+				type: 'Color',
+				uniforms: {
+					color: new Cesium.Color.fromCssColorString(color),
+				}
 			}
 		});
-		/* 加入数据集 */
-		this._entities.add(rectEntity);
+		/* 创建着色器 */
+		let appearance = new Cesium.MaterialAppearance({
+			material: material,
+		});
+		/* 返回 */
+		return appearance;
+	}
+
+	/**
+	 * 根据画布创建材质
+	 * @param {Canvas} canvas 画布
+	 */
+	_createMaterialImageAppearance(canvas) {
+		/* 创建着色器 */
+		let material = Cesium.Material.fromType('Image', {
+			image: canvas,
+		})
+		let appearance = new Cesium.MaterialAppearance({
+			material: material,
+		})
+		/* 返回 */
+		return appearance;
 	}
 
 	/**
@@ -175,10 +294,11 @@ class CrImageServerLayer {
 					let level2 = parseInt(obj2.level);
 					return level1 - level2;
 				})
+
 				/* 返回排序后的渲染瓦片数据集 开始异步计算 */
 				resolve(tilesToRender);
 			}).then(tiles => {
-				/* 异步重投影瓦片数据集 */
+				/* Cesium渲染瓦片为84投影,如果不一致需要异步重投影瓦片数据集 */
 				_self._asyncProjectionTiles(tiles);
 			})
 		}
@@ -320,9 +440,9 @@ class CrImageServerLayer {
 	 */
 	_renderTilesToViewer(tiles) {
 		let _self = this;
-		/* 确定哪些渲染实体已失效 对失效的实体进行清理 */
+		/* 确定哪些渲染瓦片已失效 对失效的实体进行清理 */
 		let deleteKeys = [];
-		for (let [key, tile] of this._renderEntities) {
+		for (let [key, tile] of this._renderPrimitives) {
 			let findTile = tiles.find(obj => {
 				return obj.key === key;
 			})
@@ -331,47 +451,85 @@ class CrImageServerLayer {
 			}
 		}
 		for (let key of deleteKeys) {
-			/* 移除元素 */
-			this._renderEntities.delete(key);
+			/* 从当前渲染集合中将失效瓦片移除元素 */
+			// this._renderPrimitives.delete(key);
 			/* 移除渲染元素 */
-			this._entities.removeById(key);
+			// this._primitives.removeById(key);
+			this._removePrimitives.set(key, {
+				key: key,
+			});
 		}
 		/* 对过滤后的数据集进行渲染 */
 		for (let tile of tiles) {
 			/* 判断当前渲染的数据是否已经渲染且有效 */
-			if (!this._renderEntities.has(tile.key)) {
+			if (!this._renderPrimitives.has(tile.key)) {
 				/* 将数据渲染到视图中 */
-				let entity = this._renderSimpleTileToViewer(tile);
-				/* 将渲染的数据加入到集合中 */
-				this._renderEntities.set(tile.key, entity);
-				/* 创建下载线程 */
-				let workBlob = new Blob([`(${downloadWorker.toString ()})()`]); // 把函数转成一个自执行函数
-				// let workBlob = new Blob([downloadWorker.toLocaleString().match(
-				// 	/(?:\/\*[\s\S]*?\*\/|\/\/.*?\r?\n|[^{])+\{([\s\S]*)\}$/)[1]]) // 把函数的主体内容拿出来进行转换
-				let worker = new Worker(URL.createObjectURL(workBlob));
-				/* 发送下载任务 */
-				worker.postMessage({
+				this._renderSimpleTileToViewer(tile);
+				/* 追加到渲染集合中 该集合中始终保持当前渲染的最新数据 */
+				this._renderPrimitives.set(tile.key, {
 					key: tile.key,
-					url: this._url,
-					x: tile.x,
-					y: tile.y,
-					level: tile.level,
-				})
-				/* 接收下载任务 */
-				worker.onmessage = function(event) {
-					_self._console(`render x:${event.data.x} y:${event.data.y} level:${event.data.level}`);
-					/* 判断是否存在 */
-					let renderEntity = _self._entities.getById(event.data.key);
-					if (renderEntity !== undefined) {
-						let key = event.data.key;
-						const canvas = _self._createCanvas(event.data, event.data.image, _self._isDebug);
-						renderEntity.rectangle.material = canvas;
+					renderImage: false,
+				});
+				/* 初始化y */
+				let tile_y = tile.y;
+				/* 利用数据提供器获取图片 */
+				this._provider.requestImage(tile.x, tile_y, tile.level).then(function(image) {
+					/* 判断是否返回图片资源 */
+					if (image !== undefined) {
+						/* 对图片资源进行Y轴翻转 */
+						let primise = createImageBitmap(image, {
+							imageOrientation: 'flipY',
+						});
+						primise.then(function(resImage) {
+							let renderPrimitive = _self._primitives.getById(tile.key);
+							if (renderPrimitive !== undefined) {
+								let canvas = _self._createCanvas(tile, resImage, _self._isDebug);
+								renderPrimitive.appearance = _self._createMaterialImageAppearance(
+									canvas);
+								/* 修改集合中内容 */
+								if (_self._renderPrimitives.has(tile.key)) {
+									let item = _self._renderPrimitives.get(tile.key);
+									item.renderImage = true;
+									_self._renderPrimitives.set(tile.key, item);
+								}
+							}
+							/* 释放图片资源 */
+							image.close();
+						})
 					}
-					worker.terminate();
-				}
+				}).catch(err => {
+					_self._console('错误', err);
+					/* 修改集合中内容 */
+					if (_self._renderPrimitives.has(tile.key)) {
+						let item = _self._renderPrimitives.get(tile.key);
+						item.renderImage = true;
+						_self._renderPrimitives.set(tile.key, item);
+					}
+				});
 			}
 		}
+		if (this._sendTask && this._removePrimitives.size > 0) {
+			this._sendTask = false;
+			this._console('发送处理任务...');
+			let renderPrimitives = new Map();
+			/* 传递之前深度克隆 */
+			for (let [key, item] of this._renderPrimitives) {
+				let strItem = JSON.stringify(item);
+				renderPrimitives.set(key, JSON.parse(strItem));
+			}
+			/* 深度克隆需要移除的实体集合 */
+			let removePrimitives = [];
+			for (let [key, removeEntity] of this._removePrimitives) {
+				removePrimitives.push(key);
+			}
+			/* 发送处理任务 */
+			this._worker.postMessage({
+				removePrimitives: removePrimitives,
+				renderPrimitives: renderPrimitives,
+			});
+		}
 		/* 重启计算标志 */
+		// this._console('循环结束...');
 		this._isUpdateTile = true;
 	}
 
@@ -384,21 +542,23 @@ class CrImageServerLayer {
 		const canvas = this._createCanvas(tile, undefined, this._isDebug);
 		let bjPositions = this._calculateRectangleOutlineCoordinates(tile
 			.rectangle);
-		let tileEntity = new Cesium.Entity({
-			name: this._renderName,
-			id: tile.key,
-			rectangle: {
-				coordinates: tile.rectangle,
-				material: canvas,
-			},
-			polyline: {
-				positions: bjPositions,
-				material: Cesium.Color.YELLOW.withAlpha(this._isDebug ? 1 : 0),
-				width: 1,
-				clampToGround: true, //开启贴地 如果有模型则贴模型
-			}
+		/* 创建图形要素 */
+		let instance = new Cesium.GeometryInstance({
+			geometry: new Cesium.RectangleGeometry({
+				rectangle: tile.rectangle,
+			})
 		});
-		return this._entities.add(tileEntity);
+		/* 创建着色器 */
+		let appearance = this._createMaterialImageAppearance(canvas);
+		/* 创建源语 */
+		let primitive = new Cesium.GroundPrimitive({
+			geometryInstances: instance,
+			appearance: appearance,
+		});
+		/* 设置Id */
+		primitive.setId(tile.key);
+		/* 加入集合 */
+		return this._primitives.add(primitive);
 	}
 
 	/**
@@ -416,7 +576,12 @@ class CrImageServerLayer {
 		const context = canvas.getContext("2d");
 		if (image !== undefined) {
 			context.globalAlpha = this._opacity;
-			context.drawImage(event.data.image, 0, 0, canvas.width, canvas.height);
+			context.drawImage(image, 0, 0, canvas.width, canvas.height);
+		}
+		if (this._isDebug) {
+			context.strokeStyle = 'rgba(255,255,0,1)';
+			context.lineWidth = 2;
+			context.strokeRect(0, 0, canvas.width, canvas.height);
 		}
 		if (islabel !== undefined && islabel === true) {
 			context.globalAlpha = 1.0;
@@ -442,6 +607,14 @@ class CrImageServerLayer {
 	 * @param {Object} tile
 	 */
 	_projectionTile(tile) {
+		if (this._tilingScheme instanceof Cesium.GeographicTilingScheme) {
+			return [{
+				x: tile.x,
+				y: tile.y,
+				level: tile.level,
+				rectangle: tile._rectangle,
+			}];
+		}
 		/* 获取矩形 */
 		let rectangle = tile._rectangle;
 		// let imageryLevel = parseInt(tile.level) + 1;
@@ -532,7 +705,7 @@ class CrImageServerLayer {
 	 */
 	_removeEntityByName(entityName) {
 		/* 获取实体集合 */
-		var entities = this._entities;
+		var entities = this._primitives;
 		/* 如果不存在实体集合或集合中没有数据 则返回 */
 		if (!entities || !entities.values) return;
 		var delEntitys = [];
@@ -560,7 +733,7 @@ Object.assign(CrImageServerLayer.prototype, {
 		/* 清理资源 */
 		this._removeEntityByName(this._renderName);
 		/* 清理渲染 */
-		this._renderEntities.clear();
+		this._renderPrimitives.clear();
 	},
 
 	/**
@@ -586,42 +759,171 @@ Object.assign(CrImageServerLayer.prototype, {
 
 /* 下载线程函数 */
 function downloadWorker() {
-	/* 接收主线程发送的文件下载请求 */
+	/** 
+	 * 判断矩形相交函数
+	 * @ignore
+	 * @param {Object} rectangle
+	 * @param {Object} otherRectangle
+	 * @param {Object} result
+	 */
+	function intersection(rectangle, otherRectangle, result) {
+		let TWO_PI = 2.0 * Math.PI;
+		let rectangleEast = rectangle.east;
+		let rectangleWest = rectangle.west;
+		let otherRectangleEast = otherRectangle.east;
+		let otherRectangleWest = otherRectangle.west;
+		if (rectangleEast < rectangleWest && otherRectangleEast > 0.0) {
+			rectangleEast += TWO_PI;
+		} else if (otherRectangleEast < otherRectangleWest && rectangleEast > 0.0) {
+			otherRectangleEast += TWO_PI;
+		}
+		if (rectangleEast < rectangleWest && otherRectangleWest < 0.0) {
+			otherRectangleWest += TWO_PI;
+		} else if (otherRectangleEast < otherRectangleWest && rectangleWest < 0.0) {
+			rectangleWest += TWO_PI;
+		}
+		const west = negativePiToPi(
+			Math.max(rectangleWest, otherRectangleWest)
+		);
+		const east = negativePiToPi(
+			Math.min(rectangleEast, otherRectangleEast)
+		);
+		if (
+			(rectangle.west < rectangle.east ||
+				otherRectangle.west < otherRectangle.east) &&
+			east <= west
+		) {
+			return undefined;
+		}
+		const south = Math.max(rectangle.south, otherRectangle.south);
+		const north = Math.min(rectangle.north, otherRectangle.north);
+		if (south >= north) {
+			return undefined;
+		}
+		if (result === undefined) {
+			return {
+				west: west,
+				south: south,
+				east: east,
+				north: north
+			};
+		}
+		result.west = west;
+		result.south = south;
+		result.east = east;
+		result.north = north;
+		return result;
+	};
+
+	/**
+	 * 判断矩形相交辅助函数
+	 * @ignore
+	 * @param {Object} angle
+	 */
+	function negativePiToPi(angle) {
+		if (angle >= -Math.PI && angle <= Math.PI) {
+			return angle;
+		}
+		return zeroToTwoPi(angle + Math.PI) - Math.PI;
+	};
+
+	/**
+	 * 判断矩形相交辅助函数
+	 * @ignore
+	 * @param {Object} angle
+	 */
+	function zeroToTwoPi(angle) {
+		let TWO_PI = 2.0 * Math.PI;
+		let EPSILON14 = 0.00000000000001;
+		if (angle >= 0 && angle <= TWO_PI) {
+			return angle;
+		}
+		const mod = mod(angle, TWO_PI);
+		if (
+			Math.abs(mod) < EPSILON14 &&
+			Math.abs(angle) > EPSILON14
+		) {
+			return TWO_PI;
+		}
+		return mod;
+	};
+
+	/**
+	 * 判断矩形相交辅助函数
+	 * @ignore
+	 * @param {Object} m
+	 * @param {Object} n
+	 */
+	function mod(m, n) {
+		if (sign(m) === sign(n) && Math.abs(m) < Math.abs(n)) {
+			return m;
+		}
+		return ((m % n) + n) % n;
+	};
+
+	/**
+	 * 判断矩形相交辅助函数
+	 * @ignore
+	 * @param {Object} value
+	 */
+	function sign(value) {
+		value = +value;
+		if (value === 0 || value !== value) {
+			return value;
+		}
+		return value > 0 ? 1 : -1;
+	};
+
+	/**
+	 * 接收主线发送的处理任务
+	 * @ignore
+	 * @param {Object} event
+	 * @param {JSON} event.data
+	 * @param {Array<String>} event.data.removePrimitives 存储当前需要移除的集合
+	 * @param {Array<JSON>} event.data.renderPrimitives 当前渲染的数据集合
+	 * event.data.entities 参数说明
+	 * @param {String} key 主键<对应Id>
+	 * @param {Boolean} renderImage 是否已经渲染了图片
+	 */
 	onmessage = function(event) {
 		let data = event.data;
-		/* 创建下载数据链接 */
-		let url = data.url + '/tile/' + data.level + '/' + data.y + '/' + data.x;
-		/* 创建下载相关 并下载 */
-		let xhr = new XMLHttpRequest();
-		xhr.open('get', url, true);
-		xhr.responseType = "blob"; //设置返回类型,此处我用于下载文件 所以返回blob
-		xhr.onload = function() {
-			// 请求完成
-			if (this.status === 200) {
-				var blob = this.response;
-				var bmpPromise = createImageBitmap(blob, {
-					imageOrientation: "none",
-					premultiplyAlpha: "none",
-					colorSpaceConversion: "default",
-				});
-				bmpPromise.then(function(image) {
-					let outObj = {
-						key: data.key,
-						x: data.x,
-						y: data.y,
-						level: data.level,
-						image: image,
-					}
-					postMessage(outObj);
-				})
-			} else {
-				console.log('===>>>', url + ' Not found');
-			}
+		let isRemove = true;
+		for (let [key, item] of data.renderPrimitives) {
+			if (item.renderImage === false) isRemove = false;
+			break;
+		}
+		if (isRemove) {
+			setTimeout(function() {
+				postMessage(data.removePrimitives);
+			}, 300);
+		} else {
+			postMessage([]);
+			console.log('===>>>', '渲染未完成!');
 		}
-		/* 发送请求 */
-		xhr.send();
 	}
 }
 
+
+/**
+ * 数据提供器类型
+ */
+CrImageServerLayer.ProviderType = Object.freeze({
+	ArcGisMapServerImageryProvider: 'ArcGisMapServerImageryProvider',
+	BingMapsImageryProvider: 'BingMapsImageryProvider',
+	OpenStreetMapImageryProvider: 'OpenStreetMapImageryProvider',
+	TileMapServiceImageryProvider: 'TileMapServiceImageryProvider',
+	GoogleEarthEnterpriseImageryProvider: 'GoogleEarthEnterpriseImageryProvider',
+	GoogleEarthEnterpriseMapsProvider: 'GoogleEarthEnterpriseMapsProvider',
+	GridImageryProvider: 'GridImageryProvider',
+	IonImageryProvider: 'IonImageryProvider',
+	MapboxImageryProvider: 'MapboxImageryProvider',
+	MapboxStyleImageryProvider: 'MapboxStyleImageryProvider',
+	SingleTileImageryProvider: 'SingleTileImageryProvider',
+	TileCoordinatesImageryProvider: 'TileCoordinatesImageryProvider',
+	UrlTemplateImageryProvider: 'UrlTemplateImageryProvider',
+	WebMapServiceImageryProvider: 'WebMapServiceImageryProvider',
+	WebMapTileServiceImageryProvider: 'WebMapTileServiceImageryProvider',
+})
+
 /* 输出类 */
 export default CrImageServerLayer

+ 497 - 242
src/components/CrMap/CrImageServerLayer_back.js

@@ -26,31 +26,58 @@ Date.prototype.Format = function(fmt) { // author: meizz
 /* 引入Cesium */
 import * as Cesium from 'cesium';
 
-import CrImageMaterialProperty from './CrImageMaterialProperty.js'
-
 /* 创建类 */
 class CrImageServerLayer {
 	/**
 	 * 构造函数
 	 * @param {Cesium.Viewer} options.viewer 地图视图容器
-	 * @param {String} options.url 服务地址
-	 * @param {Number} options.opacity 图层透明度 [默认0.3]    
+	 * @param {CrImageServerLayer.ProviderType} options.providerType 数据提供器类型
+	 * @param {JSON} options.config 对应该提供器的配置参数
+	 * @param {Number} options.opacity 图层透明度[0.0~1.0] [默认0.3]    
 	 */
 	constructor({
 		viewer,
-		url,
-		opacity = 0.3
+		providerType = CrImageServerLayer.ArcGisMapServerImageryProvider,
+		config = {},
+		opacity = 0.75,
+		show = true,
 	} = {}) {
+		/* 地图视图 外部传入 必须参数 */
 		this._viewer = viewer;
-		//http://218.59.194.74:6080/arcgis/rest/services/LYLSQ_YX_102100_202112/MapServer/WMTS
-		//http://218.59.194.74:6080/arcgis/rest/services/LYLSQ_GHT_102100_202112/MapServer/wmts
-		this._url = 'http://218.59.194.74:6080/arcgis/rest/services/LYLSQ_GHT_102100_202112/MapServer';
+		/* 服务提供者配置参数 */
+		this._providerType = providerType;
+		/* 服务提供者 */
+		this._provider = undefined;
+		/* 服务提供者切片方案 */
+		this._tilingScheme = undefined;
+		/* 服务的切片的最大/最小层级 */
+		this._maximumLevel = 0;
+		this._minimumLevel = 20;
+		/* 切片大小 */
+		this._tileWidth = 0;
+		this._tileHeight = 0;
+		/* 服务数据范围 */
+		this._rectangle = undefined;
+		/* 服务提供者的配置参数 */
+		this._config = config;
+		/* 透明度 外部传入 */
 		this._opacity = opacity;
-		this._renderName = 'suiji'; //后期要改成随机字符串
-		this._entities = this._viewer.entities;
+		/* 图层随机标识 */
+		this._renderName = this._guid();
+		/* 实体集合 */
+		/* 用DataSource 方式 以便进行多图层管理 */
+		let dataSource = new Cesium.CustomDataSource(this._renderName);
+		this._viewer.dataSources.add(dataSource);
+		this._entities = dataSource.entities;
+		/* 渲染集合 */
+		this._renderEntities = new Map();
+		this._renderImagebitmaps = new Map();
+		/* 是否渲染标志 */
+		this._isUpdateTile = show;
+		/* 是否输出测试信息 */
+		this._isDebug = true;
+		/* 初始化 */
 		this._init();
-		this._updateTiles = [];
-		this._isUpdateTile = true;
 	}
 
 	/**
@@ -58,290 +85,462 @@ class CrImageServerLayer {
 	 */
 	_init() {
 		let _self = this;
-		this._provider = new Cesium.ArcGisMapServerImageryProvider({
-			url: _self._url,
-		})
-		/* 激活provider 继而获取必要信息 */
+		/* 创建服务提供者 */
+		switch (this._providerType) {
+			case CrImageServerLayer.ProviderType.ArcGisMapServerImageryProvider:
+				this._provider = new Cesium.ArcGisMapServerImageryProvider(this._config);
+				break;
+			case CrImageServerLayer.ProviderType.UrlTemplateImageryProvider:
+				this._provider = new Cesium.UrlTemplateImageryProvider(this._config);
+				break;
+		}
+		/* 服务提供者判断 */
+		if (this._provider === undefined) {
+			this._console('没有服务提供者,无法初始化!');
+			return;
+		}
+		/* 激活服务提供者 注册刷帧事件 */
 		this._provider.readyPromise.then(function(result) {
+			/* 初始化参数 */
+			_self._rectangle = _self._provider.rectangle;
+			_self._tilingScheme = _self._provider.tilingScheme;
+			_self._maximumLevel = _self._provider.maximumLevel === undefined ? 22 : _self._provider
+				.maximumLevel;
+			_self._minimumLevel = _self._provider.minimumLevel === undefined ? 0 : _self._provider
+				.minimumLevel;
+			_self._tileWidth = _self._provider.tileWidth;
+			_self._tileHeight = _self._provider.tileHeight;
+			/* 输出调试信息 */
+			if (_self._isDebug) _self._printDebug();
 			/* 注册事件 */
 			_self._viewer.scene.postRender.addEventListener(() => {
-				if (_self._isUpdateTile === true) {
-					_self._console(_self._isUpdateTile);
-					_self._updateRenderTile();
+				if (_self._isUpdateTile) {
+					/* 设置运行标志为false 等待计算完成 */
+					_self._isUpdateTile = false;
+					/* 投影瓦片集合 */
+					_self._renderTiles();
 				}
 			});
-			/* 注册相机场景移动停止事件 */
-			// _self._viewer.camera.moveEnd.addEventListener(() => {
-			// 	_self._console('相机移动结束');
-			// 	_self._updateRenderTile();
-			// })
 		})
 	}
 
 	/**
+	 * 生成GUID随机数
+	 */
+	_guid() {
+		function S4() {
+			return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
+		}
+		return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
+	}
+
+	/**
+	 * 输出调试信息
+	 */
+	_printDebug() {
+		/* 数据提供者的切片方案 */
+		let tiling = this._provider.tilingScheme;
+		/* WGS84坐标系的切片方案 */
+		let tiling84 = new Cesium.GeographicTilingScheme();
+		/* 绘制数据提供者的数据范围 */
+		this._drawDebugRectangle(this._rectangle, Cesium.Color.GREEN);
+		/* 根据行列号和等级创建调试矩形 */
+		let rect = tiling84.tileXYToRectangle(1696, 312, 10);
+		/* 绘制调试矩形 */
+		// this._drawDebugRectangle(rect, Cesium.Color.YELLOW);
+
+		// let rect11 = Cesium.Rectangle.subsection(rect, 0, 0, 0.5, 0.5);
+		// let rect12 = Cesium.Rectangle.subsection(rect, 0.5, 0, 1.0, 0.5);
+		// let rect21 = Cesium.Rectangle.subsection(rect, 0, 0.5, 0.5, 1.0);
+		// let rect22 = Cesium.Rectangle.subsection(rect, 0.5, 0.5, 1.0, 1.0);
+		// this._drawDebugRectangle(rect11, Cesium.Color.RED);
+		// this._drawDebugRectangle(rect12, Cesium.Color.GREEN);
+		// this._drawDebugRectangle(rect21, Cesium.Color.BLUE);
+		// this._drawDebugRectangle(rect22, Cesium.Color.WHITE);
+	}
+
+	/**
+	 * 绘制调试矩形
+	 * @param {Cesium.Rectangle} rectangle 绘制的矩形
+	 * @param {Cesium.Color} color 矩形边框颜色
+	 */
+	_drawDebugRectangle(rectangle, color) {
+		/* 计算矩形的外包范围 */
+		let positions = this._calculateRectangleOutlineCoordinates(rectangle);
+		/* 创建矩形实体 */
+		let rectEntity = new Cesium.Entity({
+			name: this._renderName,
+			polyline: {
+				positions: positions,
+				material: color,
+				width: 10,
+				clampToGround: true, //开启贴地 如果有模型则贴模型
+			}
+		});
+		/* 加入数据集 */
+		this._entities.add(rectEntity);
+	}
+
+	/**
 	 * 输出消息
 	 * @param {Object} res
 	 */
 	_console(...rest) {
-		console.log('===' + new Date().Format('yyyy-MM-dd HH:mm:ss') + '>>>', rest);
+		if (this._isDebug)
+			console.log('===' + new Date().Format('yyyy-MM-dd HH:mm:ss') + '>>>', rest);
 	}
 
 	/**
-	 * 更新渲染的Tile集合
+	 * 渲染瓦片集合
 	 */
-	_updateRenderTile() {
-		/* 设置更新标志为否 */
-		this._isUpdateTile = false;
+	_renderTiles() {
 		let _self = this;
-		/* 同步 */
-		let promise = new Promise((resolve, reject) => {
-			/* 获取当前Cesium自动调度渲染的瓦片集合 */
-			let tilesToRender = _self._viewer.scene.globe._surface._tilesToRender;
-			/* 存在渲染瓦片则进行处理转换 */
-			if (tilesToRender.length !== undefined && tilesToRender.length > 0) {
-				let renderTiles = [];
-				for (let i = 0; i < tilesToRender.length; i++) {
-					let renderTile = tilesToRender[i];
-					let tile = {
-						x: renderTile.x,
-						y: renderTile.y,
-						level: renderTile.level,
-						rectangle: renderTile._rectangle,
-					}
-					renderTiles.push(tile);
-				}
-				resolve(renderTiles);
-			}
-		});
-		/* 异步 */
-		promise.then(renderTiles => {
-			_self._calculateRenderTiles(renderTiles);
-		}).catch(err => {
-			_self._console(err);
-		}).finally(() => {
-			// _self._console('执行结束');
-		});
+		/* 获取当前视图渲染的瓦片集合 */
+		let tilesToRender = this._viewer.scene.globe._surface._tilesToRender;
+		if (tilesToRender === undefined || tilesToRender.length === 0) {
+			this._isUpdateTile = true;
+			return;
+		} else {
+			new Promise((resolve, reject) => {
+				/* 对瓦片数组按照level进行排序 以保证后续瓦片重投影时的重叠移除无误 */
+				tilesToRender.sort(function(obj1, obj2) {
+					let level1 = parseInt(obj1.level);
+					let level2 = parseInt(obj2.level);
+					return level1 - level2;
+				})
+				/* 返回排序后的渲染瓦片数据集 开始异步计算 */
+				resolve(tilesToRender);
+			}).then(tiles => {
+				/* Cesium渲染瓦片为84投影,如果不一致需要异步重投影瓦片数据集 */
+				_self._asyncProjectionTiles(tiles);
+			})
+		}
 	}
 
 	/**
-	 * 投影当前瓦片
-	 * @param {Object} tile
+	 * 根据行列和等级生成key
+	 * @param {Number} x 行
+	 * @param {Number} y 列
+	 * @param {Number} level 等级
 	 */
-	_projectionTile(tile) {
-		/* 获取矩形 */
-		let rectangle = tile.rectangle;
-		let imageryLevel = tile.level;
-		let mercatorTilingScheme = this._provider.tilingScheme;
-		let res = [];
-		let resLeftTop = undefined;
-		let resRightBottom = undefined;
-		/* 判断北西角点的墨卡托投影瓦片信息 */
-		let northwestTileCoordinates = mercatorTilingScheme.positionToTileXY(
-			Cesium.Rectangle.northwest(rectangle),
-			imageryLevel
-		);
-		if (northwestTileCoordinates !== undefined) {
-			let _webRectangle = mercatorTilingScheme.tileXYToRectangle(northwestTileCoordinates.x,
-				northwestTileCoordinates.y,
-				imageryLevel);
-			resLeftTop = {
-				x: northwestTileCoordinates.x,
-				y: northwestTileCoordinates.y,
-				level: imageryLevel,
-				rectangle: _webRectangle,
-			}
-		}
-		/* 判断南东角点的墨卡托投影瓦片信息 */
-		let southeastTileCoordinates = mercatorTilingScheme.positionToTileXY(
-			Cesium.Rectangle.southeast(rectangle),
-			imageryLevel
-		);
-		if (southeastTileCoordinates !== undefined) {
-			let _webRectangle = mercatorTilingScheme.tileXYToRectangle(southeastTileCoordinates.x,
-				southeastTileCoordinates.y,
-				imageryLevel);
-			resRightBottom = {
-				x: southeastTileCoordinates.x,
-				y: southeastTileCoordinates.y,
-				level: imageryLevel,
-				rectangle: _webRectangle,
-			}
-		}
-		if (resLeftTop !== undefined && resRightBottom !== undefined) {
-			if (resLeftTop.x === resRightBottom.x && resLeftTop.y === resRightBottom.y) {
-				res.push(resLeftTop);
-			} else {
-				res.push(resLeftTop);
-				res.push(resRightBottom);
-			}
-		} else if (resLeftTop !== undefined && resRightBottom === undefined) {
-			res.push(resLeftTop);
-		} else if (resLeftTop === undefined && resRightBottom !== undefined) {
-			res.push(resRightBottom);
-		}
-		return res;
+	_createKey(x, y, level) {
+		let key = `${this._renderName}_${x}_${y}_${level}`;
+		return key;
 	}
 
 	/**
-	 * 计算渲染的瓦片集合
-	 * @param {JSON} renderTiles 渲染的瓦片集合
+	 * 投影瓦片集合
+	 * @param {Object} tiles 原始渲染瓦片集合
 	 */
-	_calculateRenderTiles(renderTiles) {
-		this._updateTiles = [];
-		let _self = this;
-		for (let i = 0; i < renderTiles.length; i++) {
-			let renderTile = renderTiles[i];
-			/* 计算重投影后的Tiles */
-			let tiles = this._projectionTile(renderTile);
-			for (let tile of tiles) {
-				let key = tile.x + '_' + tile.y + '_' + tile.level;
-				let subTile = this._updateTiles.find(obj => {
-					return obj.x === tile.x && obj.y === tile.y;
+	_asyncProjectionTiles(tiles) {
+		let renderTiles = [];
+		/* 循环投影 */
+		for (let tile of tiles) {
+			/* 对单个瓦片进行重投影 */
+			let proTiles = this._projectionTile(tile);
+			for (let proTile of proTiles) {
+				/* 瓦片实体唯一标识 */
+				let key = this._createKey(proTile.x, proTile.y, proTile.level);
+				/* 查找瓦片是否已经存在 存在则过滤 以免重复存在 */
+				let subTile = renderTiles.find(obj => {
+					return obj.x === proTile.x && obj.y === proTile.y;
 				})
 				if (subTile === undefined) {
-					this._updateTiles.push({
-						key: key,
-						x: tile.x,
-						y: tile.y,
-						level: tile.level,
-						rectangle: tile.rectangle,
-					});
+					/* 重投影瓦片范围与数据范围的叠合计算 */
+					let isExists = false;
+					for (let eTile of renderTiles) {
+						if (Cesium.Rectangle.intersection(eTile.rectangle, proTile.rectangle)) {
+							/* 追加子集 方便后期进行层级处理 */
+							eTile.childTiles.push(key);
+							isExists = true;
+							break;
+						}
+					}
+					/* 加入渲染集合 */
+					if (!isExists) {
+						renderTiles.push({
+							key: key,
+							x: proTile.x,
+							y: proTile.y,
+							level: proTile.level,
+							rectangle: proTile.rectangle,
+							childTiles: [],
+						});
+					}
 				}
 			}
 		}
-		/* 判断是否有需要渲染的瓦片 有则渲染 */
-		if (this._updateTiles.length > 0) {
-			this._renderTiles();
-		} else {
-			this._isUpdateTile = true;
+		/* 清理低层级元素 */
+		let i = renderTiles.length;
+		let appendTiles = [];
+		while (i--) {
+			let findTile = renderTiles[i];
+			if (findTile.childTiles.length >= 1) {
+				/* 创建高层级的瓦片 */
+				let tiles = this._createFourTiles(findTile);
+				for (let tile of tiles) {
+					appendTiles.push(tile);
+				}
+				/* 如果存在高层级 则删除低层级 */
+				renderTiles.splice(i, 1);
+			}
+		}
+		/* 将四叉树追加的层级数据加入到渲染集合中 */
+		for (let appendTile of appendTiles) {
+			renderTiles.push(appendTile);
 		}
+		/* 对数组进行排序 */
+		renderTiles.sort(function(obj1, obj2) {
+			let level1 = parseInt(obj1.level);
+			let level2 = parseInt(obj2.level);
+			return level1 - level2;
+		})
+		/* 渲染数据到视图中 */
+		this._renderTilesToViewer(renderTiles);
 	}
 
 	/**
-	 * 渲染瓦片集
+	 * 根据矩形和登记查询高一等级的行列号
+	 * @param {Cesium.Rectangle} rectangle 
 	 */
-	_renderTiles() {
-		this._console(this._updateTiles);
-		// this._removeEntityByName('AAA');
-		// this._renderTileToVierer(0);
-		this._isUpdateTile = true;
+	_createTileByRectangleAndLevel(rectangle, level) {
+		/* 获取矩形中心点 */
+		let center = Cesium.Rectangle.center(rectangle);
+		/* 新层级 */
+		let nLevel = parseInt(level) + 1;
+		/* 查询高一层级的行列号 */
+		let query = this._provider.tilingScheme.positionToTileXY(center, nLevel);
+		if (query === undefined) return undefined;
+		/* 返回结果 */
+		return {
+			key: this._createKey(query.x, query.y, nLevel),
+			x: query.x,
+			y: query.y,
+			level: nLevel,
+			rectangle: rectangle,
+			childTiles: [],
+		}
 	}
 
 	/**
-	 * 渲染瓦片到地图上
-	 * @param {Number} index
+	 * 创建四个高层级的瓦片
+	 * @param {Object} tile 当前瓦片
 	 */
-	_renderTileToVierer(index) {
-		let _self = this;
-		if (index === this._updateTiles.length - 1) {
-			this._isUpdateTile = true;
-			return;
+	_createFourTiles(tile) {
+		let rects = [];
+		let results = [];
+		let rectangle = tile.rectangle;
+		/* 将该矩形按照四叉树规则分割为4个高层级的矩形 */
+		rects.push(Cesium.Rectangle.subsection(rectangle, 0, 0, 0.5, 0.5));
+		rects.push(Cesium.Rectangle.subsection(rectangle, 0.5, 0, 1.0, 0.5));
+		rects.push(Cesium.Rectangle.subsection(rectangle, 0, 0.5, 0.5, 1.0));
+		rects.push(Cesium.Rectangle.subsection(rectangle, 0.5, 0.5, 1.0, 1.0));
+		for (let rect of rects) {
+			/* 判断高层级的矩形是否与谁范围存在交集 */
+			if (Cesium.Rectangle.intersection(rect, this._rectangle)) {
+				/* 查询高一层级的Tile */
+				let newTile = this._createTileByRectangleAndLevel(rect, tile.level);
+				/* 如果存在加入到返回集合中 */
+				if (newTile !== undefined) results.push(newTile);
+			}
 		}
-		try {
-			let tile = this._updateTiles[index];
-			let x = tile.x;
-			let y = tile.y;
-			let level = tile.level;
-			const canvas = document.createElement("canvas");
-			canvas.width = 256;
-			canvas.height = 256;
-			const context = canvas.getContext("2d");
-			context.strokeStyle = 'rgba(255,255,0)';
-			context.lineWidth = 2;
-			context.strokeRect(1, 1, 255, 255);
+		return results;
+	}
 
-			context.font = "bold 25px Arial";
-			context.textAlign = "center";
-			context.fillStyle = 'rgba(255,0,0)';
-			context.fillText(`L: ${level}`, 124, 86);
-			context.fillText(`X: ${x}`, 124, 136);
-			context.fillText(`Y: ${y}`, 124, 186);
-			let bjPositions = this._calculateRectangleOutlineCoordinates(tile
-				.rectangle);
-			let tileEntity = new Cesium.Entity({
-				name: 'AAA',
-				id: tile.key,
-				rectangle: {
-					coordinates: tile.rectangle,
-					material: canvas, //Cesium.Color.RED.withAlpha(0.9),
-				},
-				polyline: {
-					positions: bjPositions,
-					material: Cesium.Color.YELLOW,
-					width: 2,
-					clampToGround: true, //开启贴地 如果有模型则贴模型
-				}
-			});
-			this._entities.add(tileEntity);
-			let worker = new Worker('public/js/worker_download.js');
-			worker.onmessage = function(event) {
-				/* 重置渲染 */
-				let entity = _self._entities.getById(event.data.key);
-				const canvas = document.createElement("canvas");
-				canvas.width = 256;
-				canvas.height = 256;
-				let context = canvas.getContext('2d');
-				context.drawImage(event.data.image, 0, 0, 256, 256);
-				entity.rectangle.material = canvas;
+	/**
+	 * 渲染瓦片到视图中
+	 * @param {Object} tiles
+	 */
+	_renderTilesToViewer(tiles) {
+		let _self = this;
+		/* 确定哪些渲染实体已失效 对失效的实体进行清理 */
+		let deleteKeys = [];
+		for (let [key, tile] of this._renderEntities) {
+			let findTile = tiles.find(obj => {
+				return obj.key === key;
+			})
+			if (findTile === undefined) {
+				deleteKeys.push(key);
 			}
-			worker.postMessage({
-				key: tile.key,
-				x: tile.x,
-				y: tile.y,
-				level: tile.level,
-				url: _self._url,
-			});
-			this._renderTileToVierer(index + 1);
-		} catch (e) {
-			this._console(e.message);
-			this._renderTileToVierer(index + 1);
 		}
+		for (let key of deleteKeys) {
+			// /* 移除元素 */
+			this._renderEntities.delete(key);
+			// /* 移除渲染元素 */
+			this._entities.removeById(key);
+		}
+		/* 对过滤后的数据集进行渲染 */
+		for (let tile of tiles) {
+			/* 判断当前渲染的数据是否已经渲染且有效 */
+			if (!this._renderEntities.has(tile.key)) {
+				/* 将数据渲染到视图中 */
+				let entity = this._renderSimpleTileToViewer(tile);
+				this._renderEntities.set(tile.key, entity);
+				/* 初始化y */
+				let tile_y = tile.y;
+				/* 利用数据提供器获取图片 */
+				this._provider.requestImage(tile.x, tile_y, tile.level).then(function(image) {
+					/* 判断是否返回图片资源 */
+					if (image !== undefined) {
+						_self._console('渲染图片', image);
+						/* 对图片资源进行Y轴翻转 */
+						let primise = createImageBitmap(image, {
+							imageOrientation: 'flipY',
+						});
+						primise.then(function(resImage) {
+							let renderEntity = _self._entities.getById(tile.key);
+							if (renderEntity !== undefined) {
+								const canvas = _self._createCanvas(tile, resImage, _self._isDebug);
+								renderEntity.rectangle.material = canvas;
+							}
+							// _self._renderImagebitmaps.set(tile.key, resImage);
+							/* 释放图片资源 */
+							image.close();
+						})
+					}
+				});
+			}
+		}
+		/* 重启计算标志 */
+		this._isUpdateTile = true;
 	}
 
 	/**
-	 * 竖向翻转
-	 * @param {Array[]} sourceData 
+	 * 渲染单个瓦片到视图中
+	 * @param {Object} tile
 	 */
-	_imageDataVRevert(sourceData) {
-		let newData = {
-			width: sourceData.width,
-			height: sourceData.height,
-			data: new Uint8ClampedArray(sourceData.data.length)
-		}
-		for (var i = 0, h = sourceData.height; i < h; i++) {
-			for (var j = 0, w = sourceData.width; j < w; j++) {
-				newData.data[i * w * 4 + j * 4 + 0] =
-					sourceData.data[(h - i) * w * 4 + j * 4 + 0];
-				newData.data[i * w * 4 + j * 4 + 1] =
-					sourceData.data[(h - i) * w * 4 + j * 4 + 1];
-				newData.data[i * w * 4 + j * 4 + 2] =
-					sourceData.data[(h - i) * w * 4 + j * 4 + 2];
-				newData.data[i * w * 4 + j * 4 + 3] =
-					sourceData.data[(h - i) * w * 4 + j * 4 + 3] - 100;
+	_renderSimpleTileToViewer(tile) {
+		/* 创建画布 */
+		const canvas = this._createCanvas(tile, undefined, this._isDebug);
+		let bjPositions = this._calculateRectangleOutlineCoordinates(tile
+			.rectangle);
+		let tileEntity = new Cesium.Entity({
+			name: this._renderName,
+			id: tile.key,
+			rectangle: {
+				coordinates: tile.rectangle,
+				material: canvas,
+			},
+			polyline: {
+				positions: bjPositions,
+				material: Cesium.Color.YELLOW.withAlpha(this._isDebug ? 1 : 0),
+				width: 1,
+				clampToGround: true, //开启贴地 如果有模型则贴模型
 			}
+		});
+		return this._entities.add(tileEntity);
+	}
+
+	/**
+	 * 根据瓦片创建画布
+	 * @param {Object} tile 瓦片
+	 * @param {Object} image 绘制的图片
+	 * @param {boolean} islabel 是否绘制标签 
+	 */
+	_createCanvas(tile, image, islabel) {
+		/* 获取服务提供者的切片方案 */
+		let provider = this._provider;
+		const canvas = document.createElement("canvas");
+		canvas.width = provider.tileWidth;
+		canvas.height = provider.tileHeight;
+		const context = canvas.getContext("2d");
+		if (image !== undefined) {
+			context.globalAlpha = this._opacity;
+			context.drawImage(image, 0, 0, canvas.width, canvas.height);
+		}
+		if (islabel !== undefined && islabel === true) {
+			context.globalAlpha = 1.0;
+			/* 创建标签 */
+			context.font = "20px Arial";
+			context.textAlign = "center";
+			context.fillStyle = 'rgba(255,255,0)';
+			context.strokeStyle = 'rgba(255,255,255,1)';
+			context.lineWidth = 2;
+			context.strokeText(`L: ${tile.level}`, 126, 86);
+			context.fillText(`L: ${tile.level}`, 126, 86);
+			context.strokeText(`X: ${tile.x}`, 126, 136);
+			context.fillText(`X: ${tile.x}`, 126, 136);
+			context.strokeText(`Y: ${tile.y}`, 126, 186);
+			context.fillText(`Y: ${tile.y}`, 126, 186);
 		}
-		return newData;
+		/* 返回画布 */
+		return canvas;
 	}
 
 	/**
-	 * 横向翻转
-	 * @param {Array[]} sourceData 
-	 * @param {Array[]} newData
+	 * 投影当前瓦片
+	 * @param {Object} tile
 	 */
-	_imageDataHRevert(sourceData, newData) {
-		for (var i = 0, h = sourceData.height; i < h; i++) {
-			for (j = 0, w = sourceData.width; j < w; j++) {
-				newData.data[i * w * 4 + j * 4 + 0] =
-					sourceData.data[i * w * 4 + (w - j) * 4 + 0];
-				newData.data[i * w * 4 + j * 4 + 1] =
-					sourceData.data[i * w * 4 + (w - j) * 4 + 1];
-				newData.data[i * w * 4 + j * 4 + 2] =
-					sourceData.data[i * w * 4 + (w - j) * 4 + 2];
-				newData.data[i * w * 4 + j * 4 + 3] =
-					sourceData.data[i * w * 4 + (w - j) * 4 + 3];
+	_projectionTile(tile) {
+		if (this._tilingScheme instanceof Cesium.GeographicTilingScheme) {
+			return [{
+				x: tile.x,
+				y: tile.y,
+				level: tile.level,
+				rectangle: tile._rectangle,
+			}];
+		}
+		/* 获取矩形 */
+		let rectangle = tile._rectangle;
+		// let imageryLevel = parseInt(tile.level) + 1;
+		let imageryLevel = parseInt(tile.level);
+		let mercatorTilingScheme = this._provider.tilingScheme;
+		let res = [];
+		/* 先判断当前的切片范围是否与提供者的数据范围有交集 */
+		let interRectangle = Cesium.Rectangle.intersection(rectangle, this._rectangle);
+		/* 如果当前计算的瓦片与数据范围无交集 则舍弃 */
+		if (interRectangle === undefined) return res;
+		/* 判断北西角点的墨卡托投影瓦片信息 */
+		let northwestTileCoordinates = mercatorTilingScheme.positionToTileXY(
+			Cesium.Rectangle.northwest(rectangle),
+			imageryLevel
+		);
+		/* 判断南东角点的墨卡托投影瓦片信息 */
+		let southeastTileCoordinates = mercatorTilingScheme.positionToTileXY(
+			Cesium.Rectangle.southeast(rectangle),
+			imageryLevel
+		);
+		/* 根据不同类型分别进行计算 */
+		if (northwestTileCoordinates !== undefined && southeastTileCoordinates !== undefined) {
+			for (let i = northwestTileCoordinates.x; i <= southeastTileCoordinates.x; i++) {
+				for (let j = northwestTileCoordinates.y; j <= southeastTileCoordinates.y; j++) {
+					let _webRectangle = mercatorTilingScheme.tileXYToRectangle(i, j, imageryLevel);
+					if (Cesium.Rectangle.intersection(_webRectangle, this._rectangle)) {
+						res.push({
+							x: i,
+							y: j,
+							level: imageryLevel,
+							rectangle: _webRectangle,
+						});
+					}
+				}
+			}
+		} else if (northwestTileCoordinates !== undefined) {
+			let _webRectangle = mercatorTilingScheme.tileXYToRectangle(northwestTileCoordinates.x,
+				northwestTileCoordinates.y,
+				imageryLevel);
+			if (Cesium.Rectangle.intersection(_webRectangle, this._rectangle)) {
+				res.push({
+					x: northwestTileCoordinates.x,
+					y: northwestTileCoordinates.y,
+					level: imageryLevel,
+					rectangle: _webRectangle,
+				});
+			}
+		} else if (southeastTileCoordinates !== undefined) {
+			let _webRectangle = mercatorTilingScheme.tileXYToRectangle(southeastTileCoordinates.x,
+				southeastTileCoordinates.y,
+				imageryLevel);
+			if (Cesium.Rectangle.intersection(_webRectangle, this._rectangle)) {
+				res.push({
+					x: southeastTileCoordinates.x,
+					y: southeastTileCoordinates.y,
+					level: imageryLevel,
+					rectangle: _webRectangle,
+				});
 			}
 		}
-		return newData;
+		return res;
 	}
 
 	/**
@@ -371,7 +570,7 @@ class CrImageServerLayer {
 	 */
 	_removeEntityByName(entityName) {
 		/* 获取实体集合 */
-		var entities = this._viewer.entities;
+		var entities = this._entities;
 		/* 如果不存在实体集合或集合中没有数据 则返回 */
 		if (!entities || !entities.values) return;
 		var delEntitys = [];
@@ -388,5 +587,61 @@ class CrImageServerLayer {
 	}
 }
 
+/* 对外方法 */
+Object.assign(CrImageServerLayer.prototype, {
+	/**
+	 * 隐藏
+	 */
+	hide: function() {
+		this._console('隐藏');
+		this._isUpdateTile = false;
+		/* 清理资源 */
+		this._removeEntityByName(this._renderName);
+		/* 清理渲染 */
+		this._renderEntities.clear();
+	},
+
+	/**
+	 * 显示
+	 */
+	show: function() {
+		this._console('显示');
+		this._isUpdateTile = true;
+	},
+
+	/**
+	 * 设置透明度
+	 * @param {Number} opacity [0-1]
+	 */
+	setOpacity: function(opacity) {
+		if (opacity === undefined || typeof opacity !== 'number') return;
+		if (opacity >= 1) this._opacity = 1.0;
+		if (opacity <= 0) this._opacity = 0.0;
+		this._opacity = parseFloat(opacity);
+	}
+
+})
+
+/**
+ * 数据提供器类型
+ */
+CrImageServerLayer.ProviderType = Object.freeze({
+	ArcGisMapServerImageryProvider: 'ArcGisMapServerImageryProvider',
+	BingMapsImageryProvider: 'BingMapsImageryProvider',
+	OpenStreetMapImageryProvider: 'OpenStreetMapImageryProvider',
+	TileMapServiceImageryProvider: 'TileMapServiceImageryProvider',
+	GoogleEarthEnterpriseImageryProvider: 'GoogleEarthEnterpriseImageryProvider',
+	GoogleEarthEnterpriseMapsProvider: 'GoogleEarthEnterpriseMapsProvider',
+	GridImageryProvider: 'GridImageryProvider',
+	IonImageryProvider: 'IonImageryProvider',
+	MapboxImageryProvider: 'MapboxImageryProvider',
+	MapboxStyleImageryProvider: 'MapboxStyleImageryProvider',
+	SingleTileImageryProvider: 'SingleTileImageryProvider',
+	TileCoordinatesImageryProvider: 'TileCoordinatesImageryProvider',
+	UrlTemplateImageryProvider: 'UrlTemplateImageryProvider',
+	WebMapServiceImageryProvider: 'WebMapServiceImageryProvider',
+	WebMapTileServiceImageryProvider: 'WebMapTileServiceImageryProvider',
+})
+
 /* 输出类 */
 export default CrImageServerLayer

+ 875 - 0
src/components/CrMap/CrImageServerLayer_back01.js

@@ -0,0 +1,875 @@
+/**
+ * 创建者:王成
+ * 操作系统:MAC
+ * 创建日期:2023年1月30日
+ * 描述:通过矩形渲染tile,从而达到渲染图片可以浮动在实景三维上面的效果
+ */
+
+/* 扩展系统Date属性Format 用于格式化日期 yyMMdd HH:ss:mm */
+Date.prototype.Format = function(fmt) { // author: meizz 
+	var o = {
+		"M+": this.getMonth() + 1, // 月份 
+		"d+": this.getDate(), // 日 
+		"h+": this.getHours(), // 小时 
+		"m+": this.getMinutes(), // 分 
+		"s+": this.getSeconds(), // 秒 
+		"q+": Math.floor((this.getMonth() + 3) / 3), // 季度 
+		"S": this.getMilliseconds() // 毫秒 
+	};
+	if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
+	for (var k in o)
+		if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : ((
+			"00" + o[k]).substr(("" + o[k]).length)));
+	return fmt;
+}
+
+/* 引入Cesium */
+import * as Cesium from 'cesium';
+
+/* 创建类 */
+class CrImageServerLayer {
+	/**
+	 * 构造函数
+	 * @param {Cesium.Viewer} options.viewer 地图视图容器
+	 * @param {CrImageServerLayer.ProviderType} options.providerType 数据提供器类型
+	 * @param {JSON} options.config 对应该提供器的配置参数
+	 * @param {Number} options.opacity 图层透明度[0.0~1.0] [默认0.3]    
+	 */
+	constructor({
+		viewer,
+		providerType = CrImageServerLayer.ArcGisMapServerImageryProvider,
+		config = {},
+		opacity = 0.75,
+		show = true,
+	} = {}) {
+		let _self = this;
+		/* 地图视图 外部传入 必须参数 */
+		this._viewer = viewer;
+		/* 服务提供者配置参数 */
+		this._providerType = providerType;
+		/* 服务提供者 */
+		this._provider = undefined;
+		/* 服务提供者切片方案 */
+		this._tilingScheme = undefined;
+		/* 服务的切片的最大/最小层级 */
+		this._maximumLevel = 0;
+		this._minimumLevel = 20;
+		/* 切片大小 */
+		this._tileWidth = 0;
+		this._tileHeight = 0;
+		/* 服务数据范围 */
+		this._rectangle = undefined;
+		/* 服务提供者的配置参数 */
+		this._config = config;
+		/* 透明度 外部传入 */
+		this._opacity = opacity;
+		/* 图层随机标识 */
+		this._renderName = this._guid();
+		/* 实体集合 */
+		/* 用DataSource 方式 以便进行多图层管理 */
+		let dataSource = new Cesium.CustomDataSource(this._renderName);
+		this._viewer.dataSources.add(dataSource);
+		this._entities = dataSource.entities;
+		/* 渲染集合 */
+		this._renderEntities = new Map();
+		this._renderImagebitmaps = new Map();
+		/* 移除渲染集合 */
+		this._removeEntities = new Map();
+		/* 是否渲染标志 */
+		this._isUpdateTile = show;
+		/* 是否输出测试信息 */
+		this._isDebug = true;
+		/* 创建一个线程 用于处理移除任务 */
+		this._sendTask = true;
+		/* 本轮新渲染的实体集合 */
+		this._renderNewEntities = [];
+		let workerBlob = new Blob([`(${downloadWorker.toString ()})()`]); // 把函数转成一个自执行函数
+		this._worker = new Worker(URL.createObjectURL(workerBlob));
+		/* 接收反馈 */
+		this._worker.onmessage = function(event) {
+			if (event.data.length > 0) {
+				_self._console(event.data);
+			}
+			for (let key of event.data) {
+				_self._entities.removeById(key);
+				_self._removeEntities.delete(key);
+			}
+			this._sendTask = true;
+		}
+		/* 初始化 */
+		this._init();
+	}
+
+	/**
+	 * 初始化
+	 */
+	_init() {
+		let _self = this;
+		/* 创建服务提供者 */
+		switch (this._providerType) {
+			case CrImageServerLayer.ProviderType.ArcGisMapServerImageryProvider:
+				this._provider = new Cesium.ArcGisMapServerImageryProvider(this._config);
+				break;
+			case CrImageServerLayer.ProviderType.UrlTemplateImageryProvider:
+				this._provider = new Cesium.UrlTemplateImageryProvider(this._config);
+				break;
+		}
+		/* 服务提供者判断 */
+		if (this._provider === undefined) {
+			this._console('没有服务提供者,无法初始化!');
+			return;
+		}
+		/* 激活服务提供者 注册刷帧事件 */
+		this._provider.readyPromise.then(function(result) {
+			/* 初始化参数 */
+			_self._rectangle = _self._provider.rectangle;
+			_self._tilingScheme = _self._provider.tilingScheme;
+			_self._maximumLevel = _self._provider.maximumLevel === undefined ? 22 : _self._provider
+				.maximumLevel;
+			_self._minimumLevel = _self._provider.minimumLevel === undefined ? 0 : _self._provider
+				.minimumLevel;
+			_self._tileWidth = _self._provider.tileWidth;
+			_self._tileHeight = _self._provider.tileHeight;
+			/* 输出调试信息 */
+			if (_self._isDebug) _self._printDebug();
+			/* 注册事件 */
+			_self._viewer.scene.postRender.addEventListener(() => {
+				if (_self._isUpdateTile) {
+					/* 设置运行标志为false 等待计算完成 */
+					_self._isUpdateTile = false;
+					/* 投影瓦片集合 */
+					_self._renderTiles();
+				}
+			});
+		})
+	}
+
+	/**
+	 * 生成GUID随机数
+	 */
+	_guid() {
+		function S4() {
+			return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
+		}
+		return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
+	}
+
+	/**
+	 * 输出调试信息
+	 */
+	_printDebug() {
+		/* 数据提供者的切片方案 */
+		let tiling = this._provider.tilingScheme;
+		/* WGS84坐标系的切片方案 */
+		let tiling84 = new Cesium.GeographicTilingScheme();
+		/* 绘制数据提供者的数据范围 */
+		this._drawDebugRectangle(this._rectangle, Cesium.Color.GREEN);
+		/* 根据行列号和等级创建调试矩形 */
+		let rect = tiling84.tileXYToRectangle(1696, 312, 10);
+	}
+
+	/**
+	 * 绘制调试矩形
+	 * @param {Cesium.Rectangle} rectangle 绘制的矩形
+	 * @param {Cesium.Color} color 矩形边框颜色
+	 */
+	_drawDebugRectangle(rectangle, color) {
+		/* 计算矩形的外包范围 */
+		let positions = this._calculateRectangleOutlineCoordinates(rectangle);
+		/* 创建矩形实体 */
+		let rectEntity = new Cesium.Entity({
+			name: this._renderName,
+			polyline: {
+				positions: positions,
+				material: color,
+				width: 10,
+				clampToGround: true, //开启贴地 如果有模型则贴模型
+			}
+		});
+		/* 加入数据集 */
+		this._entities.add(rectEntity);
+	}
+
+	/**
+	 * 输出消息
+	 * @param {Object} res
+	 */
+	_console(...rest) {
+		if (this._isDebug)
+			console.log('===' + new Date().Format('yyyy-MM-dd HH:mm:ss') + '>>>', rest);
+	}
+
+	/**
+	 * 渲染瓦片集合
+	 */
+	_renderTiles() {
+		let _self = this;
+		/* 获取当前视图渲染的瓦片集合 */
+		let tilesToRender = this._viewer.scene.globe._surface._tilesToRender;
+		if (tilesToRender === undefined || tilesToRender.length === 0) {
+			this._isUpdateTile = true;
+			return;
+		} else {
+			new Promise((resolve, reject) => {
+				/* 对瓦片数组按照level进行排序 以保证后续瓦片重投影时的重叠移除无误 */
+				tilesToRender.sort(function(obj1, obj2) {
+					let level1 = parseInt(obj1.level);
+					let level2 = parseInt(obj2.level);
+					return level1 - level2;
+				})
+				/* 返回排序后的渲染瓦片数据集 开始异步计算 */
+				resolve(tilesToRender);
+			}).then(tiles => {
+				/* Cesium渲染瓦片为84投影,如果不一致需要异步重投影瓦片数据集 */
+				_self._asyncProjectionTiles(tiles);
+			})
+		}
+	}
+
+	/**
+	 * 根据行列和等级生成key
+	 * @param {Number} x 行
+	 * @param {Number} y 列
+	 * @param {Number} level 等级
+	 */
+	_createKey(x, y, level) {
+		let key = `${this._renderName}_${x}_${y}_${level}`;
+		return key;
+	}
+
+	/**
+	 * 投影瓦片集合
+	 * @param {Object} tiles 原始渲染瓦片集合
+	 */
+	_asyncProjectionTiles(tiles) {
+		let renderTiles = [];
+		/* 循环投影 */
+		for (let tile of tiles) {
+			/* 对单个瓦片进行重投影 */
+			let proTiles = this._projectionTile(tile);
+			for (let proTile of proTiles) {
+				/* 瓦片实体唯一标识 */
+				let key = this._createKey(proTile.x, proTile.y, proTile.level);
+				/* 查找瓦片是否已经存在 存在则过滤 以免重复存在 */
+				let subTile = renderTiles.find(obj => {
+					return obj.x === proTile.x && obj.y === proTile.y;
+				})
+				if (subTile === undefined) {
+					/* 重投影瓦片范围与数据范围的叠合计算 */
+					let isExists = false;
+					for (let eTile of renderTiles) {
+						if (Cesium.Rectangle.intersection(eTile.rectangle, proTile.rectangle)) {
+							/* 追加子集 方便后期进行层级处理 */
+							eTile.childTiles.push(key);
+							isExists = true;
+							break;
+						}
+					}
+					/* 加入渲染集合 */
+					if (!isExists) {
+						renderTiles.push({
+							key: key,
+							x: proTile.x,
+							y: proTile.y,
+							level: proTile.level,
+							rectangle: proTile.rectangle,
+							childTiles: [],
+						});
+					}
+				}
+			}
+		}
+		/* 清理低层级元素 */
+		let i = renderTiles.length;
+		let appendTiles = [];
+		while (i--) {
+			let findTile = renderTiles[i];
+			if (findTile.childTiles.length >= 1) {
+				/* 创建高层级的瓦片 */
+				let tiles = this._createFourTiles(findTile);
+				for (let tile of tiles) {
+					appendTiles.push(tile);
+				}
+				/* 如果存在高层级 则删除低层级 */
+				renderTiles.splice(i, 1);
+			}
+		}
+		/* 将四叉树追加的层级数据加入到渲染集合中 */
+		for (let appendTile of appendTiles) {
+			renderTiles.push(appendTile);
+		}
+		/* 对数组进行排序 */
+		renderTiles.sort(function(obj1, obj2) {
+			let level1 = parseInt(obj1.level);
+			let level2 = parseInt(obj2.level);
+			return level1 - level2;
+		})
+		/* 渲染数据到视图中 */
+		this._renderTilesToViewer(renderTiles);
+	}
+
+	/**
+	 * 根据矩形和登记查询高一等级的行列号
+	 * @param {Cesium.Rectangle} rectangle 
+	 */
+	_createTileByRectangleAndLevel(rectangle, level) {
+		/* 获取矩形中心点 */
+		let center = Cesium.Rectangle.center(rectangle);
+		/* 新层级 */
+		let nLevel = parseInt(level) + 1;
+		/* 查询高一层级的行列号 */
+		let query = this._provider.tilingScheme.positionToTileXY(center, nLevel);
+		if (query === undefined) return undefined;
+		/* 返回结果 */
+		return {
+			key: this._createKey(query.x, query.y, nLevel),
+			x: query.x,
+			y: query.y,
+			level: nLevel,
+			rectangle: rectangle,
+			childTiles: [],
+		}
+	}
+
+	/**
+	 * 创建四个高层级的瓦片
+	 * @param {Object} tile 当前瓦片
+	 */
+	_createFourTiles(tile) {
+		let rects = [];
+		let results = [];
+		let rectangle = tile.rectangle;
+		/* 将该矩形按照四叉树规则分割为4个高层级的矩形 */
+		rects.push(Cesium.Rectangle.subsection(rectangle, 0, 0, 0.5, 0.5));
+		rects.push(Cesium.Rectangle.subsection(rectangle, 0.5, 0, 1.0, 0.5));
+		rects.push(Cesium.Rectangle.subsection(rectangle, 0, 0.5, 0.5, 1.0));
+		rects.push(Cesium.Rectangle.subsection(rectangle, 0.5, 0.5, 1.0, 1.0));
+		for (let rect of rects) {
+			/* 判断高层级的矩形是否与谁范围存在交集 */
+			if (Cesium.Rectangle.intersection(rect, this._rectangle)) {
+				/* 查询高一层级的Tile */
+				let newTile = this._createTileByRectangleAndLevel(rect, tile.level);
+				/* 如果存在加入到返回集合中 */
+				if (newTile !== undefined) results.push(newTile);
+			}
+		}
+		return results;
+	}
+
+	/**
+	 * 渲染瓦片到视图中
+	 * @param {Object} tiles
+	 */
+	_renderTilesToViewer(tiles) {
+		let _self = this;
+		/* 确定哪些渲染实体已失效 对失效的实体进行清理 */
+		let deleteKeys = [];
+		for (let [key, tile] of this._renderEntities) {
+			let findTile = tiles.find(obj => {
+				return obj.key === key;
+			})
+			if (findTile === undefined) {
+				deleteKeys.push(key);
+			}
+		}
+		for (let key of deleteKeys) {
+			/* 移除元素 */
+			this._renderEntities.delete(key);
+			/* 移除渲染元素 */
+			// this._entities.removeById(key);
+			/* 追加 */
+			if (!this._removeEntities.has(key)) {
+				this._removeEntities.set(key, key);
+			}
+		}
+		/* 对过滤后的数据集进行渲染 */
+		for (let tile of tiles) {
+			/* 判断当前渲染的数据是否已经渲染且有效 */
+			if (!this._renderEntities.has(tile.key) && !this._entities.getById(tile.key)) {
+				/* 将数据渲染到视图中 */
+				let entity = this._renderSimpleTileToViewer(tile);
+				this._renderEntities.set(tile.key, entity);
+				/* 追加本轮新渲染的实体到集合中 */
+				this._renderEntities.push(entity);
+				/* 初始化y */
+				let tile_y = tile.y;
+				/* 利用数据提供器获取图片 */
+				this._provider.requestImage(tile.x, tile_y, tile.level).then(function(image) {
+					/* 判断是否返回图片资源 */
+					if (image !== undefined) {
+						/* 对图片资源进行Y轴翻转 */
+						let primise = createImageBitmap(image, {
+							imageOrientation: 'flipY',
+						});
+						primise.then(function(resImage) {
+							let renderEntity = _self._entities.getById(tile.key);
+							if (renderEntity !== undefined) {
+								const canvas = _self._createCanvas(tile, resImage, _self._isDebug);
+								renderEntity.rectangle.material = canvas;
+							}
+							/* 释放图片资源 */
+							image.close();
+						})
+					}
+				});
+			}
+		}
+		if (this._sendTask) {
+			/* 当前渲染的实体 */
+			let renderEntities = [];
+			for (let entity of this._renderEntities) {
+				let queryEntity = this._entities.getById(entity.id);
+				renderEntities.push({
+					key: queryEntity.id,
+					rectangle: queryEntity.rectangle.coordinates._value,
+					isCanvas: queryEntity.rectangle.material instanceof Cesium.ImageMaterialProperty ?
+						true : false,
+				})
+			}
+			/* 发送处理任务 */
+			this._worker.postMessage({
+				keys: this._removeEntities,
+				entities: renderEntities,
+			});
+		}
+		/* 重启计算标志 */
+		// this._console('循环结束...');
+		this._isUpdateTile = true;
+	}
+
+	/**
+	 * 渲染单个瓦片到视图中
+	 * @param {Object} tile
+	 */
+	_renderSimpleTileToViewer(tile) {
+		/* 创建画布 */
+		const canvas = this._createCanvas(tile, undefined, this._isDebug);
+		let bjPositions = this._calculateRectangleOutlineCoordinates(tile
+			.rectangle);
+		let tileEntity = new Cesium.Entity({
+			name: this._renderName,
+			id: tile.key,
+			rectangle: {
+				coordinates: tile.rectangle,
+				material: canvas,
+			},
+			polyline: {
+				positions: bjPositions,
+				material: Cesium.Color.YELLOW.withAlpha(this._isDebug ? 1 : 0),
+				width: 1,
+				clampToGround: true, //开启贴地 如果有模型则贴模型
+			}
+		});
+		return this._entities.add(tileEntity);
+	}
+
+	/**
+	 * 根据瓦片创建画布
+	 * @param {Object} tile 瓦片
+	 * @param {Object} image 绘制的图片
+	 * @param {boolean} islabel 是否绘制标签 
+	 */
+	_createCanvas(tile, image, islabel) {
+		/* 获取服务提供者的切片方案 */
+		let provider = this._provider;
+		const canvas = document.createElement("canvas");
+		canvas.width = provider.tileWidth;
+		canvas.height = provider.tileHeight;
+		const context = canvas.getContext("2d");
+		if (image !== undefined) {
+			context.globalAlpha = this._opacity;
+			context.drawImage(image, 0, 0, canvas.width, canvas.height);
+		}
+		if (islabel !== undefined && islabel === true) {
+			context.globalAlpha = 1.0;
+			/* 创建标签 */
+			context.font = "20px Arial";
+			context.textAlign = "center";
+			context.fillStyle = 'rgba(255,255,0)';
+			context.strokeStyle = 'rgba(255,255,255,1)';
+			context.lineWidth = 2;
+			context.strokeText(`L: ${tile.level}`, 126, 86);
+			context.fillText(`L: ${tile.level}`, 126, 86);
+			context.strokeText(`X: ${tile.x}`, 126, 136);
+			context.fillText(`X: ${tile.x}`, 126, 136);
+			context.strokeText(`Y: ${tile.y}`, 126, 186);
+			context.fillText(`Y: ${tile.y}`, 126, 186);
+		}
+		/* 返回画布 */
+		return canvas;
+	}
+
+	/**
+	 * 投影当前瓦片
+	 * @param {Object} tile
+	 */
+	_projectionTile(tile) {
+		if (this._tilingScheme instanceof Cesium.GeographicTilingScheme) {
+			return [{
+				x: tile.x,
+				y: tile.y,
+				level: tile.level,
+				rectangle: tile._rectangle,
+			}];
+		}
+		/* 获取矩形 */
+		let rectangle = tile._rectangle;
+		// let imageryLevel = parseInt(tile.level) + 1;
+		let imageryLevel = parseInt(tile.level);
+		let mercatorTilingScheme = this._provider.tilingScheme;
+		let res = [];
+		/* 先判断当前的切片范围是否与提供者的数据范围有交集 */
+		let interRectangle = Cesium.Rectangle.intersection(rectangle, this._rectangle);
+		/* 如果当前计算的瓦片与数据范围无交集 则舍弃 */
+		if (interRectangle === undefined) return res;
+		/* 判断北西角点的墨卡托投影瓦片信息 */
+		let northwestTileCoordinates = mercatorTilingScheme.positionToTileXY(
+			Cesium.Rectangle.northwest(rectangle),
+			imageryLevel
+		);
+		/* 判断南东角点的墨卡托投影瓦片信息 */
+		let southeastTileCoordinates = mercatorTilingScheme.positionToTileXY(
+			Cesium.Rectangle.southeast(rectangle),
+			imageryLevel
+		);
+		/* 根据不同类型分别进行计算 */
+		if (northwestTileCoordinates !== undefined && southeastTileCoordinates !== undefined) {
+			for (let i = northwestTileCoordinates.x; i <= southeastTileCoordinates.x; i++) {
+				for (let j = northwestTileCoordinates.y; j <= southeastTileCoordinates.y; j++) {
+					let _webRectangle = mercatorTilingScheme.tileXYToRectangle(i, j, imageryLevel);
+					if (Cesium.Rectangle.intersection(_webRectangle, this._rectangle)) {
+						res.push({
+							x: i,
+							y: j,
+							level: imageryLevel,
+							rectangle: _webRectangle,
+						});
+					}
+				}
+			}
+		} else if (northwestTileCoordinates !== undefined) {
+			let _webRectangle = mercatorTilingScheme.tileXYToRectangle(northwestTileCoordinates.x,
+				northwestTileCoordinates.y,
+				imageryLevel);
+			if (Cesium.Rectangle.intersection(_webRectangle, this._rectangle)) {
+				res.push({
+					x: northwestTileCoordinates.x,
+					y: northwestTileCoordinates.y,
+					level: imageryLevel,
+					rectangle: _webRectangle,
+				});
+			}
+		} else if (southeastTileCoordinates !== undefined) {
+			let _webRectangle = mercatorTilingScheme.tileXYToRectangle(southeastTileCoordinates.x,
+				southeastTileCoordinates.y,
+				imageryLevel);
+			if (Cesium.Rectangle.intersection(_webRectangle, this._rectangle)) {
+				res.push({
+					x: southeastTileCoordinates.x,
+					y: southeastTileCoordinates.y,
+					level: imageryLevel,
+					rectangle: _webRectangle,
+				});
+			}
+		}
+		return res;
+	}
+
+	/**
+	 * 计算矩形的外围坐标串
+	 * @param {Cesium.Rectangle} rectangle 矩形
+	 * @return {Array<Cesium.Cartesian3>} 坐标串集合
+	 */
+	_calculateRectangleOutlineCoordinates(rectangle) {
+		/* 计算东南角 */
+		let south_east = Cesium.Rectangle.southeast(rectangle);
+		let se = Cesium.Cartographic.toCartesian(south_east);
+		/* 计算西南角 */
+		let south_west = Cesium.Rectangle.southwest(rectangle);
+		let sw = Cesium.Cartographic.toCartesian(south_west);
+		/* 计算东北角 */
+		let north_east = Cesium.Rectangle.northeast(rectangle);
+		let ne = Cesium.Cartographic.toCartesian(north_east);
+		/* 计算西北角 */
+		let north_west = Cesium.Rectangle.northwest(rectangle);
+		let nw = Cesium.Cartographic.toCartesian(north_west);
+		return [sw, se, ne, nw, sw];
+	}
+
+	/**
+	 * 根据Entity的名称批量删除Entity
+	 * @param {String} entityName 实体名称
+	 */
+	_removeEntityByName(entityName) {
+		/* 获取实体集合 */
+		var entities = this._entities;
+		/* 如果不存在实体集合或集合中没有数据 则返回 */
+		if (!entities || !entities.values) return;
+		var delEntitys = [];
+		/* 循环获取当前集合中的所有实体 */
+		for (var i = 0; i < entities.values.length; i++) {
+			if (entities.values[i].name == entityName) {
+				delEntitys.push(entities.values[i]);
+			}
+		}
+		/* 删除符合条件的所有实体 */
+		for (var i = 0; i < delEntitys.length; i++) {
+			entities.remove(delEntitys[i]);
+		}
+	}
+}
+
+/* 对外方法 */
+Object.assign(CrImageServerLayer.prototype, {
+	/**
+	 * 隐藏
+	 */
+	hide: function() {
+		this._console('隐藏');
+		this._isUpdateTile = false;
+		/* 清理资源 */
+		this._removeEntityByName(this._renderName);
+		/* 清理渲染 */
+		this._renderEntities.clear();
+	},
+
+	/**
+	 * 显示
+	 */
+	show: function() {
+		this._console('显示');
+		this._isUpdateTile = true;
+	},
+
+	/**
+	 * 设置透明度
+	 * @param {Number} opacity [0-1]
+	 */
+	setOpacity: function(opacity) {
+		if (opacity === undefined || typeof opacity !== 'number') return;
+		if (opacity >= 1) this._opacity = 1.0;
+		if (opacity <= 0) this._opacity = 0.0;
+		this._opacity = parseFloat(opacity);
+	}
+
+})
+
+/* 下载线程函数 */
+function downloadWorker() {
+	/** 
+	 * 判断矩形相交函数
+	 * @ignore
+	 * @param {Object} rectangle
+	 * @param {Object} otherRectangle
+	 * @param {Object} result
+	 */
+	function intersection(rectangle, otherRectangle, result) {
+		let TWO_PI = 2.0 * Math.PI;
+		let rectangleEast = rectangle.east;
+		let rectangleWest = rectangle.west;
+		let otherRectangleEast = otherRectangle.east;
+		let otherRectangleWest = otherRectangle.west;
+		if (rectangleEast < rectangleWest && otherRectangleEast > 0.0) {
+			rectangleEast += TWO_PI;
+		} else if (otherRectangleEast < otherRectangleWest && rectangleEast > 0.0) {
+			otherRectangleEast += TWO_PI;
+		}
+		if (rectangleEast < rectangleWest && otherRectangleWest < 0.0) {
+			otherRectangleWest += TWO_PI;
+		} else if (otherRectangleEast < otherRectangleWest && rectangleWest < 0.0) {
+			rectangleWest += TWO_PI;
+		}
+		const west = negativePiToPi(
+			Math.max(rectangleWest, otherRectangleWest)
+		);
+		const east = negativePiToPi(
+			Math.min(rectangleEast, otherRectangleEast)
+		);
+		if (
+			(rectangle.west < rectangle.east ||
+				otherRectangle.west < otherRectangle.east) &&
+			east <= west
+		) {
+			return undefined;
+		}
+		const south = Math.max(rectangle.south, otherRectangle.south);
+		const north = Math.min(rectangle.north, otherRectangle.north);
+		if (south >= north) {
+			return undefined;
+		}
+		if (result === undefined) {
+			return {
+				west: west,
+				south: south,
+				east: east,
+				north: north
+			};
+		}
+		result.west = west;
+		result.south = south;
+		result.east = east;
+		result.north = north;
+		return result;
+	};
+
+	/**
+	 * 判断矩形相交辅助函数
+	 * @ignore
+	 * @param {Object} angle
+	 */
+	function negativePiToPi(angle) {
+		if (angle >= -Math.PI && angle <= Math.PI) {
+			return angle;
+		}
+		return zeroToTwoPi(angle + Math.PI) - Math.PI;
+	};
+
+	/**
+	 * 判断矩形相交辅助函数
+	 * @ignore
+	 * @param {Object} angle
+	 */
+	function zeroToTwoPi(angle) {
+		let TWO_PI = 2.0 * Math.PI;
+		let EPSILON14 = 0.00000000000001;
+		if (angle >= 0 && angle <= TWO_PI) {
+			return angle;
+		}
+		const mod = mod(angle, TWO_PI);
+		if (
+			Math.abs(mod) < EPSILON14 &&
+			Math.abs(angle) > EPSILON14
+		) {
+			return TWO_PI;
+		}
+		return mod;
+	};
+
+	/**
+	 * 判断矩形相交辅助函数
+	 * @ignore
+	 * @param {Object} m
+	 * @param {Object} n
+	 */
+	function mod(m, n) {
+		if (sign(m) === sign(n) && Math.abs(m) < Math.abs(n)) {
+			return m;
+		}
+		return ((m % n) + n) % n;
+	};
+
+	/**
+	 * 判断矩形相交辅助函数
+	 * @ignore
+	 * @param {Object} value
+	 */
+	function sign(value) {
+		value = +value;
+		if (value === 0 || value !== value) {
+			return value;
+		}
+		return value > 0 ? 1 : -1;
+	};
+
+	/**
+	 * 接收主线发送的处理任务
+	 * @ignore
+	 * @param {Object} event
+	 * @param {JSON} event.data
+	 * @param {Array<String>} event.data.keys 存储当前需要移除的key集合
+	 * @param {Array<JSON>} event.data.entities 当前已经渲染的Entity集合
+	 * event.data.entities 参数说明
+	 * @param {String} key 主键<对应Entity的Id>
+	 * @param {Cesium.Rectangle} rectangle 数据矩形<对应Entity的rectangle>
+	 * @param {Boolean} isCanvas 该Entity是否已经渲染了图片
+	 */
+	onmessage = function(event) {
+		let data = event.data;
+		/* 按层级将当前传递的Entity集合进行分组存储 */
+		let entityGroups = new Map();
+		for (let obj of data.entities) {
+			/* 对key进行划分 */
+			let level = obj.key.split('_')[3];
+			let objData = {
+				key: obj.key,
+				rectangle: obj.rectangle,
+				isCanvas: obj.isCanvas,
+			};
+			if (!entityGroups.has(level)) {
+				entityGroups.set(level, [objData]);
+			} else {
+				let tempData = entityGroups.get(level);
+				tempData.push(objData);
+				entityGroups.set(level, tempData);
+			}
+		}
+		/* 判断需要删除的Entity */
+		let removeKeys = [];
+		for (let [key, value] of data.keys) {
+			/* 对key进行拆分 提取层级标识 */
+			let level = key.split('_')[3];
+			/* 判断该层级中是否存在已经渲染的实体 */
+			if (entityGroups.has(level)) {
+				/* 在此层级集合中找到需要删除的实体 */
+				let findEntity = entityGroups.get(level).find(obj => {
+					return obj.key === key;
+				});
+				/* 找到需要移除的Entity,然后判断该实体上一层级是否已经存在渲染的Entity */
+				if (findEntity !== undefined) {
+					/* 获取矩形 */
+					let baseRectangle = findEntity.rectangle;
+					/* 循环寻找高层级与该实体相交且已渲染图片的的瓦片 */
+					for (let [findLevel, filterDatas] of entityGroups) {
+						if (parseFloat(findLevel) > parseFloat(level)) {
+							/* 使用多值搜索 判断高层级与之相交的全部Entity*/
+							let filterSubDatas = filterDatas.filter(obj => {
+								if (intersection(obj.rectangle, baseRectangle)) return obj;
+							})
+							/* 判断是否找到高一层级的足够数量的渲染瓦片 */
+							if (filterSubDatas.length >= 1) {
+								/* 接下来需要判断与之相交的实体 是否已经全部渲染完成 */
+								let filterSubRenders = filterSubDatas.filter(obj => {
+									return obj.isCanvas === undefined || obj.isCanvas === false;
+								})
+								if (filterSubRenders.length === 0) {
+									removeKeys.push(findEntity.key);
+									/* 退出循环 */
+									break;
+								}
+							}
+						}
+					}
+				}
+			}
+		}
+		setTimeout(function() {
+			/* 循环查找结束 */
+			postMessage(removeKeys);
+		}, 500);
+	}
+}
+
+
+/**
+ * 数据提供器类型
+ */
+CrImageServerLayer.ProviderType = Object.freeze({
+	ArcGisMapServerImageryProvider: 'ArcGisMapServerImageryProvider',
+	BingMapsImageryProvider: 'BingMapsImageryProvider',
+	OpenStreetMapImageryProvider: 'OpenStreetMapImageryProvider',
+	TileMapServiceImageryProvider: 'TileMapServiceImageryProvider',
+	GoogleEarthEnterpriseImageryProvider: 'GoogleEarthEnterpriseImageryProvider',
+	GoogleEarthEnterpriseMapsProvider: 'GoogleEarthEnterpriseMapsProvider',
+	GridImageryProvider: 'GridImageryProvider',
+	IonImageryProvider: 'IonImageryProvider',
+	MapboxImageryProvider: 'MapboxImageryProvider',
+	MapboxStyleImageryProvider: 'MapboxStyleImageryProvider',
+	SingleTileImageryProvider: 'SingleTileImageryProvider',
+	TileCoordinatesImageryProvider: 'TileCoordinatesImageryProvider',
+	UrlTemplateImageryProvider: 'UrlTemplateImageryProvider',
+	WebMapServiceImageryProvider: 'WebMapServiceImageryProvider',
+	WebMapTileServiceImageryProvider: 'WebMapTileServiceImageryProvider',
+})
+
+/* 输出类 */
+export default CrImageServerLayer

+ 929 - 0
src/components/CrMap/CrImageServerLayer_primitive.js

@@ -0,0 +1,929 @@
+/**
+ * 创建者:王成
+ * 操作系统:MAC
+ * 创建日期:2023年1月30日
+ * 描述:通过矩形渲染tile,从而达到渲染图片可以浮动在实景三维上面的效果
+ */
+
+/* 扩展系统Date属性Format 用于格式化日期 yyMMdd HH:ss:mm */
+Date.prototype.Format = function(fmt) { // author: meizz 
+	var o = {
+		"M+": this.getMonth() + 1, // 月份 
+		"d+": this.getDate(), // 日 
+		"h+": this.getHours(), // 小时 
+		"m+": this.getMinutes(), // 分 
+		"s+": this.getSeconds(), // 秒 
+		"q+": Math.floor((this.getMonth() + 3) / 3), // 季度 
+		"S": this.getMilliseconds() // 毫秒 
+	};
+	if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
+	for (var k in o)
+		if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : ((
+			"00" + o[k]).substr(("" + o[k]).length)));
+	return fmt;
+}
+
+/* 引入Cesium */
+import * as Cesium from 'cesium';
+
+/* 扩展primivite方法 */
+
+/**
+ * 设置Id
+ * @param {String} id
+ */
+Cesium.GroundPrimitive.prototype.setId = function(id) {
+	this._id = id;
+}
+
+/**
+ * 获取Id
+ */
+Cesium.GroundPrimitive.prototype.getId = function() {
+	return this._id;
+}
+
+/**
+ * 根据Id进行查询
+ * @param {String} id
+ * @return {Cesium.GroundPrimitive} 返回查询到的Primivite 未查询到 则返回undefined
+ */
+Cesium.PrimitiveCollection.prototype.getById = function(id) {
+	let findPrimivite = this._primitives.find(obj => {
+		if (obj._id === id) return obj;
+	})
+	return findPrimivite;
+}
+
+/**
+ * 根据Id进行移除操作
+ * @param {String} id
+ */
+Cesium.PrimitiveCollection.prototype.removeById = function(id) {
+	let findPrimitive = this.getById(id);
+	if (findPrimitive !== undefined) {
+		return this.remove(findPrimitive);
+	} else {
+		return false;
+	}
+}
+
+
+/* 创建类 */
+class CrImageServerLayer {
+	/**
+	 * 构造函数
+	 * @param {Cesium.Viewer} options.viewer 地图视图容器
+	 * @param {CrImageServerLayer.ProviderType} options.providerType 数据提供器类型
+	 * @param {JSON} options.config 对应该提供器的配置参数
+	 * @param {Number} options.opacity 图层透明度[0.0~1.0] [默认0.3]    
+	 */
+	constructor({
+		viewer,
+		providerType = CrImageServerLayer.ArcGisMapServerImageryProvider,
+		config = {},
+		opacity = 0.75,
+		show = true,
+	} = {}) {
+		let _self = this;
+		/* 地图视图 外部传入 必须参数 */
+		this._viewer = viewer;
+		/* 服务提供者配置参数 */
+		this._providerType = providerType;
+		/* 服务提供者 */
+		this._provider = undefined;
+		/* 服务提供者切片方案 */
+		this._tilingScheme = undefined;
+		/* 服务的切片的最大/最小层级 */
+		this._maximumLevel = 0;
+		this._minimumLevel = 20;
+		/* 切片大小 */
+		this._tileWidth = 0;
+		this._tileHeight = 0;
+		/* 服务数据范围 */
+		this._rectangle = undefined;
+		/* 服务提供者的配置参数 */
+		this._config = config;
+		/* 透明度 外部传入 */
+		this._opacity = opacity;
+		/* 图层随机标识 */
+		this._renderName = this._guid();
+		/* 当前图层的渲染集合 */
+		this._primitives = new Cesium.PrimitiveCollection();
+		this._viewer.scene.primitives.add(this._primitives);
+		/* 渲染集合 */
+		this._renderPrimitives = new Map();
+		/* 移除渲染集合 */
+		this._removePrimitives = new Map();
+		/* 是否渲染标志 */
+		this._isUpdateTile = show;
+		/* 是否输出测试信息 */
+		this._isDebug = false;
+		/* 创建一个线程 用于处理移除任务 */
+		this._sendTask = true;
+		let workerBlob = new Blob([`(${downloadWorker.toString ()})()`]); // 把函数转成一个自执行函数
+		this._worker = new Worker(URL.createObjectURL(workerBlob));
+		/* 接收反馈 */
+		this._worker.onmessage = function(event) {
+			for (let key of event.data) {
+				_self._primitives.removeById(key);
+				_self._removePrimitives.delete(key);
+				_self._renderPrimitives.delete(key);
+			}
+			_self._sendTask = true;
+		}
+		/* 初始化 */
+		this._init();
+	}
+
+	/**
+	 * 初始化
+	 */
+	_init() {
+		let _self = this;
+		/* 创建服务提供者 */
+		switch (this._providerType) {
+			case CrImageServerLayer.ProviderType.ArcGisMapServerImageryProvider:
+				this._provider = new Cesium.ArcGisMapServerImageryProvider(this._config);
+				break;
+			case CrImageServerLayer.ProviderType.UrlTemplateImageryProvider:
+				this._provider = new Cesium.UrlTemplateImageryProvider(this._config);
+				break;
+		}
+		/* 服务提供者判断 */
+		if (this._provider === undefined) {
+			this._console('没有服务提供者,无法初始化!');
+			return;
+		}
+		/* 激活服务提供者 注册刷帧事件 */
+		this._provider.readyPromise.then(function(result) {
+			/* 初始化参数 */
+			_self._rectangle = _self._provider.rectangle;
+			_self._tilingScheme = _self._provider.tilingScheme;
+			_self._maximumLevel = _self._provider.maximumLevel === undefined ? 22 : _self._provider
+				.maximumLevel;
+			_self._minimumLevel = _self._provider.minimumLevel === undefined ? 0 : _self._provider
+				.minimumLevel;
+			_self._tileWidth = _self._provider.tileWidth;
+			_self._tileHeight = _self._provider.tileHeight;
+			/* 输出调试信息 */
+			if (_self._isDebug) _self._printDebug();
+			/* 注册事件 */
+			_self._viewer.scene.postRender.addEventListener(() => {
+				if (_self._isUpdateTile) {
+					/* 设置运行标志为false 等待计算完成 */
+					_self._isUpdateTile = false;
+					/* 投影瓦片集合 */
+					_self._renderTiles();
+				}
+			});
+		})
+	}
+
+	/**
+	 * 生成GUID随机数
+	 */
+	_guid() {
+		function S4() {
+			return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
+		}
+		return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
+	}
+
+	/**
+	 * 输出调试信息
+	 */
+	_printDebug() {
+		/* 数据提供者的切片方案 */
+		let tiling = this._provider.tilingScheme;
+		/* WGS84坐标系的切片方案 */
+		let tiling84 = new Cesium.GeographicTilingScheme();
+		/* 绘制数据提供者的数据范围 */
+		this._drawDebugRectangle(this._rectangle, Cesium.Color.GREEN);
+		/* 根据行列号和等级创建调试矩形 */
+		let rect = tiling84.tileXYToRectangle(1696, 312, 10);
+	}
+
+	/**
+	 * 绘制调试矩形
+	 * @param {Cesium.Rectangle} rectangle 绘制的矩形
+	 * @param {Cesium.Color} color 矩形边框颜色
+	 */
+	_drawDebugRectangle(rectangle, color) {
+		/* 计算矩形的外包范围 */
+		let positions = this._calculateRectangleOutlineCoordinates(rectangle);
+		/* 创建矩形图元 */
+		let rectangleInstance = new Cesium.GeometryInstance({
+			geometry: new Cesium.GroundPolylineGeometry({
+				positions: positions,
+				width: 8,
+			})
+		})
+		/* 创建对象 */
+		let primivite = new Cesium.GroundPolylinePrimitive({
+			geometryInstances: rectangleInstance,
+			appearance: this._createMaterialColorAppearance('rgba(0,255,0,1)'),
+			classificationType: Cesium.ClassificationType.BOTH,
+		})
+		/* 加入数据集 */
+		this._primitives.add(primivite);
+	}
+
+	/**
+	 * 创建颜色着色器
+	 * @param {String} color rgba(r,g,b,a)
+	 */
+	_createMaterialColorAppearance(color) {
+		/* 创建材质 */
+		let material = new Cesium.Material({
+			fabric: {
+				type: 'Color',
+				uniforms: {
+					color: new Cesium.Color.fromCssColorString(color),
+				}
+			}
+		});
+		/* 创建着色器 */
+		let appearance = new Cesium.MaterialAppearance({
+			material: material,
+		});
+		/* 返回 */
+		return appearance;
+	}
+
+	/**
+	 * 根据画布创建材质
+	 * @param {Canvas} canvas 画布
+	 */
+	_createMaterialImageAppearance(canvas) {
+		/* 创建着色器 */
+		let material = Cesium.Material.fromType('Image', {
+			image: canvas,
+		})
+		let appearance = new Cesium.MaterialAppearance({
+			material: material,
+		})
+		/* 返回 */
+		return appearance;
+	}
+
+	/**
+	 * 输出消息
+	 * @param {Object} res
+	 */
+	_console(...rest) {
+		if (this._isDebug)
+			console.log('===' + new Date().Format('yyyy-MM-dd HH:mm:ss') + '>>>', rest);
+	}
+
+	/**
+	 * 渲染瓦片集合
+	 */
+	_renderTiles() {
+		let _self = this;
+		/* 获取当前视图渲染的瓦片集合 */
+		let tilesToRender = this._viewer.scene.globe._surface._tilesToRender;
+		if (tilesToRender === undefined || tilesToRender.length === 0) {
+			this._isUpdateTile = true;
+			return;
+		} else {
+			new Promise((resolve, reject) => {
+				/* 对瓦片数组按照level进行排序 以保证后续瓦片重投影时的重叠移除无误 */
+				tilesToRender.sort(function(obj1, obj2) {
+					let level1 = parseInt(obj1.level);
+					let level2 = parseInt(obj2.level);
+					return level1 - level2;
+				})
+
+				/* 返回排序后的渲染瓦片数据集 开始异步计算 */
+				resolve(tilesToRender);
+			}).then(tiles => {
+				/* Cesium渲染瓦片为84投影,如果不一致需要异步重投影瓦片数据集 */
+				_self._asyncProjectionTiles(tiles);
+			})
+		}
+	}
+
+	/**
+	 * 根据行列和等级生成key
+	 * @param {Number} x 行
+	 * @param {Number} y 列
+	 * @param {Number} level 等级
+	 */
+	_createKey(x, y, level) {
+		let key = `${this._renderName}_${x}_${y}_${level}`;
+		return key;
+	}
+
+	/**
+	 * 投影瓦片集合
+	 * @param {Object} tiles 原始渲染瓦片集合
+	 */
+	_asyncProjectionTiles(tiles) {
+		let renderTiles = [];
+		/* 循环投影 */
+		for (let tile of tiles) {
+			/* 对单个瓦片进行重投影 */
+			let proTiles = this._projectionTile(tile);
+			for (let proTile of proTiles) {
+				/* 瓦片实体唯一标识 */
+				let key = this._createKey(proTile.x, proTile.y, proTile.level);
+				/* 查找瓦片是否已经存在 存在则过滤 以免重复存在 */
+				let subTile = renderTiles.find(obj => {
+					return obj.x === proTile.x && obj.y === proTile.y;
+				})
+				if (subTile === undefined) {
+					/* 重投影瓦片范围与数据范围的叠合计算 */
+					let isExists = false;
+					for (let eTile of renderTiles) {
+						if (Cesium.Rectangle.intersection(eTile.rectangle, proTile.rectangle)) {
+							/* 追加子集 方便后期进行层级处理 */
+							eTile.childTiles.push(key);
+							isExists = true;
+							break;
+						}
+					}
+					/* 加入渲染集合 */
+					if (!isExists) {
+						renderTiles.push({
+							key: key,
+							x: proTile.x,
+							y: proTile.y,
+							level: proTile.level,
+							rectangle: proTile.rectangle,
+							childTiles: [],
+						});
+					}
+				}
+			}
+		}
+		/* 清理低层级元素 */
+		let i = renderTiles.length;
+		let appendTiles = [];
+		while (i--) {
+			let findTile = renderTiles[i];
+			if (findTile.childTiles.length >= 1) {
+				/* 创建高层级的瓦片 */
+				let tiles = this._createFourTiles(findTile);
+				for (let tile of tiles) {
+					appendTiles.push(tile);
+				}
+				/* 如果存在高层级 则删除低层级 */
+				renderTiles.splice(i, 1);
+			}
+		}
+		/* 将四叉树追加的层级数据加入到渲染集合中 */
+		for (let appendTile of appendTiles) {
+			renderTiles.push(appendTile);
+		}
+		/* 对数组进行排序 */
+		renderTiles.sort(function(obj1, obj2) {
+			let level1 = parseInt(obj1.level);
+			let level2 = parseInt(obj2.level);
+			return level1 - level2;
+		})
+		/* 渲染数据到视图中 */
+		this._renderTilesToViewer(renderTiles);
+	}
+
+	/**
+	 * 根据矩形和登记查询高一等级的行列号
+	 * @param {Cesium.Rectangle} rectangle 
+	 */
+	_createTileByRectangleAndLevel(rectangle, level) {
+		/* 获取矩形中心点 */
+		let center = Cesium.Rectangle.center(rectangle);
+		/* 新层级 */
+		let nLevel = parseInt(level) + 1;
+		/* 查询高一层级的行列号 */
+		let query = this._provider.tilingScheme.positionToTileXY(center, nLevel);
+		if (query === undefined) return undefined;
+		/* 返回结果 */
+		return {
+			key: this._createKey(query.x, query.y, nLevel),
+			x: query.x,
+			y: query.y,
+			level: nLevel,
+			rectangle: rectangle,
+			childTiles: [],
+		}
+	}
+
+	/**
+	 * 创建四个高层级的瓦片
+	 * @param {Object} tile 当前瓦片
+	 */
+	_createFourTiles(tile) {
+		let rects = [];
+		let results = [];
+		let rectangle = tile.rectangle;
+		/* 将该矩形按照四叉树规则分割为4个高层级的矩形 */
+		rects.push(Cesium.Rectangle.subsection(rectangle, 0, 0, 0.5, 0.5));
+		rects.push(Cesium.Rectangle.subsection(rectangle, 0.5, 0, 1.0, 0.5));
+		rects.push(Cesium.Rectangle.subsection(rectangle, 0, 0.5, 0.5, 1.0));
+		rects.push(Cesium.Rectangle.subsection(rectangle, 0.5, 0.5, 1.0, 1.0));
+		for (let rect of rects) {
+			/* 判断高层级的矩形是否与谁范围存在交集 */
+			if (Cesium.Rectangle.intersection(rect, this._rectangle)) {
+				/* 查询高一层级的Tile */
+				let newTile = this._createTileByRectangleAndLevel(rect, tile.level);
+				/* 如果存在加入到返回集合中 */
+				if (newTile !== undefined) results.push(newTile);
+			}
+		}
+		return results;
+	}
+
+	/**
+	 * 渲染瓦片到视图中
+	 * @param {Object} tiles
+	 */
+	_renderTilesToViewer(tiles) {
+		let _self = this;
+		/* 确定哪些渲染瓦片已失效 对失效的实体进行清理 */
+		let deleteKeys = [];
+		for (let [key, tile] of this._renderPrimitives) {
+			let findTile = tiles.find(obj => {
+				return obj.key === key;
+			})
+			if (findTile === undefined) {
+				deleteKeys.push(key);
+			}
+		}
+		for (let key of deleteKeys) {
+			/* 从当前渲染集合中将失效瓦片移除元素 */
+			// this._renderPrimitives.delete(key);
+			/* 移除渲染元素 */
+			// this._primitives.removeById(key);
+			this._removePrimitives.set(key, {
+				key: key,
+			});
+		}
+		/* 对过滤后的数据集进行渲染 */
+		for (let tile of tiles) {
+			/* 判断当前渲染的数据是否已经渲染且有效 */
+			if (!this._renderPrimitives.has(tile.key)) {
+				/* 将数据渲染到视图中 */
+				this._renderSimpleTileToViewer(tile);
+				/* 追加到渲染集合中 该集合中始终保持当前渲染的最新数据 */
+				this._renderPrimitives.set(tile.key, {
+					key: tile.key,
+					renderImage: false,
+				});
+				/* 初始化y */
+				let tile_y = tile.y;
+				/* 利用数据提供器获取图片 */
+				this._provider.requestImage(tile.x, tile_y, tile.level).then(function(image) {
+					/* 判断是否返回图片资源 */
+					if (image !== undefined) {
+						/* 对图片资源进行Y轴翻转 */
+						let primise = createImageBitmap(image, {
+							imageOrientation: 'flipY',
+						});
+						primise.then(function(resImage) {
+							let renderPrimitive = _self._primitives.getById(tile.key);
+							if (renderPrimitive !== undefined) {
+								let canvas = _self._createCanvas(tile, resImage, _self._isDebug);
+								renderPrimitive.appearance = _self._createMaterialImageAppearance(
+									canvas);
+								/* 修改集合中内容 */
+								if (_self._renderPrimitives.has(tile.key)) {
+									let item = _self._renderPrimitives.get(tile.key);
+									item.renderImage = true;
+									_self._renderPrimitives.set(tile.key, item);
+								}
+							}
+							/* 释放图片资源 */
+							image.close();
+						})
+					}
+				}).catch(err => {
+					_self._console('错误', err);
+					/* 修改集合中内容 */
+					if (_self._renderPrimitives.has(tile.key)) {
+						let item = _self._renderPrimitives.get(tile.key);
+						item.renderImage = true;
+						_self._renderPrimitives.set(tile.key, item);
+					}
+				});
+			}
+		}
+		if (this._sendTask && this._removePrimitives.size > 0) {
+			this._sendTask = false;
+			this._console('发送处理任务...');
+			let renderPrimitives = new Map();
+			/* 传递之前深度克隆 */
+			for (let [key, item] of this._renderPrimitives) {
+				let strItem = JSON.stringify(item);
+				renderPrimitives.set(key, JSON.parse(strItem));
+			}
+			/* 深度克隆需要移除的实体集合 */
+			let removePrimitives = [];
+			for (let [key, removeEntity] of this._removePrimitives) {
+				removePrimitives.push(key);
+			}
+			/* 发送处理任务 */
+			this._worker.postMessage({
+				removePrimitives: removePrimitives,
+				renderPrimitives: renderPrimitives,
+			});
+		}
+		/* 重启计算标志 */
+		// this._console('循环结束...');
+		this._isUpdateTile = true;
+	}
+
+	/**
+	 * 渲染单个瓦片到视图中
+	 * @param {Object} tile
+	 */
+	_renderSimpleTileToViewer(tile) {
+		/* 创建画布 */
+		const canvas = this._createCanvas(tile, undefined, this._isDebug);
+		let bjPositions = this._calculateRectangleOutlineCoordinates(tile
+			.rectangle);
+		/* 创建图形要素 */
+		let instance = new Cesium.GeometryInstance({
+			geometry: new Cesium.RectangleGeometry({
+				rectangle: tile.rectangle,
+			})
+		});
+		/* 创建着色器 */
+		let appearance = this._createMaterialImageAppearance(canvas);
+		/* 创建源语 */
+		let primitive = new Cesium.GroundPrimitive({
+			geometryInstances: instance,
+			appearance: appearance,
+		});
+		/* 设置Id */
+		primitive.setId(tile.key);
+		/* 加入集合 */
+		return this._primitives.add(primitive);
+	}
+
+	/**
+	 * 根据瓦片创建画布
+	 * @param {Object} tile 瓦片
+	 * @param {Object} image 绘制的图片
+	 * @param {boolean} islabel 是否绘制标签 
+	 */
+	_createCanvas(tile, image, islabel) {
+		/* 获取服务提供者的切片方案 */
+		let provider = this._provider;
+		const canvas = document.createElement("canvas");
+		canvas.width = provider.tileWidth;
+		canvas.height = provider.tileHeight;
+		const context = canvas.getContext("2d");
+		if (image !== undefined) {
+			context.globalAlpha = this._opacity;
+			context.drawImage(image, 0, 0, canvas.width, canvas.height);
+		}
+		if (this._isDebug) {
+			context.strokeStyle = 'rgba(255,255,0,1)';
+			context.lineWidth = 2;
+			context.strokeRect(0, 0, canvas.width, canvas.height);
+		}
+		if (islabel !== undefined && islabel === true) {
+			context.globalAlpha = 1.0;
+			/* 创建标签 */
+			context.font = "20px Arial";
+			context.textAlign = "center";
+			context.fillStyle = 'rgba(255,255,0)';
+			context.strokeStyle = 'rgba(255,255,255,1)';
+			context.lineWidth = 2;
+			context.strokeText(`L: ${tile.level}`, 126, 86);
+			context.fillText(`L: ${tile.level}`, 126, 86);
+			context.strokeText(`X: ${tile.x}`, 126, 136);
+			context.fillText(`X: ${tile.x}`, 126, 136);
+			context.strokeText(`Y: ${tile.y}`, 126, 186);
+			context.fillText(`Y: ${tile.y}`, 126, 186);
+		}
+		/* 返回画布 */
+		return canvas;
+	}
+
+	/**
+	 * 投影当前瓦片
+	 * @param {Object} tile
+	 */
+	_projectionTile(tile) {
+		if (this._tilingScheme instanceof Cesium.GeographicTilingScheme) {
+			return [{
+				x: tile.x,
+				y: tile.y,
+				level: tile.level,
+				rectangle: tile._rectangle,
+			}];
+		}
+		/* 获取矩形 */
+		let rectangle = tile._rectangle;
+		// let imageryLevel = parseInt(tile.level) + 1;
+		let imageryLevel = parseInt(tile.level);
+		let mercatorTilingScheme = this._provider.tilingScheme;
+		let res = [];
+		/* 先判断当前的切片范围是否与提供者的数据范围有交集 */
+		let interRectangle = Cesium.Rectangle.intersection(rectangle, this._rectangle);
+		/* 如果当前计算的瓦片与数据范围无交集 则舍弃 */
+		if (interRectangle === undefined) return res;
+		/* 判断北西角点的墨卡托投影瓦片信息 */
+		let northwestTileCoordinates = mercatorTilingScheme.positionToTileXY(
+			Cesium.Rectangle.northwest(rectangle),
+			imageryLevel
+		);
+		/* 判断南东角点的墨卡托投影瓦片信息 */
+		let southeastTileCoordinates = mercatorTilingScheme.positionToTileXY(
+			Cesium.Rectangle.southeast(rectangle),
+			imageryLevel
+		);
+		/* 根据不同类型分别进行计算 */
+		if (northwestTileCoordinates !== undefined && southeastTileCoordinates !== undefined) {
+			for (let i = northwestTileCoordinates.x; i <= southeastTileCoordinates.x; i++) {
+				for (let j = northwestTileCoordinates.y; j <= southeastTileCoordinates.y; j++) {
+					let _webRectangle = mercatorTilingScheme.tileXYToRectangle(i, j, imageryLevel);
+					if (Cesium.Rectangle.intersection(_webRectangle, this._rectangle)) {
+						res.push({
+							x: i,
+							y: j,
+							level: imageryLevel,
+							rectangle: _webRectangle,
+						});
+					}
+				}
+			}
+		} else if (northwestTileCoordinates !== undefined) {
+			let _webRectangle = mercatorTilingScheme.tileXYToRectangle(northwestTileCoordinates.x,
+				northwestTileCoordinates.y,
+				imageryLevel);
+			if (Cesium.Rectangle.intersection(_webRectangle, this._rectangle)) {
+				res.push({
+					x: northwestTileCoordinates.x,
+					y: northwestTileCoordinates.y,
+					level: imageryLevel,
+					rectangle: _webRectangle,
+				});
+			}
+		} else if (southeastTileCoordinates !== undefined) {
+			let _webRectangle = mercatorTilingScheme.tileXYToRectangle(southeastTileCoordinates.x,
+				southeastTileCoordinates.y,
+				imageryLevel);
+			if (Cesium.Rectangle.intersection(_webRectangle, this._rectangle)) {
+				res.push({
+					x: southeastTileCoordinates.x,
+					y: southeastTileCoordinates.y,
+					level: imageryLevel,
+					rectangle: _webRectangle,
+				});
+			}
+		}
+		return res;
+	}
+
+	/**
+	 * 计算矩形的外围坐标串
+	 * @param {Cesium.Rectangle} rectangle 矩形
+	 * @return {Array<Cesium.Cartesian3>} 坐标串集合
+	 */
+	_calculateRectangleOutlineCoordinates(rectangle) {
+		/* 计算东南角 */
+		let south_east = Cesium.Rectangle.southeast(rectangle);
+		let se = Cesium.Cartographic.toCartesian(south_east);
+		/* 计算西南角 */
+		let south_west = Cesium.Rectangle.southwest(rectangle);
+		let sw = Cesium.Cartographic.toCartesian(south_west);
+		/* 计算东北角 */
+		let north_east = Cesium.Rectangle.northeast(rectangle);
+		let ne = Cesium.Cartographic.toCartesian(north_east);
+		/* 计算西北角 */
+		let north_west = Cesium.Rectangle.northwest(rectangle);
+		let nw = Cesium.Cartographic.toCartesian(north_west);
+		return [sw, se, ne, nw, sw];
+	}
+
+	/**
+	 * 根据Entity的名称批量删除Entity
+	 * @param {String} entityName 实体名称
+	 */
+	_removeEntityByName(entityName) {
+		/* 获取实体集合 */
+		var entities = this._primitives;
+		/* 如果不存在实体集合或集合中没有数据 则返回 */
+		if (!entities || !entities.values) return;
+		var delEntitys = [];
+		/* 循环获取当前集合中的所有实体 */
+		for (var i = 0; i < entities.values.length; i++) {
+			if (entities.values[i].name == entityName) {
+				delEntitys.push(entities.values[i]);
+			}
+		}
+		/* 删除符合条件的所有实体 */
+		for (var i = 0; i < delEntitys.length; i++) {
+			entities.remove(delEntitys[i]);
+		}
+	}
+}
+
+/* 对外方法 */
+Object.assign(CrImageServerLayer.prototype, {
+	/**
+	 * 隐藏
+	 */
+	hide: function() {
+		this._console('隐藏');
+		this._isUpdateTile = false;
+		/* 清理资源 */
+		this._removeEntityByName(this._renderName);
+		/* 清理渲染 */
+		this._renderPrimitives.clear();
+	},
+
+	/**
+	 * 显示
+	 */
+	show: function() {
+		this._console('显示');
+		this._isUpdateTile = true;
+	},
+
+	/**
+	 * 设置透明度
+	 * @param {Number} opacity [0-1]
+	 */
+	setOpacity: function(opacity) {
+		if (opacity === undefined || typeof opacity !== 'number') return;
+		if (opacity >= 1) this._opacity = 1.0;
+		if (opacity <= 0) this._opacity = 0.0;
+		this._opacity = parseFloat(opacity);
+	}
+
+})
+
+/* 下载线程函数 */
+function downloadWorker() {
+	/** 
+	 * 判断矩形相交函数
+	 * @ignore
+	 * @param {Object} rectangle
+	 * @param {Object} otherRectangle
+	 * @param {Object} result
+	 */
+	function intersection(rectangle, otherRectangle, result) {
+		let TWO_PI = 2.0 * Math.PI;
+		let rectangleEast = rectangle.east;
+		let rectangleWest = rectangle.west;
+		let otherRectangleEast = otherRectangle.east;
+		let otherRectangleWest = otherRectangle.west;
+		if (rectangleEast < rectangleWest && otherRectangleEast > 0.0) {
+			rectangleEast += TWO_PI;
+		} else if (otherRectangleEast < otherRectangleWest && rectangleEast > 0.0) {
+			otherRectangleEast += TWO_PI;
+		}
+		if (rectangleEast < rectangleWest && otherRectangleWest < 0.0) {
+			otherRectangleWest += TWO_PI;
+		} else if (otherRectangleEast < otherRectangleWest && rectangleWest < 0.0) {
+			rectangleWest += TWO_PI;
+		}
+		const west = negativePiToPi(
+			Math.max(rectangleWest, otherRectangleWest)
+		);
+		const east = negativePiToPi(
+			Math.min(rectangleEast, otherRectangleEast)
+		);
+		if (
+			(rectangle.west < rectangle.east ||
+				otherRectangle.west < otherRectangle.east) &&
+			east <= west
+		) {
+			return undefined;
+		}
+		const south = Math.max(rectangle.south, otherRectangle.south);
+		const north = Math.min(rectangle.north, otherRectangle.north);
+		if (south >= north) {
+			return undefined;
+		}
+		if (result === undefined) {
+			return {
+				west: west,
+				south: south,
+				east: east,
+				north: north
+			};
+		}
+		result.west = west;
+		result.south = south;
+		result.east = east;
+		result.north = north;
+		return result;
+	};
+
+	/**
+	 * 判断矩形相交辅助函数
+	 * @ignore
+	 * @param {Object} angle
+	 */
+	function negativePiToPi(angle) {
+		if (angle >= -Math.PI && angle <= Math.PI) {
+			return angle;
+		}
+		return zeroToTwoPi(angle + Math.PI) - Math.PI;
+	};
+
+	/**
+	 * 判断矩形相交辅助函数
+	 * @ignore
+	 * @param {Object} angle
+	 */
+	function zeroToTwoPi(angle) {
+		let TWO_PI = 2.0 * Math.PI;
+		let EPSILON14 = 0.00000000000001;
+		if (angle >= 0 && angle <= TWO_PI) {
+			return angle;
+		}
+		const mod = mod(angle, TWO_PI);
+		if (
+			Math.abs(mod) < EPSILON14 &&
+			Math.abs(angle) > EPSILON14
+		) {
+			return TWO_PI;
+		}
+		return mod;
+	};
+
+	/**
+	 * 判断矩形相交辅助函数
+	 * @ignore
+	 * @param {Object} m
+	 * @param {Object} n
+	 */
+	function mod(m, n) {
+		if (sign(m) === sign(n) && Math.abs(m) < Math.abs(n)) {
+			return m;
+		}
+		return ((m % n) + n) % n;
+	};
+
+	/**
+	 * 判断矩形相交辅助函数
+	 * @ignore
+	 * @param {Object} value
+	 */
+	function sign(value) {
+		value = +value;
+		if (value === 0 || value !== value) {
+			return value;
+		}
+		return value > 0 ? 1 : -1;
+	};
+
+	/**
+	 * 接收主线发送的处理任务
+	 * @ignore
+	 * @param {Object} event
+	 * @param {JSON} event.data
+	 * @param {Array<String>} event.data.removePrimitives 存储当前需要移除的集合
+	 * @param {Array<JSON>} event.data.renderPrimitives 当前渲染的数据集合
+	 * event.data.entities 参数说明
+	 * @param {String} key 主键<对应Id>
+	 * @param {Boolean} renderImage 是否已经渲染了图片
+	 */
+	onmessage = function(event) {
+		let data = event.data;
+		let isRemove = true;
+		for (let [key, item] of data.renderPrimitives) {
+			if (item.renderImage === false) isRemove = false;
+			break;
+		}
+		if (isRemove) {
+			setTimeout(function() {
+				postMessage(data.removePrimitives);
+			}, 300);
+		} else {
+			postMessage([]);
+			console.log('===>>>', '渲染未完成!');
+		}
+	}
+}
+
+
+/**
+ * 数据提供器类型
+ */
+CrImageServerLayer.ProviderType = Object.freeze({
+	ArcGisMapServerImageryProvider: 'ArcGisMapServerImageryProvider',
+	BingMapsImageryProvider: 'BingMapsImageryProvider',
+	OpenStreetMapImageryProvider: 'OpenStreetMapImageryProvider',
+	TileMapServiceImageryProvider: 'TileMapServiceImageryProvider',
+	GoogleEarthEnterpriseImageryProvider: 'GoogleEarthEnterpriseImageryProvider',
+	GoogleEarthEnterpriseMapsProvider: 'GoogleEarthEnterpriseMapsProvider',
+	GridImageryProvider: 'GridImageryProvider',
+	IonImageryProvider: 'IonImageryProvider',
+	MapboxImageryProvider: 'MapboxImageryProvider',
+	MapboxStyleImageryProvider: 'MapboxStyleImageryProvider',
+	SingleTileImageryProvider: 'SingleTileImageryProvider',
+	TileCoordinatesImageryProvider: 'TileCoordinatesImageryProvider',
+	UrlTemplateImageryProvider: 'UrlTemplateImageryProvider',
+	WebMapServiceImageryProvider: 'WebMapServiceImageryProvider',
+	WebMapTileServiceImageryProvider: 'WebMapTileServiceImageryProvider',
+})
+
+/* 输出类 */
+export default CrImageServerLayer

+ 627 - 0
src/components/CrMap/CrImageServerLayer_work.js

@@ -0,0 +1,627 @@
+/**
+ * 创建者:王成
+ * 操作系统:MAC
+ * 创建日期:2023年1月30日
+ * 描述:通过矩形渲染tile,从而达到渲染图片可以浮动在实景三维上面的效果
+ */
+
+/* 扩展系统Date属性Format 用于格式化日期 yyMMdd HH:ss:mm */
+Date.prototype.Format = function(fmt) { // author: meizz 
+	var o = {
+		"M+": this.getMonth() + 1, // 月份 
+		"d+": this.getDate(), // 日 
+		"h+": this.getHours(), // 小时 
+		"m+": this.getMinutes(), // 分 
+		"s+": this.getSeconds(), // 秒 
+		"q+": Math.floor((this.getMonth() + 3) / 3), // 季度 
+		"S": this.getMilliseconds() // 毫秒 
+	};
+	if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
+	for (var k in o)
+		if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : ((
+			"00" + o[k]).substr(("" + o[k]).length)));
+	return fmt;
+}
+
+/* 引入Cesium */
+import * as Cesium from 'cesium';
+// import Worker from '../../../public/worker/download.js?worker';
+
+/* 创建类 */
+class CrImageServerLayer {
+	/**
+	 * 构造函数
+	 * @param {Cesium.Viewer} options.viewer 地图视图容器
+	 * @param {String} options.url 服务地址
+	 * @param {Number} options.opacity 图层透明度[0.0~1.0] [默认0.3]    
+	 */
+	constructor({
+		viewer,
+		url,
+		opacity = 0.75,
+		show = true,
+	} = {}) {
+		/* 地图视图 外部传入 必须参数 */
+		this._viewer = viewer;
+		/* 服务地址 外部传入 */
+		this._url = url;
+		/* 透明度 外部传入 */
+		this._opacity = opacity;
+		/* 图层随机标识 */
+		this._renderName = this._guid();
+		/* 实体集合 */
+		/* 用DataSource 方式 以便进行多图层管理 */
+		let dataSource = new Cesium.CustomDataSource(this._renderName);
+		this._viewer.dataSources.add(dataSource);
+		this._entities = dataSource.entities;
+		/* 渲染集合 */
+		this._renderEntities = new Map();
+		/* 是否渲染标志 */
+		this._isUpdateTile = show;
+		/* 是否输出测试信息 */
+		this._isDebug = false;
+		/* 初始化 */
+		this._init();
+	}
+
+	/**
+	 * 初始化
+	 */
+	_init() {
+		let _self = this;
+		/* 创建服务提供者 */
+		this._provider = new Cesium.ArcGisMapServerImageryProvider({
+			url: _self._url,
+		})
+		/* 激活服务提供者 注册刷帧事件 */
+		this._provider.readyPromise.then(function(result) {
+			/* 服务提供者的数据范围 */
+			_self._rectangle = _self._provider.rectangle;
+			/* 输出调试信息 */
+			if (_self._isDebug) _self._printDebug();
+			/* 注册事件 */
+			_self._viewer.scene.postRender.addEventListener(() => {
+				if (_self._isUpdateTile) {
+					/* 设置运行标志为false 等待计算完成 */
+					_self._isUpdateTile = false;
+					/* 投影瓦片集合 */
+					_self._renderTiles();
+				}
+			});
+		})
+	}
+
+	/**
+	 * 生成GUID随机数
+	 */
+	_guid() {
+		function S4() {
+			return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
+		}
+		return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
+	}
+
+	/**
+	 * 输出调试信息
+	 */
+	_printDebug() {
+		/* 数据提供者的切片方案 */
+		let tiling = this._provider.tilingScheme;
+		/* WGS84坐标系的切片方案 */
+		let tiling84 = new Cesium.GeographicTilingScheme();
+		/* 绘制数据提供者的数据范围 */
+		this._drawDebugRectangle(this._rectangle, Cesium.Color.GREEN);
+		/* 根据行列号和等级创建调试矩形 */
+		let rect = tiling84.tileXYToRectangle(1696, 312, 10);
+		/* 绘制调试矩形 */
+		// this._drawDebugRectangle(rect, Cesium.Color.YELLOW);
+
+		// let rect11 = Cesium.Rectangle.subsection(rect, 0, 0, 0.5, 0.5);
+		// let rect12 = Cesium.Rectangle.subsection(rect, 0.5, 0, 1.0, 0.5);
+		// let rect21 = Cesium.Rectangle.subsection(rect, 0, 0.5, 0.5, 1.0);
+		// let rect22 = Cesium.Rectangle.subsection(rect, 0.5, 0.5, 1.0, 1.0);
+		// this._drawDebugRectangle(rect11, Cesium.Color.RED);
+		// this._drawDebugRectangle(rect12, Cesium.Color.GREEN);
+		// this._drawDebugRectangle(rect21, Cesium.Color.BLUE);
+		// this._drawDebugRectangle(rect22, Cesium.Color.WHITE);
+	}
+
+	/**
+	 * 绘制调试矩形
+	 * @param {Cesium.Rectangle} rectangle 绘制的矩形
+	 * @param {Cesium.Color} color 矩形边框颜色
+	 */
+	_drawDebugRectangle(rectangle, color) {
+		/* 计算矩形的外包范围 */
+		let positions = this._calculateRectangleOutlineCoordinates(rectangle);
+		/* 创建矩形实体 */
+		let rectEntity = new Cesium.Entity({
+			name: this._renderName,
+			polyline: {
+				positions: positions,
+				material: color,
+				width: 10,
+				clampToGround: true, //开启贴地 如果有模型则贴模型
+			}
+		});
+		/* 加入数据集 */
+		this._entities.add(rectEntity);
+	}
+
+	/**
+	 * 输出消息
+	 * @param {Object} res
+	 */
+	_console(...rest) {
+		if (this._isDebug)
+			console.log('===' + new Date().Format('yyyy-MM-dd HH:mm:ss') + '>>>', rest);
+	}
+
+	/**
+	 * 渲染瓦片集合
+	 */
+	_renderTiles() {
+		let _self = this;
+		/* 获取当前视图渲染的瓦片集合 */
+		let tilesToRender = this._viewer.scene.globe._surface._tilesToRender;
+		if (tilesToRender === undefined || tilesToRender.length === 0) {
+			this._isUpdateTile = true;
+			return;
+		} else {
+			new Promise((resolve, reject) => {
+				/* 对瓦片数组按照level进行排序 以保证后续瓦片重投影时的重叠移除无误 */
+				tilesToRender.sort(function(obj1, obj2) {
+					let level1 = parseInt(obj1.level);
+					let level2 = parseInt(obj2.level);
+					return level1 - level2;
+				})
+				/* 返回排序后的渲染瓦片数据集 开始异步计算 */
+				resolve(tilesToRender);
+			}).then(tiles => {
+				/* 异步重投影瓦片数据集 */
+				_self._asyncProjectionTiles(tiles);
+			})
+		}
+	}
+
+	/**
+	 * 根据行列和等级生成key
+	 * @param {Number} x 行
+	 * @param {Number} y 列
+	 * @param {Number} level 等级
+	 */
+	_createKey(x, y, level) {
+		let key = `${this._renderName}_${x}_${y}_${level}`;
+		return key;
+	}
+
+	/**
+	 * 投影瓦片集合
+	 * @param {Object} tiles 原始渲染瓦片集合
+	 */
+	_asyncProjectionTiles(tiles) {
+		let renderTiles = [];
+		/* 循环投影 */
+		for (let tile of tiles) {
+			/* 对单个瓦片进行重投影 */
+			let proTiles = this._projectionTile(tile);
+			for (let proTile of proTiles) {
+				/* 瓦片实体唯一标识 */
+				let key = this._createKey(proTile.x, proTile.y, proTile.level);
+				/* 查找瓦片是否已经存在 存在则过滤 以免重复存在 */
+				let subTile = renderTiles.find(obj => {
+					return obj.x === proTile.x && obj.y === proTile.y;
+				})
+				if (subTile === undefined) {
+					/* 重投影瓦片范围与数据范围的叠合计算 */
+					let isExists = false;
+					for (let eTile of renderTiles) {
+						if (Cesium.Rectangle.intersection(eTile.rectangle, proTile.rectangle)) {
+							/* 追加子集 方便后期进行层级处理 */
+							eTile.childTiles.push(key);
+							isExists = true;
+							break;
+						}
+					}
+					/* 加入渲染集合 */
+					if (!isExists) {
+						renderTiles.push({
+							key: key,
+							x: proTile.x,
+							y: proTile.y,
+							level: proTile.level,
+							rectangle: proTile.rectangle,
+							childTiles: [],
+						});
+					}
+				}
+			}
+		}
+		/* 清理低层级元素 */
+		let i = renderTiles.length;
+		let appendTiles = [];
+		while (i--) {
+			let findTile = renderTiles[i];
+			if (findTile.childTiles.length >= 1) {
+				/* 创建高层级的瓦片 */
+				let tiles = this._createFourTiles(findTile);
+				for (let tile of tiles) {
+					appendTiles.push(tile);
+				}
+				/* 如果存在高层级 则删除低层级 */
+				renderTiles.splice(i, 1);
+			}
+		}
+		/* 将四叉树追加的层级数据加入到渲染集合中 */
+		for (let appendTile of appendTiles) {
+			renderTiles.push(appendTile);
+		}
+		/* 对数组进行排序 */
+		renderTiles.sort(function(obj1, obj2) {
+			let level1 = parseInt(obj1.level);
+			let level2 = parseInt(obj2.level);
+			return level1 - level2;
+		})
+		/* 渲染数据到视图中 */
+		this._renderTilesToViewer(renderTiles);
+	}
+
+	/**
+	 * 根据矩形和登记查询高一等级的行列号
+	 * @param {Cesium.Rectangle} rectangle 
+	 */
+	_createTileByRectangleAndLevel(rectangle, level) {
+		/* 获取矩形中心点 */
+		let center = Cesium.Rectangle.center(rectangle);
+		/* 新层级 */
+		let nLevel = parseInt(level) + 1;
+		/* 查询高一层级的行列号 */
+		let query = this._provider.tilingScheme.positionToTileXY(center, nLevel);
+		if (query === undefined) return undefined;
+		/* 返回结果 */
+		return {
+			key: this._createKey(query.x, query.y, nLevel),
+			x: query.x,
+			y: query.y,
+			level: nLevel,
+			rectangle: rectangle,
+			childTiles: [],
+		}
+	}
+
+	/**
+	 * 创建四个高层级的瓦片
+	 * @param {Object} tile 当前瓦片
+	 */
+	_createFourTiles(tile) {
+		let rects = [];
+		let results = [];
+		let rectangle = tile.rectangle;
+		/* 将该矩形按照四叉树规则分割为4个高层级的矩形 */
+		rects.push(Cesium.Rectangle.subsection(rectangle, 0, 0, 0.5, 0.5));
+		rects.push(Cesium.Rectangle.subsection(rectangle, 0.5, 0, 1.0, 0.5));
+		rects.push(Cesium.Rectangle.subsection(rectangle, 0, 0.5, 0.5, 1.0));
+		rects.push(Cesium.Rectangle.subsection(rectangle, 0.5, 0.5, 1.0, 1.0));
+		for (let rect of rects) {
+			/* 判断高层级的矩形是否与谁范围存在交集 */
+			if (Cesium.Rectangle.intersection(rect, this._rectangle)) {
+				/* 查询高一层级的Tile */
+				let newTile = this._createTileByRectangleAndLevel(rect, tile.level);
+				/* 如果存在加入到返回集合中 */
+				if (newTile !== undefined) results.push(newTile);
+			}
+		}
+		return results;
+	}
+
+	/**
+	 * 渲染瓦片到视图中
+	 * @param {Object} tiles
+	 */
+	_renderTilesToViewer(tiles) {
+		let _self = this;
+		/* 确定哪些渲染实体已失效 对失效的实体进行清理 */
+		let deleteKeys = [];
+		for (let [key, tile] of this._renderEntities) {
+			let findTile = tiles.find(obj => {
+				return obj.key === key;
+			})
+			if (findTile === undefined) {
+				deleteKeys.push(key);
+			}
+		}
+		for (let key of deleteKeys) {
+			/* 移除元素 */
+			this._renderEntities.delete(key);
+			/* 移除渲染元素 */
+			this._entities.removeById(key);
+		}
+		/* 对过滤后的数据集进行渲染 */
+		for (let tile of tiles) {
+			/* 判断当前渲染的数据是否已经渲染且有效 */
+			if (!this._renderEntities.has(tile.key)) {
+				/* 将数据渲染到视图中 */
+				let entity = this._renderSimpleTileToViewer(tile);
+				/* 将渲染的数据加入到集合中 */
+				this._renderEntities.set(tile.key, entity);
+				/* 创建下载线程 */
+				let workBlob = new Blob([`(${downloadWorker.toString ()})()`]); // 把函数转成一个自执行函数
+				// let workBlob = new Blob([downloadWorker.toLocaleString().match(
+				// 	/(?:\/\*[\s\S]*?\*\/|\/\/.*?\r?\n|[^{])+\{([\s\S]*)\}$/)[1]]) // 把函数的主体内容拿出来进行转换
+				let worker = new Worker(URL.createObjectURL(workBlob));
+				/* 发送下载任务 */
+				worker.postMessage({
+					key: tile.key,
+					url: this._url,
+					x: tile.x,
+					y: tile.y,
+					level: tile.level,
+				})
+				/* 接收下载任务 */
+				worker.onmessage = function(event) {
+					_self._console(`render x:${event.data.x} y:${event.data.y} level:${event.data.level}`);
+					/* 判断是否存在 */
+					let renderEntity = _self._entities.getById(event.data.key);
+					if (renderEntity !== undefined) {
+						let key = event.data.key;
+						const canvas = _self._createCanvas(event.data, event.data.image, _self._isDebug);
+						renderEntity.rectangle.material = canvas;
+					}
+					worker.terminate();
+				}
+			}
+		}
+		/* 重启计算标志 */
+		this._isUpdateTile = true;
+	}
+
+	/**
+	 * 渲染单个瓦片到视图中
+	 * @param {Object} tile
+	 */
+	_renderSimpleTileToViewer(tile) {
+		/* 创建画布 */
+		const canvas = this._createCanvas(tile, undefined, this._isDebug);
+		let bjPositions = this._calculateRectangleOutlineCoordinates(tile
+			.rectangle);
+		let tileEntity = new Cesium.Entity({
+			name: this._renderName,
+			id: tile.key,
+			rectangle: {
+				coordinates: tile.rectangle,
+				material: canvas,
+			},
+			polyline: {
+				positions: bjPositions,
+				material: Cesium.Color.YELLOW.withAlpha(this._isDebug ? 1 : 0),
+				width: 1,
+				clampToGround: true, //开启贴地 如果有模型则贴模型
+			}
+		});
+		return this._entities.add(tileEntity);
+	}
+
+	/**
+	 * 根据瓦片创建画布
+	 * @param {Object} tile 瓦片
+	 * @param {Object} image 绘制的图片
+	 * @param {boolean} islabel 是否绘制标签 
+	 */
+	_createCanvas(tile, image, islabel) {
+		/* 获取服务提供者的切片方案 */
+		let provider = this._provider;
+		const canvas = document.createElement("canvas");
+		canvas.width = provider.tileWidth;
+		canvas.height = provider.tileHeight;
+		const context = canvas.getContext("2d");
+		if (image !== undefined) {
+			context.globalAlpha = this._opacity;
+			context.drawImage(event.data.image, 0, 0, canvas.width, canvas.height);
+		}
+		if (islabel !== undefined && islabel === true) {
+			context.globalAlpha = 1.0;
+			/* 创建标签 */
+			context.font = "20px Arial";
+			context.textAlign = "center";
+			context.fillStyle = 'rgba(255,255,0)';
+			context.strokeStyle = 'rgba(255,255,255,1)';
+			context.lineWidth = 2;
+			context.strokeText(`L: ${tile.level}`, 126, 86);
+			context.fillText(`L: ${tile.level}`, 126, 86);
+			context.strokeText(`X: ${tile.x}`, 126, 136);
+			context.fillText(`X: ${tile.x}`, 126, 136);
+			context.strokeText(`Y: ${tile.y}`, 126, 186);
+			context.fillText(`Y: ${tile.y}`, 126, 186);
+		}
+		/* 返回画布 */
+		return canvas;
+	}
+
+	/**
+	 * 投影当前瓦片
+	 * @param {Object} tile
+	 */
+	_projectionTile(tile) {
+		/* 获取矩形 */
+		let rectangle = tile._rectangle;
+		// let imageryLevel = parseInt(tile.level) + 1;
+		let imageryLevel = parseInt(tile.level);
+		let mercatorTilingScheme = this._provider.tilingScheme;
+		let res = [];
+		/* 先判断当前的切片范围是否与提供者的数据范围有交集 */
+		let interRectangle = Cesium.Rectangle.intersection(rectangle, this._rectangle);
+		/* 如果当前计算的瓦片与数据范围无交集 则舍弃 */
+		if (interRectangle === undefined) return res;
+		/* 判断北西角点的墨卡托投影瓦片信息 */
+		let northwestTileCoordinates = mercatorTilingScheme.positionToTileXY(
+			Cesium.Rectangle.northwest(rectangle),
+			imageryLevel
+		);
+		/* 判断南东角点的墨卡托投影瓦片信息 */
+		let southeastTileCoordinates = mercatorTilingScheme.positionToTileXY(
+			Cesium.Rectangle.southeast(rectangle),
+			imageryLevel
+		);
+		/* 根据不同类型分别进行计算 */
+		if (northwestTileCoordinates !== undefined && southeastTileCoordinates !== undefined) {
+			for (let i = northwestTileCoordinates.x; i <= southeastTileCoordinates.x; i++) {
+				for (let j = northwestTileCoordinates.y; j <= southeastTileCoordinates.y; j++) {
+					let _webRectangle = mercatorTilingScheme.tileXYToRectangle(i, j, imageryLevel);
+					if (Cesium.Rectangle.intersection(_webRectangle, this._rectangle)) {
+						res.push({
+							x: i,
+							y: j,
+							level: imageryLevel,
+							rectangle: _webRectangle,
+						});
+					}
+				}
+			}
+		} else if (northwestTileCoordinates !== undefined) {
+			let _webRectangle = mercatorTilingScheme.tileXYToRectangle(northwestTileCoordinates.x,
+				northwestTileCoordinates.y,
+				imageryLevel);
+			if (Cesium.Rectangle.intersection(_webRectangle, this._rectangle)) {
+				res.push({
+					x: northwestTileCoordinates.x,
+					y: northwestTileCoordinates.y,
+					level: imageryLevel,
+					rectangle: _webRectangle,
+				});
+			}
+		} else if (southeastTileCoordinates !== undefined) {
+			let _webRectangle = mercatorTilingScheme.tileXYToRectangle(southeastTileCoordinates.x,
+				southeastTileCoordinates.y,
+				imageryLevel);
+			if (Cesium.Rectangle.intersection(_webRectangle, this._rectangle)) {
+				res.push({
+					x: southeastTileCoordinates.x,
+					y: southeastTileCoordinates.y,
+					level: imageryLevel,
+					rectangle: _webRectangle,
+				});
+			}
+		}
+		return res;
+	}
+
+	/**
+	 * 计算矩形的外围坐标串
+	 * @param {Cesium.Rectangle} rectangle 矩形
+	 * @return {Array<Cesium.Cartesian3>} 坐标串集合
+	 */
+	_calculateRectangleOutlineCoordinates(rectangle) {
+		/* 计算东南角 */
+		let south_east = Cesium.Rectangle.southeast(rectangle);
+		let se = Cesium.Cartographic.toCartesian(south_east);
+		/* 计算西南角 */
+		let south_west = Cesium.Rectangle.southwest(rectangle);
+		let sw = Cesium.Cartographic.toCartesian(south_west);
+		/* 计算东北角 */
+		let north_east = Cesium.Rectangle.northeast(rectangle);
+		let ne = Cesium.Cartographic.toCartesian(north_east);
+		/* 计算西北角 */
+		let north_west = Cesium.Rectangle.northwest(rectangle);
+		let nw = Cesium.Cartographic.toCartesian(north_west);
+		return [sw, se, ne, nw, sw];
+	}
+
+	/**
+	 * 根据Entity的名称批量删除Entity
+	 * @param {String} entityName 实体名称
+	 */
+	_removeEntityByName(entityName) {
+		/* 获取实体集合 */
+		var entities = this._entities;
+		/* 如果不存在实体集合或集合中没有数据 则返回 */
+		if (!entities || !entities.values) return;
+		var delEntitys = [];
+		/* 循环获取当前集合中的所有实体 */
+		for (var i = 0; i < entities.values.length; i++) {
+			if (entities.values[i].name == entityName) {
+				delEntitys.push(entities.values[i]);
+			}
+		}
+		/* 删除符合条件的所有实体 */
+		for (var i = 0; i < delEntitys.length; i++) {
+			entities.remove(delEntitys[i]);
+		}
+	}
+}
+
+/* 对外方法 */
+Object.assign(CrImageServerLayer.prototype, {
+	/**
+	 * 隐藏
+	 */
+	hide: function() {
+		this._console('隐藏');
+		this._isUpdateTile = false;
+		/* 清理资源 */
+		this._removeEntityByName(this._renderName);
+		/* 清理渲染 */
+		this._renderEntities.clear();
+	},
+
+	/**
+	 * 显示
+	 */
+	show: function() {
+		this._console('显示');
+		this._isUpdateTile = true;
+	},
+
+	/**
+	 * 设置透明度
+	 * @param {Number} opacity [0-1]
+	 */
+	setOpacity: function(opacity) {
+		if (opacity === undefined || typeof opacity !== 'number') return;
+		if (opacity >= 1) this._opacity = 1.0;
+		if (opacity <= 0) this._opacity = 0.0;
+		this._opacity = parseFloat(opacity);
+	}
+
+})
+
+/* 下载线程函数 */
+function downloadWorker() {
+	/* 接收主线程发送的文件下载请求 */
+	onmessage = function(event) {
+		let data = event.data;
+		/* 创建下载数据链接 */
+		let url = data.url + '/tile/' + data.level + '/' + data.y + '/' + data.x;
+		/* 创建下载相关 并下载 */
+		let xhr = new XMLHttpRequest();
+		xhr.open('get', url, true);
+		xhr.responseType = "blob"; //设置返回类型,此处我用于下载文件 所以返回blob
+		xhr.onload = function() {
+			// 请求完成
+			if (this.status === 200) {
+				var blob = this.response;
+				var bmpPromise = createImageBitmap(blob, {
+					imageOrientation: "none",
+					premultiplyAlpha: "none",
+					colorSpaceConversion: "default",
+				});
+				bmpPromise.then(function(image) {
+					let outObj = {
+						key: data.key,
+						x: data.x,
+						y: data.y,
+						level: data.level,
+						image: image,
+					}
+					postMessage(outObj);
+				})
+			} else {
+				console.log('===>>>', url + ' Not found');
+			}
+		}
+		/* 发送请求 */
+		xhr.send();
+	}
+}
+
+/* 输出类 */
+export default CrImageServerLayer

+ 2 - 1
src/components/CrMap/CrMap.js

@@ -974,7 +974,8 @@ Object.assign(CrMap.prototype, {
 	addFloatLayer(options, callSuccess) {
 		let layer = new CrImageServerLayer({
 			viewer: this._viewer,
-			url: options.url,
+			providerType: options.providerType,
+			config: options,
 			opacity: options.opacity,
 			show: true,
 		});

+ 43 - 13
src/components/CrMap/CrMap.vue

@@ -448,17 +448,17 @@ onMounted(() => {
 	});
 
 	/* 添加模版影像地图 */
-	proxy.CMapApi.addLayer({
-		layId: 'mpYxt',
-		layName: '牟平影像图',
-		layType: CrMap.LayerType.templateLayer,
-		isShow: true,
-		config: {
-			url: 'http://202.102.167.52:16282/geoserver/gwc/service/tms/1.0.0/ytmp%3Atdt@EPSG%3A900913@png/{z}/{x}/{reverseY}.png',
-			minimumLevel: 0,
-			maximumLevel: 18
-		}
-	});
+	// proxy.CMapApi.addLayer({
+	// 	layId: 'mpYxt',
+	// 	layName: '牟平影像图',
+	// 	layType: CrMap.LayerType.templateLayer,
+	// 	isShow: true,
+	// 	config: {
+	// 		url: 'http://202.102.167.52:16282/geoserver/gwc/service/tms/1.0.0/ytmp%3Atdt@EPSG%3A900913@png/{z}/{x}/{reverseY}.png',
+	// 		minimumLevel: 0,
+	// 		maximumLevel: 18
+	// 	}
+	// });
 
 	/* 添加网格地图 */
 	// proxy.CMapApi.addLayer({
@@ -467,9 +467,39 @@ onMounted(() => {
 	// 	layType: CrMap.LayerType.floatLayer,
 	// 	isShow: true,
 	// 	config: {
+	// 		providerType: 'ArcGisMapServerImageryProvider',
 	// 		url: 'http://218.59.194.74:6080/arcgis/rest/services/LYLSQ_GHT_102100_202112/MapServer',
-	// 		// url: 'http://218.59.194.74:6080/arcgis/rest/services/LYLSQ_YX_102100_202112/MapServer',
-	// 		opacity: 0.7
+	// 		// url: 'http://218.59.194.82:6080/arcgis/rest/services/LSQZRZY_RE_WEB_V1/MapServer',
+	// 		// layers: '24',
+	// 		opacity: 0.45
+	// 	}
+	// });
+
+	// proxy.CMapApi.addLayer({
+	// 	layId: 'floatGHT',
+	// 	layName: '浮动规划图',
+	// 	layType: CrMap.LayerType.floatLayer,
+	// 	isShow: true,
+	// 	config: {
+	// 		providerType: 'ArcGisMapServerImageryProvider',
+	// 		url: 'http://218.59.194.74:6080/arcgis/rest/services/LYLSQ_YX_102100_202112/MapServer',
+	// 		// url: 'http://218.59.194.82:6080/arcgis/rest/services/LSQZRZY_RE_WEB_V1/MapServer',
+	// 		// layers: '24',
+	// 		opacity: 1.0
+	// 	}
+	// });
+
+	/* 添加网格地图 */
+	// proxy.CMapApi.addLayer({
+	// 	layId: 'floatGHT',
+	// 	layName: '浮动规划图',
+	// 	layType: CrMap.LayerType.floatLayer,
+	// 	isShow: true,
+	// 	config: {
+	// 		providerType: 'UrlTemplateImageryProvider',
+	// 		// url: 'http://202.102.167.52:16282/geoserver/gwc/service/tms/1.0.0/ytmp%3Amap_zrzy_trfhl@EPSG%3A900913@png/{z}/{x}/{reverseY}.png',
+	// 		url: 'http://202.102.167.52:16282/geoserver/gwc/service/tms/1.0.0/ytmp%3Atdt@EPSG%3A900913@png/{z}/{x}/{reverseY}.png',
+	// 		opacity: 1
 	// 	}
 	// });
 

+ 8 - 8
src/components/CrMap/DrawTools.js

@@ -889,7 +889,7 @@ class DrawTools {
  */
 Object.assign(DrawTools.prototype, {
 	/**
-	 * �����������置点击点显示�����标记
+	 * ���������������������������������置点击点显示�����标记
 	 * @param {JSNO} options 配置项
 	 * @param {String} options.lineLabel 线点文字标注
 	 * @param {String} options.polygonLabel 面点文字标注
@@ -1225,12 +1225,12 @@ Object.assign(DrawTools.prototype, {
 		entityParam.outlineWidth = _self._param.outlineWidth;
 		/* 渲染贴地面 */
 		this._drawEntity = this._entities.add(entityPolygon);
-		if (polygonType === undefined || polygonType === DrawTools.PolygonType.NormalPolygon) {
+		if (polygonType !== undefined && polygonType === DrawTools.PolygonType.NormalPolygon) {
 			this._drawEntity.setEntityType(DrawTools.DrawType.Polygon);
 			entityParam.id = DrawTools.DrawType.Polygon;
-		} else if (polygonType != undefined && polygonType === DrawTools.PolygonType.HousePolygon) {
+		} else if (polygonType !== undefined && polygonType === DrawTools.PolygonType.HousePolygon) {
 			this._drawEntity.setEntityType(DrawTools.DrawType.House);
-			entityParam.id = DrawTools.DrawType.HousePolygon;
+			entityParam.id = DrawTools.DrawType.House;
 		}
 		/* 设置实体参数 */
 		this._drawEntity.setParams(entityParam);
@@ -1256,6 +1256,8 @@ Object.assign(DrawTools.prototype, {
 			};
 			this._drawEntity.polyline.positions = this._sketchPoints;
 		} else if (entityType === DrawTools.DrawType.House) {
+			/* 删除底面实体之前获取存储的属性 */
+			let entityParam = this._drawEntity.getParams();
 			/* 删除原来创建的实体 */
 			this._removeEntityByObject(this._drawEntity);
 			/* 创建房屋的高度 */
@@ -1277,8 +1279,6 @@ Object.assign(DrawTools.prototype, {
 			this._drawEntity = this._entities.add(houseEntity);
 			/* 设置实体类型 */
 			this._drawEntity.setEntityType(entityType);
-			/* 房屋附加属性 */
-			let entityParam = this._drawEntity.getParams();
 			entityParam.height = _self._param.wallHeight;
 			entityParam.bottomHeight = height;
 			entityParam.color = _self._param.houseColor;
@@ -2669,7 +2669,7 @@ Object.assign(DrawTools.prototype, {
  */
 Object.assign(DrawTools.prototype, {
 	/**
-	 * 提示标签初始
+	 * 提���标���初���
 	 * @ignore 生成方法时不对外公开
 	 * @param {String} text 显示的文本内���
 	 * @param {JSON} mousePosition 鼠标位置 
@@ -4322,7 +4322,7 @@ Object.assign(DrawTools.prototype, {
 				/* 更新移动点数组 */
 				this._ellipseOutlineCoordinates[i] = position.clone();
 			}
-			/* 更新中心位置数组 */
+			/* ���新中心���置数组 */
 			this._movePoint = endLoc.sLocation;
 		} else {
 			/* 循环���理所有移动点 */

+ 25 - 20
src/components/jt-dialog/dialogEditProperty.vue

@@ -115,6 +115,10 @@ const props = defineProps({
 			type: Number,
 			default: () => 13
 		},
+		bottomHeight: {
+			type: Number,
+			default: () => 0
+		},
 		color: {
 			type: String,
 			default: () => '255,255,0,0.9'
@@ -397,26 +401,27 @@ defineExpose({
  * 提交更改
  */
 function submit() {
-	emit('submit', {
-		id: props.params.id,
-		height: wallHeight.value,
-		color: color.value,
-		direction: directions.filter(item => {
-			return item.key === radioDirection.value;
-		})[0].value,
-		order: orders.filter(item => {
-			return item.key === radioOrder.value;
-		})[0].value,
-		count: yCount.value,
-		text: txtContent.value,
-		lineWidth: lineWidth.value,
-		power: glowPower.value,
-		outlineColor: outlineColor.value,
-		outlineWidth: outlineWidth.value,
-		duration: speed.value * 1000,
-		videoUrl: txtVideoUrl.value,
-		odlineHeight: arcHeight.value
-	});
+	let outParam = DrawTools.initEditPropertyParams();
+	outParam.id = props.params.id;
+	outParam.height = wallHeight.value;
+	outParam.color = color.value;
+	outParam.direction = directions.filter(item => {
+		return item.key === radioDirection.value;
+	})[0].value;
+	outParam.order = orders.filter(item => {
+		return item.key === radioOrder.value;
+	})[0].value;
+	outParam.count = yCount.value;
+	outParam.text = txtContent.value;
+	outParam.lineWidth = lineWidth.value;
+	outParam.power = glowPower.value;
+	outParam.outlineColor = outlineColor.value;
+	outParam.outlineWidth = outlineWidth.value;
+	outParam.duration = speed.value * 1000;
+	outParam.videoUrl = txtVideoUrl.value;
+	outParam.odlineHeight = arcHeight.value;
+	outParam.bottomHeight = props.params.bottomHeight;
+	emit('submit', outParam);
 	dialogVisible.value = false;
 }
 

+ 23 - 0
src/demo.html

@@ -70,5 +70,28 @@
 	</body>
 </html>
 <script>
+	let json = [{
+		name: '你好',
+	}]
 
+	function test() {
+		json[0].name = '测试';
+	}
+
+	let kkk = [];
+	for (let i = 0; i < json.length; i++) {
+		let mmm = JSON.stringify(json[i]);
+
+		kkk.push(JSON.parse(mmm));
+	}
+
+	function mmm(www) {
+		setTimeout(function() {
+			console.log(json[0].name);
+			console.log(www[0].name);
+			mmm(www);
+		}, 1000);
+	}
+
+	mmm(kkk);
 </script>