Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
D
DSMS
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
詹银鑫
DSMS
Commits
e6670372
提交
e6670372
authored
5月 27, 2025
作者:
詹银鑫
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
加载无人机模型并添加点击弹窗和无人机动画
上级
d28ccc7e
显示空白字符变更
内嵌
并排
正在显示
3 个修改的文件
包含
1132 行增加
和
838 行删除
+1132
-838
Flying_drone..glb
public/assets/json/Flying_drone..glb
+0
-0
Flying_drone.png
public/assets/json/Flying_drone.png
+0
-0
map.js
src/views/gdMap/map.js
+1132
-838
没有找到文件。
public/assets/json/Flying_drone..glb
0 → 100644
浏览文件 @
e6670372
File added
public/assets/json/Flying_drone.png
0 → 100644
浏览文件 @
e6670372
130.0 KB
src/views/gdMap/map.js
浏览文件 @
e6670372
...
...
@@ -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="关闭">×</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
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论