|
@@ -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
|