refactor(map): 迁移至 Cesium 模块化导入

master
LiuJiaNan 2026-08-21 15:03:50 +08:00
parent 9f3bf572fd
commit 6c3cac4dc1
11 changed files with 288 additions and 314 deletions

View File

@ -1,3 +1,14 @@
const path = require("node:path");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const webpack = require("webpack");
const cesiumBuildPath = path.join(
path.dirname(require.resolve("cesium/package.json")),
"Build/Cesium",
);
const appIdentifier = "bi-h5";
const cesiumStaticPath = `${appIdentifier}/static/cesium`;
module.exports = { module.exports = {
// 应用后端git地址部署上线需要 // 应用后端git地址部署上线需要
javaGit: "<git-url>", javaGit: "<git-url>",
@ -9,7 +20,7 @@ module.exports = {
// 应用后端分支名称,部署上线需要 // 应用后端分支名称,部署上线需要
javaGitBranch: "<branch-name>", javaGitBranch: "<branch-name>",
// 接口服务地址 // 接口服务地址
API_HOST: "https://gbs-gateway.qhdsafety.com", API_HOST: "http://192.168.198.8:30140",
}, },
production: { production: {
// 应用后端分支名称,部署上线需要 // 应用后端分支名称,部署上线需要
@ -19,7 +30,7 @@ module.exports = {
}, },
}, },
// 应用唯一标识符 // 应用唯一标识符
appIdentifier: "bi-h5", appIdentifier,
// 应用上下文注入全局变量 // 应用上下文注入全局变量
contextInject: { contextInject: {
// 应用Key // 应用Key
@ -71,5 +82,16 @@ module.exports = {
// 自动注入编译后的文件到public/index.html中 // 自动注入编译后的文件到public/index.html中
inject: true, inject: true,
}, },
plugins: [
new CopyWebpackPlugin({
patterns: ["Assets", "ThirdParty", "Widgets", "Workers"].map(name => ({
from: path.join(cesiumBuildPath, name),
to: `${cesiumStaticPath}/${name}`,
})),
}),
new webpack.DefinePlugin({
CESIUM_BASE_URL: JSON.stringify(`/${cesiumStaticPath}/`),
}),
],
}, },
}; };

View File

@ -28,6 +28,7 @@
"animate.css": "^4.1.1", "animate.css": "^4.1.1",
"antd": "6.5.0", "antd": "6.5.0",
"autofit.js": "^3.2.8", "autofit.js": "^3.2.8",
"cesium": "1.144.0",
"dayjs": "^1.11.7", "dayjs": "^1.11.7",
"echarts": "^6.0.0", "echarts": "^6.0.0",
"immer": "^11.1.4", "immer": "^11.1.4",

View File

@ -52,6 +52,4 @@
<% const { root } = $element; %> <% const { root } = $element; %>
<div id="<%= root.id %>" style="width: 100%; height: 100%; position: relative;overflow-y: auto;"></div> <div id="<%= root.id %>" style="width: 100%; height: 100%; position: relative;overflow-y: auto;"></div>
</body> </body>
<script src="https://cesium.com/downloads/cesiumjs/releases/1.91/Build/Cesium/Cesium.js"></script>
<link href="https://cesium.com/downloads/cesiumjs/releases/1.91/Build/Cesium/Widgets/widgets.css" rel="stylesheet">
</html> </html>

View File

