Browse Source

悬浮图层(浮动于实景三维之上)基本完成

不会爬树的猴 2 years ago
parent
commit
7c3403f0d8

+ 42 - 0
public/worker/demo.js

@@ -0,0 +1,42 @@
+var count = 0;
+
+/**
+ * 下载图片
+ * @param {String} url 图片下载地址
+ */
+function downloadImage(url, callSuccess) {
+	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) {
+				callSuccess(image);
+			})
+		} else {
+			console.log(url + ' Not found');
+		}
+	}
+	/* 发送请求 */
+	xhr.send();
+}
+
+/* 接收主线程发送的文件下载请求 */
+onmessage = function(event) {
+	this._data = event.data;
+	let url = this._data.url + '/tile/' + this._data.level + '/' + this._data.y + '/' + this._data.x;
+	/* 发送请求下载文件 */
+	downloadImage(url, function(image) {
+		postMessage({
+			key: this._data.key,
+			image: image,
+		});
+	})
+}

+ 46 - 0
public/worker/download.js

@@ -0,0 +1,46 @@
+var data = 0;
+
+/**
+ * 下载图片
+ * @param {String} url 图片下载地址
+ */
+function downloadImage(url, callSuccess) {
+	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) {
+				callSuccess(image);
+			})
+		} else {
+			console.log('===>>>', url + ' Not found');
+		}
+	}
+	/* 发送请求 */
+	xhr.send();
+}
+
+/* 接收主线程发送的文件下载请求 */
+onmessage = function(event) {
+	data = event.data;
+	let url = data.url + '/tile/' + data.level + '/' + data.y + '/' + data.x;
+	/* 发送请求下载文件 */
+	downloadImage(url, function(image) {
+		let outObj = {
+			key: data.key,
+			x: data.x,
+			y: data.y,
+			level: data.level,
+			image: image,
+		}
+		postMessage(outObj);
+	})
+}

+ 474 - 319
src/components/CrMap/CrImageServerLayer.js

@@ -5,6 +5,7 @@
  * 描述:通过矩形渲染tile,从而达到渲染图片可以浮动在实景三维上面的效果
  */
 
