This commit is contained in:
jingna 2025-07-02 14:01:02 +08:00
commit 296a1e9585
27 changed files with 11278 additions and 1054 deletions

View File

@ -4,13 +4,13 @@ export default {
'/api/f': {
target: 'http://192.168.1.58:8100',
changeOrigin: true,
rewrite: path => path.replace(/^\/api\/f/, '')
rewrite: path => path.replace(/^\/api\/f/, 'de2api')
},
// 使用 proxy 实例
'/api': {
target: 'http://192.168.1.58:8100',
changeOrigin: true,
rewrite: path => path.replace(/^\/api/, '')
rewrite: path => path.replace(/^\/api/, 'de2api')
}
},
port: 8080

View File

@ -16,6 +16,7 @@
"dependencies": {
"@antv/g2plot": "^2.4.29",
"@antv/l7": "^2.22.0",
"@antv/l7-three": "^2.22.5",
"@antv/l7plot": "^0.5.5",
"@antv/s2": "^1.49.0",
"@codemirror/lang-sql": "^6.4.0",
@ -26,6 +27,7 @@
"@npkg/tinymce-plugins": "^0.0.7",
"@tinymce/tinymce-vue": "^5.1.0",
"@turf/centroid": "^7.0.0",
"@types/three": "^0.160.0",
"@videojs-player/vue": "^1.0.0",
"@vue/compiler-sfc": "^3.5.15",
"@vueuse/core": "^9.13.0",
@ -59,6 +61,7 @@
"qs": "^6.11.0",
"screenfull": "^6.0.2",
"snowflake-id": "^1.1.0",
"three": "^0.160.0",
"tinymce": "^5.8.2",
"vant": "^4.8.3",
"video.js": "^7.21.6",

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,14 @@
# 3ds Max Wavefront OBJ Exporter v0.97b - (c)2007 guruware
# 创建的文件:23.12.2020 17:11:48
newmtl 02___Default
Ns 10.0000
Ni 1.5000
d 0.3000
Tr 0.7000
Tf 0.3000 0.3000 0.3000
illum 2
Ka 0.5961 0.4196 0.0745
Kd 0.5961 0.4196 0.0745
Ks 0.5400 0.5400 0.5400
Ke 0.0000 0.0000 0.0000

View File

@ -0,0 +1,86 @@
# 3ds Max Wavefront OBJ Exporter v0.97b - (c)2007 guruware
# ´´½¨µÄÎļþ:23.12.2020 17:11:48
mtllib XiaoSanJiao.mtl
#
# object Cone001
#
v 0.1414 0.4000 -0.1411
v 0.1414 0.4000 0.1418
v 0.0943 0.2667 0.0946
v 0.0943 0.2667 -0.0939
v -0.1414 0.4000 0.1418
v -0.0943 0.2667 0.0946
v -0.1414 0.4000 -0.1411
v -0.0943 0.2667 -0.0939
v 0.0471 0.1333 0.0475
v 0.0471 0.1333 -0.0468
v -0.0471 0.1333 0.0475
v -0.0471 0.1333 -0.0468
v 0.0000 0.0000 0.0004
# 13 vertices
vn 0.9428 -0.3333 -0.0000
vn 0.9428 -0.3333 0.0000
vn -0.0000 -0.3333 0.9428
vn -0.9428 -0.3333 -0.0000
vn -0.0000 -0.3333 -0.9428
vn 0.7071 0.0000 -0.7071
vn 0.0000 1.0000 0.0000
# 7 vertex normals
vt 0.7500 0.0000 1.0000
vt 1.0000 0.0000 1.0000
vt 1.0000 0.3333 0.6667
vt 0.7500 0.3333 0.6667
vt 0.0000 0.0000 1.0000
vt 0.2500 0.0000 1.0000
vt 0.2500 0.3333 0.6667
vt 0.0000 0.3333 0.6667
vt 0.5000 0.0000 1.0000
vt 0.5000 0.3333 0.6667
vt 1.0000 0.6667 0.3333
vt 0.7500 0.6667 0.3333
vt 0.2500 0.6667 0.3333
vt 0.0000 0.6667 0.3333
vt 0.5000 0.6667 0.3333
vt 0.5000 1.0000 0.0000
vt 0.5000 0.0000 -0.2500
vt 0.0000 0.5000 -0.2500
vt 0.5000 1.0000 -0.2500
vt 1.0000 0.5000 -0.2500
# 20 texture coords
g Cone001
usemtl 02___Default
s 1
f 1/1/1 2/2/2 3/3/2 4/4/1
s 2
f 2/5/3 5/6/3 6/7/3 3/8/3
s 1
f 5/6/4 7/9/4 8/10/4 6/7/4
s 2
f 7/9/5 1/1/5 4/4/5 8/10/5
s 1
f 4/4/1 3/3/2 9/11/1 10/12/1
s 2
f 3/8/3 6/7/3 11/13/3 9/14/3
s 1
f 6/7/4 8/10/4 12/15/4 11/13/4
s 2
f 8/10/5 4/4/5 10/12/5 12/15/5
s 1
f 10/12/1 9/11/1 13/16/1 13/16/6
s 2
f 9/14/3 11/13/3 13/16/3 13/16/6
s 1
f 11/13/4 12/15/4 13/16/4 13/16/6
s 2
f 12/15/5 10/12/5 13/16/5 13/16/6
s 4
f 5/17/7 2/18/7 1/19/7 7/20/7
f 13/16/6 13/16/6 13/16/6 13/16/6
# 14 polygons

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -34,6 +34,9 @@ import { GaodeMap } from '@antv/l7-maps';
import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js' //
import { ThreeLayer, ThreeRender } from '@antv/l7-three';
const { t } = useI18n()
const dvMainStore = dvMainStoreWithOut()
const { nowPanelTrackInfo, nowPanelJumpInfo, mobileInPc, embeddedCallBack, inMobile } =
@ -122,11 +125,8 @@ const state = reactive({
let chartData = shallowRef<Partial<Chart['data']>>({
fields: []
})
// Three.js
let threeScene: THREE.Scene | null = null;
let threeRenderer: THREE.WebGLRenderer | null = null;
let threeCamera: THREE.PerspectiveCamera | null = null;
let model: THREE.Object3D | null = null;
const containerId = 'container-' + showPosition.value + '-' + view.value.id + '-' + suffixId.value
const viewTrack = ref(null)
@ -200,7 +200,7 @@ const calcData = async (view, callback) => {
isError.value = false
const v = JSON.parse(JSON.stringify(view))
getData(v)
.then(async res => {
.then(async (res: any) => {
if (res.code && res.code !== 0) {
isError.value = true
errMsg.value = res.msg
@ -279,7 +279,7 @@ const renderChart = async (view, callback?) => {
}
}
let myChart = null
let g2Timer: number
let g2Timer: any
const renderG2Plot = async (chart, chartView: G2PlotChartView<any, any>) => {
g2Timer && clearTimeout(g2Timer)
g2Timer = setTimeout(async () => {
@ -308,7 +308,7 @@ const country = ref('')
const appStore = useAppStoreWithOut()
const chartContainer = ref<HTMLElement>(null)
let scope
let mapTimer: number
let mapTimer: any
const renderL7Plot = async (chart: ChartObj, chartView: L7PlotChartView<any, any>, callback) => {
const map = parseJson(chart.customAttr).map
let areaId = map.id
@ -387,6 +387,7 @@ class SatelliteControl extends Control {
let mapL7Timer: any
let scaleControl: Scale | null = null //
let fullscreenControl
let content = null
let satelliteControlInstance = null; //
const renderL7 = async (chart: ChartObj, chartView: L7ChartView<any, any>, callback) => {
mapL7Timer && clearTimeout(mapL7Timer);
@ -424,12 +425,190 @@ const renderL7 = async (chart: ChartObj, chartView: L7ChartView<any, any>, callb
myChart.getScene()?.addControl(satelliteControlInstance);
}
// ====== ======
threel7()
myChart?.render();
callback?.();
emit('resetLoading');
}, 500);
};
//
let threeJSLayerRef:any = null
const threel7 = () => {
// ====== ======
const scene = myChart.getScene(); //
scene.registerRenderService(ThreeRender);
threeJSLayerRef = new ThreeLayer({
enableMultiPassRenderer: false,
onAddMeshes: (threeScene: any, layer: any) => {
//
const camera = new THREE.PerspectiveCamera(
75,
scene.width / scene.height,
0.1,
1000000000
);
camera.position.set(0, 0, 10000000);
threeScene.add(camera);
layer.camera = camera; //
threeScene.add(new THREE.AmbientLight(0xffffff));
const sunlight: any = new THREE.DirectionalLight(0xffffff, 0.25);
sunlight.position.set(0, 80000000, 100000000);
sunlight.matrixWorldNeedsUpdate = true;
threeScene.add(sunlight);
// 使 Three.js glTFLoader
const manager: any = new THREE.LoadingManager()
manager.setURLModifier((url: any, path: any) => {
return (path || '') + url
})
const loader = new GLTFLoader(manager);
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath('./static/js/');
dracoLoader.setDecoderConfig({ type: 'js' });
loader.setDRACOLoader(dracoLoader);
loader.load(
`./static/3DModel/scene.glb`,
(gltf) => {
// debugger
const gltfScene: any = gltf.scene
// setDouble(gltfScene);
content = gltfScene
layer.adjustMeshToMap(gltfScene);
// gltfScene.scale.set(1000, 1000, 1000)
layer.setMeshScale(gltfScene, 10, 10, 10);
layer.setObjectLngLat(gltfScene, [116.397428, 39.91923], 0);
//
threeScene.add(new THREE.AmbientLight(0xffffff, 0.3));
// UV Mapping
gltfScene.traverse((node) => {
if (node.isMesh) {
const material = node.material;
if (material.map) {
const uv = node.geometry.attributes.uv;
for (let i = 0; i < uv.count; i++) {
uv.setX(i, /* 新的 U 值 */);
uv.setY(i, /* 新的 V 值 */);
}
uv.needsUpdate = true;
}
}
});
//
gltfScene.traverse((node) => {
if (node.isMesh) {
const material = node.material;
if (material.map) {
material.map.repeat.set(1, 1);
material.map.offset.set(0, 0);
material.map.wrapS = THREE.ClampToEdgeWrapping;
material.map.wrapT = THREE.ClampToEdgeWrapping;
}
}
});
//
const sunlight = new THREE.DirectionalLight(0xffffff, 0.4);
sunlight.position.set(50, 100, 50);
sunlight.target.position.set(0, 0, 0);
sunlight.matrixWorldNeedsUpdate = true;
threeScene.add(sunlight);
//
const pointLight = new THREE.PointLight(0xffffff, 0.6, 1000);
pointLight.position.set(10, 15, -5);
threeScene.add(pointLight);
//
const spotLight = new THREE.SpotLight(0xffffff, 0.8);
spotLight.position.set(10, 25, 15);
spotLight.angle = Math.PI / 4;
threeScene.add(spotLight);
//
scene.on('click', handleModelClick);
//
threeScene.add(gltfScene);
// //
layer.render();
},
);
},
}).animate(true);
scene.addLayer(threeJSLayerRef);
// ====== ======
}
//
const handleModelClick = (e: any) => {
// debugger
//
if (!threeJSLayerRef || !threeJSLayerRef.camera) {
console.warn('Camera not initialized');
return;
}
// 1.
const point = e.containerPoint || { x: e.originEvent.x, y: e.originEvent.y }; //
const scene = myChart.getScene();
const container = scene.getContainer();
const width = container.clientWidth;
const height = container.clientHeight;
// 2.
const mouse = new THREE.Vector2();
mouse.x = (point.x / width) * 2 - 1;
mouse.y = -(point.y / height) * 2 + 1;
// 3. 线
const raycaster = new THREE.Raycaster();
raycaster.setFromCamera(mouse, threeJSLayerRef.camera);
// 4.
const allObjects = [];
content.traverse(child => {
if (child.isMesh && child.visible) {
allObjects.push(child);
}
});
const intersects = raycaster.intersectObjects(allObjects);
// 5.
if (intersects.length > 0) {
const closest = intersects[0];
console.log('模型被点击:', closest.object);
// 6.
highlightSelectedObject(closest.object);
} else {
//
clearSelection();
}
};
//
const highlightSelectedObject = (object) => {
//
if (!object.userData.originalMaterial) {
object.userData.originalMaterial = object.material;
}
//
object.material = new THREE.MeshBasicMaterial({
color: 0xff0000,
transparent: true,
opacity: 0.7
});
};
//
const clearSelection = () => {
content.traverse(child => {
if (child.userData.originalMaterial) {
child.material = child.userData.originalMaterial;
delete child.userData.originalMaterial;
}
});
};
const pointClickTrans = () => {
if (embeddedCallBack.value === 'yes') {
trackClick('pointClick')
@ -736,140 +915,11 @@ defineExpose({
clearLinkage
})
// three.js
// - Three.js
const initThree = (container: HTMLElement) => {
//
threeScene = new THREE.Scene();
//
threeCamera = new THREE.PerspectiveCamera(
75,
container.clientWidth / container.clientHeight,
0.1,
1000
);
threeCamera.position.z = 5;
//
threeRenderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });
threeRenderer.setSize(container.clientWidth, container.clientHeight);
//
threeRenderer.domElement.style.position = 'absolute';
threeRenderer.domElement.style.top = '0';
threeRenderer.domElement.style.left = '0';
threeRenderer.domElement.style.zIndex = '1'; //
container.appendChild(threeRenderer.domElement);
//
const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
threeScene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
directionalLight.position.set(10, 10, 10);
threeScene.add(directionalLight);
};
// -
const loadModel = (filePath: string) => {
const loader = new GLTFLoader();
const dracoLoader = new DRACOLoader()
dracoLoader.setDecoderPath('./static/js/')
dracoLoader.setDecoderConfig({ type: 'js' })
loader.setDRACOLoader(dracoLoader)
//
if (!myChart?.getScene()) {
console.warn('地图场景尚未初始化,延迟加载模型');
//
setTimeout(() => loadModel(filePath), 500);
return;
}
const scene = myChart.getScene();
//
if (scene.loaded) {
//
loadModelInternal(loader, filePath);
} else {
//
const loadedHandler = () => {
scene.off('loaded', loadedHandler); //
loadModelInternal(loader, filePath);
};
scene.on('loaded', loadedHandler);
}
};
//
const loadModelInternal = (loader, filePath) => {
loader.load(
filePath,
(gltf) => {
console.log('Model loaded successfully:', gltf);
model = gltf.scene;
threeScene?.add(model);
// animate();
placeModelByLngLat(116.3974, 39.9093); //
},
(progress) => {
console.log('Loading progress:', progress);
},
(error) => {
console.error('模型加载失败:', error);
}
);
};
// -
const placeModelByLngLat = (lng: number, lat: number) => {
if (!model || !myChart?.getScene()) {
console.warn('模型或地图场景未初始化');
return;
}
const scene = myChart.getScene();
console.log('地图场景状态:', scene);
try {
const containerPoint = scene.lngLatToContainer([lng, lat]);
console.log('容器坐标:', containerPoint);
const container = document.getElementById(containerId);
if (!container) {
console.error('容器元素未找到');
return;
}
// Three.js
const x = (containerPoint.x / container.clientWidth) * 2 - 1;
const y = -(containerPoint.y / container.clientHeight) * 2 + 1;
console.log('Three.js坐标:', { x, y });
//
model.position.set(x * 5, y * 5, 0);
//
if (threeCamera) {
threeCamera.lookAt(model.position);
console.log('相机已调整朝向模型');
}
} catch (e) {
console.error('坐标转换错误:', e);
}
};
//
const animate = () => {
requestAnimationFrame(animate);
if (threeRenderer && threeScene && threeCamera) {
threeRenderer.render(threeScene, threeCamera);
}
};
let resizeObserver
const TOLERANCE = 0.01
const RESIZE_MONITOR_CHARTS = ['map', 'bubble-map', 'flow-map', 'heat-map']
onMounted(() => {
console.log('Three.js实际版本:', THREE.REVISION);
const containerDom = document.getElementById(containerId)
const { offsetWidth, offsetHeight } = containerDom
const preSize = [offsetWidth, offsetHeight]
@ -893,14 +943,7 @@ onMounted(() => {
useEmitt({ name: 'l7-prepare-picture', callback: preparePicture })
useEmitt({ name: 'l7-unprepare-picture', callback: unPreparePicture })
// Three.js
// const container = document.getElementById(containerId);
// if (container) {
// initThree(container);
// //
// // loadModel(`./static/3DModel/Camera1.glb`);
// // loadModel('static/3DModel/scene.glb');
// }
})
onBeforeUnmount(() => {
try {
@ -909,9 +952,7 @@ onBeforeUnmount(() => {
} catch (e) {
console.warn(e)
}
if (threeRenderer) {
threeRenderer.dispose();
}
})
</script>
@ -953,16 +994,19 @@ onBeforeUnmount(() => {
fill: #fff !important;
color: #fff !important;
}
:deep(.l7-control-zoom) {
position: fixed !important;
right: 0px;
bottom: 65px;
}
:deep(.l7-control-button) {
position: fixed !important;
right: 0px;
bottom: 35px;
}
// :deep(.l7-button-control){
// position:fixed;
// right: 0px;

File diff suppressed because it is too large Load Diff