@ -1,4 +1,13 @@
const Cesium = window.Cesium; import {
Cartesian2,
Cartographic,
Cesium3DTileFeature,
Cesium3DTileset,
Math as CesiumMath,
EllipsoidTerrainProvider,
Model,
SceneTransforms,
} from "cesium";
export class Coord { export class Coord {
viewer; viewer;
@ -18,19 +27,19 @@ export class Coord {
if (!Number.isNaN(Number(i))) { if (!Number.isNaN(Number(i))) {
const pick = picks[i]; const pick = picks[i];
isOn3dtiles isOn3dtiles
= (pick && pick.primitive instanceof Cesium.Cesium3DTileFeature) = (pick && pick.primitive instanceof Cesium3DTileFeature)
|| (pick && pick.primitive instanceof Cesium.Cesium3DTileset) || (pick && pick.primitive instanceof Cesium3DTileset)
|| (pick && pick.primitive instanceof Cesium.Model); || (pick && pick.primitive instanceof Model);
if (isOn3dtiles) { if (isOn3dtiles) {
viewer.scene.pick(position); viewer.scene.pick(position);
cartesian3 = viewer.scene.pickPosition(position); cartesian3 = viewer.scene.pickPosition(position);
if (cartesian3) { if (cartesian3) {
const cartographic const cartographic
= Cesium.Cartographic.fromCartesian(cartesian3); = Cartographic.fromCartesian(cartesian3);
if (cartographic.height < 0) if (cartographic.height < 0)
cartographic.height = 0; cartographic.height = 0;
const lon = Cesium.CesiumMath.toDegrees(cartographic.longitude); const lon = CesiumMath.toDegrees(cartographic.longitude);
const lat = Cesium.CesiumMath.toDegrees(cartographic.latitude); const lat = CesiumMath.toDegrees(cartographic.latitude);
const height = cartographic.height; const height = cartographic.height;
cartesian3 = this.lnglatToCartesian3(lon, lat, height); cartesian3 = this.lnglatToCartesian3(lon, lat, height);
return cartesian3; return cartesian3;
@ -42,7 +51,7 @@ export class Coord {
// 不在模型上 // 不在模型上
if (!isOn3dtiles) { if (!isOn3dtiles) {
const isTerrain const isTerrain
= viewer.terrainProvider instanceof Cesium.EllipsoidTerrainProvider; // 是否存在地形 = viewer.terrainProvider instanceof EllipsoidTerrainProvider; // 是否存在地形
if (!isTerrain) { if (!isTerrain) {
// 无地形 // 无地形
const ray = viewer.scene.camera.getPickRay(position); const ray = viewer.scene.camera.getPickRay(position);
@ -80,7 +89,7 @@ export class Coord {
} }
cartesian3ToCartesian2(cartesian3) { cartesian3ToCartesian2(cartesian3) {
return Cesium.SceneTransforms.wgs84ToWindowCoordinates( return SceneTransforms.worldToWindowCoordinates(
this.viewer.scene, this.viewer.scene,
cartesian3, cartesian3,
); );
@ -92,7 +101,7 @@ export class Coord {
if (typeof extend === "undefined") { if (typeof extend === "undefined") {
const coordToLonlat = (viewer, x, y) => { const coordToLonlat = (viewer, x, y) => {
const { camera, scene } = viewer; const { camera, scene } = viewer;
const d2 = new Cesium.Cartesian2(x, y); const d2 = new Cartesian2(x, y);
const ellipsoid = scene.globe.ellipsoid; const ellipsoid = scene.globe.ellipsoid;
// 2D转3D世界坐标 // 2D转3D世界坐标
const d3 = camera.pickEllipsoid(d2, ellipsoid); const d3 = camera.pickEllipsoid(d2, ellipsoid);
@ -101,10 +110,10 @@ export class Coord {
const upperLeftCartographic const upperLeftCartographic
= scene.globe.ellipsoid.cartesianToCartographic(d3); = scene.globe.ellipsoid.cartesianToCartographic(d3);
// 弧度转经纬度 // 弧度转经纬度
const lon = Cesium.CesiumMath.toDegrees( const lon = CesiumMath.toDegrees(
upperLeftCartographic.longitude, upperLeftCartographic.longitude,
); );
const lat = Cesium.CesiumMath.toDegrees( const lat = CesiumMath.toDegrees(
upperLeftCartographic.latitude, upperLeftCartographic.latitude,
); );
return { lon, lat }; return { lon, lat };
@ -134,10 +143,10 @@ export class Coord {
else { else {
// 三维视图 // 三维视图
bounds = [ bounds = [
Cesium.CesiumMath.toDegrees(extend.west), CesiumMath.toDegrees(extend.west),
Cesium.CesiumMath.toDegrees(extend.south), CesiumMath.toDegrees(extend.south),
Cesium.CesiumMath.toDegrees(extend.east), CesiumMath.toDegrees(extend.east),
Cesium.CesiumMath.toDegrees(extend.north), CesiumMath.toDegrees(extend.north),
]; ];
} }
return bounds; return bounds;
@ -168,8 +177,8 @@ export class Coord {
if (cartesian3) { if (cartesian3) {
const radians const radians
= this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian3); = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian3);
const latitude = Cesium.CesiumMath.toDegrees(radians.latitude); // 弧度转度 const latitude = CesiumMath.toDegrees(radians.latitude); // 弧度转度
const longitude = Cesium.CesiumMath.toDegrees(radians.longitude); const longitude = CesiumMath.toDegrees(radians.longitude);
const height = radians.height; const height = radians.height;
return { longitude, latitude, height }; return { longitude, latitude, height };
} }

View File

@ -23,6 +23,7 @@ import {
resetBottomUtilsMittKey, resetBottomUtilsMittKey,
} from "./js/mittKey"; } from "./js/mittKey";
import useInitMap from "./js/useInitMap"; import useInitMap from "./js/useInitMap";
import "cesium/Build/Cesium/Widgets/widgets.css";
function Map(props) { function Map(props) {
const query = useGetUrlQuery(); const query = useGetUrlQuery();

View File

@ -1,16 +1,25 @@
import {
Cartesian3,
Cartographic,
Cesium3DTileset,
Math as CesiumMath,
createGuid,
CustomDataSource,
HeightReference,
HorizontalOrigin,
Matrix4,
VerticalOrigin,
} from "cesium";
import { getBillboardCanvases } from "./utils"; import { getBillboardCanvases } from "./utils";
const Cesium = window.Cesium; // 接口经纬度可能以字符串返回,统一在 Cesium 坐标入口转换为数值。
// 获取经纬度
export const getPosition = (x, y, z = 0.0) => { export const getPosition = (x, y, z = 0.0) => {
return Cesium.Cartesian3.fromDegrees(x, y, z); return Cartesian3.fromDegrees(Number(x), Number(y), Number(z));
}; };
// 创建倾斜摄影 // 创建倾斜摄影
export const createObliquePhotography = (url, viewer) => { export const createObliquePhotography = async (url, viewer) => {
const tileset = new Cesium.Cesium3DTileset({ const tileset = await Cesium3DTileset.fromUrl(url, {
url,
skipLevelOfDetail: true, skipLevelOfDetail: true,
baseScreenSpaceError: 1024, baseScreenSpaceError: 1024,
maximumScreenSpaceError: 128, // 数值加大,能让最终成像变模糊 maximumScreenSpaceError: 128, // 数值加大,能让最终成像变模糊
@ -23,42 +32,32 @@ export const createObliquePhotography = (url, viewer) => {
cullRequestsWhileMovingMultiplier: 10, // 值越小能够更快的剔除 cullRequestsWhileMovingMultiplier: 10, // 值越小能够更快的剔除
preloadWhenHidden: true, preloadWhenHidden: true,
preferLeaves: true, preferLeaves: true,
maximumMemoryUsage: 128, // 内存分配变小有利于倾斜摄影数据回收,提升性能体验 cacheBytes: 128 * 1024 * 1024, // 限制瓦片缓存,便于倾斜摄影数据及时回收。
progressiveResolutionHeightFraction: 0.5, // 数值偏于0能够让初始加载变得模糊 progressiveResolutionHeightFraction: 0.5, // 数值偏于0能够让初始加载变得模糊
dynamicScreenSpaceErrorDensity: 0.5, // 数值加大,能让周边加载变快 dynamicScreenSpaceErrorDensity: 0.5, // 数值加大,能让周边加载变快
dynamicScreenSpaceErrorFactor: 1, // 不知道起了什么作用没,反正放着吧先 dynamicScreenSpaceErrorFactor: 1, // 不知道起了什么作用没,反正放着吧先
dynamicScreenSpaceError: true, // 有了这个后,会在真正的全屏加载完之后才清晰化房屋 dynamicScreenSpaceError: true, // 有了这个后,会在真正的全屏加载完之后才清晰化房屋
}); });
tileset.readyPromise.then((tileset) => { // 新版 Cesium 通过 fromUrl 完成异步初始化,解析完成后再计算模型偏移。
// 笛卡尔转换为弧度 const cartographic = Cartographic.fromCartesian(tileset.boundingSphere.center);
const cartographic = Cesium.Cartographic.fromCartesian( const lng = CesiumMath.toDegrees(cartographic.longitude);
tileset.boundingSphere.center, const lat = CesiumMath.toDegrees(cartographic.latitude);
); const surface = Cartesian3.fromDegrees(lng, lat, 0);
const lng = Cesium.Math.toDegrees(cartographic.longitude); // 使用经纬度和弧度的转换将WGS84弧度坐标系转换到目标值弧度转度 const offset = Cartesian3.fromDegrees(lng, lat, 5);
const lat = Cesium.Math.toDegrees(cartographic.latitude); const translation = Cartesian3.subtract(offset, surface, new Cartesian3());
// 计算中心点位置的地表坐标 tileset.modelMatrix = Matrix4.fromTranslation(translation);
const surface = Cesium.Cartesian3.fromDegrees(lng, lat, 0);
// 偏移后的坐标
const offset = Cesium.Cartesian3.fromDegrees(lng, lat, 5);
const translation = Cesium.Cartesian3.subtract(
offset,
surface,
new Cesium.Cartesian3(),
);
tileset.modelMatrix = Cesium.Matrix4.fromTranslation(translation);
});
viewer.scene.primitives.add(tileset); viewer.scene.primitives.add(tileset);
}; };
// 创建唯一Id // 创建唯一Id
export const createId = () => { export const createId = () => {
return Cesium.createGuid(); return createGuid();
}; };
// 创建数据源 // 创建数据源
export const createEntityCollection = (name) => { export const createEntityCollection = (name) => {
return new Cesium.CustomDataSource(`${name}_${createId()}`); return new CustomDataSource(`${name}_${createId()}`);
}; };
// 创建 billboard // 创建 billboard
@ -68,17 +67,24 @@ export const getBillboard = async ({ image, name = "" }) => {
image: base64, image: base64,
width, width,
height, height,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM, verticalOrigin: VerticalOrigin.BOTTOM,
horizontalOrigin: Cesium.HorizontalOrigin.CENTER, horizontalOrigin: HorizontalOrigin.CENTER,
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, heightReference: HeightReference.CLAMP_TO_GROUND,
disableDepthTestDistance: Number.POSITIVE_INFINITY, disableDepthTestDistance: Number.POSITIVE_INFINITY,
clampToGround: true,
}; };
}; };
// DataSourceCollection 仅通过公开的 length/get 接口遍历,避免依赖内部数组结构。
const getDataSources = (viewer) => {
return Array.from(
{ length: viewer.dataSources.length },
(_, index) => viewer.dataSources.get(index),
);
};
// 移除数据源 // 移除数据源
export const removeEntityCollection = (viewer, name) => { export const removeEntityCollection = (viewer, name) => {
viewer.dataSources._dataSources getDataSources(viewer)
.filter(ds => ds.name.startsWith(`${name}_`)) .filter(ds => ds.name.startsWith(`${name}_`))
.forEach((item) => { .forEach((item) => {
viewer.dataSources.remove(item); viewer.dataSources.remove(item);
@ -88,7 +94,7 @@ export const removeEntityCollection = (viewer, name) => {
// 合并数据源 // 合并数据源
export const createMergedEntityCollection = (viewer, name) => { export const createMergedEntityCollection = (viewer, name) => {
const mergedDataSource = createEntityCollection(name); const mergedDataSource = createEntityCollection(name);
viewer.dataSources._dataSources getDataSources(viewer)
.filter(ds => .filter(ds =>
ds.name.startsWith(`${name.substring(0, name.indexOf("Merged"))}_`), ds.name.startsWith(`${name.substring(0, name.indexOf("Merged"))}_`),
) )

View File

@ -1,81 +1,28 @@
const Cesium = window.Cesium; import { Material } from "cesium";
function TrajectoryPolylineTrailLinkMaterialProperty(viewer) { const materialSource = `
this.viewer = viewer;
this._definitionChanged = new Cesium.Event();
this._uTime = 0;
}
Object.defineProperties(TrajectoryPolylineTrailLinkMaterialProperty.prototype, {
isConstant: {
get() {
return false;
},
},
definitionChanged: {
get() {
return this._definitionChanged;
},
},
uTime: Cesium.createPropertyDescriptor("uTime"),
});
TrajectoryPolylineTrailLinkMaterialProperty.prototype.getType = function () {
return "CustomMaterial";
};
TrajectoryPolylineTrailLinkMaterialProperty.prototype.getValue = function (
time,
result,
) {
if (!Cesium.defined(result)) {
result = {};
}
this._uTime += 0.005;
if (this._uTime > 1.0) {
this._uTime = 0;
}
result.uTime = this._uTime;
this.viewer.scene.requestRender();
return result;
};
TrajectoryPolylineTrailLinkMaterialProperty.prototype.equals = function (
other,
) {
return (
this === other
|| (other instanceof TrajectoryPolylineTrailLinkMaterialProperty
&& this._uTime === other._uTime)
);
};
Cesium.Material.CustomMaterialType = "CustomMaterial";
Cesium.Material.CustomMaterialSource = `
czm_material czm_getMaterial(czm_materialInput materialInput) czm_material czm_getMaterial(czm_materialInput materialInput)
{ {
czm_material material = czm_getDefaultMaterial(materialInput); czm_material material = czm_getDefaultMaterial(materialInput);
float progress = mod(1.0 - materialInput.st.s + uTime, 1.0); float progress = mod(1.0 - materialInput.st.s + uTime, 1.0);
float head = smoothstep(0.95, 1.0, progress) * 2.0; float head = smoothstep(0.95, 1.0, progress) * 2.0;
vec3 baseColor = vec3(1, 0, 0); vec3 baseColor = vec3(1.0, 0.0, 0.0);
float tailFade = smoothstep(0.3, 0.0, progress); float tailFade = smoothstep(0.3, 0.0, progress);
vec3 tailColor = mix(vec3(0), vec3(1), tailFade); vec3 tailColor = mix(vec3(0.0), vec3(1.0), tailFade);
material.diffuse = baseColor + tailColor * 0.8 + vec3(head); material.diffuse = baseColor + tailColor * 0.8 + vec3(head);
material.emission = material.diffuse * 0.5; material.emission = material.diffuse * 0.5;
material.alpha = 1.0;
return material; return material;
}`; }`;
Cesium.Material._materialCache.addMaterial(Cesium.Material.CustomMaterialType, { // Primitive 可以直接使用 Fabric 材质,无需向 Cesium 私有材质缓存注册类型。
fabric: { export default function createTrajectoryPolylineTrailMaterial() {
type: Cesium.Material.CustomMaterialType, return new Material({
uniforms: { fabric: {
uTime: 0, uniforms: {
uTime: 0,
},
source: materialSource,
}, },
source: Cesium.Material.CustomMaterialSource, });
}, }
});
Cesium.TrajectoryPolylineTrailLinkMaterialProperty
= TrajectoryPolylineTrailLinkMaterialProperty;

View File

@ -1,102 +1,32 @@
import { Color, Material } from "cesium";
import PolylineTrailLinkImage from "~/assets/images/map_bi/wall_img.png"; import PolylineTrailLinkImage from "~/assets/images/map_bi/wall_img.png";
const Cesium = window.Cesium; const materialSource = `
czm_material czm_getMaterial(czm_materialInput materialInput)
{
czm_material material = czm_getDefaultMaterial(materialInput);
vec2 st = materialInput.st;
vec4 colorImage = texture(image, vec2(fract(st.t - time), st.t));
vec4 fragColor = czm_gammaCorrect(color);
material.alpha = colorImage.a * color.a;
material.diffuse = color.rgb;
material.emission = fragColor.rgb;
return material;
}`;
function WallPolylineTrailLinkMaterialProperty( // Primitive 可以直接使用 Fabric 材质,无需向 Cesium 私有材质缓存注册类型。
viewer, export default function createWallPolylineTrailMaterial(
options = { color = Color.fromBytes(201, 118, 243).withAlpha(0.5),
color: Cesium.Color.fromBytes(201, 118, 243).withAlpha(0.5),
duration: 2000,
},
) { ) {
this.viewer = viewer; return new Material({
this._definitionChanged = new Cesium.Event(); translucent: true,
this._color = undefined;
this._colorSubscription = undefined;
this.color = options.color;
this.duration = options.duration;
this._time = new Date().getTime();
}
Object.defineProperties(WallPolylineTrailLinkMaterialProperty.prototype, {
isConstant: {
get() {
return false;
},
},
definitionChanged: {
get() {
return this._definitionChanged;
},
},
color: Cesium.createPropertyDescriptor("color"),
});
WallPolylineTrailLinkMaterialProperty.prototype.getType = function () {
return "PolylineTrailLink";
};
WallPolylineTrailLinkMaterialProperty.prototype.getValue = function (
time,
result,
) {
if (!Cesium.defined(result)) {
result = {};
}
result.color = Cesium.Property.getValueOrClonedDefault(
this._color,
time,
Cesium.Color.WHITE,
result.color,
);
result.image = Cesium.Material.PolylineTrailLinkImage;
if (this.duration) {
result.time
= ((new Date().getTime() - this._time) % this.duration) / this.duration;
}
this.viewer.scene.requestRender();
return result;
};
WallPolylineTrailLinkMaterialProperty.prototype.equals = function (other) {
return (
this === other
|| (other instanceof WallPolylineTrailLinkMaterialProperty
&& Cesium.Property.equals(this._color, other._color))
);
};
Cesium.WallPolylineTrailLinkMaterialProperty
= WallPolylineTrailLinkMaterialProperty;
Cesium.Material.PolylineTrailLinkType = "PolylineTrailLink";
Cesium.Material.PolylineTrailLinkImage = PolylineTrailLinkImage;
Cesium.Material.PolylineTrailLinkSource = `czm_material czm_getMaterial(czm_materialInput
materialInput)\n\
{\n\
czm_material material =
czm_getDefaultMaterial(materialInput);\n\
vec2 st = materialInput.st;\n\
vec4 colorImage = texture2D(image,
vec2(fract(st.t - time), st.t));\n\
vec4 fragColor;\n\
fragColor.rgb = color.rgb / 1.0;\n\
fragColor = czm_gammaCorrect(fragColor);\n\
material.alpha = colorImage.a * color.a;\n\
material.diffuse = color.rgb;\n\
material.emission = fragColor.rgb;\n\
return material;\n\
}`;
Cesium.Material._materialCache.addMaterial(
Cesium.Material.PolylineTrailLinkType,
{
fabric: { fabric: {
type: Cesium.Material.PolylineTrailLinkType,
uniforms: { uniforms: {
color: new Cesium.Color(1.0, 1.0, 1.0, 1), color,
image: Cesium.Material.PolylineTrailLinkImage, image: PolylineTrailLinkImage,
time: 0, time: 0,
}, },
source: Cesium.Material.PolylineTrailLinkSource, source: materialSource,
}, },
translucent() { });
return true; }
},
},
);

View File

@ -1,11 +1,18 @@
import {
CameraEventType,
defined,
ImageryLayer,
ScreenSpaceEventHandler,
ScreenSpaceEventType,
Viewer,
WebMapTileServiceImageryProvider,
} from "cesium";
import { useRef } from "react"; import { useRef } from "react";
import { createObliquePhotography } from "~/pages/Container/Map/js/mapUtils"; import { createObliquePhotography } from "~/pages/Container/Map/js/mapUtils";
import useMapMethods from "./useMapMethods"; import useMapMethods from "./useMapMethods";
import usePointClickEvent from "./usePointClickEvent"; import usePointClickEvent from "./usePointClickEvent";
const Cesium = window.Cesium;
export default function useInitMap(options) { export default function useInitMap(options) {
// 页面和地图工具共用同一个 Cesium 引用,避免内外各维护一份实例。 // 页面和地图工具共用同一个 Cesium 引用,避免内外各维护一份实例。
const viewer = useRef(null); const viewer = useRef(null);
@ -22,10 +29,11 @@ export default function useInitMap(options) {
const getViewer = () => viewer.current; const getViewer = () => viewer.current;
// 倾斜摄影 // 倾斜摄影
// 当前按业务要求暂停初始化,保留入口以便服务恢复后重新启用。
const initObliquePhotography = () => { const initObliquePhotography = () => {
const viewer = getViewer(); const viewer = getViewer();
viewer.scene.globe.depthTestAgainstTerrain = true; viewer.scene.globe.depthTestAgainstTerrain = true;
Cesium.ExperimentalFeatures.enableModelExperimental = true;
createObliquePhotography( createObliquePhotography(
"http://192.168.192.215:8021/ware/upload/%E6%9B%B9%E5%A6%83%E7%94%B8%E6%B8%AF%E4%B8%9C/%E6%9B%B9%E5%A6%83%E7%94%B8%E6%B8%AF%E4%B8%9C/merge_tile.json", "http://192.168.192.215:8021/ware/upload/%E6%9B%B9%E5%A6%83%E7%94%B8%E6%B8%AF%E4%B8%9C/%E6%9B%B9%E5%A6%83%E7%94%B8%E6%B8%AF%E4%B8%9C/merge_tile.json",
viewer, viewer,
@ -55,26 +63,36 @@ export default function useInitMap(options) {
// 注册点击事件 // 注册点击事件
const registerClickEvent = () => { const registerClickEvent = () => {
const viewer = getViewer(); const viewer = getViewer();
viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK); viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK); viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(ScreenSpaceEventType.LEFT_CLICK);
const screenSpaceEventHandler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas); const screenSpaceEventHandler = new ScreenSpaceEventHandler(viewer.scene.canvas);
screenSpaceEventHandler.setInputAction((movement) => { screenSpaceEventHandler.setInputAction((movement) => {
const pick = viewer.scene.pick(movement.position); const pick = viewer.scene.pick(movement.position);
if (Cesium.defined(pick) && pick.id?.id) { if (defined(pick) && pick.id?.id) {
pointClickEventRef.current.pointClickEvent(pick.id); pointClickEventRef.current.pointClickEvent(pick.id);
} }
else { else {
pointClickEventRef.current.closePopup(); pointClickEventRef.current.closePopup();
} }
}, Cesium.ScreenSpaceEventType.LEFT_CLICK); }, ScreenSpaceEventType.LEFT_CLICK);
}; };
// 初始化地图 // 初始化地图
const initMap = () => { const initMap = () => {
const tianDiTuKey = "06494bcf2d4b66df7f3c586cc65af0cb"; const tianDiTuKey = "06494bcf2d4b66df7f3c586cc65af0cb";
const subdomains = ["0", "1", "2", "3", "4", "5", "6", "7"]; const subdomains = ["0", "1", "2", "3", "4", "5", "6", "7"];
viewer.current = new Cesium.Viewer("cesiumContainer", { const imageryProvider = new WebMapTileServiceImageryProvider({
// terrainProvider: Cesium.createWorldTerrain() // 影像底图
url:
`https://t{s}.tianditu.gov.cn/img_w/wmts?service=wmts&request=GetTile&version=1.0.0&LAYER=img&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}&style=default&format=tiles&tk=${
tianDiTuKey}`,
subdomains,
layer: "tdtImgLayer",
style: "default",
format: "image/jpeg",
tileMatrixSetID: "GoogleMapsCompatible", // 使用谷歌的瓦片切片方式
});
viewer.current = new Viewer("cesiumContainer", {
animation: false, // 动画 animation: false, // 动画
homeButton: true, // home键 homeButton: true, // home键
geocoder: true, // 地址编码 geocoder: true, // 地址编码
@ -86,34 +104,23 @@ export default function useInitMap(options) {
navigationInstructionsInitiallyVisible: false, // 导航指令 navigationInstructionsInitiallyVisible: false, // 导航指令
navigationHelpButton: false, // 帮助信息 navigationHelpButton: false, // 帮助信息
selectionIndicator: false, // 选择 selectionIndicator: false, // 选择
imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ baseLayer: new ImageryLayer(imageryProvider),
// 影像底图
url:
`https://t{s}.tianditu.gov.cn/img_w/wmts?service=wmts&request=GetTile&version=1.0.0&LAYER=img&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}&style=default&format=tiles&tk=${
tianDiTuKey}`,
subdomains,
layer: "tdtImgLayer",
style: "default",
format: "image/jpeg",
tileMatrixSetID: "GoogleMapsCompatible", // 使用谷歌的瓦片切片方式
show: true,
}),
}); });
// 调整 Cesium 默认相机操作:左键旋转地图,右键调整俯仰角,实现从平面俯视到立体视角的切换。 // 调整 Cesium 默认相机操作:左键旋转地图,右键调整俯仰角,实现从平面俯视到立体视角的切换。
const cameraController = viewer.current.scene.screenSpaceCameraController; const cameraController = viewer.current.scene.screenSpaceCameraController;
cameraController.rotateEventTypes = Cesium.CameraEventType.LEFT_DRAG; cameraController.rotateEventTypes = CameraEventType.LEFT_DRAG;
cameraController.tiltEventTypes = [ cameraController.tiltEventTypes = [
Cesium.CameraEventType.RIGHT_DRAG, CameraEventType.RIGHT_DRAG,
Cesium.CameraEventType.MIDDLE_DRAG, CameraEventType.MIDDLE_DRAG,
Cesium.CameraEventType.PINCH, CameraEventType.PINCH,
]; ];
cameraController.zoomEventTypes = [ cameraController.zoomEventTypes = [
Cesium.CameraEventType.WHEEL, CameraEventType.WHEEL,
Cesium.CameraEventType.PINCH, CameraEventType.PINCH,
]; ];
viewer.current._cesiumWidget._creditContainer.style.display = "none"; // 隐藏cesium ion viewer.current.creditDisplay.container.style.display = "none"; // 隐藏 Cesium 版权信息容器
viewer.current.imageryLayers.addImageryProvider( viewer.current.imageryLayers.addImageryProvider(
new Cesium.WebMapTileServiceImageryProvider({ new WebMapTileServiceImageryProvider({
// 影像注记 // 影像注记
url: url:
`https://t{s}.tianditu.gov.cn/cia_w/wmts?service=wmts&request=GetTile&version=1.0.0&LAYER=cia&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}&style=default.jpg&tk=${ `https://t{s}.tianditu.gov.cn/cia_w/wmts?service=wmts&request=GetTile&version=1.0.0&LAYER=cia&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}&style=default.jpg&tk=${
@ -123,7 +130,6 @@ export default function useInitMap(options) {
style: "default", style: "default",
format: "image/jpeg", format: "image/jpeg",
tileMatrixSetID: "GoogleMapsCompatible", tileMatrixSetID: "GoogleMapsCompatible",
show: true,
}), }),
); );
initObliquePhotography(); initObliquePhotography();

View File

@ -1,3 +1,26 @@
import {
Cartesian3,
ClassificationType,
ClockRange,
Color,
defined,
Entity,
ExtrapolationType,
GeometryInstance,
GroundPolylineGeometry,
GroundPolylinePrimitive,
HeightReference,
HorizontalOrigin,
JulianDate,
MaterialAppearance,
PinBuilder,
PolylineMaterialAppearance,
Primitive,
SampledPositionProperty,
SceneMode,
VerticalOrigin,
WallGeometry,
} from "cesium";
import { useRef } from "react"; import { useRef } from "react";
import portEntityBillboardImage from "~/assets/images/map_bi/point/dianwei.png"; import portEntityBillboardImage from "~/assets/images/map_bi/point/dianwei.png";
import branchOfficeEntityBillboardImage from "~/assets/images/map_bi/point/gongsidianwei.png"; import branchOfficeEntityBillboardImage from "~/assets/images/map_bi/point/gongsidianwei.png";
@ -17,11 +40,11 @@ import {
getPosition, getPosition,
removeEntityCollection, removeEntityCollection,
} from "./mapUtils"; } from "./mapUtils";
import createTrajectoryPolylineTrailMaterial from "./material/TrajectoryPolylineTrailLinkMaterialProperty";
import createWallPolylineTrailMaterial from "./material/WallPolylineTrailLinkMaterialProperty";
import mitt from "./mitt"; import mitt from "./mitt";
import { changeCoverMaskVisibleMittKey } from "./mittKey"; import { changeCoverMaskVisibleMittKey } from "./mittKey";
import { chunkedLoad, filterNull, formatPolygon } from "./utils"; import { chunkedLoad, filterNull, formatPolygon } from "./utils";
import "./material/TrajectoryPolylineTrailLinkMaterialProperty.js";
import "./material/WallPolylineTrailLinkMaterialProperty";
const portPoint = [ const portPoint = [
{ {
@ -64,8 +87,6 @@ const peopleImg = {
yellow: people_yellow, yellow: people_yellow,
}; // 人员定位颜色图片 }; // 人员定位颜色图片
const Cesium = window.Cesium;
export default function useMapMethods(viewerRef, request) { export default function useMapMethods(viewerRef, request) {
// 获取当前 Cesium 实例:初始化前为空,地图方法会在 initMap 完成后被调用。 // 获取当前 Cesium 实例:初始化前为空,地图方法会在 initMap 完成后被调用。
const getViewer = () => viewerRef.current; const getViewer = () => viewerRef.current;
@ -97,6 +118,10 @@ export default function useMapMethods(viewerRef, request) {
// 当前人员定位会话共用的采样起始时间 // 当前人员定位会话共用的采样起始时间
const peoplePositionStartTime = useRef(null); const peoplePositionStartTime = useRef(null);
// Primitive 不属于 Entity/DataSource单独保存实例和动画注销函数以便完整清理。
const wallPrimitivesRef = useRef([]);
const peopleTrajectoryPrimitiveRef = useRef(null);
// 设置中心点 // 设置中心点
const flyTo = ({ longitude, latitude, height } = defineCenterPoint) => { const flyTo = ({ longitude, latitude, height } = defineCenterPoint) => {
const viewer = getViewer(); const viewer = getViewer();
@ -123,7 +148,7 @@ export default function useMapMethods(viewerRef, request) {
// 切换场景模式 // 切换场景模式
const changeSceneMode = (type = "3d") => { const changeSceneMode = (type = "3d") => {
const viewer = getViewer(); const viewer = getViewer();
viewer.scene.mode = { "2d": Cesium.SceneMode.COLUMBUS_VIEW, "3d": Cesium.SceneMode.SCENE3D }[type]; viewer.scene.mode = { "2d": SceneMode.COLUMBUS_VIEW, "3d": SceneMode.SCENE3D }[type];
}; };
// 添加港口点 // 添加港口点
@ -133,7 +158,7 @@ export default function useMapMethods(viewerRef, request) {
viewer.dataSources.add(entityCollection); viewer.dataSources.add(entityCollection);
await chunkedLoad(portPoint, 50, async (item) => { await chunkedLoad(portPoint, 50, async (item) => {
entityCollection.entities.add( entityCollection.entities.add(
new Cesium.Entity({ new Entity({
id: item.id, id: item.id,
name: item.name, name: item.name,
position: getPosition(item.position.x, item.position.y), position: getPosition(item.position.x, item.position.y),
@ -171,7 +196,7 @@ export default function useMapMethods(viewerRef, request) {
viewer.dataSources.add(entityCollection); viewer.dataSources.add(entityCollection);
await chunkedLoad(branchOfficePoint, 50, async (item) => { await chunkedLoad(branchOfficePoint, 50, async (item) => {
entityCollection.entities.add( entityCollection.entities.add(
new Cesium.Entity({ new Entity({
id: item.id, id: item.id,
name: item.corpName, name: item.corpName,
position: getPosition(item.longitude, item.latitude), position: getPosition(item.longitude, item.latitude),
@ -232,15 +257,15 @@ export default function useMapMethods(viewerRef, request) {
itemsToRender.forEach((item) => { itemsToRender.forEach((item) => {
const latitudeAndLongitude = formatPolygon(item); const latitudeAndLongitude = formatPolygon(item);
entityCollection.entities.add( entityCollection.entities.add(
new Cesium.Entity({ new Entity({
id: createId(), id: createId(),
polygon: { polygon: {
hierarchy: Cesium.Cartesian3.fromDegreesArray(latitudeAndLongitude), hierarchy: Cartesian3.fromDegreesArray(latitudeAndLongitude),
extrudedHeight: item.stretchHeight, extrudedHeight: item.stretchHeight,
height: item.height, height: item.height,
material: Cesium.Color.fromCssColorString(item.color), material: Color.fromCssColorString(item.color),
outline: !!item.strokeColor, outline: !!item.strokeColor,
outlineColor: Cesium.Color.fromCssColorString(item.strokeColor), outlineColor: Color.fromCssColorString(item.strokeColor),
}, },
}), }),
); );
@ -263,15 +288,15 @@ export default function useMapMethods(viewerRef, request) {
viewer.dataSources.add(entityCollection); viewer.dataSources.add(entityCollection);
areaList.forEach((area) => { areaList.forEach((area) => {
entityCollection.entities.add( entityCollection.entities.add(
new Cesium.Entity({ new Entity({
id: createId(), id: createId(),
name: area.closedAreaName, name: area.closedAreaName,
polygon: { polygon: {
hierarchy: Cesium.Cartesian3.fromDegreesArray(formatPolygon(area)), hierarchy: Cartesian3.fromDegreesArray(formatPolygon(area)),
material: Cesium.Color.fromCssColorString("rgba(221,0,0,0.4)"), material: Color.fromCssColorString("rgba(221,0,0,0.4)"),
outline: true, outline: true,
outlineColor: Cesium.Color.fromCssColorString("rgba(51,35,108,0.63)"), outlineColor: Color.fromCssColorString("rgba(51,35,108,0.63)"),
classificationType: Cesium.ClassificationType.BOTH, classificationType: ClassificationType.BOTH,
zIndex: 1, zIndex: 1,
}, },
}), }),
@ -297,8 +322,6 @@ export default function useMapMethods(viewerRef, request) {
const viewer = getViewer(); const viewer = getViewer();
mitt.emit(changeCoverMaskVisibleMittKey, true); mitt.emit(changeCoverMaskVisibleMittKey, true);
const currentEdge = edgeMap[id](); const currentEdge = edgeMap[id]();
const entityCollection = createEntityCollection("wallEntityCollection");
viewer.dataSources.add(entityCollection);
const wallList = currentEdge.wallList; const wallList = currentEdge.wallList;
if (!Array.isArray(wallList)) if (!Array.isArray(wallList))
return; return;
@ -306,33 +329,51 @@ export default function useMapMethods(viewerRef, request) {
// 筛选需要渲染的边界墙 // 筛选需要渲染的边界墙
const itemsToRender = wallList.filter(item => !corpionId || item.corpinfoId === corpionId); const itemsToRender = wallList.filter(item => !corpionId || item.corpinfoId === corpionId);
// 统一渲染 const geometryInstances = itemsToRender.map((item) => {
itemsToRender.forEach((item) => {
const latitudeAndLongitude = formatPolygon(item); const latitudeAndLongitude = formatPolygon(item);
const positions const positions = Cartesian3.fromDegreesArray(latitudeAndLongitude);
= Cesium.Cartesian3.fromDegreesArray(latitudeAndLongitude);
const pointCount = latitudeAndLongitude.length / 2; const pointCount = latitudeAndLongitude.length / 2;
entityCollection.entities.add( return new GeometryInstance({
new Cesium.Entity({ id: createId(),
id: createId(), geometry: new WallGeometry({
wall: { positions,
positions, maximumHeights: Array.from({ length: pointCount }).fill(40),
material: new Cesium.WallPolylineTrailLinkMaterialProperty(viewer), minimumHeights: Array.from({ length: pointCount }).fill(0),
maximumHeights: Array.from({ length: pointCount }).fill(40), vertexFormat: MaterialAppearance.MaterialSupport.TEXTURED.vertexFormat,
minimumHeights: Array.from({ length: pointCount }).fill(0),
},
}), }),
); });
}); });
if (geometryInstances.length) {
const material = createWallPolylineTrailMaterial();
const primitive = viewer.scene.primitives.add(new Primitive({
geometryInstances,
appearance: new MaterialAppearance({
material,
faceForward: true,
translucent: true,
}),
}));
const startTime = Date.now();
const removeAnimation = viewer.scene.preUpdate.addEventListener(() => {
material.uniforms.time = ((Date.now() - startTime) % 2000) / 2000;
viewer.scene.requestRender();
});
wallPrimitivesRef.current.push({ primitive, removeAnimation });
}
mitt.emit(changeCoverMaskVisibleMittKey, false); mitt.emit(changeCoverMaskVisibleMittKey, false);
}; };
// 删除墙 // 删除墙
const removeWall = () => { const removeWall = () => {
const viewer = getViewer(); const viewer = getViewer();
removeEntityCollection(viewer, "wallEntityCollection"); wallPrimitivesRef.current.forEach(({ primitive, removeAnimation }) => {
removeAnimation();
viewer.scene.primitives.remove(primitive);
});
wallPrimitivesRef.current = [];
}; };
// 点位聚合 // 点位聚合
@ -342,26 +383,26 @@ export default function useMapMethods(viewerRef, request) {
dataSource.clustering.minimumClusterSize = 5; // 设置最小的聚合点数目,超过此数目才能聚合 dataSource.clustering.minimumClusterSize = 5; // 设置最小的聚合点数目,超过此数目才能聚合
let removeListener; let removeListener;
// 按聚合层级创建对应图标 // 按聚合层级创建对应图标
const pinBuilder = new Cesium.PinBuilder(); const pinBuilder = new PinBuilder();
const pin100 = pinBuilder const pin100 = pinBuilder
.fromText("100+", Cesium.Color.BLUE, 48) .fromText("100+", Color.BLUE, 48)
.toDataURL(); .toDataURL();
const pin50 = pinBuilder.fromText("50+", Cesium.Color.BLUE, 48).toDataURL(); const pin50 = pinBuilder.fromText("50+", Color.BLUE, 48).toDataURL();
const pin40 = pinBuilder.fromText("40+", Cesium.Color.RED, 48).toDataURL(); const pin40 = pinBuilder.fromText("40+", Color.RED, 48).toDataURL();
const pin30 = pinBuilder.fromText("30+", Cesium.Color.RED, 48).toDataURL(); const pin30 = pinBuilder.fromText("30+", Color.RED, 48).toDataURL();
const pin20 = pinBuilder.fromText("20+", Cesium.Color.RED, 48).toDataURL(); const pin20 = pinBuilder.fromText("20+", Color.RED, 48).toDataURL();
const pin10 = pinBuilder.fromText("10+", Cesium.Color.RED, 48).toDataURL(); const pin10 = pinBuilder.fromText("10+", Color.RED, 48).toDataURL();
// 10以内聚合图标 // 10以内聚合图标
const singleDigitPins = Array.from({ length: 8 }); const singleDigitPins = Array.from({ length: 8 });
for (let i = 0; i < singleDigitPins.length; ++i) { for (let i = 0; i < singleDigitPins.length; ++i) {
singleDigitPins[i] = pinBuilder singleDigitPins[i] = pinBuilder
.fromText(`${i + 2}`, Cesium.Color.VIOLET, 48) .fromText(`${i + 2}`, Color.VIOLET, 48)
.toDataURL(); .toDataURL();
} }
customStyle(); customStyle();
function customStyle() { function customStyle() {
if (Cesium.defined(removeListener)) { if (defined(removeListener)) {
removeListener(); removeListener();
removeListener = undefined; removeListener = undefined;
} }
@ -371,10 +412,10 @@ export default function useMapMethods(viewerRef, request) {
cluster.label.show = false; cluster.label.show = false;
cluster.billboard.show = true; cluster.billboard.show = true;
cluster.billboard.id = cluster.label.id; cluster.billboard.id = cluster.label.id;
cluster.billboard.verticalOrigin = Cesium.VerticalOrigin.BOTTOM; cluster.billboard.verticalOrigin = VerticalOrigin.BOTTOM;
cluster.billboard.horizontalOrigin = Cesium.HorizontalOrigin.CENTER; cluster.billboard.horizontalOrigin = HorizontalOrigin.CENTER;
cluster.billboard.heightReference cluster.billboard.heightReference
= Cesium.HeightReference.CLAMP_TO_GROUND; = HeightReference.CLAMP_TO_GROUND;
cluster.billboard.disableDepthTestDistance cluster.billboard.disableDepthTestDistance
= Number.POSITIVE_INFINITY; = Number.POSITIVE_INFINITY;
const thresholdMap = [ const thresholdMap = [
@ -422,7 +463,7 @@ export default function useMapMethods(viewerRef, request) {
await chunkedLoad(filterNull(pointList), 50, async (item) => { await chunkedLoad(filterNull(pointList), 50, async (item) => {
const name = item[options.titleKey] || ""; const name = item[options.titleKey] || "";
entityCollection.entities.add( entityCollection.entities.add(
new Cesium.Entity({ new Entity({
id: createId(), id: createId(),
name, name,
position: getPosition(item.longitude || item.lng, item.latitude || item.lat), position: getPosition(item.longitude || item.lng, item.latitude || item.lat),
@ -456,7 +497,12 @@ export default function useMapMethods(viewerRef, request) {
// 查询新轨迹前先移除旧轨迹,确保地图上始终只展示当前筛选结果。 // 查询新轨迹前先移除旧轨迹,确保地图上始终只展示当前筛选结果。
const removePeopleTrajectory = () => { const removePeopleTrajectory = () => {
const viewer = getViewer(); const viewer = getViewer();
viewer.entities.removeById("peopleTrajectoryEntity"); const current = peopleTrajectoryPrimitiveRef.current;
if (!current)
return;
current.removeAnimation();
viewer.scene.primitives.remove(current.primitive);
peopleTrajectoryPrimitiveRef.current = null;
}; };
// 将接口返回的经纬高点位绘制为动态轨迹线,少于两个点时不创建无意义的线段。 // 将接口返回的经纬高点位绘制为动态轨迹线,少于两个点时不创建无意义的线段。
@ -466,26 +512,34 @@ export default function useMapMethods(viewerRef, request) {
return; return;
const viewer = getViewer(); const viewer = getViewer();
const coordinates = points.flatMap(point => [point.lon, point.lat, point.alt || 0]); const coordinates = points.flatMap(point => [Number(point.lon), Number(point.lat)]);
viewer.entities.add({ const material = createTrajectoryPolylineTrailMaterial();
id: "peopleTrajectoryEntity", const primitive = viewer.scene.primitives.add(new GroundPolylinePrimitive({
polyline: { geometryInstances: new GeometryInstance({
positions: Cesium.Cartesian3.fromDegreesArrayHeights(coordinates), id: "peopleTrajectoryPrimitive",
width: 5, geometry: new GroundPolylineGeometry({
material: new Cesium.TrajectoryPolylineTrailLinkMaterialProperty(viewer), positions: Cartesian3.fromDegreesArray(coordinates),
clampToGround: true, width: 5,
}, }),
}),
appearance: new PolylineMaterialAppearance({ material }),
}));
const startTime = Date.now();
const removeAnimation = viewer.scene.preUpdate.addEventListener(() => {
material.uniforms.uTime = ((Date.now() - startTime) % 3300) / 3300;
viewer.scene.requestRender();
}); });
peopleTrajectoryPrimitiveRef.current = { primitive, removeAnimation };
}; };
// 人员定位使用 Viewer 的全局时钟;每次开启定位仅初始化一次,避免首批点位互相重置时钟。 // 人员定位使用 Viewer 的全局时钟;每次开启定位仅初始化一次,避免首批点位互相重置时钟。
const initPeoplePositionClock = () => { const initPeoplePositionClock = () => {
const start = Cesium.JulianDate.now(); const start = JulianDate.now();
const viewer = getViewer(); const viewer = getViewer();
peoplePositionStartTime.current = start; peoplePositionStartTime.current = start;
viewer.clock.startTime = start.clone(); viewer.clock.startTime = start.clone();
viewer.clock.currentTime = start.clone(); viewer.clock.currentTime = start.clone();
viewer.clock.clockRange = Cesium.ClockRange.CLAMPED; viewer.clock.clockRange = ClockRange.CLAMPED;
viewer.clock.shouldAnimate = false; viewer.clock.shouldAnimate = false;
return start; return start;
}; };
@ -499,13 +553,13 @@ export default function useMapMethods(viewerRef, request) {
throw new Error("请传入markType扎点类型"); throw new Error("请传入markType扎点类型");
const viewer = getViewer(); const viewer = getViewer();
const clonePoint = { ...point }; const clonePoint = { ...point };
point.property = new Cesium.SampledPositionProperty(); point.property = new SampledPositionProperty();
// 下一条实时定位到达前保持最后有效位置,避免全局时钟前进后点位短暂消失。 // 下一条实时定位到达前保持最后有效位置,避免全局时钟前进后点位短暂消失。
point.property.forwardExtrapolationType = Cesium.ExtrapolationType.HOLD; point.property.forwardExtrapolationType = ExtrapolationType.HOLD;
point.property.forwardExtrapolationDuration = 0; point.property.forwardExtrapolationDuration = 0;
// 首批人员必须共用同一采样起点,后续实体创建不会影响已存在人员的播放时间。 // 首批人员必须共用同一采样起点,后续实体创建不会影响已存在人员的播放时间。
const start = peoplePositionStartTime.current || initPeoplePositionClock(); const start = peoplePositionStartTime.current || initPeoplePositionClock();
const position = Cesium.Cartesian3.fromDegrees(point.x, point.y, 0); const position = getPosition(point.x, point.y);
point.property.addSample(start, position); point.property.addSample(start, position);
point.lastTime = start; point.lastTime = start;
point.lastIconType = point.icon_type; point.lastIconType = point.icon_type;
@ -542,11 +596,11 @@ export default function useMapMethods(viewerRef, request) {
).image; ).image;
point.lastIconType = point.icon_type; point.lastIconType = point.icon_type;
} }
const position = Cesium.Cartesian3.fromDegrees(point.x, point.y, 0); const position = getPosition(point.x, point.y);
const nextTime = Cesium.JulianDate.addSeconds( const nextTime = JulianDate.addSeconds(
point.lastTime, point.lastTime,
10, 10,
new Cesium.JulianDate(), new JulianDate(),
); );
point.property.addSample(nextTime, position); point.property.addSample(nextTime, position);
point.lastTime = nextTime; point.lastTime = nextTime;

View File

@ -55,8 +55,8 @@ export const closeWindow = () => {
window.close(); window.close();
setTimeout(() => { setTimeout(() => {
if (!window.closed && !window.opener) { if (!window.closed && !window.opener) {
window.location.href = "https://gbs-gateway.qhdsafety.com/"; // window.location.href = "https://gbs-gateway.qhdsafety.com/";
// window.location.href = "http://192.168.198.8:30140/"; window.location.href = "http://192.168.198.8:30140/";
} }
}, 500); }, 500);
}; };