+/* 扩展系统Date属性Format 用于格式化日期 yyMMdd HH:ss:mm */
 Date.prototype.Format = function(fmt) { // author: meizz 
 	var o = {
 		"M+": this.getMonth() + 1, // 月份 
@@ -24,8 +25,7 @@ Date.prototype.Format = function(fmt) { // author: meizz
 
 /* 引入Cesium */
 import * as Cesium from 'cesium';
-
-import CrImageMaterialProperty from './CrImageMaterialProperty.js'
+// import Worker from '../../../public/worker/download.js?worker';
 
 /* 创建类 */
 class CrImageServerLayer {
@@ -33,29 +33,35 @@ class CrImageServerLayer {
 	 * 构造函数
 	 * @param {Cesium.Viewer} options.viewer 地图视图容器
 	 * @param {String} options.url 服务地址
-	 * @param {Number} options.opacity 图层透明度 [默认0.3]    
+	 * @param {Number} options.opacity 图层透明度[0.0~1.0] [默认0.3]    
 	 */
 	constructor({
 		viewer,
 		url,
-		opacity = 0.3
+		opacity = 0.75,
+		show = true,
 	} = {}) {
+		/* 地图视图 外部传入 必须参数 */
 		this._viewer = viewer;
+		/* 服务地址 外部传入 */
 		this._url = url;
+		/* 透明度 外部传入 */
 		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._isUpdateTile = show;
+		/* 是否输出测试信息 */
+		this._isDebug = false;
+		/* 初始化 */
 		this._init();
-		this._isUpdateTile = true;
-		this._updateTiles = new Map();
-	}
-
-	/**
-	 * 控制台输出
-	 * @param {Object} params 参数集合
-	 */
-	_console(params) {
-		console.log('CrImageServerLayer', params);
 	}
 
 	/**
@@ -63,365 +69,440 @@ class CrImageServerLayer {
 	 */
 	_init() {
 		let _self = this;
-		//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
-		let baseUrl =
-			'http://218.59.194.74:6080/arcgis/rest/services/LYLSQ_GHT_102100_202112/MapServer';
+		/* 创建服务提供者 */
 		this._provider = new Cesium.ArcGisMapServerImageryProvider({
-			url: baseUrl,
+			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 === true) {
-					_self._updateRenderTile();
+				if (_self._isUpdateTile) {
+					/* 设置运行标志为false 等待计算完成 */
+					_self._isUpdateTile = false;
+					/* 投影瓦片集合 */
+					_self._renderTiles();
 				}
 			});
-			_self._viewer.camera.moveEnd.addEventListener(function(event) {
-
-			});
 		})
 	}
 
 	/**
+	 * 生成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(res) {
-		console.log('===' + new Date().Format('yyyy-MM-dd HH:mm:ss') + '>>>', res);
+	_console(...rest) {
+		if (this._isDebug)
+			console.log('===' + new Date().Format('yyyy-MM-dd HH:mm:ss') + '>>>', rest);
 	}
 
 	/**
-	 * 更新渲染的Tile集合
+	 * 渲染瓦片集合
 	 */
-	_updateRenderTile() {
+	_renderTiles() {
 		let _self = this;
-		/* 同步 */
-		let promise = new Promise((resolve, reject) => {
-			_self._isUpdateTile = false;
-			let tilesToRender = _self._viewer.scene.globe._surface._tilesToRender;
-			_self._console(tilesToRender.length);
-			if (tilesToRender.length !== undefined && tilesToRender.length > 0) {
-				let renderTiles = [];
-				for (let i = 0; i < tilesToRender.length; i++) {
-					let renderTile = tilesToRender[i];
-					renderTiles.push(renderTile);
-				}
-				resolve(renderTiles);
-			} else {
-				_self._isUpdateTile = true;
-				reject();
-			}
-		});
-		/* 异步 */
-		promise.then(renderTiles => {
-			_self._calculateRenderTiles(renderTiles);
-		}).catch(error => {
-			_self._console(error);
-		}).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 => {
+				/* 异步重投影瓦片数据集 */
+				_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 {JSON} renderTiles 渲染的瓦片集合
+	 * 投影瓦片集合
+	 * @param {Object} tiles 原始渲染瓦片集合
 	 */
-	_calculateRenderTiles(renderTiles) {
-		let keys = [];
-		for (let i = 0; i < renderTiles.length; i++) {
-			let renderTile = renderTiles[i];
-			/* 计算重投影后的Tiles */
-			let tiles = this._calculateTile(renderTile);
-			for (let tile of tiles) {
-				let key = tile.x + '_' + tile.y + '_' + tile.level;
-				if (!this._updateTiles.has(key)) {
-					this._updateTiles.set(key, {
-						key: key,
-						x: tile.x,
-						y: tile.y,
-						level: tile.level,
-						rectangle: tile.rectangle,
-						state: 1,
-					});
-					this._console('添加动作', key);
+	_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: [],
+						});
+					}
 				}
-				keys.push(key);
 			}
 		}
-		/* 循环剔除 */
-		for (let [key, value] of this._updateTiles) {
-			if (keys.indexOf(key) === -1) {
-				value.state = -1;
-				this._updateTiles.set(key, value);
-				this._console('移除动作', key);
+		/* 清理低层级元素 */
+		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);
 			}
 		}
-		this._isUpdateTile = true;
-		this._render(this._updateTiles);
-		this._console('本次计算结束');
+		/* 将四叉树追加的层级数据加入到渲染集合中 */
+		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);
 	}
 
-	_render(tiles) {
-		let _self = this;
-		for (let [key, tile] of tiles) {
-			this._console('渲染', tile);
-			if (tile.state === 1) {
-				let promise = _self._provider.requestImage(tile.x, tile.y, tile.level);
-				promise.then(function(image) {
-					let canvas = document.createElement("canvas");
-					canvas.width = 256;
-					canvas.height = 256;
-					let context = canvas.getContext("2d");
-					context.drawImage(image, 0, 0, canvas.width, canvas.height);
-					let bjPositions = _self._calculateRectangleOutlineCoordinates(tile.rectangle);
-					let tileEntity = new Cesium.Entity({
-						name: 'AAA',
-						id: tile.key,
-						// rectangle: {
-						// 	coordinates: tileJson.rectangle,
-						// 	material: material, //Cesium.Color.RED.withAlpha(0.9),
-						// },
-						polyline: {
-							positions: bjPositions,
-							material: Cesium.Color.YELLOW,
-							// width: 2,
-							clampToGround: true, //开启贴地 如果有模型则贴模型
-						},
-					});
-					_self._entities.add(tileEntity);
-					image.close();
-					tile.state = 0;
-					tiles.set(key, value);
-				});
-			} else if (tile.state === -1) {
-				this._entities.removeById(tile.key);
-			}
+	/**
+	 * 根据矩形和登记查询高一等级的行列号
+	 * @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: [],
 		}
 	}
 
-	_calculateTile(render) {
-		let tiles = [];
-		/* 定义坐标系统参数 */
-		let mercatorTilingScheme = this._provider.tilingScheme;
-		let imageryLevel = render.level;
-		/* 获取矩形 */
-		let rectangle = render._rectangle;
-		/* 判断北西角点的墨卡托投影瓦片信息 */
-		let northwestTileCoordinates = mercatorTilingScheme.positionToTileXY(
-			Cesium.Rectangle.northwest(rectangle),
-			imageryLevel
-		);
-		if (northwestTileCoordinates !== undefined) {
-			let _webRectangle = mercatorTilingScheme.tileXYToRectangle(northwestTileCoordinates.x,
-				northwestTileCoordinates.y,
-				imageryLevel);
-			tiles.push({
-				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);
-			tiles.push({
-				x: southeastTileCoordinates.x,
-				y: southeastTileCoordinates.y,
-				level: imageryLevel,
-				rectangle: _webRectangle,
-			});
+	/**
+	 * 创建四个高层级的瓦片
+	 * @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 tiles;
+		return results;
 	}
 
-	_initTileGrid() {
+	/**
+	 * 渲染瓦片到视图中
+	 * @param {Object} tiles
+	 */
+	_renderTilesToViewer(tiles) {
 		let _self = this;
-		/* 获取当前渲染的瓦片集合 */
-		let tilesToRender = this._viewer.scene.globe._surface._tilesToRender;
-		/* 定义渲染的矩形集合 */
-		let renderRectangles = {};
-		/* 定义坐标系统参数 */
-		let mercatorTilingScheme = this._provider.tilingScheme;
-		/* 循环处理 */
-		for (let i = 0; i < tilesToRender.length; i++) {
-			let render = tilesToRender[i];
-			let imageryLevel = render.level;
-			/* 获取矩形 */
-			let rectangle = render._rectangle;
-			/* 判断北西角点的墨卡托投影瓦片信息 */
-			let northwestTileCoordinates = mercatorTilingScheme.positionToTileXY(
-				Cesium.Rectangle.northwest(rectangle),
-				imageryLevel
-			);
-			if (northwestTileCoordinates !== undefined) {
-				let _webRectangle = mercatorTilingScheme.tileXYToRectangle(northwestTileCoordinates.x,
-					northwestTileCoordinates.y,
-					imageryLevel);
-				let jsonIndex = '[' + northwestTileCoordinates.x + ',' + northwestTileCoordinates.y + ',' +
-					imageryLevel + ']';
-				if (renderRectangles[jsonIndex] === undefined) {
-					renderRectangles[jsonIndex] = {
-						x: northwestTileCoordinates.x,
-						y: northwestTileCoordinates.y,
-						level: imageryLevel,
-						rectangle: _webRectangle,
-						lineColor: Cesium.Color.YELLOW,
-					}
-				}
+		/* 确定哪些渲染实体已失效 对失效的实体进行清理 */
+		let deleteKeys = [];
+		for (let [key, tile] of this._renderEntities) {
+			let findTile = tiles.find(obj => {
+				return obj.key === key;
+			})
+			if (findTile === undefined) {
+				deleteKeys.push(key);
 			}
-			/* 判断南东角点的墨卡托投影瓦片信息 */
-			let southeastTileCoordinates = mercatorTilingScheme.positionToTileXY(
-				Cesium.Rectangle.southeast(rectangle),
-				imageryLevel
-			);
-			if (southeastTileCoordinates !== undefined) {
-				let _webRectangle = mercatorTilingScheme.tileXYToRectangle(southeastTileCoordinates.x,
-					southeastTileCoordinates.y,
-					imageryLevel);
-				let jsonIndex = '[' + southeastTileCoordinates.x + ',' + southeastTileCoordinates.y + ',' +
-					imageryLevel +
-					']';
-				if (renderRectangles[jsonIndex] === undefined) {
-					renderRectangles[jsonIndex] = {
-						x: southeastTileCoordinates.x,
-						y: southeastTileCoordinates.y,
-						level: imageryLevel,
-						rectangle: _webRectangle,
-						lineColor: Cesium.Color.YELLOW,
+		}
+		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();
 				}
 			}
 		}
-		if (JSON.stringify(renderRectangles) !== '{}') {
-			_self._renderImageToRectangle(renderRectangles);
-		}
+		/* 重启计算标志 */
+		this._isUpdateTile = true;
 	}
 
-	_renderImageToRectangle(tilesJson) {
-		let _self = this;
-		this._removeEntityByName(this._renderName);
-		for (let tile in tilesJson) {
-			let tileJson = tilesJson[tile];
-			let tileRow = tileJson.x;
-			let tileColumn = tileJson.y;
-			let tileLevel = tileJson.level;
-			let entityId = this._renderName + "_" + tileRow + "_" + tileColumn + "_" + tileLevel;
-			/* 查询实体是否存在 */
-			if (_self._entities.getById(entityId) === undefined) {
-				let promise = _self._provider.requestImage(tileRow, tileColumn, tileLevel);
-				promise.then(function(image) {
-					// let data = Cesium.getImagePixels(image, 256, 256);
-					// console.log('===dataAAA>>>', data);
-					let canvas = document.createElement("canvas");
-					canvas.width = 256;
-					canvas.height = 256;
-					let context = canvas.getContext("2d");
-					context.drawImage(image, 0, 0, canvas.width, canvas.height);
-					// context.font = "bold 25px Arial";
-					// context.textAlign = "center";
-					// context.fillStyle = 'rgba(255,255,255,1.0)';
-					// context.fillText(`L: ${tileLevel}`, 124, 86);
-					// context.fillText(`X: ${tileRow}`, 124, 136);
-					// context.fillText(`Y: ${tileColumn}`, 124, 186);
-
-					let imageData = context.getImageData(0, 0, 256, 256);
-					console.log('===dataAAA>>>', imageData);
-					// let newImageData = _self._imageDataVRevert({
-					// 	width: 256,
-					// 	height: 256,
-					// 	data: data,
-					// });
-					// console.log('===data>>>', newImageData);
-					// let newImageData = context.getImageData(0, 0, 256, 256);
-					// context.putImageData(_self._imageDataVRevert(newImageData, imageData), 0, 0);
-
-					// context.putImageData(newImageData, 256, 256);
-					// let material = new Cesium.ImageMaterialProperty({
-					// 	image: canvas,
-					// 	transparent: true,
-					// });
-					// let bjPositions = _self._calculateRectangleOutlineCoordinates(tileJson
-					// 	.rectangle);
-					// /* 计算矩形的中心点 */
-					// let center = Cesium.Rectangle.center(tileJson.rectangle);
-					// let centerPosition = Cesium.Cartesian3.fromRadians(center.longitude, center
-					// 	.latitude,
-					// 	center.height);
-					// let tileEntity = new Cesium.Entity({
-					// 	name: _self._renderName,
-					// 	id: entityId,
-					// 	// position: centerPosition,
-					// 	rectangle: {
-					// 		coordinates: tileJson.rectangle,
-					// 		material: material, //Cesium.Color.RED.withAlpha(0.9),
-					// 	},
-					// 	polyline: {
-					// 		positions: bjPositions,
-					// 		material: Cesium.Color.BLUE,
-					// 		// width: 2,
-					// 		clampToGround: true, //开启贴地 如果有模型则贴模型
-					// 	},
-					// });
-					// _self._entities.add(tileEntity);
-					image.close();
-				})
+	/**
+	 * 渲染单个瓦片到视图中
+	 * @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 {Array[]} sourceData 
+	 * 根据瓦片创建画布
+	 * @param {Object} tile 瓦片
+	 * @param {Object} image 绘制的图片
+	 * @param {boolean} islabel 是否绘制标签 
 	 */
-	_imageDataVRevert(sourceData) {
-		let newData = {
-			width: sourceData.width,
-			height: sourceData.height,
-			data: new Uint8ClampedArray(sourceData.data.length)
+	_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);
 		}
-		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;
-			}
+		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) {
+		/* 获取矩形 */
+		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;
 	}
 
 	/**
@@ -451,7 +532,7 @@ class CrImageServerLayer {
 	 */
 	_removeEntityByName(entityName) {
 		/* 获取实体集合 */
-		var entities = this._viewer.entities;
+		var entities = this._entities;
 		/* 如果不存在实体集合或集合中没有数据 则返回 */
 		if (!entities || !entities.values) return;
 		var delEntitys = [];
@@ -468,5 +549,79 @@ 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);
+	}
+
+})
+
+/* 下载线程函数 */
+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

+ 392 - 0
src/components/CrMap/CrImageServerLayer_back.js

@@ -0,0 +1,392 @@
+/**
+ * 创建者:王成
+ * 操作系统: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 CrImageMaterialProperty from './CrImageMaterialProperty.js'
+
+/* 创建类 */
+class CrImageServerLayer {
+	/**
+	 * 构造函数
+	 * @param {Cesium.Viewer} options.viewer 地图视图容器
+	 * @param {String} options.url 服务地址
+	 * @param {Number} options.opacity 图层透明度 [默认0.3]    
+	 */
+	constructor({
+		viewer,
+		url,
+		opacity = 0.3
+	} = {}) {
+		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._opacity = opacity;
+		this._renderName = 'suiji'; //后期要改成随机字符串
+		this._entities = this._viewer.entities;
+		this._init();
+		this._updateTiles = [];
+		this._isUpdateTile = true;
+	}
+
+	/**
+	 * 初始化
+	 */
+	_init() {
+		let _self = this;
+		this._provider = new Cesium.ArcGisMapServerImageryProvider({
+			url: _self._url,
+		})
+		/* 激活provider 继而获取必要信息 */
+		this._provider.readyPromise.then(function(result) {
+			/* 注册事件 */
+			_self._viewer.scene.postRender.addEventListener(() => {
+				if (_self._isUpdateTile === true) {
+					_self._console(_self._isUpdateTile);
+					_self._updateRenderTile();
+				}
+			});
+			/* 注册相机场景移动停止事件 */
+			// _self._viewer.camera.moveEnd.addEventListener(() => {
+			// 	_self._console('相机移动结束');
+			// 	_self._updateRenderTile();
+			// })
+		})
+	}
+
+	/**
+	 * 输出消息
+	 * @param {Object} res
+	 */
+	_console(...rest) {
+		console.log('===' + new Date().Format('yyyy-MM-dd HH:mm:ss') + '>>>', rest);
+	}
+
+	/**
+	 * 更新渲染的Tile集合
+	 */
+	_updateRenderTile() {
+		/* 设置更新标志为否 */
+		this._isUpdateTile = false;
+		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('执行结束');
+		});
+	}
+
+	/**
+	 * 投影当前瓦片
+	 * @param {Object} tile
+	 */
+	_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;
+	}
+
+	/**
+	 * 计算渲染的瓦片集合
+	 * @param {JSON} renderTiles 渲染的瓦片集合
+	 */
+	_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;
+				})
+				if (subTile === undefined) {
+					this._updateTiles.push({
+						key: key,
+						x: tile.x,
+						y: tile.y,
+						level: tile.level,
+						rectangle: tile.rectangle,
+					});
+				}
+			}
+		}
+		/* 判断是否有需要渲染的瓦片 有则渲染 */
+		if (this._updateTiles.length > 0) {
+			this._renderTiles();
+		} else {
+			this._isUpdateTile = true;
+		}
+	}
+
+	/**
+	 * 渲染瓦片集
+	 */
+	_renderTiles() {
+		this._console(this._updateTiles);
+		// this._removeEntityByName('AAA');
+		// this._renderTileToVierer(0);
+		this._isUpdateTile = true;
+	}
+
+	/**
+	 * 渲染瓦片到地图上
+	 * @param {Number} index
+	 */
+	_renderTileToVierer(index) {
+		let _self = this;
+		if (index === this._updateTiles.length - 1) {
+			this._isUpdateTile = true;
+			return;
+		}
+		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);
+
+			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;
+			}
+			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);
+		}
+	}
+
+	/**
+	 * 竖向翻转
+	 * @param {Array[]} sourceData 
+	 */
+	_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;
+			}
+		}
+		return newData;
+	}
+
+	/**
+	 * 横向翻转
+	 * @param {Array[]} sourceData 
+	 * @param {Array[]} newData
+	 */
+	_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];
+			}
+		}
+		return newData;
+	}
+
+	/**
+	 * 计算矩形的外围坐标串
+	 * @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._viewer.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]);
+		}
+	}
+}
+
+/* 输出类 */
+export default CrImageServerLayer

