提交 e6670372 authored 作者: 詹银鑫's avatar 詹银鑫

加载无人机模型并添加点击弹窗和无人机动画

上级 d28ccc7e
......@@ -31,8 +31,8 @@ import {
FileLoader,
Shape,
ExtrudeGeometry,
} from "three"
import * as THREE from "three"
} from "three";
import * as THREE from "three";
import {
Mini3d,
......@@ -46,39 +46,39 @@ import {
GradientShader,
DiffuseShader,
Focus,
} from "@/mini3d"
} from "@/mini3d";
import { geoMercator } from "d3-geo"
import labelIcon from "@/assets/texture/label-icon.png"
import chinaData from "./map/chinaData"
import provincesData from "./map/provincesData"
import scatterData from "./map/scatter"
import infoData from "./map/infoData"
import gsap from "gsap"
import emitter from "@/utils/emitter"
import { InteractionManager } from "three.interactive"
import { geoMercator } from "d3-geo";
import labelIcon from "@/assets/texture/label-icon.png";
import chinaData from "./map/chinaData";
import provincesData from "./map/provincesData";
import scatterData from "./map/scatter";
import infoData from "./map/infoData";
import gsap from "gsap";
import emitter from "@/utils/emitter";
import { InteractionManager } from "three.interactive";
// 引入模型加载模块
import { Resource } from "@/mini3d/utils/Resource"
import { Resource } from "@/mini3d/utils/Resource";
function sortByValue(data) {
data.sort((a, b) => b.value - a.value)
return data
data.sort((a, b) => b.value - a.value);
return data;
}
export class World extends Mini3d {
constructor(canvas, assets) {
super(canvas)
super(canvas);
// 中心坐标
// this.geoProjectionCenter = [113.280637, 23.125178]
this.geoProjectionCenter = [110.840171, 39.864362]
this.geoProjectionCenter = [110.840171, 39.864362];
// 缩放比例
this.geoProjectionScale = 700
this.geoProjectionScale = 700;
// this.geoProjectionScale = 120
// 飞线中心
// this.flyLineCenter = [113.544372, 23.329249]
this.flyLineCenter = [111.319412,39.781603]
this.flyLineCenter = [111.319412, 39.781603];
// 地图拉伸高度
this.depth = 0.5
this.depth = 0.5;
// this.mapFocusLabelInfo = {
// name: "广东省",
// enName: "GUANGDONG PROVINCE",
......@@ -88,76 +88,84 @@ export class World extends Mini3d {
name: "准格尔旗",
enName: "ZHUNGEER QI",
center: [110.840171, 39.864362],
}
};
// 是否点击
this.clicked = false
this.clicked = false;
// 雾
this.scene.fog = new Fog(0x102736, 1, 50)
this.scene.fog = new Fog(0x102736, 1, 50);
// 背景
this.scene.background = new Color(0x102736)
this.scene.background = new Color(0x102736);
// 相机初始位置
// this.camera.instance.position.set(-13.767695123014105, 12.990152163077308, 39.28228164159694)
this.camera.instance.position.set(-13.767695123014105, 12.990152163077308, 19.28228164159694)
this.camera.instance.near = 0.1
this.camera.instance.far = 10000
this.camera.instance.updateProjectionMatrix()
this.camera.instance.position.set(
-13.767695123014105,
12.990152163077308,
19.28228164159694
);
this.camera.instance.near = 0.1;
this.camera.instance.far = 10000;
this.camera.instance.updateProjectionMatrix();
// 创建交互管理
this.interactionManager = new InteractionManager(this.renderer.instance, this.camera.instance, this.canvas)
this.interactionManager = new InteractionManager(
this.renderer.instance,
this.camera.instance,
this.canvas
);
this.assets = assets
this.assets = assets;
// 创建环境光
this.initEnvironment()
this.init()
console.log("执行了 这些代码")
this.initEnvironment();
this.init();
console.log("执行了 这些代码");
}
init() {
// 标签组
this.labelGroup = new Group()
this.label3d = new Label3d(this)
this.labelGroup.rotation.x = -Math.PI / 2
this.scene.add(this.labelGroup)
this.labelGroup = new Group();
this.label3d = new Label3d(this);
this.labelGroup.rotation.x = -Math.PI / 2;
this.scene.add(this.labelGroup);
// 飞线焦点光圈组
this.flyLineFocusGroup = new Group()
this.flyLineFocusGroup.visible = false
this.flyLineFocusGroup.rotation.x = -Math.PI / 2
this.scene.add(this.flyLineFocusGroup)
this.flyLineFocusGroup = new Group();
this.flyLineFocusGroup.visible = false;
this.flyLineFocusGroup.rotation.x = -Math.PI / 2;
this.scene.add(this.flyLineFocusGroup);
// 区域事件元素
this.eventElement = []
this.eventElement = [];
// 鼠标移上移除的材质
this.defaultMaterial = null // 默认材质
this.defaultLightMaterial = null // 高亮材质
this.defaultMaterial = null; // 默认材质
this.defaultLightMaterial = null; // 高亮材质
// 创建地形模型初始化
this.terrainResource = new Resource()
this.terrainResource = new Resource();
// 创建底部高亮
this.createBottomBg()
this.createBottomBg();
// 模糊边线
this.createChinaBlurLine()
this.createChinaBlurLine();
// 扩散网格
this.createGrid()
this.createGrid();
// 旋转圆环
this.createRotateBorder()
this.createRotateBorder();
// 创建标签
this.createLabel(this.mapFocusLabelInfo)
this.createLabel(this.mapFocusLabelInfo);
// 创建地图
this.createMap()
this.createMap();
// 添加事件
this.createEvent()
this.createEvent();
// 创建飞线
this.createFlyLine()
this.createFlyLine();
// 创建飞线焦点
this.createFocus()
this.createFocus();
// 创建粒子
this.createParticles()
this.createParticles();
// 创建散点图
this.createScatter()
this.createScatter();
// 创建信息点
this.createInfoPoint()
this.createInfoPoint();
// 创建轮廓
this.createStorke()
this.createStorke();
// 创建圆滑曲线
this.createSmoothLine([
[110.9801, 39.8002],
......@@ -165,7 +173,14 @@ export class World extends Mini3d {
[111.1803, 39.6054],
[110.9008, 39.8056],
[111.1003, 39.7386],
])
]);
this.showDroneAtLngLat(
"../../../public/assets/json/Flying_drone..glb",
110.9801,
39.8002,
0.5,
5
);
// 创造3d地形
// this.createTerrain()
// 创造geoJson图
......@@ -176,12 +191,12 @@ export class World extends Mini3d {
// 创建动画时间线
let tl = gsap.timeline({
onComplete: () => {},
})
tl.pause()
this.animateTl = tl
tl.addLabel("focusMap", 1.5)
tl.addLabel("focusMapOpacity", 2)
tl.addLabel("bar", 3)
});
tl.pause();
this.animateTl = tl;
tl.addLabel("focusMap", 1.5);
tl.addLabel("focusMapOpacity", 2);
tl.addLabel("bar", 3);
tl.to(this.camera.instance.position, {
duration: 2,
x: -0.17427287762525134,
......@@ -189,9 +204,9 @@ export class World extends Mini3d {
z: 20.688611202093714,
ease: "circ.out",
onStart: () => {
this.flyLineFocusGroup.visible = false
this.flyLineFocusGroup.visible = false;
},
})
});
tl.to(
this.focusMapGroup.position,
{
......@@ -201,7 +216,7 @@ export class World extends Mini3d {
z: 0,
},
"focusMap"
)
);
tl.to(
this.focusMapGroup.scale,
......@@ -212,14 +227,14 @@ export class World extends Mini3d {
z: 1,
ease: "circ.out",
onComplete: () => {
this.flyLineGroup.visible = true
this.scatterGroup.visible = true
this.InfoPointGroup.visible = true
this.createInfoPointLabelLoop()
this.flyLineGroup.visible = true;
this.scatterGroup.visible = true;
this.InfoPointGroup.visible = true;
this.createInfoPointLabelLoop();
},
},
"focusMap"
)
);
tl.to(
this.focusMapTopMaterial,
......@@ -229,7 +244,7 @@ export class World extends Mini3d {
ease: "circ.out",
},
"focusMapOpacity"
)
);
tl.to(
this.focusMapSideMaterial,
{
......@@ -237,13 +252,13 @@ export class World extends Mini3d {
opacity: 1,
ease: "circ.out",
onComplete: () => {
this.focusMapSideMaterial.transparent = false
this.focusMapSideMaterial.transparent = false;
},
},
"focusMapOpacity"
)
);
this.otherLabel.map((item, index) => {
let element = item.element.querySelector(".other-label")
let element = item.element.querySelector(".other-label");
tl.to(
element,
{
......@@ -254,8 +269,8 @@ export class World extends Mini3d {
ease: "circ.out",
},
"focusMapOpacity"
)
})
);
});
tl.to(
this.mapLineMaterial,
{
......@@ -264,7 +279,7 @@ export class World extends Mini3d {
opacity: 1,
},
"focusMapOpacity"
)
);
tl.to(
this.rotateBorder1.scale,
{
......@@ -276,7 +291,7 @@ export class World extends Mini3d {
ease: "circ.out",
},
"focusMapOpacity"
)
);
tl.to(
this.rotateBorder2.scale,
{
......@@ -287,15 +302,15 @@ export class World extends Mini3d {
z: 1,
ease: "circ.out",
onComplete: () => {
this.flyLineFocusGroup.visible = true
emitter.$emit("mapPlayComplete")
this.flyLineFocusGroup.visible = true;
emitter.$emit("mapPlayComplete");
},
},
"focusMapOpacity"
)
);
this.allBar.map((item, index) => {
if (item.userData.name === "广州市") {
return false
return false;
}
tl.to(
item.scale,
......@@ -308,8 +323,8 @@ export class World extends Mini3d {
ease: "circ.out",
},
"bar"
)
})
);
});
this.allBarMaterial.map((item, index) => {
tl.to(
item,
......@@ -320,16 +335,16 @@ export class World extends Mini3d {
ease: "circ.out",
},
"bar"
)
})
);
});
this.allProvinceLabel.map((item, index) => {
let element = item.element.querySelector(".provinces-label-wrap")
let number = item.element.querySelector(".number .value")
let numberVal = Number(number.innerText)
let element = item.element.querySelector(".provinces-label-wrap");
let number = item.element.querySelector(".number .value");
let numberVal = Number(number.innerText);
let numberAnimate = {
score: 0,
}
};
tl.to(
element,
{
......@@ -340,7 +355,7 @@ export class World extends Mini3d {
ease: "circ.out",
},
"bar"
)
);
tl.to(
numberAnimate,
{
......@@ -350,11 +365,11 @@ export class World extends Mini3d {
onUpdate: showScore,
},
"bar"
)
);
function showScore() {
number.innerText = numberAnimate.score.toFixed(0)
number.innerText = numberAnimate.score.toFixed(0);
}
})
});
this.allGuangquan.map((item, index) => {
tl.to(
item.children[0].scale,
......@@ -367,7 +382,7 @@ export class World extends Mini3d {
ease: "circ.out",
},
"bar"
)
);
tl.to(
item.children[1].scale,
{
......@@ -379,20 +394,20 @@ export class World extends Mini3d {
ease: "circ.out",
},
"bar"
)
})
);
});
}
initEnvironment() {
let sun = new AmbientLight(0xffffff, 5)
this.scene.add(sun)
let directionalLight = new DirectionalLight(0xffffff, 5)
directionalLight.position.set(-30, 6, -8)
directionalLight.castShadow = true
directionalLight.shadow.radius = 20
directionalLight.shadow.mapSize.width = 1024
directionalLight.shadow.mapSize.height = 1024
this.scene.add(directionalLight)
let sun = new AmbientLight(0xffffff, 5);
this.scene.add(sun);
let directionalLight = new DirectionalLight(0xffffff, 5);
directionalLight.position.set(-30, 6, -8);
directionalLight.castShadow = true;
directionalLight.shadow.radius = 20;
directionalLight.shadow.mapSize.width = 1024;
directionalLight.shadow.mapSize.height = 1024;
this.scene.add(directionalLight);
this.createPointLight({
color: "#1d5e5e",
intensity: 800,
......@@ -400,7 +415,7 @@ export class World extends Mini3d {
x: -9,
y: 3,
z: -3,
})
});
this.createPointLight({
color: "#1d5e5e",
intensity: 200,
......@@ -409,50 +424,54 @@ export class World extends Mini3d {
// y: 2,
y: -2,
z: 5,
})
});
}
createPointLight(pointParams) {
const pointLight = new PointLight(0x1d5e5e, pointParams.intensity, pointParams.distance)
pointLight.position.set(pointParams.x, pointParams.y, pointParams.z)
this.scene.add(pointLight)
const pointLight = new PointLight(
0x1d5e5e,
pointParams.intensity,
pointParams.distance
);
pointLight.position.set(pointParams.x, pointParams.y, pointParams.z);
this.scene.add(pointLight);
}
createMap() {
let mapGroup = new Group()
let focusMapGroup = new Group()
this.focusMapGroup = focusMapGroup
let { china, chinaTopLine } = this.createChina()
let { map, mapTop, mapLine } = this.createProvince()
let { waterGroup } = this.createWater()
let { lineWaterGroup } = this.createLineWater()
china.setParent(mapGroup)
chinaTopLine.setParent(mapGroup)
let mapGroup = new Group();
let focusMapGroup = new Group();
this.focusMapGroup = focusMapGroup;
let { china, chinaTopLine } = this.createChina();
let { map, mapTop, mapLine } = this.createProvince();
let { waterGroup } = this.createWater();
let { lineWaterGroup } = this.createLineWater();
china.setParent(mapGroup);
chinaTopLine.setParent(mapGroup);
// 创建扩散
this.createDiffuse()
map.setParent(focusMapGroup)
mapTop.setParent(focusMapGroup)
mapLine.setParent(focusMapGroup)
focusMapGroup.add(waterGroup)
focusMapGroup.add(lineWaterGroup)
focusMapGroup.position.set(0, 0, -0.01)
focusMapGroup.scale.set(1, 1, 0)
focusMapGroup.name = "focusMapGroup"
mapGroup.add(focusMapGroup)
mapGroup.rotation.x = -Math.PI / 2
mapGroup.position.set(0, 0.2, 0)
this.scene.add(mapGroup)
this.createBar()
this.createDiffuse();
map.setParent(focusMapGroup);
mapTop.setParent(focusMapGroup);
mapLine.setParent(focusMapGroup);
focusMapGroup.add(waterGroup);
focusMapGroup.add(lineWaterGroup);
focusMapGroup.position.set(0, 0, -0.01);
focusMapGroup.scale.set(1, 1, 0);
focusMapGroup.name = "focusMapGroup";
mapGroup.add(focusMapGroup);
mapGroup.rotation.x = -Math.PI / 2;
mapGroup.position.set(0, 0.2, 0);
this.scene.add(mapGroup);
this.createBar();
}
createChina() {
let params = {
chinaBgMaterialColor: "#152c47",
lineColor: "#3f82cd",
}
let chinaData = this.assets.instance.getResource("china")
};
let chinaData = this.assets.instance.getResource("china");
let chinaBgMaterial = new MeshLambertMaterial({
color: new Color(params.chinaBgMaterialColor),
transparent: true,
opacity: 1,
})
});
let china = new BaseMap(this, {
//position: new Vector3(0, 0, -0.03),
data: chinaData,
......@@ -461,10 +480,10 @@ export class World extends Mini3d {
merge: true,
material: chinaBgMaterial,
renderOrder: 2,
})
});
let chinaTopLineMaterial = new LineBasicMaterial({
color: params.lineColor,
})
});
let chinaTopLine = new Line(this, {
// position: new Vector3(0, 0, -0.02),
data: chinaData,
......@@ -472,15 +491,15 @@ export class World extends Mini3d {
geoProjectionScale: this.geoProjectionScale,
material: chinaTopLineMaterial,
renderOrder: 3,
})
chinaTopLine.lineGroup.position.z += 0.01
return { china, chinaTopLine }
});
chinaTopLine.lineGroup.position.z += 0.01;
return { china, chinaTopLine };
}
createProvince() {
let mapJsonData = this.assets.instance.getResource("mapJson")
let [topMaterial, sideMaterial] = this.createProvinceMaterial()
this.focusMapTopMaterial = topMaterial
this.focusMapSideMaterial = sideMaterial
let mapJsonData = this.assets.instance.getResource("mapJson");
let [topMaterial, sideMaterial] = this.createProvinceMaterial();
this.focusMapTopMaterial = topMaterial;
this.focusMapSideMaterial = sideMaterial;
let map = new ExtrudeMap(this, {
geoProjectionCenter: this.geoProjectionCenter,
geoProjectionScale: this.geoProjectionScale,
......@@ -490,23 +509,23 @@ export class World extends Mini3d {
topFaceMaterial: topMaterial,
sideMaterial: sideMaterial,
renderOrder: 9,
})
});
let faceMaterial = new MeshStandardMaterial({
color: 0xffffff,
transparent: true,
opacity: 0.5,
// fog: false,
})
});
let faceGradientShader = new GradientShader(faceMaterial, {
// uColor1: 0x2a6e92,
// uColor2: 0x102736,
uColor1: 0x12bbe0,
uColor2: 0x0094b5,
})
this.defaultMaterial = faceMaterial
this.defaultLightMaterial = this.defaultMaterial.clone()
this.defaultLightMaterial.color = new Color("rgba(115,208,255,1)")
this.defaultLightMaterial.opacity = 0.8
});
this.defaultMaterial = faceMaterial;
this.defaultLightMaterial = this.defaultMaterial.clone();
this.defaultLightMaterial.color = new Color("rgba(115,208,255,1)");
this.defaultLightMaterial.opacity = 0.8;
// this.defaultLightMaterial.emissive.setHex(new Color("rgba(115,208,255,1)"));
// this.defaultLightMaterial.emissiveIntensity = 3.5;
let mapTop = new BaseMap(this, {
......@@ -516,34 +535,34 @@ export class World extends Mini3d {
data: mapJsonData,
material: faceMaterial,
renderOrder: 2,
})
});
mapTop.mapGroup.children.map((group) => {
group.name = group.userData.name
group.name = group.userData.name;
group.children.map((mesh) => {
if (mesh.type === "Mesh") {
this.eventElement.push(mesh)
this.eventElement.push(mesh);
}
})
})
});
});
this.mapLineMaterial = new LineBasicMaterial({
color: 0xffffff,
opacity: 0,
transparent: true,
fog: false,
})
});
let mapLine = new Line(this, {
geoProjectionCenter: this.geoProjectionCenter,
geoProjectionScale: this.geoProjectionScale,
data: mapJsonData,
material: this.mapLineMaterial,
renderOrder: 3,
})
mapLine.lineGroup.position.z += this.depth + 0.23
});
mapLine.lineGroup.position.z += this.depth + 0.23;
return {
map,
mapTop,
mapLine,
}
};
}
createProvinceMaterial() {
let topMaterial = new MeshLambertMaterial({
......@@ -552,13 +571,13 @@ export class World extends Mini3d {
opacity: 0,
fog: false,
side: DoubleSide,
})
});
topMaterial.onBeforeCompile = (shader) => {
shader.uniforms = {
...shader.uniforms,
uColor1: { value: new Color(0x2a6e92) }, // 419daa
uColor2: { value: new Color(0x102736) },
}
};
shader.vertexShader = shader.vertexShader.replace(
"void main() {",
`
......@@ -569,7 +588,7 @@ export class World extends Mini3d {
vAlpha = alpha;
vPosition = position;
`
)
);
shader.fragmentShader = shader.fragmentShader.replace(
"void main() {",
`
......@@ -579,7 +598,7 @@ export class World extends Mini3d {
uniform vec3 uColor2;
void main() {
`
)
);
shader.fragmentShader = shader.fragmentShader.replace(
"#include <opaque_fragment>",
/* glsl */ `
......@@ -597,29 +616,29 @@ export class World extends Mini3d {
}
gl_FragColor = vec4( outgoingLight, diffuseColor.a );
`
)
}
let sideMap = this.assets.instance.getResource("side")
sideMap.wrapS = RepeatWrapping
sideMap.wrapT = RepeatWrapping
sideMap.repeat.set(1, 1.5)
sideMap.offset.y += 0.065
);
};
let sideMap = this.assets.instance.getResource("side");
sideMap.wrapS = RepeatWrapping;
sideMap.wrapT = RepeatWrapping;
sideMap.repeat.set(1, 1.5);
sideMap.offset.y += 0.065;
let sideMaterial = new MeshStandardMaterial({
color: 0xffffff,
map: sideMap,
fog: false,
opacity: 0,
side: DoubleSide,
})
});
this.time.on("tick", () => {
sideMap.offset.y += 0.005
})
sideMap.offset.y += 0.005;
});
sideMaterial.onBeforeCompile = (shader) => {
shader.uniforms = {
...shader.uniforms,
uColor1: { value: new Color(0x2a6e92) },
uColor2: { value: new Color(0x2a6e92) },
}
};
shader.vertexShader = shader.vertexShader.replace(
"void main() {",
`
......@@ -630,7 +649,7 @@ export class World extends Mini3d {
vAlpha = alpha;
vPosition = position;
`
)
);
shader.fragmentShader = shader.fragmentShader.replace(
"void main() {",
`
......@@ -640,7 +659,7 @@ export class World extends Mini3d {
uniform vec3 uColor2;
void main() {
`
)
);
shader.fragmentShader = shader.fragmentShader.replace(
"#include <opaque_fragment>",
/* glsl */ `
......@@ -654,64 +673,73 @@ export class World extends Mini3d {
outgoingLight = outgoingLight*gradient;
gl_FragColor = vec4( outgoingLight, diffuseColor.a );
`
)
}
return [topMaterial, sideMaterial]
);
};
return [topMaterial, sideMaterial];
}
createBar() {
let self = this
let data = sortByValue(provincesData).filter((item, index) => index < 7)
const barGroup = new Group()
this.barGroup = barGroup
const factor = 0.7
const height = 4.0 * factor
const max = data[0].value
this.allBar = []
this.allBarMaterial = []
this.allGuangquan = []
this.allProvinceLabel = []
let self = this;
let data = sortByValue(provincesData).filter((item, index) => index < 7);
const barGroup = new Group();
this.barGroup = barGroup;
const factor = 0.7;
const height = 4.0 * factor;
const max = data[0].value;
this.allBar = [];
this.allBarMaterial = [];
this.allGuangquan = [];
this.allProvinceLabel = [];
data.map((item, index) => {
let geoHeight = height * (item.value / max)
let geoHeight = height * (item.value / max);
let material = new MeshBasicMaterial({
color: 0xffffff,
transparent: true,
opacity: 0,
depthTest: false,
fog: false,
})
});
new GradientShader(material, {
uColor1: index > 3 ? 0xfbdf88 : 0x50bbfe,
uColor2: index > 3 ? 0xfffef4 : 0x77fbf5,
size: geoHeight,
dir: "y",
})
const geo = new BoxGeometry(0.1 * factor, 0.1 * factor, geoHeight)
geo.translate(0, 0, geoHeight / 2)
const mesh = new Mesh(geo, material)
mesh.renderOrder = 5
let areaBar = mesh
let [x, y] = this.geoProjection(item.centroid)
areaBar.position.set(x, -y, this.depth + 0.45)
areaBar.scale.set(1, 1, 0)
areaBar.userData = { ...item }
let guangQuan = this.createQuan(new Vector3(x, this.depth + 0.44, y), index)
let hg = this.createHUIGUANG(geoHeight, index > 3 ? 0xfffef4 : 0x77fbf5)
areaBar.add(...hg)
barGroup.add(areaBar)
barGroup.rotation.x = -Math.PI / 2
let barLabel = labelStyle04(item, index, new Vector3(x, -y, this.depth + 1.1 + geoHeight))
this.allBar.push(areaBar)
this.allBarMaterial.push(material)
this.allGuangquan.push(guangQuan)
this.allProvinceLabel.push(barLabel)
})
this.scene.add(barGroup)
});
const geo = new BoxGeometry(0.1 * factor, 0.1 * factor, geoHeight);
geo.translate(0, 0, geoHeight / 2);
const mesh = new Mesh(geo, material);
mesh.renderOrder = 5;
let areaBar = mesh;
let [x, y] = this.geoProjection(item.centroid);
areaBar.position.set(x, -y, this.depth + 0.45);
areaBar.scale.set(1, 1, 0);
areaBar.userData = { ...item };
let guangQuan = this.createQuan(
new Vector3(x, this.depth + 0.44, y),
index
);
let hg = this.createHUIGUANG(geoHeight, index > 3 ? 0xfffef4 : 0x77fbf5);
areaBar.add(...hg);
barGroup.add(areaBar);
barGroup.rotation.x = -Math.PI / 2;
let barLabel = labelStyle04(
item,
index,
new Vector3(x, -y, this.depth + 1.1 + geoHeight)
);
this.allBar.push(areaBar);
this.allBarMaterial.push(material);
this.allGuangquan.push(guangQuan);
this.allProvinceLabel.push(barLabel);
});
this.scene.add(barGroup);
function labelStyle04(data, index, position) {
let label = self.label3d.create("", "provinces-label", false)
let label = self.label3d.create("", "provinces-label", false);
label.init(
`<div class="provinces-label ${index > 4 ? "yellow" : ""}">
<div class="provinces-label-wrap">
<div class="number"><span class="value">${data.value}</span><span class="unit">万人</span></div>
<div class="number"><span class="value">${
data.value
}</span><span class="unit">万人</span></div>
<div class="name">
<span class="zh">${data.name}</span>
<span class="en">${data.enName.toUpperCase()}</span>
......@@ -720,84 +748,86 @@ export class World extends Mini3d {
</div>
</div>`,
position
)
self.label3d.setLabelStyle(label, 0.01, "x")
label.setParent(self.labelGroup)
return label
);
self.label3d.setLabelStyle(label, 0.01, "x");
label.setParent(self.labelGroup);
return label;
}
}
createEvent() {
let objectsHover = []
let objectsHover = [];
const reset = (mesh) => {
mesh.traverse((obj) => {
if (obj.isMesh) {
obj.material = this.defaultMaterial
}
})
obj.material = this.defaultMaterial;
}
});
};
const move = (mesh) => {
mesh.traverse((obj) => {
if (obj.isMesh) {
obj.material = this.defaultLightMaterial
}
})
obj.material = this.defaultLightMaterial;
}
});
};
this.eventElement.map((mesh) => {
this.interactionManager.add(mesh)
this.interactionManager.add(mesh);
mesh.addEventListener("mousedown", (ev) => {
let countryName = ev.target.userData.name
this.countryData = ev.target.parent.parent.children
if(ev.originalEvent.buttons === 1) {
console.log("label",this.label112)
this.focusMapGroup.children[0].visible = false
let countryName = ev.target.userData.name;
this.countryData = ev.target.parent.parent.children;
if (ev.originalEvent.buttons === 1) {
console.log("label", this.label112);
this.focusMapGroup.children[0].visible = false;
this.countryData.map((item) => {
// console.log("this.mapFocusLabel",this.mapFocusLabel)
if (item.name != countryName) {
item.visible = false // 隐藏其他区域
item.visible = false; // 隐藏其他区域
} else {
console.log("item",item)
item.visible = true // 显示被点击的区域
const [x, y] = this.geoProjection([109.840171, 38.864362])
console.log("item", item);
item.visible = true; // 显示被点击的区域
const [x, y] = this.geoProjection([109.840171, 38.864362]);
// console.log("mapFocusLabel",this.mapFocusLabel)
this.mapFocusLabel.element.innerHTML = `<div class="other-label" style="translate: none; rotate: none; scale: none; opacity: 1; transform: translate(0px, 0px);"><span>${item.name}</span><span>ZHUNGEERQI</span></div>`
this.mapFocusLabel.element.innerHTML = `<div class="other-label" style="translate: none; rotate: none; scale: none; opacity: 1; transform: translate(0px, 0px);"><span>${item.name}</span><span>ZHUNGEERQI</span></div>`;
// this.mapFocusLabel.position.set(x, -y, 0.4);
}
})
});
}
})
});
mesh.addEventListener("mouseover", (event) => {
if (!objectsHover.includes(event.target.parent)) {
objectsHover.push(event.target.parent)
objectsHover.push(event.target.parent);
}
document.body.style.cursor = "pointer"
move(event.target.parent)
})
document.body.style.cursor = "pointer";
move(event.target.parent);
});
mesh.addEventListener("mouseout", (event) => {
objectsHover = objectsHover.filter((n) => n.userData.name !== event.target.parent.userData.name)
objectsHover = objectsHover.filter(
(n) => n.userData.name !== event.target.parent.userData.name
);
if (objectsHover.length > 0) {
const mesh = objectsHover[objectsHover.length - 1]
}
reset(event.target.parent)
document.body.style.cursor = "default"
})
})
document.addEventListener("contextmenu",(event) => {
this.focusMapGroup.children[0].visible = true
if(this.countryData.length > 0) {
const mesh = objectsHover[objectsHover.length - 1];
}
reset(event.target.parent);
document.body.style.cursor = "default";
});
});
document.addEventListener("contextmenu", (event) => {
this.focusMapGroup.children[0].visible = true;
if (this.countryData.length > 0) {
this.countryData.map((item) => {
item.visible = true // 显示所有区域
this.mapFocusLabel.element.innerHTML = `<div class="other-label" style="translate: none; rotate: none; scale: none; opacity: 1; transform: translate(0px, 0px);"><span>准格尔旗</span><span>ZHUNGEER QI</span></div>`
})
item.visible = true; // 显示所有区域
this.mapFocusLabel.element.innerHTML = `<div class="other-label" style="translate: none; rotate: none; scale: none; opacity: 1; transform: translate(0px, 0px);"><span>准格尔旗</span><span>ZHUNGEER QI</span></div>`;
});
}
})
});
}
createHUIGUANG(h, color) {
let geometry = new PlaneGeometry(0.35, h)
geometry.translate(0, h / 2, 0)
const texture = this.assets.instance.getResource("huiguang")
texture.colorSpace = SRGBColorSpace
texture.wrapS = RepeatWrapping
texture.wrapT = RepeatWrapping
let geometry = new PlaneGeometry(0.35, h);
geometry.translate(0, h / 2, 0);
const texture = this.assets.instance.getResource("huiguang");
texture.colorSpace = SRGBColorSpace;
texture.wrapS = RepeatWrapping;
texture.wrapT = RepeatWrapping;
let material = new MeshBasicMaterial({
color: color,
map: texture,
......@@ -806,20 +836,20 @@ export class World extends Mini3d {
depthWrite: false,
side: DoubleSide,
blending: AdditiveBlending,
})
let mesh = new Mesh(geometry, material)
mesh.renderOrder = 10
mesh.rotateX(Math.PI / 2)
let mesh2 = mesh.clone()
let mesh3 = mesh.clone()
mesh2.rotateY((Math.PI / 180) * 60)
mesh3.rotateY((Math.PI / 180) * 120)
return [mesh, mesh2, mesh3]
});
let mesh = new Mesh(geometry, material);
mesh.renderOrder = 10;
mesh.rotateX(Math.PI / 2);
let mesh2 = mesh.clone();
let mesh3 = mesh.clone();
mesh2.rotateY((Math.PI / 180) * 60);
mesh3.rotateY((Math.PI / 180) * 120);
return [mesh, mesh2, mesh3];
}
createQuan(position, index) {
const guangquan1 = this.assets.instance.getResource("guangquan1")
const guangquan2 = this.assets.instance.getResource("guangquan2")
let geometry = new PlaneGeometry(0.5, 0.5)
const guangquan1 = this.assets.instance.getResource("guangquan1");
const guangquan2 = this.assets.instance.getResource("guangquan2");
let geometry = new PlaneGeometry(0.5, 0.5);
let material1 = new MeshBasicMaterial({
color: 0xffffff,
map: guangquan1,
......@@ -829,7 +859,7 @@ export class World extends Mini3d {
depthTest: false,
fog: false,
blending: AdditiveBlending,
})
});
let material2 = new MeshBasicMaterial({
color: 0xffffff,
map: guangquan2,
......@@ -839,40 +869,40 @@ export class World extends Mini3d {
depthTest: false,
fog: false,
blending: AdditiveBlending,
})
let mesh1 = new Mesh(geometry, material1)
let mesh2 = new Mesh(geometry, material2)
mesh1.renderOrder = 6
mesh2.renderOrder = 6
mesh1.rotateX(-Math.PI / 2)
mesh2.rotateX(-Math.PI / 2)
mesh1.position.copy(position)
mesh2.position.copy(position)
mesh2.position.y -= 0.001
mesh1.scale.set(0, 0, 0)
mesh2.scale.set(0, 0, 0)
this.quanGroup = new Group()
this.quanGroup.add(mesh1, mesh2)
this.scene.add(this.quanGroup)
});
let mesh1 = new Mesh(geometry, material1);
let mesh2 = new Mesh(geometry, material2);
mesh1.renderOrder = 6;
mesh2.renderOrder = 6;
mesh1.rotateX(-Math.PI / 2);
mesh2.rotateX(-Math.PI / 2);
mesh1.position.copy(position);
mesh2.position.copy(position);
mesh2.position.y -= 0.001;
mesh1.scale.set(0, 0, 0);
mesh2.scale.set(0, 0, 0);
this.quanGroup = new Group();
this.quanGroup.add(mesh1, mesh2);
this.scene.add(this.quanGroup);
this.time.on("tick", () => {
mesh1.rotation.z += 0.05
})
return this.quanGroup
mesh1.rotation.z += 0.05;
});
return this.quanGroup;
}
// 创建扩散
createDiffuse() {
let geometry = new PlaneGeometry(200, 200)
let geometry = new PlaneGeometry(200, 200);
let material = new MeshBasicMaterial({
color: 0x000000,
depthWrite: false,
// depthTest: false,
transparent: true,
blending: CustomBlending,
})
});
// 使用CustomBlending 实现混合叠加
material.blendEquation = AddEquation
material.blendSrc = DstColorFactor
material.blendDst = OneFactor
material.blendEquation = AddEquation;
material.blendSrc = DstColorFactor;
material.blendDst = OneFactor;
let diffuse = new DiffuseShader({
material,
time: this.time,
......@@ -887,15 +917,15 @@ export class World extends Mini3d {
repeat: -1,
duration: 6,
ease: "power1.easeIn",
})
}, 3)
});
}, 3);
},
})
let mesh = new Mesh(geometry, material)
mesh.renderOrder = 3
mesh.rotation.x = -Math.PI / 2
mesh.position.set(0, 0.21, 0)
this.scene.add(mesh)
});
let mesh = new Mesh(geometry, material);
mesh.renderOrder = 3;
mesh.rotation.x = -Math.PI / 2;
mesh.position.set(0, 0.21, 0);
this.scene.add(mesh);
}
createGrid() {
new Grid(this, {
......@@ -906,63 +936,63 @@ export class World extends Mini3d {
shapeColor: 0x2a5f8a,
pointSize: 0.1,
pointColor: 0x154d7d,
})
});
}
createBottomBg() {
let geometry = new PlaneGeometry(20, 20)
const texture = this.assets.instance.getResource("ocean")
texture.colorSpace = SRGBColorSpace
texture.wrapS = RepeatWrapping
texture.wrapT = RepeatWrapping
texture.repeat.set(1, 1)
let geometry = new PlaneGeometry(20, 20);
const texture = this.assets.instance.getResource("ocean");
texture.colorSpace = SRGBColorSpace;
texture.wrapS = RepeatWrapping;
texture.wrapT = RepeatWrapping;
texture.repeat.set(1, 1);
let material = new MeshBasicMaterial({
map: texture,
opacity: 1,
fog: false,
})
let mesh = new Mesh(geometry, material)
mesh.rotation.x = -Math.PI / 2
mesh.position.set(0, -0.7, 0)
this.scene.add(mesh)
});
let mesh = new Mesh(geometry, material);
mesh.rotation.x = -Math.PI / 2;
mesh.position.set(0, -0.7, 0);
this.scene.add(mesh);
}
createChinaBlurLine() {
let geometry = new PlaneGeometry(147, 147)
const texture = this.assets.instance.getResource("chinaBlurLine")
texture.colorSpace = SRGBColorSpace
texture.wrapS = RepeatWrapping
texture.wrapT = RepeatWrapping
texture.generateMipmaps = false
texture.minFilter = NearestFilter
texture.repeat.set(1, 1)
let geometry = new PlaneGeometry(147, 147);
const texture = this.assets.instance.getResource("chinaBlurLine");
texture.colorSpace = SRGBColorSpace;
texture.wrapS = RepeatWrapping;
texture.wrapT = RepeatWrapping;
texture.generateMipmaps = false;
texture.minFilter = NearestFilter;
texture.repeat.set(1, 1);
let material = new MeshBasicMaterial({
color: 0x3f82cd,
alphaMap: texture,
transparent: true,
opacity: 0.5,
})
let mesh = new Mesh(geometry, material)
mesh.rotateX(-Math.PI / 2)
mesh.position.set(-19.3, -0.5, -19.7)
this.scene.add(mesh)
});
let mesh = new Mesh(geometry, material);
mesh.rotateX(-Math.PI / 2);
mesh.position.set(-19.3, -0.5, -19.7);
this.scene.add(mesh);
}
createLabel(val) {
let self = this
let labelGroup = this.labelGroup
let label3d = this.label3d
let otherLabel = []
let self = this;
let labelGroup = this.labelGroup;
let label3d = this.label3d;
let otherLabel = [];
chinaData.map((province) => {
if (province.hide == true) return false
let label = labelStyle01(province, label3d, labelGroup)
otherLabel.push(label)
})
if (province.hide == true) return false;
let label = labelStyle01(province, label3d, labelGroup);
otherLabel.push(label);
});
this.mapFocusLabel = labelStyle02(
{
...val,
},
label3d,
labelGroup
)
);
let iconLabel1 = labelStyle03(
{
icon: labelIcon,
......@@ -973,7 +1003,7 @@ export class World extends Mini3d {
},
label3d,
labelGroup
)
);
let iconLabel2 = labelStyle03(
{
icon: labelIcon,
......@@ -984,47 +1014,55 @@ export class World extends Mini3d {
},
label3d,
labelGroup
)
otherLabel.push(this.mapFocusLabel)
otherLabel.push(iconLabel1)
otherLabel.push(iconLabel2)
this.otherLabel = otherLabel
);
otherLabel.push(this.mapFocusLabel);
otherLabel.push(iconLabel1);
otherLabel.push(iconLabel2);
this.otherLabel = otherLabel;
function labelStyle01(province, label3d, labelGroup) {
let label = label3d.create("", `china-label ${province.blur ? " blur" : ""}`, false)
const [x, y] = self.geoProjection(province.center)
let label = label3d.create(
"",
`china-label ${province.blur ? " blur" : ""}`,
false
);
const [x, y] = self.geoProjection(province.center);
label.init(
`<div class="other-label"><img class="label-icon" src="${labelIcon}">${province.name}</div>`,
new Vector3(x, -y, 0.4)
)
label3d.setLabelStyle(label, 0.02, "x")
label.setParent(labelGroup)
return label
);
label3d.setLabelStyle(label, 0.02, "x");
label.setParent(labelGroup);
return label;
}
function labelStyle02(province, label3d, labelGroup) {
let label = label3d.create("", "map-label", false)
const [x, y] = self.geoProjection(province.center)
let label = label3d.create("", "map-label", false);
const [x, y] = self.geoProjection(province.center);
label.init(
`<div class="other-label"><span>${province.name}</span><span>${province.enName}</span></div>`,
new Vector3(x, -y, 0.4)
)
label3d.setLabelStyle(label, 0.015, "x")
label.setParent(labelGroup)
return label
);
label3d.setLabelStyle(label, 0.015, "x");
label.setParent(labelGroup);
return label;
}
function labelStyle03(data, label3d, labelGroup) {
let label = label3d.create("", `decoration-label ${data.reflect ? " reflect" : ""}`, false)
const [x, y] = self.geoProjection(data.center)
let label = label3d.create(
"",
`decoration-label ${data.reflect ? " reflect" : ""}`,
false
);
const [x, y] = self.geoProjection(data.center);
label.init(
`<div class="other-label"><img class="label-icon" style="width:${data.width};height:${data.height}" src="${data.icon}">`,
new Vector3(x, -y, 0.4)
)
label3d.setLabelStyle(label, 0.02, "x")
label.setParent(labelGroup)
return label
);
label3d.setLabelStyle(label, 0.02, "x");
label.setParent(labelGroup);
return label;
}
function labelStyle04(data, label3d, labelGroup, index) {
let label = label3d.create("", "provinces-label", false)
const [x, y] = self.geoProjection(data.center)
let label = label3d.create("", "provinces-label", false);
const [x, y] = self.geoProjection(data.center);
label.init(
`<div class="provinces-label">
<div class="provinces-label-wrap">
......@@ -1037,16 +1075,16 @@ export class World extends Mini3d {
</div>
</div>`,
new Vector3(x, -y, 2.4)
)
label3d.setLabelStyle(label, 0.02, "x")
label.setParent(labelGroup)
return label
);
label3d.setLabelStyle(label, 0.02, "x");
label.setParent(labelGroup);
return label;
}
}
createRotateBorder() {
let max = 12
let rotationBorder1 = this.assets.instance.getResource("rotationBorder1")
let rotationBorder2 = this.assets.instance.getResource("rotationBorder2")
let max = 12;
let rotationBorder1 = this.assets.instance.getResource("rotationBorder1");
let rotationBorder2 = this.assets.instance.getResource("rotationBorder2");
let plane01 = new Plane(this, {
width: max * 1.178,
needRotate: true,
......@@ -1061,11 +1099,11 @@ export class World extends Mini3d {
blending: AdditiveBlending,
}),
position: new Vector3(0, 0.28, 0),
})
plane01.instance.rotation.x = -Math.PI / 2
plane01.instance.renderOrder = 6
plane01.instance.scale.set(0, 0, 0)
plane01.setParent(this.scene)
});
plane01.instance.rotation.x = -Math.PI / 2;
plane01.instance.renderOrder = 6;
plane01.instance.scale.set(0, 0, 0);
plane01.setParent(this.scene);
let plane02 = new Plane(this, {
width: max * 1.116,
needRotate: true,
......@@ -1080,27 +1118,27 @@ export class World extends Mini3d {
blending: AdditiveBlending,
}),
position: new Vector3(0, 0.3, 0),
})
plane02.instance.rotation.x = -Math.PI / 2
plane02.instance.renderOrder = 6
plane02.instance.scale.set(0, 0, 0)
plane02.setParent(this.scene)
this.rotateBorder1 = plane01.instance
this.rotateBorder2 = plane02.instance
});
plane02.instance.rotation.x = -Math.PI / 2;
plane02.instance.renderOrder = 6;
plane02.instance.scale.set(0, 0, 0);
plane02.setParent(this.scene);
this.rotateBorder1 = plane01.instance;
this.rotateBorder2 = plane02.instance;
}
createFlyLine() {
this.flyLineGroup = new Group()
this.flyLineGroup.visible = false
this.scene.add(this.flyLineGroup)
const texture = this.assets.instance.getResource("mapFlyline")
texture.wrapS = texture.wrapT = RepeatWrapping
texture.repeat.set(0.5, 2)
const tubeRadius = 0.1
const tubeSegments = 32
const tubeRadialSegments = 2
const closed = false
let [centerX, centerY] = this.geoProjection(this.flyLineCenter)
let centerPoint = new Vector3(centerX, -centerY, 0)
this.flyLineGroup = new Group();
this.flyLineGroup.visible = false;
this.scene.add(this.flyLineGroup);
const texture = this.assets.instance.getResource("mapFlyline");
texture.wrapS = texture.wrapT = RepeatWrapping;
texture.repeat.set(0.5, 2);
const tubeRadius = 0.1;
const tubeSegments = 32;
const tubeRadialSegments = 2;
const closed = false;
let [centerX, centerY] = this.geoProjection(this.flyLineCenter);
let centerPoint = new Vector3(centerX, -centerY, 0);
const material = new MeshBasicMaterial({
map: texture,
// alphaMap: texture,
......@@ -1110,34 +1148,40 @@ export class World extends Mini3d {
opacity: 1,
depthTest: false,
blending: AdditiveBlending,
})
});
this.time.on("tick", () => {
texture.offset.x -= 0.006
})
texture.offset.x -= 0.006;
});
provincesData
.filter((item, index) => index < 7)
.map((city) => {
let [x, y] = this.geoProjection(city.centroid)
let point = new Vector3(x, -y, 0)
const center = new Vector3()
center.addVectors(centerPoint, point).multiplyScalar(0.5)
center.setZ(3)
const curve = new QuadraticBezierCurve3(centerPoint, center, point)
const tubeGeometry = new TubeGeometry(curve, tubeSegments, tubeRadius, tubeRadialSegments, closed)
const mesh = new Mesh(tubeGeometry, material)
mesh.rotation.x = -Math.PI / 2
mesh.position.set(0, this.depth + 0.44, 0)
mesh.renderOrder = 21
this.flyLineGroup.add(mesh)
})
let [x, y] = this.geoProjection(city.centroid);
let point = new Vector3(x, -y, 0);
const center = new Vector3();
center.addVectors(centerPoint, point).multiplyScalar(0.5);
center.setZ(3);
const curve = new QuadraticBezierCurve3(centerPoint, center, point);
const tubeGeometry = new TubeGeometry(
curve,
tubeSegments,
tubeRadius,
tubeRadialSegments,
closed
);
const mesh = new Mesh(tubeGeometry, material);
mesh.rotation.x = -Math.PI / 2;
mesh.position.set(0, this.depth + 0.44, 0);
mesh.renderOrder = 21;
this.flyLineGroup.add(mesh);
});
}
// 创建焦点
createFocus() {
let focusObj = new Focus(this, { color1: 0xbdfdfd, color2: 0xbdfdfd })
let [x, y] = this.geoProjection(this.flyLineCenter)
focusObj.position.set(x, -y, this.depth + 0.44)
focusObj.scale.set(1, 1, 1)
this.flyLineFocusGroup.add(focusObj)
let focusObj = new Focus(this, { color1: 0xbdfdfd, color2: 0xbdfdfd });
let [x, y] = this.geoProjection(this.flyLineCenter);
focusObj.position.set(x, -y, this.depth + 0.44);
focusObj.scale.set(1, 1, 1);
this.flyLineFocusGroup.add(focusObj);
}
// 创建粒子
createParticles() {
......@@ -1158,54 +1202,54 @@ export class World extends Mini3d {
blending: AdditiveBlending,
sizeAttenuation: true,
}),
})
this.particleGroup = new Group()
this.scene.add(this.particleGroup)
this.particleGroup.rotation.x = -Math.PI / 2
this.particles.setParent(this.particleGroup)
this.particles.enable = true
this.particleGroup.visible = true
});
this.particleGroup = new Group();
this.scene.add(this.particleGroup);
this.particleGroup.rotation.x = -Math.PI / 2;
this.particles.setParent(this.particleGroup);
this.particles.enable = true;
this.particleGroup.visible = true;
}
createScatter() {
this.scatterGroup = new Group()
this.scatterGroup.visible = false
this.scatterGroup.rotation.x = -Math.PI / 2
this.scene.add(this.scatterGroup)
const texture = this.assets.instance.getResource("arrow")
this.scatterGroup = new Group();
this.scatterGroup.visible = false;
this.scatterGroup.rotation.x = -Math.PI / 2;
this.scene.add(this.scatterGroup);
const texture = this.assets.instance.getResource("arrow");
const material = new SpriteMaterial({
map: texture,
color: 0xfffef4,
fog: false,
transparent: true,
depthTest: false,
})
let scatterAllData = sortByValue(scatterData)
let max = scatterAllData[0].value
});
let scatterAllData = sortByValue(scatterData);
let max = scatterAllData[0].value;
scatterAllData.map((data) => {
const sprite = new Sprite(material)
sprite.renderOrder = 23
let scale = 0.1 + (data.value / max) * 0.2
sprite.scale.set(scale, scale, scale)
let [x, y] = this.geoProjection([data.lng, data.lat])
sprite.position.set(x, -y, this.depth + 0.45)
sprite.userData.position = [x, -y, this.depth + 0.45]
this.scatterGroup.add(sprite)
})
const sprite = new Sprite(material);
sprite.renderOrder = 23;
let scale = 0.1 + (data.value / max) * 0.2;
sprite.scale.set(scale, scale, scale);
let [x, y] = this.geoProjection([data.lng, data.lat]);
sprite.position.set(x, -y, this.depth + 0.45);
sprite.userData.position = [x, -y, this.depth + 0.45];
this.scatterGroup.add(sprite);
});
}
createInfoPoint() {
let self = this
this.InfoPointGroup = new Group()
this.scene.add(this.InfoPointGroup)
this.InfoPointGroup.visible = false
this.InfoPointGroup.rotation.x = -Math.PI / 2
this.infoPointIndex = 0
this.infoPointLabelTime = null
this.infoLabelElement = []
let label3d = this.label3d
const texture = this.assets.instance.getResource("point")
let colors = [0xfffef4, 0x77fbf5]
let infoAllData = sortByValue(infoData)
let max = infoAllData[0].value
let self = this;
this.InfoPointGroup = new Group();
this.scene.add(this.InfoPointGroup);
this.InfoPointGroup.visible = false;
this.InfoPointGroup.rotation.x = -Math.PI / 2;
this.infoPointIndex = 0;
this.infoPointLabelTime = null;
this.infoLabelElement = [];
let label3d = this.label3d;
const texture = this.assets.instance.getResource("point");
let colors = [0xfffef4, 0x77fbf5];
let infoAllData = sortByValue(infoData);
let max = infoAllData[0].value;
infoAllData.map((data, index) => {
const material = new SpriteMaterial({
map: texture,
......@@ -1213,49 +1257,49 @@ export class World extends Mini3d {
fog: false,
transparent: true,
depthTest: false,
})
const sprite = new Sprite(material)
sprite.renderOrder = 23
let scale = 0.7 + (data.value / max) * 0.4
sprite.scale.set(scale, scale, scale)
let [x, y] = this.geoProjection([data.lng, data.lat])
let position = [x, -y, this.depth + 0.7]
sprite.position.set(...position)
sprite.userData.position = [...position]
});
const sprite = new Sprite(material);
sprite.renderOrder = 23;
let scale = 0.7 + (data.value / max) * 0.4;
sprite.scale.set(scale, scale, scale);
let [x, y] = this.geoProjection([data.lng, data.lat]);
let position = [x, -y, this.depth + 0.7];
sprite.position.set(...position);
sprite.userData.position = [...position];
sprite.userData = {
position: [x, -y, this.depth + 0.7],
name: data.name,
value: data.value,
level: data.level,
index: index,
}
this.InfoPointGroup.add(sprite)
let label = infoLabel(data, label3d, this.InfoPointGroup)
this.infoLabelElement.push(label)
this.interactionManager.add(sprite)
};
this.InfoPointGroup.add(sprite);
let label = infoLabel(data, label3d, this.InfoPointGroup);
this.infoLabelElement.push(label);
this.interactionManager.add(sprite);
sprite.addEventListener("mousedown", (ev) => {
if (this.clicked || !this.InfoPointGroup.visible) return false
this.clicked = true
this.infoPointIndex = ev.target.userData.index
if (this.clicked || !this.InfoPointGroup.visible) return false;
this.clicked = true;
this.infoPointIndex = ev.target.userData.index;
this.infoLabelElement.map((label) => {
label.visible = false
})
label.visible = true
this.createInfoPointLabelLoop()
})
label.visible = false;
});
label.visible = true;
this.createInfoPointLabelLoop();
});
sprite.addEventListener("mouseup", (ev) => {
this.clicked = false
})
this.clicked = false;
});
sprite.addEventListener("mouseover", (event) => {
document.body.style.cursor = "pointer"
})
document.body.style.cursor = "pointer";
});
sprite.addEventListener("mouseout", (event) => {
document.body.style.cursor = "default"
})
})
document.body.style.cursor = "default";
});
});
function infoLabel(data, label3d, labelGroup) {
let label = label3d.create("", "info-point", true)
const [x, y] = self.geoProjection([data.lng, data.lat])
let label = label3d.create("", "info-point", true);
const [x, y] = self.geoProjection([data.lng, data.lat]);
label.init(
` <div class="info-point-wrap">
<div class="info-point-wrap-inner">
......@@ -1273,34 +1317,34 @@ export class World extends Mini3d {
</div>
`,
new Vector3(x, -y, self.depth + 1.9)
)
label3d.setLabelStyle(label, 0.015, "x")
label.setParent(labelGroup)
label.visible = false
return label
);
label3d.setLabelStyle(label, 0.015, "x");
label.setParent(labelGroup);
label.visible = false;
return label;
}
}
createInfoPointLabelLoop() {
clearInterval(this.infoPointLabelTime)
clearInterval(this.infoPointLabelTime);
this.infoPointLabelTime = setInterval(() => {
this.infoPointIndex++
this.infoPointIndex++;
if (this.infoPointIndex >= this.infoLabelElement.length) {
this.infoPointIndex = 0
this.infoPointIndex = 0;
}
this.infoLabelElement.map((label, i) => {
if (this.infoPointIndex === i) {
label.visible = true
label.visible = true;
} else {
label.visible = false
label.visible = false;
}
})
}, 3000)
});
}, 3000);
}
createStorke() {
const mapStroke = this.assets.instance.getResource("mapStroke")
const texture = this.assets.instance.getResource("pathLine3")
texture.wrapS = texture.wrapT = RepeatWrapping
texture.repeat.set(2, 1)
const mapStroke = this.assets.instance.getResource("mapStroke");
const texture = this.assets.instance.getResource("pathLine3");
texture.wrapS = texture.wrapT = RepeatWrapping;
texture.repeat.set(2, 1);
let pathLine = new Line(this, {
geoProjectionCenter: this.geoProjectionCenter,
......@@ -1319,18 +1363,21 @@ export class World extends Mini3d {
type: "Line3",
renderOrder: 22,
tubeRadius: 0.03,
})
});
// 设置父级
this.focusMapGroup.add(pathLine.lineGroup)
this.focusMapGroup.add(pathLine.lineGroup);
this.time.on("tick", () => {
texture.offset.x += 0.005
})
texture.offset.x += 0.005;
});
}
// 创建地形模型
createTerrain() {
this.pngTexture = this.terrainResource.loaders.Texture.load("../../../public/assets/json/TrueColorImage.png");
this.pngTexture = this.terrainResource.loaders.Texture.load(
"../../../public/assets/json/TrueColorImage.png"
);
this.pngTexture.flipY = false;
this.terrainResource.loaders.GLTF.load("../../../public/assets/json/Scene_cq15_200.gltf",
this.terrainResource.loaders.GLTF.load(
"../../../public/assets/json/Scene_cq15_200.gltf",
(gltf) => {
let terrain = gltf.scene;
// 调整 GLTF 模型的缩放比例和位置
......@@ -1351,149 +1398,151 @@ export class World extends Mini3d {
this.scene.add(terrain);
},
(xhr) => {
console.log((xhr.loaded / xhr.total * 100) + '% 已加载');
console.log((xhr.loaded / xhr.total) * 100 + "% 已加载");
},
(error) => {
console.error('加载模型出错:', error);
console.error("加载模型出错:", error);
}
)
);
// this.scene.add(barGroup)
}
// 创建geoJson
createGeoJson() {
this.FileLoader = new FileLoader()
this.FileLoader.load("../../../public/assets/json/surfacewater.json", (data) => {
let jsonData = JSON.parse(data)
this.FileLoader = new FileLoader();
this.FileLoader.load(
"../../../public/assets/json/surfacewater.json",
(data) => {
let jsonData = JSON.parse(data);
console.log("jsonData", jsonData);
const roadGeoJson = new Group();
const roadProjection = geoMercator().center(this.geoProjectionCenter)
const roadProjection = geoMercator().center(this.geoProjectionCenter);
// 遍历Json的feature
jsonData.features.forEach((feature,i)=>{
jsonData.features.forEach((feature, i) => {
// 获取feature中的geometry数据,方便引用
const geometry = feature.geometry;
const type = geometry.type;
// 创建分组,把同一个市的形状放在一个分组,便于管理
const city = new Group();
if(type === 'LineString'){
if (type === "LineString") {
// 遍历geometry中的数据
geometry.coordinates.forEach((multipolygon)=>{
geometry.coordinates.forEach((multipolygon) => {
// 创建形状,用于展示地理形状
const shape = new Shape()
const shape = new Shape();
// 存储每个坐标,用于绘制边界线
const arr = []
multipolygon.forEach((polygon)=>{
polygon.forEach((item,index) => {
const arr = [];
multipolygon.forEach((polygon) => {
polygon.forEach((item, index) => {
// 使用d3转换坐标
const [x,y]= roadProjection.translate([0,0])(item);
const [x, y] = roadProjection.translate([0, 0])(item);
// 根据转换后的坐标绘制形状
if(index === 0){
shape.moveTo(x,y)
}else {
shape.lineTo(x,y)
if (index === 0) {
shape.moveTo(x, y);
} else {
shape.lineTo(x, y);
}
arr.push(x,y,3)
arr.push(x, y, 3);
});
});
})
console.log("arr", arr);
// 绘制边界线
createLine(arr,city)
createLine(arr, city);
// 创建 ExtrudeGeometry用于显示3d效果
const extrudGeometry = new ExtrudeGeometry(shape,{
depth:2 // 地图的厚度
})
const extrudGeometry = new ExtrudeGeometry(shape, {
depth: 2, // 地图的厚度
});
// 创建材质,用于显示地图的外观
const material = new MeshBasicMaterial({
color:'#ffff33'
color: "#ffff33",
});
// 创建物体,用于显示地图
const mesh = new Mesh(extrudGeometry,material)
mesh.position.set(0,0,0)
const mesh = new Mesh(extrudGeometry, material);
mesh.position.set(0, 0, 0);
// 添加到分组
city.add(mesh)
})
city.add(mesh);
});
}
// 添加到分组
roadGeoJson.add(city)
})
roadGeoJson.add(city);
});
this.scene.add(roadGeoJson);
})
}
);
}
// createSmoothLine(lngLatArr) {
// const z = this.depth + 0.5;
// const points = lngLatArr.map(([lng, lat]) => {
// const [x, y] = this.geoProjection([lng, lat]);
// return new THREE.Vector3(x, z, y);
// });
// const curve = new THREE.CatmullRomCurve3(points, false, 'catmullrom', 0.5);
// const curvePoints = curve.getPoints(100);
// createSmoothLine(lngLatArr) {
// const z = this.depth + 0.5;
// const points = lngLatArr.map(([lng, lat]) => {
// const [x, y] = this.geoProjection([lng, lat]);
// return new THREE.Vector3(x, z, y);
// });
// const curve = new THREE.CatmullRomCurve3(points, false, 'catmullrom', 0.5);
// const curvePoints = curve.getPoints(100);
// // 计算每个点的累积距离
// let distances = [0];
// for (let i = 1; i < curvePoints.length; i++) {
// distances[i] = distances[i - 1] + curvePoints[i].distanceTo(curvePoints[i - 1]);
// }
// const totalLength = distances[distances.length - 1];
// // 计算每个点的累积距离
// let distances = [0];
// for (let i = 1; i < curvePoints.length; i++) {
// distances[i] = distances[i - 1] + curvePoints[i].distanceTo(curvePoints[i - 1]);
// }
// const totalLength = distances[distances.length - 1];
// // 添加距离属性
// const geometry = new THREE.BufferGeometry().setFromPoints(curvePoints);
// const distanceAttr = new Float32Array(distances);
// geometry.setAttribute('aDistance', new THREE.BufferAttribute(distanceAttr, 1));
// // 添加距离属性
// const geometry = new THREE.BufferGeometry().setFromPoints(curvePoints);
// const distanceAttr = new Float32Array(distances);
// geometry.setAttribute('aDistance', new THREE.BufferAttribute(distanceAttr, 1));
// // ShaderMaterial
// const material = new THREE.ShaderMaterial({
// uniforms: {
// color: { value: new THREE.Color(0xff0000) },
// dashSize: { value: 0.2 },
// gapSize: { value: 0.1 },
// totalLength: { value: totalLength },
// dashOffset: { value: 0 },
// },
// vertexShader: `
// attribute float aDistance;
// varying float vDistance;
// void main() {
// vDistance = aDistance;
// gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
// }
// `,
// fragmentShader: `
// uniform vec3 color;
// uniform float dashSize;
// uniform float gapSize;
// uniform float totalLength;
// uniform float dashOffset;
// varying float vDistance;
// void main() {
// float unitLen = dashSize + gapSize;
// float dist = mod(vDistance + dashOffset * totalLength, unitLen);
// if(dist > dashSize) discard;
// gl_FragColor = vec4(color, 1.0);
// }
// `,
// transparent: true
// });
// // ShaderMaterial
// const material = new THREE.ShaderMaterial({
// uniforms: {
// color: { value: new THREE.Color(0xff0000) },
// dashSize: { value: 0.2 },
// gapSize: { value: 0.1 },
// totalLength: { value: totalLength },
// dashOffset: { value: 0 },
// },
// vertexShader: `
// attribute float aDistance;
// varying float vDistance;
// void main() {
// vDistance = aDistance;
// gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
// }
// `,
// fragmentShader: `
// uniform vec3 color;
// uniform float dashSize;
// uniform float gapSize;
// uniform float totalLength;
// uniform float dashOffset;
// varying float vDistance;
// void main() {
// float unitLen = dashSize + gapSize;
// float dist = mod(vDistance + dashOffset * totalLength, unitLen);
// if(dist > dashSize) discard;
// gl_FragColor = vec4(color, 1.0);
// }
// `,
// transparent: true
// });
// const line = new THREE.Line(geometry, material);
// this.scene.add(line);
// const line = new THREE.Line(geometry, material);
// this.scene.add(line);
// // 动画
// this.time.on("tick", () => {
// material.uniforms.dashOffset.value += 0.001; // 控制流动速度
// if(material.uniforms.dashOffset.value > 1.0) material.uniforms.dashOffset.value -= 1.0;
// });
// // 动画
// this.time.on("tick", () => {
// material.uniforms.dashOffset.value += 0.001; // 控制流动速度
// if(material.uniforms.dashOffset.value > 1.0) material.uniforms.dashOffset.value -= 1.0;
// });
// return line;
// }
createSmoothLine(lngLatArr) {
// return line;
// }
createSmoothLine(lngLatArr) {
const z = this.depth + 0.5;
// 生成原始曲线
const points = lngLatArr.map(([lng, lat]) => {
const [x, y] = this.geoProjection([lng, lat]);
return new THREE.Vector3(x, z, y);
});
const curve = new THREE.CatmullRomCurve3(points, false, 'catmullrom', 0.5);
const curve = new THREE.CatmullRomCurve3(points, false, "catmullrom", 0.5);
// 创建管道几何体(控制宽度)
const radius = 0.05; // 控制线条宽度
const radialSegments = 8; // 控制管道圆滑度
......@@ -1544,7 +1593,7 @@ createSmoothLine(lngLatArr) {
gl_FragColor = vec4(color, 1.0);
}
`,
transparent: true
transparent: true,
});
// 创建网格对象
const mesh = new THREE.Mesh(tubeGeometry, material);
......@@ -1553,31 +1602,37 @@ createSmoothLine(lngLatArr) {
// 保持原有动画逻辑
this.time.on("tick", () => {
material.uniforms.dashOffset.value += 0.001;
if(material.uniforms.dashOffset.value > 1.0) {
if (material.uniforms.dashOffset.value > 1.0) {
material.uniforms.dashOffset.value -= 1.0;
}
});
return mesh;
}
// 创建水面
}
// 创建水面
createWater() {
createWater() {
// 获取水面GeoJSON数据
let mapJsonData = this.assets.instance.getResource("surfaceWater");
let waterJson;
try {
waterJson = typeof mapJsonData === "string" ? JSON.parse(mapJsonData) : mapJsonData;
waterJson =
typeof mapJsonData === "string" ? JSON.parse(mapJsonData) : mapJsonData;
} catch (e) {
console.error("surfaceWater 解析失败", e);
return { waterGroup: null };
}
// 创建水面组
const waterGroup = new Group();
const projection = geoMercator().center(this.geoProjectionCenter).scale(this.geoProjectionScale).translate([0, 0]);
const projection = geoMercator()
.center(this.geoProjectionCenter)
.scale(this.geoProjectionScale)
.translate([0, 0]);
// 加载法线贴图
const textureLoader = new THREE.TextureLoader();
let base_url = import.meta.env.BASE_URL || "/";
const normalMap = textureLoader.load(base_url + "assets/json/waternormals.jpg");
const normalMap = textureLoader.load(
base_url + "assets/json/waternormals.jpg"
);
normalMap.wrapS = normalMap.wrapT = THREE.RepeatWrapping;
// 可选:加载一张水面颜色贴图
// const waterMap = textureLoader.load(base_url + "assets/json/watercolor.png");
......@@ -1595,7 +1650,10 @@ createWater() {
const geometry = feature.geometry;
if (!geometry) return;
if (geometry.type === "Polygon" || geometry.type === "MultiPolygon") {
const polygons = geometry.type === "Polygon" ? [geometry.coordinates] : geometry.coordinates;
const polygons =
geometry.type === "Polygon"
? [geometry.coordinates]
: geometry.coordinates;
polygons.forEach((polygon) => {
polygon.forEach((ring) => {
const shape = new Shape();
......@@ -1631,13 +1689,14 @@ createWater() {
return {
waterGroup,
};
}
createLineWater() {
}
createLineWater() {
// 获取水的GeoJSON线数据
let mapJsonData = this.assets.instance.getResource("linewater");
let lineWaterJson;
try {
lineWaterJson = typeof mapJsonData === "string" ? JSON.parse(mapJsonData) : mapJsonData;
lineWaterJson =
typeof mapJsonData === "string" ? JSON.parse(mapJsonData) : mapJsonData;
} catch (e) {
console.error("linewater 解析失败", e);
return { lineWaterGroup: null };
......@@ -1646,7 +1705,9 @@ createLineWater() {
// 加载法线贴图
const textureLoader = new THREE.TextureLoader();
let base_url = import.meta.env.BASE_URL || "/";
const normalMap = textureLoader.load(base_url + "assets/json/waternormals.jpg");
const normalMap = textureLoader.load(
base_url + "assets/json/waternormals.jpg"
);
normalMap.wrapS = normalMap.wrapT = THREE.RepeatWrapping;
// 可选:加载一张水面颜色贴图
// const waterMap = textureLoader.load(base_url + "assets/json/watercolor.png");
......@@ -1662,7 +1723,10 @@ createLineWater() {
// 创建线水组
const lineWaterGroup = new Group();
const projection = geoMercator().center(this.geoProjectionCenter).scale(this.geoProjectionScale).translate([0, 0]);
const projection = geoMercator()
.center(this.geoProjectionCenter)
.scale(this.geoProjectionScale)
.translate([0, 0]);
(lineWaterJson.features || []).forEach((feature) => {
const geometry = feature.geometry;
if (!geometry) return;
......@@ -1723,229 +1787,454 @@ createLineWater() {
return {
lineWaterGroup,
};
}
}
// createLineWater() {
// // 获取水的GeoJSON线数据
// let mapJsonData = this.assets.instance.getResource("linewater");
// let lineWaterJson;
// try {
// lineWaterJson = typeof mapJsonData === "string" ? JSON.parse(mapJsonData) : mapJsonData;
// } catch (e) {
// console.error("linewater 解析失败", e);
// return { lineWaterGroup: null };
// }
// // 加载法线贴图
// const textureLoader = new THREE.TextureLoader();
// let base_url = import.meta.env.BASE_URL || "/";
// const normalMap = textureLoader.load(base_url + "assets/json/waternormals.jpg");
// normalMap.wrapS = normalMap.wrapT = THREE.RepeatWrapping;
// const waterMap = textureLoader.load(base_url + "assets/json/watercolor.png"); // 你需要准备一张水波纹PNG
// waterMap.wrapS = waterMap.wrapT = THREE.RepeatWrapping;
// // 动画流动
// this.time.on("tick", () => {
// normalMap.offset.x += 0.002;
// normalMap.offset.y += 0.001;
// waterMap.offset.x += 0.002; // 让颜色贴图也流动
// });
// // 创建线水组
// const lineWaterGroup = new Group();
// const projection = geoMercator().center(this.geoProjectionCenter).scale(this.geoProjectionScale).translate([0, 0]);
// (lineWaterJson.features || []).forEach((feature) => {
// const geometry = feature.geometry;
// if (!geometry) return;
// let lines = [];
// if (geometry.type === "LineString") {
// lines = [geometry.coordinates];
// } else if (geometry.type === "MultiLineString") {
// lines = geometry.coordinates;
// }
// lines.forEach((line) => {
// // 生成带宽度的水带
// const points = line.map(([lng, lat]) => {
// const [x, y] = projection([lng, lat]);
// return new THREE.Vector3(x, -y, this.depth + 0.26); // 保证高于地表
// });
// if (points.length < 2) return;
// // 用TubeGeometry生成带宽度的水带
// const curve = new THREE.CatmullRomCurve3(points);
// const tubeGeometry = new THREE.TubeGeometry(curve, Math.max(32, points.length * 2), 0.01, 16);
// const material = new THREE.MeshStandardMaterial({
// color: 0x4fc3ff,
// transparent: true,
// opacity: 0.35,
// side: DoubleSide,
// depthWrite: false,
// normalMap: normalMap,
// normalScale: new THREE.Vector2(2, 2),
// map: waterMap, // 使用颜色贴图
// metalness: 0.3,
// roughness: 0.7,
// });
// const mesh = new Mesh(tubeGeometry, material);
// mesh.renderOrder = 11;
// lineWaterGroup.add(mesh);
// });
// });
// return {
// lineWaterGroup,
// };
// }
// createLineWater() {
// let mapJsonData = this.assets.instance.getResource("linewater");
// let lineWaterJson;
// try {
// lineWaterJson = typeof mapJsonData === "string" ? JSON.parse(mapJsonData) : mapJsonData;
// } catch (e) {
// console.error("linewater 解析失败", e);
// return { lineWaterGroup: null };
// }
// const textureLoader = new THREE.TextureLoader();
// let base_url = import.meta.env.BASE_URL || "/";
// const normalMap = textureLoader.load(base_url + "assets/json/waternormals.jpg");
// normalMap.wrapS = normalMap.wrapT = THREE.RepeatWrapping;
// const waterMap = textureLoader.load(base_url + "assets/json/watercolor.png");
// waterMap.wrapS = waterMap.wrapT = THREE.RepeatWrapping;
// // 流动速度更快
// this.time.on("tick", () => {
// normalMap.offset.x += 0.03;
// normalMap.offset.y += 0.015;
// waterMap.offset.x += 0.03;
// waterMap.offset.y += 0.015;
// });
// createLineWater() {
// // 获取水的GeoJSON线数据
// let mapJsonData = this.assets.instance.getResource("linewater");
// let lineWaterJson;
// try {
// lineWaterJson = typeof mapJsonData === "string" ? JSON.parse(mapJsonData) : mapJsonData;
// } catch (e) {
// console.error("linewater 解析失败", e);
// return { lineWaterGroup: null };
// }
// const lineWaterGroup = new Group();
// const projection = geoMercator().center(this.geoProjectionCenter).scale(this.geoProjectionScale).translate([0, 0]);
// // 加载法线贴图
// const textureLoader = new THREE.TextureLoader();
// let base_url = import.meta.env.BASE_URL || "/";
// const normalMap = textureLoader.load(base_url + "assets/json/waternormals.jpg");
// normalMap.wrapS = normalMap.wrapT = THREE.RepeatWrapping;
// const waterMap = textureLoader.load(base_url + "assets/json/watercolor.png"); // 你需要准备一张水波纹PNG
// waterMap.wrapS = waterMap.wrapT = THREE.RepeatWrapping;
// // 动画流动
// this.time.on("tick", () => {
// normalMap.offset.x += 0.002;
// normalMap.offset.y += 0.001;
// waterMap.offset.x += 0.002; // 让颜色贴图也流动
// });
// (lineWaterJson.features || []).forEach((feature) => {
// const geometry = feature.geometry;
// if (!geometry) return;
// let lines = [];
// if (geometry.type === "LineString") {
// lines = [geometry.coordinates];
// } else if (geometry.type === "MultiLineString") {
// lines = geometry.coordinates;
// }
// lines.forEach((line) => {
// const points = line.map(([lng, lat]) => {
// const [x, y] = projection([lng, lat]);
// return new THREE.Vector3(x, -y, this.depth + 0.26);
// });
// if (points.length < 2) return;
// // 创建线水组
// const lineWaterGroup = new Group();
// const projection = geoMercator().center(this.geoProjectionCenter).scale(this.geoProjectionScale).translate([0, 0]);
// // 宽度渐变:首尾变窄
// const riverWidthMax = 0.08, riverWidthMin = 0.02;
// const lefts = [], rights = [];
// for (let i = 0; i < points.length; i++) {
// let t = points.length === 1 ? 0 : i / (points.length - 1);
// let width = riverWidthMin + (1 - Math.abs(t * 2 - 1)) * (riverWidthMax - riverWidthMin);
// let dir;
// if (i === 0) {
// dir = points[1].clone().sub(points[0]);
// } else if (i === points.length - 1) {
// dir = points[i].clone().sub(points[i - 1]);
// } else {
// dir = points[i + 1].clone().sub(points[i - 1]);
// }
// dir.z = 0;
// dir.normalize();
// const normal = new THREE.Vector3(-dir.y, dir.x, 0);
// lefts.push(points[i].clone().add(normal.clone().multiplyScalar(width / 2)));
// rights.push(points[i].clone().add(normal.clone().multiplyScalar(-width / 2)));
// }
// (lineWaterJson.features || []).forEach((feature) => {
// const geometry = feature.geometry;
// if (!geometry) return;
// let lines = [];
// if (geometry.type === "LineString") {
// lines = [geometry.coordinates];
// } else if (geometry.type === "MultiLineString") {
// lines = geometry.coordinates;
// }
// lines.forEach((line) => {
// // 生成带宽度的水带
// const points = line.map(([lng, lat]) => {
// const [x, y] = projection([lng, lat]);
// return new THREE.Vector3(x, -y, this.depth + 0.26); // 保证高于地表
// });
// if (points.length < 2) return;
// // 用TubeGeometry生成带宽度的水带
// const curve = new THREE.CatmullRomCurve3(points);
// const tubeGeometry = new THREE.TubeGeometry(curve, Math.max(32, points.length * 2), 0.01, 16);
// const material = new THREE.MeshStandardMaterial({
// color: 0x4fc3ff,
// transparent: true,
// opacity: 0.35,
// side: DoubleSide,
// depthWrite: false,
// normalMap: normalMap,
// normalScale: new THREE.Vector2(2, 2),
// map: waterMap, // 使用颜色贴图
// metalness: 0.3,
// roughness: 0.7,
// });
// const mesh = new Mesh(tubeGeometry, material);
// mesh.renderOrder = 11;
// lineWaterGroup.add(mesh);
// });
// });
// return {
// lineWaterGroup,
// };
// }
// // 顶点、uv、透明度
// const vertices = [];
// const uvs = [];
// const alphas = [];
// let totalLen = 0;
// for (let i = 0; i < points.length; i++) {
// if (i > 0) totalLen += points[i].distanceTo(points[i - 1]);
// let t = points.length === 1 ? 0 : i / (points.length - 1);
// let edgeAlpha = 0.7 + 0.3 * (1 - Math.abs(t * 2 - 1));
// // 左点
// vertices.push(lefts[i]);
// uvs.push(totalLen * 2, 0); // UV缩放更密集
// alphas.push(edgeAlpha);
// // 右点
// vertices.push(rights[i]);
// uvs.push(totalLen * 2, 1);
// alphas.push(edgeAlpha);
// }
// createLineWater() {
// let mapJsonData = this.assets.instance.getResource("linewater");
// let lineWaterJson;
// try {
// lineWaterJson = typeof mapJsonData === "string" ? JSON.parse(mapJsonData) : mapJsonData;
// } catch (e) {
// console.error("linewater 解析失败", e);
// return { lineWaterGroup: null };
// }
// const indices = [];
// for (let i = 0; i < points.length - 1; i++) {
// const a = i * 2, b = i * 2 + 1, c = i * 2 + 2, d = i * 2 + 3;
// indices.push(a, b, c, b, d, c);
// }
// const textureLoader = new THREE.TextureLoader();
// let base_url = import.meta.env.BASE_URL || "/";
// const normalMap = textureLoader.load(base_url + "assets/json/waternormals.jpg");
// normalMap.wrapS = normalMap.wrapT = THREE.RepeatWrapping;
// const waterMap = textureLoader.load(base_url + "assets/json/watercolor.png");
// waterMap.wrapS = waterMap.wrapT = THREE.RepeatWrapping;
// const geometry = new THREE.BufferGeometry();
// const posArr = new Float32Array(vertices.length * 3);
// for (let i = 0; i < vertices.length; i++) {
// posArr[i * 3] = vertices[i].x;
// posArr[i * 3 + 1] = vertices[i].y;
// posArr[i * 3 + 2] = vertices[i].z;
// }
// geometry.setAttribute('position', new THREE.BufferAttribute(posArr, 3));
// geometry.setAttribute('uv', new THREE.BufferAttribute(new Float32Array(uvs), 2));
// geometry.setAttribute('alpha', new THREE.BufferAttribute(new Float32Array(alphas), 1));
// geometry.setIndex(indices);
// // 流动速度更快
// this.time.on("tick", () => {
// normalMap.offset.x += 0.03;
// normalMap.offset.y += 0.015;
// waterMap.offset.x += 0.03;
// waterMap.offset.y += 0.015;
// });
// // ShaderMaterial实现边缘羽化和流动水波
// const material = new THREE.ShaderMaterial({
// uniforms: {
// map: { value: waterMap },
// normalMap: { value: normalMap },
// color: { value: new THREE.Color(0x4fc3ff) },
// opacity: { value: 0.5 },
// },
// vertexShader: `
// attribute float alpha;
// varying vec2 vUv;
// varying float vAlpha;
// void main() {
// vUv = uv;
// vAlpha = alpha;
// gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
// }
// `,
// fragmentShader: `
// uniform sampler2D map;
// uniform sampler2D normalMap;
// uniform vec3 color;
// uniform float opacity;
// varying vec2 vUv;
// varying float vAlpha;
// void main() {
// vec4 texColor = texture2D(map, vUv);
// float alpha = texColor.a * opacity * vAlpha;
// vec3 finalColor = mix(color, texColor.rgb, 0.8); // 贴图主导
// if(alpha < 0.05) discard;
// gl_FragColor = vec4(finalColor, alpha);
// }
// `,
// transparent: true,
// side: DoubleSide,
// depthWrite: false,
// });
// const lineWaterGroup = new Group();
// const projection = geoMercator().center(this.geoProjectionCenter).scale(this.geoProjectionScale).translate([0, 0]);
// const mesh = new Mesh(geometry, material);
// mesh.renderOrder = 11;
// lineWaterGroup.add(mesh);
// });
// });
// return {
// lineWaterGroup,
// };
// }
// 加载3d模型
showDroneAtLngLat(url, lng, lat, height, scale) {
// 经纬度转平面坐标
const [x, y] = this.geoProjection([lng, lat]);
// z 轴为地表高度加上无人机高度
const z = this.depth + height + 0.5;
// 创建 THREE.Vector3 位置
const position = new THREE.Vector3(x, z, -y);
// 调用已有的加载方法
this.loadDroneModel(url, position, scale);
}
/**
* 加载无人机 glb 模型并添加到场景
* @param {string} url glb模型路径
* @param {THREE.Vector3} position 模型放置位置
* @param {number} scale 模型缩放
*/
loadDroneModel(url, position = new THREE.Vector3(0, 0, 2), scale = 1) {
// 复用 Resource 工具或直接用 THREE.GLTFLoader
const loader =
this.terrainResource?.loaders?.GLTF || new THREE.GLTFLoader();
loader.load(
url,
(gltf) => {
const drone = gltf.scene;
drone.position.copy(position);
drone.scale.set(scale, scale, scale);
// 可根据需要调整旋转
// drone.rotation.set(0, Math.PI, 0);
// let propeller1 = drone.getObjectByName("phase8_Master25");
let propeller1 = drone.getObjectByName("prop_1_jnt34");
let propeller2 = drone.getObjectByName("prop_2_jnt35");
let propeller3 = drone.getObjectByName("prop_3_jnt36");
let propeller4 = drone.getObjectByName("prop_4_jnt37");
if (propeller1 && propeller2 && propeller3 && propeller4) {
// 每帧旋转扇叶
this.time.on("tick", () => {
propeller1.rotation.y += 0.5; // 控制转速
propeller2.rotation.y += 0.5;
propeller3.rotation.y += 0.5;
propeller4.rotation.y += 0.5;
});
} else {
console.warn("未找到扇叶节点,请确认节点名称");
}
this.scene.add(drone);
// (lineWaterJson.features || []).forEach((feature) => {
// const geometry = feature.geometry;
// if (!geometry) return;
// let lines = [];
// if (geometry.type === "LineString") {
// lines = [geometry.coordinates];
// } else if (geometry.type === "MultiLineString") {
// lines = geometry.coordinates;
// }
// lines.forEach((line) => {
// const points = line.map(([lng, lat]) => {
// const [x, y] = projection([lng, lat]);
// return new THREE.Vector3(x, -y, this.depth + 0.26);
// });
// if (points.length < 2) return;
// 添加交互事件
this.interactionManager.add(drone);
drone.addEventListener("mousedown", (event) => {
this.showDronePopup(drone);
});
this.moveDroneAlongPath(drone, [
[110.9801, 39.8002],
[111.0806, 39.7005],
[111.1803, 39.6054],
[110.9008, 39.8056],
[111.1003, 39.7386],
], 20);
console.log("无人机模型加载完成", drone);
},
(xhr) => {
// 加载进度
console.log(
`无人机模型加载进度: ${((xhr.loaded / xhr.total) * 100).toFixed(2)}%`
);
},
(error) => {
console.error("无人机模型加载失败:", error);
}
);
}
// 显示无人机弹窗
showDronePopup(drone) {
// 自动插入样式(只插入一次)
if (!document.getElementById("drone-popup-style")) {
const style = document.createElement("style");
style.id = "drone-popup-style";
style.innerHTML = `
.drone-popup {
z-index: 9999;
min-width: 140px;
max-width: 240px;
box-shadow: 0 2px 8px rgba(0,0,0,0.3);
font-size: 14px;
user-select: none;
transition: opacity 0.2s;
position: absolute;
background: rgba(0,0,0,0.8);
color: #fff;
padding: 10px 18px;
border-radius: 8px;
pointer-events: auto;
}
.drone-popup .close-btn {
position: absolute;
right: 8px;
top: 4px;
color: #fff;
cursor: pointer;
font-size: 16px;
opacity: 0.7;
}
.drone-popup .close-btn:hover {
opacity: 1;
}
.drone-popup video {
width: 100%;
margin-top: 8px;
border-radius: 4px;
background: #000;
display: block;
}
`;
document.head.appendChild(style);
}
// 如果已存在弹窗,先移除
if (this.dronePopup) {
document.body.removeChild(this.dronePopup);
this.time.off("tick", this._updateDronePopupPos);
this.dronePopup = null;
}
// // 宽度渐变:首尾变窄
// const riverWidthMax = 0.08, riverWidthMin = 0.02;
// const lefts = [], rights = [];
// for (let i = 0; i < points.length; i++) {
// let t = points.length === 1 ? 0 : i / (points.length - 1);
// let width = riverWidthMin + (1 - Math.abs(t * 2 - 1)) * (riverWidthMax - riverWidthMin);
// let dir;
// if (i === 0) {
// dir = points[1].clone().sub(points[0]);
// } else if (i === points.length - 1) {
// dir = points[i].clone().sub(points[i - 1]);
// } else {
// dir = points[i + 1].clone().sub(points[i - 1]);
// }
// dir.z = 0;
// dir.normalize();
// const normal = new THREE.Vector3(-dir.y, dir.x, 0);
// lefts.push(points[i].clone().add(normal.clone().multiplyScalar(width / 2)));
// rights.push(points[i].clone().add(normal.clone().multiplyScalar(-width / 2)));
// }
// 创建弹窗
const popup = document.createElement("div");
popup.className = "drone-popup";
popup.innerHTML = `
<span class="close-btn" title="关闭">&times;</span>
<div style="margin-top:4px;">
<b>无人机信息</b><br>
位置:${drone.position.x.toFixed(2)}, ${drone.position.z.toFixed(2)}<br>
<span style="font-size:12px;opacity:0.7;">(内容可自定义)</span>
<video src="https://media.w3.org/2010/05/sintel/trailer.mp4" controls poster="" preload="metadata" custom-cache="false" ></video>
</div>
`;
document.body.appendChild(popup);
this.dronePopup = popup;
// 优化全屏性能卡顿
document.addEventListener("fullscreenchange", () => {
if (document.fullscreenElement) {
// 暂停 Three.js 动画
this.time.pause && this.time.pause();
} else {
// 恢复 Three.js 动画
this.time.resume && this.time.resume();
}
});
// // 顶点、uv、透明度
// const vertices = [];
// const uvs = [];
// const alphas = [];
// let totalLen = 0;
// for (let i = 0; i < points.length; i++) {
// if (i > 0) totalLen += points[i].distanceTo(points[i - 1]);
// let t = points.length === 1 ? 0 : i / (points.length - 1);
// let edgeAlpha = 0.7 + 0.3 * (1 - Math.abs(t * 2 - 1));
// // 左点
// vertices.push(lefts[i]);
// uvs.push(totalLen * 2, 0); // UV缩放更密集
// alphas.push(edgeAlpha);
// // 右点
// vertices.push(rights[i]);
// uvs.push(totalLen * 2, 1);
// alphas.push(edgeAlpha);
// }
// 关闭按钮
popup.querySelector(".close-btn").onclick = () => {
if (this.dronePopup) {
document.body.removeChild(this.dronePopup);
this.time.off("tick", this._updateDronePopupPos);
this.dronePopup = null;
}
};
// const indices = [];
// for (let i = 0; i < points.length - 1; i++) {
// const a = i * 2, b = i * 2 + 1, c = i * 2 + 2, d = i * 2 + 3;
// indices.push(a, b, c, b, d, c);
// }
// 跟随无人机位置
this._updateDronePopupPos = () => {
// 获取无人机世界坐标
const worldPos = new THREE.Vector3();
drone.getWorldPosition(worldPos);
// 转换为屏幕坐标
worldPos.project(this.camera.instance);
let x = (worldPos.x * 0.5 + 0.5) * window.innerWidth;
let y = (1 - (worldPos.y * 0.5 + 0.5)) * window.innerHeight;
// const geometry = new THREE.BufferGeometry();
// const posArr = new Float32Array(vertices.length * 3);
// for (let i = 0; i < vertices.length; i++) {
// posArr[i * 3] = vertices[i].x;
// posArr[i * 3 + 1] = vertices[i].y;
// posArr[i * 3 + 2] = vertices[i].z;
// }
// geometry.setAttribute('position', new THREE.BufferAttribute(posArr, 3));
// geometry.setAttribute('uv', new THREE.BufferAttribute(new Float32Array(uvs), 2));
// geometry.setAttribute('alpha', new THREE.BufferAttribute(new Float32Array(alphas), 1));
// geometry.setIndex(indices);
// 防止弹窗超出屏幕
const rect = popup.getBoundingClientRect();
x = Math.min(
Math.max(0, x - rect.width / 2),
window.innerWidth - rect.width
);
y = Math.min(
Math.max(0, y - rect.height - 20),
window.innerHeight - rect.height
);
// // ShaderMaterial实现边缘羽化和流动水波
// const material = new THREE.ShaderMaterial({
// uniforms: {
// map: { value: waterMap },
// normalMap: { value: normalMap },
// color: { value: new THREE.Color(0x4fc3ff) },
// opacity: { value: 0.5 },
// },
// vertexShader: `
// attribute float alpha;
// varying vec2 vUv;
// varying float vAlpha;
// void main() {
// vUv = uv;
// vAlpha = alpha;
// gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
// }
// `,
// fragmentShader: `
// uniform sampler2D map;
// uniform sampler2D normalMap;
// uniform vec3 color;
// uniform float opacity;
// varying vec2 vUv;
// varying float vAlpha;
// void main() {
// vec4 texColor = texture2D(map, vUv);
// float alpha = texColor.a * opacity * vAlpha;
// vec3 finalColor = mix(color, texColor.rgb, 0.8); // 贴图主导
// if(alpha < 0.05) discard;
// gl_FragColor = vec4(finalColor, alpha);
// }
// `,
// transparent: true,
// side: DoubleSide,
// depthWrite: false,
// });
popup.style.left = `${x}px`;
popup.style.top = `${y}px`;
};
this.time.on("tick", this._updateDronePopupPos);
// 初始化一次
this._updateDronePopupPos();
}
/**
* 让无人机沿指定经纬度路径平滑移动
* @param {THREE.Object3D} drone 无人机模型对象
* @param {Array} lngLatArr 经纬度数组
* @param {number} duration 动画时长(秒)
*/
moveDroneAlongPath(drone, lngLatArr, duration = 10) {
// 1. 经纬度转three世界坐标
const z = this.depth + 1; // 高度可调整
const points = lngLatArr.map(([lng, lat]) => {
const [x, y] = this.geoProjection([lng, lat]);
return new THREE.Vector3(x, z, y);
});
// 2. 创建平滑曲线
const curve = new THREE.CatmullRomCurve3(points, false, "catmullrom", 0.5);
// const mesh = new Mesh(geometry, material);
// mesh.renderOrder = 11;
// lineWaterGroup.add(mesh);
// });
// });
// return {
// lineWaterGroup,
// };
// }
// 3. 动画
let startTime = null;
const animate = (now) => {
if (!startTime) startTime = now;
const elapsed = (now - startTime) / 1000;
let t = elapsed / duration;
if (t > 1) t = 1;
// 沿曲线取点
const pos = curve.getPoint(t);
drone.position.copy(pos);
// 可选:让无人机朝向运动方向
if (t < 1) {
const nextPos = curve.getPoint(Math.min(t + 0.01, 1));
drone.lookAt(nextPos);
}
if (t < 1) {
drone._moveReq = requestAnimationFrame(animate);
}
};
// 停止之前的动画
if (drone._moveReq) cancelAnimationFrame(drone._moveReq);
drone._moveReq = requestAnimationFrame(animate);
}
// 跳转到指定group
zoomToFocusMapGroup(group) {
// 创建一个 Box3 来计算 focusMapGroup 的边界盒
......@@ -1966,7 +2255,9 @@ createLineWater() {
distance *= 1.2;
// 设置摄像机位置(沿着 Z 轴方向)
const cameraPosition = center.clone().add(new THREE.Vector3(0, 0, distance));
const cameraPosition = center
.clone()
.add(new THREE.Vector3(0, 0, distance));
this.camera.instance.position.copy(cameraPosition);
// 让摄像机看向 focusMapGroup 的中心
......@@ -1976,14 +2267,17 @@ createLineWater() {
this.camera.instance.updateProjectionMatrix();
}
geoProjection(args) {
return geoMercator().center(this.geoProjectionCenter).scale(this.geoProjectionScale).translate([0, 0])(args)
return geoMercator()
.center(this.geoProjectionCenter)
.scale(this.geoProjectionScale)
.translate([0, 0])(args);
}
update() {
super.update()
this.interactionManager && this.interactionManager.update()
super.update();
this.interactionManager && this.interactionManager.update();
}
destroy() {
super.destroy()
this.label3d && this.label3d.destroy()
super.destroy();
this.label3d && this.label3d.destroy();
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论