+ 59 - 56
src/components/CrMap/CrMap.js

@@ -8,60 +8,60 @@ import ArcgisImageryProvider from './ArcgisImageryProvider.js';
 /* 引入自定义图层 */
 import CrImageServerLayer from './CrImageServerLayer.js';
 
-/* 扩展更改属性 */
-Cesium.TileCoordinatesImageryProvider.prototype.requestImage = function(
-	x,
-	y,
-	level,
-	request
-) {
-	const canvas = document.createElement("canvas");
-	canvas.width = 256;
-	canvas.height = 256;
-	const context = canvas.getContext("2d");
+// /* 扩展更改属性 */
+// Cesium.TileCoordinatesImageryProvider.prototype.requestImage = function(
+// 	x,
+// 	y,
+// 	level,
+// 	request
+// ) {
+// 	const canvas = document.createElement("canvas");
+// 	canvas.width = 256;
+// 	canvas.height = 256;
+// 	const context = canvas.getContext("2d");
 
-	const cssColor = this._color.toCssColorString();
+// 	const cssColor = this._color.toCssColorString();
 
-	context.strokeStyle = cssColor;
-	context.lineWidth = 2;
-	context.strokeRect(1, 1, 255, 255);
+// 	context.strokeStyle = cssColor;
+// 	context.lineWidth = 2;
+// 	context.strokeRect(1, 1, 255, 255);
 
-	context.font = "bold 25px Arial";
-	context.textAlign = "center";
-	context.fillStyle = cssColor;
-	context.fillText(`L: ${level}`, 124, 86);
-	context.fillText(`X: ${x}`, 124, 136);
-	context.fillText(`Y: ${y}`, 124, 186);
+// 	context.font = "bold 25px Arial";
+// 	context.textAlign = "center";
+// 	context.fillStyle = cssColor;
+// 	context.fillText(`L: ${level}`, 124, 86);
+// 	context.fillText(`X: ${x}`, 124, 136);
+// 	context.fillText(`Y: ${y}`, 124, 186);
 
-	/* 填充图片试试 */
-	let baseUrl =
-		'http://218.59.194.74:6080/arcgis/rest/services/LYLSQ_GHT_102100_202112/MapServer/Tile/';
-	let imageObj = new Image();
-	imageObj.crossOrigin = "anonymous"; // 添加这行代码
-	imageObj.width = 256;
-	imageObj.height = 256;
-	imageObj.style.opacity = 0.3;
-	/* 做个转换 */
-	let rectangle = this._tilingScheme.tileXYToNativeRectangle(x, y, level);
-	// if (this.onRequestRectangle) this.onRequestRectangle(x, y, level, rectangle);
-	// return Promise.resolve(canvas);
-	return new Promise(function(resolve, reject) {
-		imageObj.onload = function() {
-			console.log('===>>>', '填充图片');
-			context.fillStyle = context.createPattern(imageObj, 'no-repeat');
-			context.fillRect(0, 0, 256, 256);
-			resolve(canvas);
-			// let entity = new Cesium.Entity({
-			// 	rectangle: {
-			// 		coordinates: rectangle,
-			// 		material: Cesium.Color.RED,
-			// 	}
-			// });
-			// resolve(entity);
-		}
-		imageObj.src = baseUrl + level + '/' + y + '/' + x;
-	})
-};
+// 	/* 填充图片试试 */
+// 	let baseUrl =
+// 		'http://218.59.194.74:6080/arcgis/rest/services/LYLSQ_GHT_102100_202112/MapServer/Tile/';
+// 	let imageObj = new Image();
+// 	imageObj.crossOrigin = "anonymous"; // 添加这行代码
+// 	imageObj.width = 256;
+// 	imageObj.height = 256;
+// 	imageObj.style.opacity = 0.3;
+// 	/* 做个转换 */
+// 	let rectangle = this._tilingScheme.tileXYToNativeRectangle(x, y, level);
+// 	// if (this.onRequestRectangle) this.onRequestRectangle(x, y, level, rectangle);
+// 	// return Promise.resolve(canvas);
+// 	return new Promise(function(resolve, reject) {
+// 		imageObj.onload = function() {
+// 			console.log('===>>>', '填充图片');
+// 			context.fillStyle = context.createPattern(imageObj, 'no-repeat');
+// 			context.fillRect(0, 0, 256, 256);
+// 			resolve(canvas);
+// 			// let entity = new Cesium.Entity({
+// 			// 	rectangle: {
+// 			// 		coordinates: rectangle,
+// 			// 		material: Cesium.Color.RED,
+// 			// 	}
+// 			// });
+// 			// resolve(entity);
+// 		}
+// 		imageObj.src = baseUrl + level + '/' + y + '/' + x;
+// 	})
+// };
 
 class CrMap {
 	/**
@@ -780,8 +780,8 @@ Object.assign(CrMap.prototype, {
 			this.addAGSVectorLayer(options.config);
 		} else if (options.layType === CrMap.LayerType.templateLayer) {
 			this.addUrlTemplateImageryLayer(options.config);
-		} else if (options.layType === CrMap.LayerType.tileGridLayer) {
-			this.addTileCoordinateImageProvider(options.config);
+		} else if (options.layType === CrMap.LayerType.floatLayer) {
+			this.addFloatLayer(options.config);
 		}
 	},
 
@@ -967,15 +967,18 @@ Object.assign(CrMap.prototype, {
 	},
 
 	/**
-	 * 加载瓦片网格图层
+	 * 添加浮动图层 悬浮于实景三维之上
 	 * @param {Object} options
 	 * @param {Object} callSuccess
 	 */
-	addTileCoordinateImageProvider(options, callSuccess) {
+	addFloatLayer(options, callSuccess) {
 		let layer = new CrImageServerLayer({
 			viewer: this._viewer,
-			url: options.url
+			url: options.url,
+			opacity: options.opacity,
+			show: true,
 		});
+		window[options.id] = layer;
 	}
 })
 
@@ -1015,7 +1018,7 @@ CrMap.LayerType = Object.freeze({
 	geoJsonLayer: 'geoJsonLayer', //geoJson 类型图层
 	imageLayer: 'imageLayer', //叠加三维的图片图层
 	templateLayer: 'templateLayer', //模版类型图层
-	tileGridLayer: 'tileGridLayer', //网格
+	floatLayer: 'floatLayer', //浮动图层
 })
 
 /* 输出 */

+ 27 - 4
src/components/CrMap/CrMap.vue

@@ -1,5 +1,9 @@
 <template>
 	<div id="cesiumContainer" class="jt-map"></div>
+	<div class="jt-map-tools">
+		<button @click="openFloatLayer()">打开浮动图层</button>
+		<button @click="closeFloatLayer()">关闭浮动图层</button>
+	</div>
 </template>
 <script setup>
 import { param } from 'jquery';
@@ -311,6 +315,17 @@ defineExpose({
 		});
 	}
 });
+
+const openFloatLayer = function() {
+	/* 添加网格地图 */
+	window['floatGHT'].show();
+};
+
+const closeFloatLayer = function() {
+	console.log(window['floatGHT']);
+	window['floatGHT'].hide();
+};
+
 /* 初始化 */
 onMounted(() => {
 	let _self = proxy;
@@ -431,12 +446,14 @@ onMounted(() => {
 
 	/* 添加网格地图 */
 	proxy.CMapApi.addLayer({
-		layId: 'ghtGrid',
-		layName: '规划图网格',
-		layType: CrMap.LayerType.tileGridLayer,
+		layId: 'floatGHT',
+		layName: '浮动规划图',
+		layType: CrMap.LayerType.floatLayer,
 		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'
+			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
 		}
 	});
 
@@ -498,6 +515,12 @@ onMounted(() => {
 	background-color: blue;
 }
 
+.jt-map-tools {
+	position: absolute;
+	left: 100px;
+	top: 30px;
+}
+
 .cesium-performanceDisplay-defaultContainer {
 	top: unset !important;
 	bottom: 100px !important;

+ 5 - 2
src/components/CrMap/DrawTools.js

@@ -1463,7 +1463,7 @@ Object.assign(DrawTools.prototype, {
 		} else if (entityType === DrawTools.DrawType.House) {
 			/* 删除原来创�����的实体 */
 			this._removeEntityByObject(this._drawEntity);
-			/* ���������������������������������������������������������������������建房屋的高度 */
+			/* �������������������������������������������������������������������������������建房屋的高度 */
 			let height = parseFloat(this._sketchOutputPoints[0].height);
 			let houseHeight = height + 30;
 			/* 创建一个房屋实体 */
@@ -3292,6 +3292,7 @@ Object.assign(DrawTools.prototype, {
 				let centerPosition = entity.position._value;
 				/* 获取圆的半径 */
 				let radius = entity.ellipse.semiMajorAxis._value;
+				console.log("===>>>", centerPosition, radius);
 				let cbPoint = this._calculateCircleBoundaryPoint(centerPosition, radius);
 				return [centerPosition, cbPoint];
 			} else if (editEntityType === DrawTools.DrawType.NormalWall || editEntityType === DrawTools
@@ -3427,6 +3428,7 @@ Object.assign(DrawTools.prototype, {
 		};
 		let _self = this;
 		/* 设置实体类型 返回该实体用于绘制的点集合*/
+		console.log("===当前可编辑实体>>>", editEntity);
 		let positions = this._getEntityEditData(editEntity);
 		/* 删除所有临时绘制的点 */
 		this._removePointEntitys();
@@ -3865,7 +3867,8 @@ Object.assign(DrawTools.prototype, {
 			if (_self._editEntity.polyline != undefined) {
 				_self._editEntity.polyline.positions = _self._rectangleOutlineCoordinates;
 			}
-		} else if (entityType === DrawTools.DrawType.Circle) {
+		} else if (entityType === DrawTools.DrawType.Circle || entityType === DrawTools.DrawType
+			.DynamicCircle) {
 			/* 移动的是圆的点 需要特殊处理 */
 			_self._editEntity.ellipse.semiMajorAxis = _self._sketchEllipseRadius;
 			_self._editEntity.ellipse.semiMinorAxis = _self._sketchEllipseRadius;

+ 1 - 1
src/components/jt-dialog/dialogEditProperty.vue

@@ -307,7 +307,7 @@ function updateParams(params) {
 	glowPower.value = params.power;
 	outlineColor.value = params.outlineColor;
 	outlineWidth.value = params.outlineWidth;
-	console.log('===设置参数显示>>>', params.lineWidth);
+	// console.log('===设置参数显示>>>', params.lineWidth);
 }
 
 /**

+ 130 - 6
src/demo.html

@@ -3,17 +3,141 @@
 	<head>
 		<meta charset="utf-8">
 		<title></title>
+		<style>
+			.jt-draw-tools-main {
+				width: 300px;
+				height: 400px;
+				position: absolute;
+				top: 100px;
+				left: 100px;
+				display: flex;
+				flex-direction: column;
+				border-radius: 5px;
+				/* 为了避免设置border-radius导致顶部覆盖底部进而显示不出来 */
+				overflow: auto;
+			}
+
+			.jt-draw-tools-main .top-head {
+				width: 100%;
+				height: 40px;
+				background-color: rgb(0, 0, 191);
+				display: flex;
+				justify-content: center;
+				align-items: center;
+				color: rgba(255, 255, 255, 1);
+				font-size: 15px;
+			}
+
+			.jt-draw-tools-main .top-head:after {
+				width: 100%;
+				position: absolute;
+				height: 1.5px;
+				background: #fff;
+				content: "";
+				top: 9px;
+				left: 0;
+				transform: rotate(134deg);
+				-ms-transform: rotate(134deg);
+				-moz-transform: rotate(134deg);
+				-webkit-transform: rotate(134deg);
+				-o-transform: rotate(134deg);
+
+			}
+
+			.jt-draw-tools-main .top-head:before {
+				width: 100%;
+				position: absolute;
+				height: 1.5px;
+				background: #fff;
+				content: "";
+				top: 9px;
+				right: 0;
+				transform: rotate(45deg);
+				-ms-transform: rotate(45deg);
+				-moz-transform: rotate(45deg);
+				-webkit-transform: rotate(45deg);
+				-o-transform: rotate(45deg);
+			}
+
+			.jt-draw-tools-main .content {
+				background-color: rgba(1, 26, 83, 0.85);
+				width: 100%;
+				height: calc(100% - 40px);
+			}
+		</style>
 	</head>
-	<body style="background-color: blue;">
+	<body>
 		<button onclick="test()">测试</button>
+		<button onclick="test1111()">测试1111</button>
+		<!-- <div class="jt-draw-tools-main">
+			<div class="top-head">编辑框</div>
+			<div class="content"></div>
+		</div> -->
+		<canvas id="canvas"></canvas>
+		<div id="viewText">mmmm</div>
 	</body>
 </html>
 <script>
+	if (typeof(Worker) !== "undefined") {
+		console.log('支持 Web worker!');
+	} else {
+		console.log('抱歉!不支持 Web Worker!');
+	}
+
+	let viewText = document.getElementById('viewText');
+	let canvas = document.getElementById('canvas');
+	canvas.width = 256;
+	canvas.height = 256;
+	let context = canvas.getContext('2d');
+
+
 	function test() {
-		let a = '王成';
-		let b = '周仁将';
-		let message = `欢迎 ${a} ${b}`;
-		console.log(message);
+		let worker = new Worker('./worker/worker_demo.js');
+		worker.onmessage = function(event) {
+			console.log(event.data);
+			context.drawImage(event.data, 0, 0, 256, 256);
+		}
+		worker.postMessage({
+			url: 'http://218.59.194.74:6080/arcgis/rest/services/LYLSQ_YX_102100_202210/MapServer/tile/15/12953/27142'
+		})
+	}
+
+	let res = [{
+			x: 1,
+			y: 1,
+			level: 3
+		}, {
+			x: 1,
+			y: 2,
+			level: 5,
+		},
+		{
+			x: 1,
+			y: 1,
+			level: 5,
+		}
+	]
+
+	let mmm = {
+		x: 1,
+		y: 1,
+		level: 3
+	}
+
+	function test1111() {
+		let mks = [];
+		for (let i = 0; i < res.length; i++) {
+			let aaa = res[i];
+			let sub = mks.find(obj => {
+				return obj.x === aaa.x && obj.y === aaa.y;
+			})
+			if (sub === undefined) {
+				mks.push(aaa);
+			}
+		}
+		console.log('执行...');
+		console.log(mks)
+
+
 	}
-	let img = new Image();
 </script>

+ 2 - 2
src/pages/tab-cmap.vue

@@ -422,7 +422,7 @@ export default {
 		 * @param {JSON} param 传递的编辑参数
 		 */
 		onEditProperty(param) {
-			console.log('===传递参数,打开编辑框>>>', param);
+			// console.log('===传递参数,打开编辑框>>>', param);
 			/* 打开对话框 */
 			this.showEditDialog = true;
 			/* 赋值参数 */
@@ -437,7 +437,7 @@ export default {
 		 * @param {JSON} param 参数
 		 */
 		submit(param) {
-			console.log(param);
+			// console.log(param);
 			this.$refs['cmap'].onSubmitEditProperty(param);
 		}
 	}

+ 39 - 0
src/worker/worker_demo.js

@@ -0,0 +1,39 @@
+var count = 0;
+
+/**
+ * 下载图片
+ * @param {String} url 图片下载地址
+ */
+function downloadImage(url, callSuccess) {
+	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) {
+				callSuccess(image);
+			})
+		} else {
+			console.log(url + ' Not found');
+		}
+	}
+	/* 发送请求 */
+	xhr.send();
+}
+
+/* 接收主线程发送的文件下载请求 */
+onmessage = function(event) {
+	this._data = event.data;
+	let url = event.data.url;
+	/* 发送请求下载文件 */
+	downloadImage(url, function(image) {
+		postMessage(image);
+	})
+}