This commit is contained in:
ann 2024-06-22 11:58:18 +08:00
commit 17e69af293
70 changed files with 190277 additions and 3 deletions

View File

@ -3,3 +3,4 @@ ENV = 'development'
# base api
VUE_APP_BASE_API = '/jcc-ks'
VUE_APP_PUBLIC_SOURCE_API = ''

View File

@ -3,4 +3,5 @@ ENV = 'production'
# base api
VUE_APP_BASE_API = '/jcc-ks'
VUE_APP_PUBLIC_SOURCE_API = '/monitor'

View File

@ -48,6 +48,8 @@
"script-loader": "0.7.2",
"sortablejs": "1.8.4",
"spark-md5": "^3.0.2",
"three": "^0.126.1",
"three.meshline": "^1.4.0",
"vue": "2.6.10",
"vue-codemirror": "^4.0.6",
"vue-count-to": "1.0.13",

BIN
public/china_under.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 976 KiB

BIN
public/cloud.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 596 KiB

BIN
public/earth.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1004 KiB

BIN
public/earth_cloud.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

BIN
public/green_line.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

BIN
public/light.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

View File

@ -97,7 +97,8 @@
"dataSafe": "Data Security",
"storageMana": "Storage Mgmt",
"appObserve": "App Monitoring",
"logMana": "Log Mgmt"
"logMana": "Log Mgmt",
"monitorSelectPcm": "材料AI云际计算平台"
},
"check": {
"input": "Please Input",

View File

@ -97,7 +97,8 @@
"dataSafe": "数据安全",
"storageMana": "存储管理",
"appObserve": "应用观测",
"logMana": "日志管理"
"logMana": "日志管理",
"monitorSelectPcm": "材料AI云际计算平台"
},
"check": {
"input": "请输入",

BIN
public/point.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

38
public/statusEnd.svg Normal file
View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="_层_2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 19.8 29.7" style="enable-background:new 0 0 19.8 29.7;" xml:space="preserve">
<style type="text/css">
.st0{fill:url(#SVGID_1_);}
.st1{fill:url(#SVGID_2_);}
.st2{fill:url(#SVGID_3_);}
.st3{fill:#FF8B00;}
.st4{fill:url(#SVGID_4_);}
</style>
<radialGradient id="SVGID_1_" cx="9.92" cy="-284.2275" r="9.92" gradientTransform="matrix(1 0 0 -0.66 0 -164.76)" gradientUnits="userSpaceOnUse">
<stop offset="0.48" style="stop-color:#FFF76A"/>
<stop offset="1" style="stop-color:#FFE66A;stop-opacity:0"/>
</radialGradient>
<ellipse class="st0" cx="9.9" cy="23.1" rx="9.9" ry="6.6"/>
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="9.92" y1="5.28" x2="9.92" y2="14.66" gradientTransform="matrix(1 0 0 -1 0 32)">
<stop offset="0" style="stop-color:#EB5E00"/>
<stop offset="1" style="stop-color:#F0DF5E"/>
</linearGradient>
<ellipse class="st1" cx="9.9" cy="22" rx="7.3" ry="4.7"/>
<g>
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="9.98" y1="7.75" x2="9.98" y2="13.1904" gradientTransform="matrix(1 0 0 -1 0 32)">
<stop offset="0" style="stop-color:#FFDCC0"/>
<stop offset="1" style="stop-color:#FFE1C0"/>
</linearGradient>
<path class="st2" d="M10,24.3C7.3,24.3,5,23,5,21.5s2.3-2.7,4.9-2.7s4.9,1.2,4.9,2.7S12.7,24.3,10,24.3z"/>
<path class="st3" d="M10,19.3c2.5,0,4.4,1.2,4.4,2.2s-1.9,2.2-4.4,2.2s-4.4-1.2-4.4-2.2S7.4,19.3,10,19.3 M10,18.3
c-3,0-5.4,1.4-5.4,3.2S7,24.8,10,24.8s5.4-1.4,5.4-3.2S13,18.3,10,18.3L10,18.3z"/>
</g>
<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="10.1568" y1="20.5234" x2="10.1568" y2="0.757">
<stop offset="0" style="stop-color:#FFFFFF"/>
<stop offset="1" style="stop-color:#FF8B00"/>
</linearGradient>
<path class="st4" d="M10.2,0.8C6.2,0.8,3,4,3,7.9c0,5.8,7.2,12.6,7.2,12.6s7.2-6.7,7.2-12.6C17.3,4,14.1,0.8,10.2,0.8z M10.2,11.5
c-2,0-3.6-1.6-3.6-3.6s1.6-3.6,3.6-3.6c2,0,3.6,1.6,3.6,3.6S12.1,11.5,10.2,11.5z"/>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

33
public/statusIng.svg Normal file
View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="_层_2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 19.8 29.7" style="enable-background:new 0 0 19.8 29.7;" xml:space="preserve">
<style type="text/css">
.st0{fill:url(#SVGID_1_);}
.st1{fill:url(#SVGID_2_);}
.st2{fill:#CCFFFB;}
.st3{fill:#00FFB6;}
.st4{fill:url(#SVGID_3_);}
</style>
<radialGradient id="SVGID_1_" cx="9.92" cy="-303.9175" r="9.92" gradientTransform="matrix(1 0 0 -0.66 0 -177.8)" gradientUnits="userSpaceOnUse">
<stop offset="0.48" style="stop-color:#6CF8FF"/>
<stop offset="1" style="stop-color:#6CFFD8;stop-opacity:0"/>
</radialGradient>
<ellipse class="st0" cx="9.9" cy="23.1" rx="9.9" ry="6.6"/>
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="9.92" y1="5.28" x2="9.92" y2="14.66" gradientTransform="matrix(1 0 0 -1 0 32)">
<stop offset="0" style="stop-color:#15C252"/>
<stop offset="1" style="stop-color:#1586D1;stop-opacity:0.69"/>
</linearGradient>
<ellipse class="st1" cx="9.9" cy="22" rx="7.3" ry="4.7"/>
<g>
<path class="st2" d="M10,24.3C7.3,24.3,5,23,5,21.5s2.3-2.7,4.9-2.7s4.9,1.2,4.9,2.7S12.7,24.3,10,24.3z"/>
<path class="st3" d="M10,19.3c2.5,0,4.4,1.2,4.4,2.2s-1.9,2.2-4.4,2.2s-4.4-1.2-4.4-2.2S7.4,19.3,10,19.3 M10,18.3
c-3,0-5.4,1.4-5.4,3.2S7,24.8,10,24.8s5.4-1.4,5.4-3.2S13,18.3,10,18.3L10,18.3z"/>
</g>
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="9.98" y1="20.7665" x2="9.98" y2="1">
<stop offset="0" style="stop-color:#BDF9E1"/>
<stop offset="1" style="stop-color:#25CB96"/>
</linearGradient>
<path class="st4" d="M10,1C6,1,2.8,4.2,2.8,8.2C2.8,14,10,20.8,10,20.8s7.2-6.7,7.2-12.6C17.2,4.2,13.9,1,10,1z M10,11.8
c-2,0-3.6-1.6-3.6-3.6S8,4.6,10,4.6c2,0,3.6,1.6,3.6,3.6S12,11.8,10,11.8z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

34
public/statusUn.svg Normal file
View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="_层_2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 19.8 29.8" style="enable-background:new 0 0 19.8 29.8;" xml:space="preserve">
<style type="text/css">
.st0{fill:url(#SVGID_1_);}
.st1{fill:url(#SVGID_2_);}
.st2{fill:#CAE8FF;}
.st3{fill:#0086FF;}
.st4{fill:url(#SVGID_3_);}
</style>
<radialGradient id="SVGID_1_" cx="9.92" cy="-323.9676" r="9.92" gradientTransform="matrix(1 0 0 -0.66 0 -190.96)" gradientUnits="userSpaceOnUse">
<stop offset="0.48" style="stop-color:#3AA9FC"/>
<stop offset="1" style="stop-color:#57B7FF;stop-opacity:0"/>
</radialGradient>
<ellipse class="st0" cx="9.9" cy="23.2" rx="9.9" ry="6.6"/>
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="9.84" y1="5.28" x2="9.84" y2="14.66" gradientTransform="matrix(1 0 0 -1 0 32)">
<stop offset="0" style="stop-color:#0000FF"/>
<stop offset="1" style="stop-color:#2AAEF1"/>
</linearGradient>
<ellipse class="st1" cx="9.8" cy="22" rx="7.3" ry="4.7"/>
<g>
<path class="st2" d="M9.8,24.3c-2.7,0-4.9-1.2-4.9-2.7s2.3-2.7,4.9-2.7c2.7,0,4.9,1.2,4.9,2.7S12.5,24.3,9.8,24.3z"/>
<path class="st3" d="M9.8,19.3c2.5,0,4.4,1.2,4.4,2.2s-1.9,2.2-4.4,2.2s-4.4-1.2-4.4-2.2S7.3,19.3,9.8,19.3 M9.8,18.3
c-3,0-5.4,1.4-5.4,3.2s2.4,3.2,5.4,3.2s5.4-1.4,5.4-3.2S12.8,18.3,9.8,18.3L9.8,18.3z"/>
</g>
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="9.92" y1="20.9674" x2="9.92" y2="1.201">
<stop offset="0" style="stop-color:#DEF5FF"/>
<stop offset="0.53" style="stop-color:#2AAEFF;stop-opacity:0.7"/>
<stop offset="1" style="stop-color:#008CFF"/>
</linearGradient>
<path class="st4" d="M9.9,1.2c-4,0-7.2,3.2-7.2,7.2C2.7,14.2,9.9,21,9.9,21s7.2-6.7,7.2-12.6C17.1,4.4,13.9,1.2,9.9,1.2z M9.9,12
c-2,0-3.6-1.6-3.6-3.6s1.6-3.6,3.6-3.6c2,0,3.6,1.6,3.6,3.6S11.9,12,9.9,12z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
src/assets/monitor/b-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
src/assets/monitor/b-p.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

BIN
src/assets/monitor/b.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 287 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 273 KiB

BIN
src/assets/monitor/g-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

BIN
src/assets/monitor/g-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

BIN
src/assets/monitor/t-p.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 KiB

View File

@ -129,7 +129,7 @@ export default {
this.$router.push({ path: '/monitorSelect' })
},
toJCCE() {
window.open(window.location.origin + '/monitor/monitorSelect')
window.open(window.location.origin + '/monitorSelectPcm')
},
toPCM() {
this.$router.push({ path: '/monitorSelectNew' })

View File

@ -92,6 +92,12 @@ export const constantRoutes = [
component: () => import('@/views/monitorSelect/index'),
meta: { title: 'monitorSelect' },
hidden: true
},
{
path: '/monitorSelectPcm',
component: () => import('@/views/monitorSelectPcm/index'),
meta: { title: 'monitorSelectPcm' },
hidden: true
}
// {
// path: '/resourceList',

View File

@ -0,0 +1,307 @@
<template>
<!-- 计算域信息 -->
<div style="height:100%">
<el-row class="top">
<el-col :span="10"><div class="img" /></el-col>
<el-col :span="14">
<div class="text">
<el-carousel direction="vertical" :autoplay="false" @change="changeItem">
<el-carousel-item v-for="(item, index) in areaItem" :key="'areaItem' + index" class="areaList">
<div class="area">{{ item.domainName || 'DomainName' }}</div>
<table>
<tr>
<td>
<span>资源类型</span>
</td>
<td>
{{ item.resourceType }}
</td>
</tr>
<tr>
<td>
<span>适配技术栈</span>
</td>
<td>
{{ item.stack }}
</td>
</tr>
</table>
</el-carousel-item>
</el-carousel>
</div>
</el-col>
</el-row>
<el-row class="bottom">
<el-col :span="10">
<div id="radarChart" ref="radarChart" style="width: 100%; height: 14vh" />
</el-col>
<el-col :span="14">
<div class="text">
<table>
<tr>
<td>
<span>本地存储</span>
</td>
<td>
<el-progress :stroke-width="8" :percentage="Number(computePercent.disk)" />
</td>
<td>
<span>/ {{ computePercent.diskTotal }} GB</span>
</td>
</tr>
<tr>
<td>
<span>节点数</span>
</td>
<td>
<el-progress :stroke-width="8" :percentage="Number(computePercent.nodeCount)" />
</td>
<td>
<span> / {{ computePercent.nodeTotal }}</span>
</td>
</tr>
<tr>
<td>
<span>内存</span>
</td>
<td>
<el-progress :stroke-width="8" :percentage="Number(computePercent.memory)" />
</td>
<td>
<span>/ {{ computePercent.memoryTotal }} GB</span>
</td>
</tr>
<tr>
<td>
<span>cpu</span>
</td>
<td>
<el-progress :stroke-width="8" :percentage="Number(computePercent.cpu)" />
</td>
<td>
<span>/ {{ computePercent.cpuTotal }} Core</span>
</td>
</tr>
</table>
</div>
</el-col>
</el-row>
</div>
</template>
<script>
import * as echarts from 'echarts'
import { getComputeArea } from '@/api/container/monitorSelect.js'
import { debounce } from '@/utils'
export default {
data() {
return {
areaItem: [],
radarChart: undefined,
computePercent: {
disk: 0,
memory: 0,
nodeCount: 0,
cpu: 0
}
}
},
mounted() {
getComputeArea().then((res) => {
this.areaItem = res.data.domainResourceList
const charts = echarts.init(this.$refs.radarChart)
const { disk, memory, nodeCount, cpu } = this.areaItem[0]
this.computePercent = this.areaItem[0]
charts.setOption(this.returnRadarChart([disk, memory, nodeCount, cpu]))
window.addEventListener('resize', debounce(() => {
charts.resize()
}, 100))
this.radarChart = charts
})
},
methods: {
changeItem(e) {
const { disk, memory, nodeCount, cpu } = this.areaItem[e]
this.computePercent = this.areaItem[e]
this.radarChart.setOption(this.returnRadarChart([disk, memory, nodeCount, cpu]))
},
fontSize(rem) {
const scale = window.innerHeight / 900
return scale >= 1 ? 16 * rem : 14 * rem
},
returnRadarChart(data) {
return {
tooltip: {
trigger: 'item',
backgroundColor: '#000033',
textStyle: { color: '#fff' },
borderWidth: 0,
position: 'right'
},
radar: {
radius: '60%',
shape: 'circle',
splitArea: {
show: false,
areaStyle: {
color: ['rgba(255,255,255,0.45)', 'rgba(255,255,255,0.35)', 'rgba(255,255,255,0.25)', 'rgba(255,255,255,0.15)', 'rgba(255,255,255,0.1)']
}
},
splitLine: {
lineStyle: {
color: 'rgba(14, 55, 100, 1)'
}
},
axisLine: { // 线
show: false // show
},
name: { // ()
formatter: '{value}',
textStyle: {
fontSize: this.fontSize(0.7)
}
},
indicator: [
{ name: '本地存储', max: 100 },
{ name: '内存', max: 100 },
{ name: '节点数', max: 100 },
{ name: 'cpu', max: 100 }
],
nameGap: 4
},
series: [{
name: '计算域信息',
type: 'radar',
symbol: 'none',
data: [
{
value: data
}
],
itemStyle: {
color: ['red'],
opacity: 1
},
lineStyle: {
color: 'rgba(35, 162, 236, 0.8)',
type: 'dashed'
},
areaStyle: //
{
color: 'rgba(1, 154, 251, 0.5)'
}
}]
}
}
}
}
</script>
<style lang="scss" scoped>
.top{
// display: flex;
// justify-content: space-between;
// padding: 5px 3%;
margin: 1vh 0;
::v-deep .el-carousel__indicators{
display: none;
}
.img{
height: 8vh;
background: url('../../../assets/images/monitorSelect/computingArea.png') center no-repeat;
background-size: auto 100%;
// margin-left: 3vw;
}
}
.text{
// width: 65%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
height: 8vh;
.areaList{
height: 8vh;
}
.area{
height: 2vh;
line-height: 2vh;
font-size: 1.13rem;
margin: 0.4vh 0;
background-image: linear-gradient(0deg, #00C0FF 0%, #ffffff 100%);
background-clip: text;
-webkit-text-fill-color: transparent;
}
table{
padding: 0;
border-spacing: 0px;
width: 100%;
td{
@media screen and (max-height: 900px) {
transform: scale(0.8);
transform-origin: 0 0;
}
color: #DDDDDD;
height: 3vh;
}
}
}
.bottom{
.text{
margin-top: 0.5vh;
height: 14vh;
}
table tr td:nth-child(2) {
padding-right: 2.5rem;
}
span{
margin: 0;
// height: 2.4vh;
// line-height: 3.4vh;
// @media screen and (max-height: 900px) {
// transform: scale(0.8);
// transform-origin: 0 0;
// }
}
}
::v-deep {
.el-progress{
height: 2.4vh;
line-height: 2.4vh;
}
.el-progress-bar{
margin: 0;
line-height: 2.5rem;
margin-right: 0px;
padding-right: 0px;
margin-left: -10px;
}
.el-progress__text{
color: white;
font-size: 0.5rem!important;
}
.el-progress-bar__outer {
background-color: rgba(135, 189, 245, 0.2);
}
.el-progress-bar__inner{
background-image: linear-gradient(90deg, #419eff, #00d9a6);
}
}
// @media screen and (min-width: 1921px) {
// .top{
// .img{
// width: auto;
// height: 100%;
// }
// .text{
// .area{
// font-size: 20px;
// }
// }
// }
// }
</style>

View File

@ -0,0 +1,93 @@
<template>
<!-- 算力中心总数 -->
<div>
<div class="two">
<div v-for="(item, index) in dataArray" :key="'data'+index">
<p class="title">{{ item.name }}</p>
<div class="num">{{ item.value }}</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
dataArray: [
{
name: '算力中心总数(计算域)',
value: 34
},
{
name: '已接入算力 POps@FP16',
value: '112.06'
},
{
name: '接入集群数',
value: '48'
}
]
}
},
methods: {
}
}
</script>
<style lang="scss" scoped>
.two{
display: flex;
justify-content: space-between;
margin-top: 10px;
// text-align: center;
>div{
padding: 10px;
padding-top: 0;
}
.title{
font-size: 1.1rem;
margin: 0.5rem;
margin-bottom: 0.3rem;
letter-spacing: 0.1rem;
font-weight: bold;
color: #DDDDDD;
}
.num{
font-size: 1.9rem;
font-family: Impact;
font-weight: 400;
// padding-bottom: 5px;
width: 80%;
// text-indent: 130%;
letter-spacing: 0.1rem;
display: inline-block;
padding: 0 15px 3px;
}
}
// @media screen and (min-width: 1921px) {
// .one{
// background-size: 39px 39px;
// font-size: 20px;
// .num{
// font-size: 38px;
// }
// }
// .two{
// p{
// margin: 16px 0 ;
// }
// .title{
// font-size: 14px;
// }
// .num{
// font-size: 27px;
// padding: 0 17px 5px;
// }
// }
// }
</style>

View File

@ -0,0 +1,218 @@
<!-- 算力使用趋势 -->
<template>
<div :id="id" ref="echart" style="width: 100%; height: 80%" />
</template>
<script>
import { debounce } from '@/utils'
export default {
name: 'LineChart',
props: {
id: {
type: String,
default: ''
},
data: {
type: Object,
default: () => ({})
},
config: {
type: Object,
default: () => ({})
},
type: {
type: Number,
default: 0
}
},
data() {
return {
Data: { used: [], xData: [] }
// xDataNumber: 120,
}
},
watch: {
data: {
handler(newValue, oldValue) {
const TempData = JSON.parse(JSON.stringify(newValue))
this.Data.used = TempData.used
this.Data.xData = TempData.xData
this.drawLine()
},
deep: true
}
},
mounted() {
// this.Data = { used: [59688.1, 59252.5, 59189.0, 55766.5, 55537.2, 54804.4, 52764.9], xData: ["2022-06-30", "2022-07-31", "2022-07-31", "2022-08-31", "2022-09-30", "2022-10-31", "2022-11-30"] }
this.$nextTick(() => {
this.drawLine()
})
},
destroyed() {
clearInterval(this.timer)
},
methods: {
fontSize(rem) {
const scale = window.innerHeight / 900
return scale >= 1 ? 16 * rem : 12 * rem
},
drawLine() {
const scaleRate = window.innerHeight / 1080 >= 1
// domecharts
const chart = this.$echarts.init(this.$refs.echart)
var option
option = {
title: {
text: '',
textStyle: {
color: '#008B45'
}
},
color: ['rgba(79, 172, 254, 1)'],
tooltip: {
trigger: 'axis',
axisPointer: {
show: false
},
backgroundColor: '#000033',
textStyle: { fontSize: this.fontSize(0.7), color: '#fff' },
borderWidth: 0
},
grid: {
right: '5%',
bottom: '25%',
top: scaleRate ? '15%' : '20%',
left: '13%'
},
xAxis: {
type: 'category',
boundaryGap: false,
data: this.Data.xData,
axisLine: {
lineStyle: {
color: 'rgba(135, 189, 245, 0.1)'
}
},
axisLabel: {
show: true,
interval: 28,
// rotate: -18,
// padding: [1, 0, 0, -10],
margin: scaleRate ? 14 : 10,
textStyle: {
fontSize: this.fontSize(0.75),
lineHeight: scaleRate ? 20 : 10,
color: '#DDDDDD',
fontFamily: 'Source Han Sans CN'
},
formatter: function(params) {
return params.slice(5).replaceAll('-', '/')
}
// formatter: function(params) {
// switch (params) {
// case '2023-04-30':
// return params.slice(2).replaceAll('-', '/')
// case '2023-03-31':
// return params.slice(2).replaceAll('-', '/')
// case '2023-02-28':
// return params.slice(2).replaceAll('-', '/')
// case '2023-01-31':
// return params.slice(2).replaceAll('-', '/')
// case '2022-12-31':
// return params.slice(2).replaceAll('-', '/')
// case '2022-11-30':
// return params.slice(2).replaceAll('-', '/')
// case '2022-10-31':
// return params.slice(2).replaceAll('-', '/')
// case '2022-09-30':
// return params.slice(2).replaceAll('-', '/')
// default:
// // return params.slice(2).replaceAll('-', '/')
// }
// }
},
axisTick: {
// x
show: false
}
},
yAxis: {
type: 'value',
name: this.config.unit,
// nameTextStyle: { //
// padding: this.config.unit.length > 7 ? [0, 0, 0, 45] : [0, 0, 0, 0]
// },
nameTextStyle: {
color: '#aaa',
fontSize: this.fontSize(0.75),
nameLocation: 'start'
},
splitLine: {
show: true,
lineStyle: {
color: 'rgba(135, 189, 245, 0.1)'
}
},
nameGap: 10,
data: [],
axisLine: {
lineStyle: {
color: '#fff'
}
},
axisLabel: {
show: true,
interval: 0,
align: 'right',
textStyle: {
fontSize: this.fontSize(0.75),
color: 'rgba(221, 221, 221, 1)',
fontFamily: 'Source Han Sans CN'
}
},
scale: true,
min: 0,
splitNumber: 3
},
series: [
{
name: this.config.status[0] ? this.config.status[0] : '',
type: 'line',
symbol: 'none',
label: {
show: false
},
data: this.Data.used,
areaStyle: {
opacity: 1,
color: new this.$echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: 'rgba(0, 242, 254, 1)' // 0%
},
{
offset: 1,
color: 'rgba(79, 172, 254, 1)' // 100%
}
])
}
}
],
animation: true,
animationDuration: function(idx) {
//
return idx * 500
},
animationEasing: 'backln'
}
chart.setOption(option)
window.addEventListener('resize', debounce(() => {
chart.resize()
}, 100))
}
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,349 @@
<!-- 算力使用情况 -->
<template>
<div :id="id" ref="echart" style="width: 95%; height: 85%" />
</template>
<script>
import { debounce } from '@/utils'
export default {
name: 'Histogram',
props: {
id: {
type: String,
default: ''
},
data: {
type: Object,
default: () => { }
},
config: {
type: Object,
default: () => ({})
}
},
data() {
return {
timer: null,
Data: {
unused: [], used: [], xData: []
},
barWidth: '40%',
Max: 0
}
},
watch: {
data: {
handler(newValue, oldValue) {
const Data = { unused: [], used: [], xData: [] }
clearInterval(this.timer)
const TempData = JSON.parse(JSON.stringify(newValue))
// if (TempData.xData.length <= 5) {
// this.barWidth = this.fontSize(1.62)
// } else {
// this.barWidth = this.fontSize(0.81)
// }
Data.xData = TempData.xData
Data.used = TempData.used ? TempData.used : []
Data.unused = TempData.unused ? TempData.unused : []
if (Data.unused.length !== 0) { this.Max = Math.max(...Data.used) + Math.max(...Data.unused) } else { this.Max = Math.max(...Data.used) }
// const num = this.digit(this.Max)
// let number = this.Max.toString()[0]
// number = parseFloat(number)
// if (number < 9) {
// number++
// if (num <= 3) { this.Max = number + '00' } else if (num <= 4) { this.Max = number + '000' } else if (num <= 5) { this.Max = number + '0000' }
// } else {
// if (num <= 3) { this.Max = 1000 } else if (num <= 4) { this.Max = 10000 } else if (num <= 5) { this.Max = 100000 }
// }
if (TempData.xData.length <= 5) {
this.Data = Data
this.drawLine()
} else {
this.Data.unused = Data.unused.slice(0, 5)
this.Data.used = Data.used.slice(0, 5)
this.Data.xData = Data.xData.slice(0, 5)
this.drawLine()
this.timer = setInterval(() => {
const unused = Data.unused.shift()
const used = Data.used.shift()
const xData = Data.xData.shift()
Data.unused.push(unused)
Data.used.push(used)
Data.xData.push(xData)
this.Data.unused = Data.unused.slice(0, 5)
this.Data.used = Data.used.slice(0, 5)
this.Data.xData = Data.xData.slice(0, 5)
this.drawLine()
}, 3000)
}
},
deep: true
}
},
mounted() {
// this.Data = {
// used: [1400, 700, 200, 800, 600], xData
// : ["", "", "", "GPU",""]
// }
this.$nextTick(() => {
this.drawLine()
const newValue = this.data
const Data = { unused: [], used: [], xData: [] }
clearInterval(this.timer)
const TempData = JSON.parse(JSON.stringify(newValue))
// if (TempData.xData.length <= 5) {
// this.barWidth = this.fontSize(1.62)
// } else {
// this.barWidth = this.fontSize(0.81)
// }
Data.xData = TempData.xData
Data.used = TempData.used ? TempData.used : []
Data.unused = TempData.unused ? TempData.unused : []
if (Data.unused.length !== 0) { this.Max = Math.max(...Data.used) + Math.max(...Data.unused) } else { this.Max = Math.max(...Data.used) }
// const num = this.digit(this.Max)
// let number = this.Max.toString()[0]
// number = parseFloat(number)
// if (number < 9) {
// number++
// if (num <= 3) { this.Max = number + '00' } else if (num <= 4) { this.Max = number + '000' } else if (num <= 5) { this.Max = number + '0000' }
// } else {
// if (num <= 3) { this.Max = 1000 } else if (num <= 4) { this.Max = 10000 } else if (num <= 5) { this.Max = 100000 }
// }
if (TempData.xData.length <= 5) {
this.Data = Data
this.drawLine()
} else {
this.Data.unused = Data.unused.slice(0, 5)
this.Data.used = Data.used.slice(0, 5)
this.Data.xData = Data.xData.slice(0, 5)
this.drawLine()
this.timer = setInterval(() => {
const unused = Data.unused.shift()
const used = Data.used.shift()
const xData = Data.xData.shift()
Data.unused.push(unused)
Data.used.push(used)
Data.xData.push(xData)
this.Data.unused = Data.unused.slice(0, 5)
this.Data.used = Data.used.slice(0, 5)
this.Data.xData = Data.xData.slice(0, 5)
this.drawLine()
}, 3000)
}
})
},
destroyed() {
clearInterval(this.timer)
},
methods: {
fontSize(rem) {
const scale = window.innerHeight / 900
return scale >= 1 ? 16 * rem : 12 * rem
},
drawLine() {
const scaleRate = window.innerHeight / 900 >= 1
const chart = this.$echarts.init(this.$refs.echart)
var option
option = {
title: {
text: '',
textStyle: {
color: '#008B45'
},
padding: [10, 0, 0, 10] //
},
color: ['rgba(135, 189, 245, 1)', 'rgba(62, 223, 252, 1)', 'rgba(5, 155, 252, 1)'],
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'none',
show: false
},
backgroundColor: '#000033',
textStyle: { fontSize: this.fontSize(0.7), color: '#fff' },
borderWidth: 0
},
legend: {
right: '0',
itemWidth: 15,
selectedMode: false, //
textStyle: {
color: '#fff',
fontSize: this.fontSize(0.75),
fontFamily: 'Source Han Sans CN'
}
},
grid: {
right: '1%',
bottom: '20%',
top: scaleRate ? '15%' : '20%',
left: '15%'
},
xAxis: {
type: 'category',
data: this.Data.xData,
axisLine: {
lineStyle: {
color: 'rgba(135, 189, 245, 0.1)'
}
},
axisLabel: {
show: true,
interval: 0,
textStyle: {
fontSize: this.fontSize(0.75),
lineHeight: scaleRate ? 20 : 10,
color: 'rgba(221, 221, 221, 1)',
fontFamily: 'Source Han Sans CN'
},
margin: scaleRate ? (this.config.unit.length > 10 ? 35 : 8) : 10,
formatter: function(params) {
var provideNumber = 4 //
return params.slice(0, provideNumber) + (params.length > provideNumber ? '...' : '')
}
},
axisTick: {
// x
alignWithLabel: true
}
},
yAxis: {
type: 'value',
// offset: this.config.unit.length > 10 ? -40 : 0,
splitLine: {
show: true,
lineStyle: {
color: 'rgba(135, 189, 245, 0.1)'
}
},
name: this.config.unit,
nameTextStyle: {
color: '#aaa',
padding: [0, 10, 0, 0],
fontSize: this.fontSize(0.75),
nameLocation: 'start'
},
nameGap: 10,
data: [],
axisLine: {
lineStyle: {
color: 'rgba(135, 189, 245, 0.1)'
}
},
axisLabel: {
show: true,
textStyle: {
fontSize: this.fontSize(0.75),
color: 'rgba(221, 221, 221, 1)',
fontFamily: 'Source Han Sans CN'
}
},
scale: true,
min: 0,
splitNumber: 3
},
series: [
{
name: this.config.status[0] ? this.config.status[0] : '',
type: 'bar',
stack: 'total',
barWidth: this.barWidth,
label: {
show: false
},
emphasis: {
focus: 'series'
},
data: this.Data.used ? this.Data.used : [],
itemStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{
offset: 0,
color: 'rgb(24, 144, 255)' // 0%
},
{
offset: 1,
color: 'rgba(24, 144, 255,0.5)' // 100%
}
],
global: false // false
}
}
},
{
name: this.config.status[1] ? this.config.status[1] : '',
type: 'bar',
stack: 'total',
barWidth: this.barWidth,
label: {
show: false
},
emphasis: {
focus: 'series'
},
data: this.Data.unused !== [] ? this.Data.unused : [],
itemStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{
offset: 0,
color: 'rgba(30, 231, 231,0.5)' // 0%
},
{
offset: 1,
color: 'rgb(30, 231, 231)' // 100%
}
],
global: false // false
}
}
}
],
animation: true,
animationDuration: function(idx) {
//
return idx * 100
},
animationEasing: 'backln'
}
chart.setOption(option)
window.addEventListener('resize', debounce(() => {
chart.resize()
}, 100))
},
digit(val) {
let num = Math.trunc(val)
// const number = num.toString() //
// var temp = num
var count = 0
if (num === 0) {
return 0
} else {
while (num !== 0) {
count++ //
num = parseInt(num / 10) // num 使
}
return count
}
}
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,350 @@
<!-- 计算资源负载 -->
<template>
<div id="myBarEchart" ref="myBarEchart" style="width: 100%; height: 80%" />
</template>
<script>
import * as echarts from 'echarts'
import { getTotalAverage } from '@/api/top-menu/TotalNum'
import moment from 'moment'
import { debounce } from '@/utils'
export default {
data() {
const day = [[], [], [], [], [], [], []]
for (let i = 0; i < 7; i++) {
day[i][0] = moment().subtract(7 - i, 'days').endOf('day').unix()
day[i][1] = moment().subtract(7 - i, 'days').endOf('day').format('MMDD')
}
return {
day,
ramLoad: [2, 3, 4, 5, 6, 4, 5], //
cpuLoad: [1, 2, 3, 4, 5, 3, 4], // CPU
cpuAverage: [3, 4, 5, 3, 4, 3, 4], // cpu
ramAverage: [7, 6, 5, 4, 6, 5, 4] //
}
},
computed: {
jcceTheme() {
return localStorage.getItem('jcceTheme')
}
},
mounted() {
this.getAllData()
},
methods: {
fontSize(rem) {
const scale = window.innerHeight / 900
return scale >= 1 ? 16 * rem : 12 * rem
},
//
async getAllData() {
await getTotalAverage().then(res => {
const data = res.data
// GB
const ramData = data.find(item => item.metric_name === 'mem_total_usage').data.result[0].values || []
ramData.forEach(element => {
this.ramLoad.push(((element[1] - 0) / 1024 / 1024 / 1024).toFixed(2))
// this.date.push(moment(element[0] * 1000).format('MM/DD'))
})
this.ramLoad = this.ramLoad.slice(0, 7)
// CPU Core
const cpuLoad = data.find(item => item.metric_name === 'cpu_total_usage').data.result[0].values || []
cpuLoad.forEach(element => {
this.cpuLoad.push(((element[1] - 0)).toFixed(2))
})
this.cpuLoad = this.cpuLoad.slice(0, 7)
// cpu (%)
const cpuData = data.find(item => item.metric_name === 'cpu_avg_usage').data.result[0].values || []
cpuData.forEach(element => {
this.cpuAverage.push((element[1] - 0).toFixed(2))
// this.date.push(moment(element[0] * 1000).format('MM/DD'))
})
this.cpuAverage = this.cpuAverage.slice(0, 7)
// (%)
const ramAverage = data.find(item => item.metric_name === 'mem_avg_usage').data.result[0].values || []
ramAverage.forEach(element => {
this.ramAverage.push(((element[1] - 0) / 1024 / 1024 / 1024).toFixed(2))
})
this.ramAverage = this.ramAverage.slice(0, 7)
})
this.initCharts()
},
// echart
initCharts() {
const scaleRate = window.innerHeight / 900 >= 1
const chart = echarts.init(this.$refs.myBarEchart)
//
const legend = ['CPU整体负载', '内存整体负载', 'CPU平均负载', '内存平均负载']
// const legend = ['CPU', '', 'CPU']
chart.setOption({
legend: {
right: '0',
itemWidth: 14,
data: legend,
itemHeight: scaleRate ? 10 : 2,
selectedMode: false, //
textStyle: {
color: '#FFFFFF',
fontSize: this.fontSize(0.7)
}
},
grid: {
right: '12%',
bottom: '16%',
top: scaleRate ? '25%' : '30%',
left: '12%'
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
label: {
backgroundColor: '#000033'
}
},
backgroundColor: '#000033',
textStyle: { fontSize: this.fontSize(0.7), color: '#fff' },
borderWidth: 0,
formatter: (params) => {
let val = params[0].name
for (let i = 0; i < params.length; i++) {
const unit = params[i].seriesName.indexOf('CPU') > -1 ? '核' : 'GB'
val += '<br/>' + params[i].marker + (params[i].seriesName.indexOf('平均') > -1 ? '七日' : '') + params[i].seriesName + ' ' + params[i].value + unit
}
return val
}
},
xAxis: {
type: 'category',
data: this.day.map(n => n[1]),
axisTick: {
show: false
},
axisLabel: {
textStyle: {
fontSize: this.fontSize(0.75),
color: 'rgba(221, 221, 221, 1)'
},
interval: 0,
margin: scaleRate ? 14 : 10
},
axisLine: {
lineStyle: {
color: 'rgba(135, 189, 245, 0.01)'
}
}
},
yAxis: [
{
name: '单位:核',
nameTextStyle: {
color: '#aaa',
// padding: [0, 10, 0, 0],
fontSize: this.fontSize(0.75),
nameLocation: 'start'
},
axisLabel: {
textStyle: {
fontSize: this.fontSize(0.75),
color: 'rgba(221, 221, 221, 1)'
},
formatter: '{value}'
},
splitLine: {
lineStyle: {
color: 'rgba(135, 189, 245, 0.1)'
}},
axisLine: {
lineStyle: {
color: '#DDDDDD'
}
},
splitNumber: 3,
position: 'left',
alignTicks: true
},
{
name: '单位GB',
nameTextStyle: {
color: '#aaa',
// padding: [0, 10, 0, 0],
fontSize: this.fontSize(0.75),
nameLocation: 'start'
},
axisLabel: {
textStyle: {
fontSize: this.fontSize(0.75),
color: 'rgba(221, 221, 221, 1)'
},
formatter: '{value}'
},
position: 'right',
alignTicks: true,
splitLine: {
lineStyle: {
color: 'rgba(255,255,255,0.1)'
}},
splitNumber: 3,
axisLine: {
lineStyle: {
color: '#999999'
}
}
}
],
color: '#3282CE',
series: [
{
name: legend[0],
type: 'pictorialBar',
symbolSize: [12, 3],
yAxisIndex: 0,
tooltip: {
show: false
},
symbolOffset: [-9, 3],
z: 12,
color: 'rgba(5, 155, 252, 0.8)',
data: this.cpuLoad
},
{
name: legend[0],
type: 'pictorialBar',
symbolSize: [16, 6],
yAxisIndex: 0,
tooltip: {
show: false
},
symbolOffset: [-9, 6],
z: 12,
color: 'rgba(5, 155, 252, 0.5)',
data: this.cpuLoad
},
{
name: legend[0],
type: 'pictorialBar',
symbolSize: [20, 9],
yAxisIndex: 0,
tooltip: {
show: false
},
symbolOffset: [-9, 9],
z: 12,
color: 'rgba(5, 155, 252, 0.25)',
data: this.cpuLoad
},
{
type: 'bar',
name: legend[0],
barWidth: '10',
yAxisIndex: 0,
itemStyle: {
normal: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: 'rgba(5, 155, 252, 0)' }, { offset: 1, color: 'rgba(5, 155, 252, 1)' }])
}
},
data: this.cpuLoad
},
{
name: legend[1],
yAxisIndex: 1,
type: 'pictorialBar',
symbolSize: [12, 3],
tooltip: {
show: false
},
symbolOffset: [9, 3],
z: 12,
color: 'rgba(62, 223, 252, 1)',
data: this.ramLoad
},
{
name: legend[1],
yAxisIndex: 1,
type: 'pictorialBar',
symbolSize: [16, 6],
tooltip: {
show: false
},
symbolOffset: [9, 6],
z: 12,
color: 'rgba(62, 223, 252, 0.5)',
data: this.ramLoad
},
{
name: legend[1],
yAxisIndex: 1,
type: 'pictorialBar',
symbolSize: [20, 9],
tooltip: {
show: false
},
symbolOffset: [9, 9],
z: 12,
color: 'rgba(62, 223, 252, 0.25)',
data: this.ramLoad
},
{
type: 'bar',
name: legend[1],
barWidth: '10',
barGap: '80%',
yAxisIndex: 1,
itemStyle: {
normal: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: 'rgba(5, 155, 252, 0)' }, { offset: 1, color: 'rgba(62, 223, 252, 1)' }])
}
},
data: this.ramLoad
},
{
name: legend[2],
data: this.cpuAverage,
type: 'line',
showSymbol: true,
symbol: 'circle',
symbolSize: 8,
itemStyle: {
color: '#30BFB6',
shadowColor: '#30BFB6',
shadowBlur: 8
},
yAxisIndex: 0,
lineStyle: {
color: '#30BFB6', // 线
width: 1
},
smooth: true
},
{
name: legend[3],
data: this.ramAverage,
yAxisIndex: 1,
type: 'line',
showSymbol: true,
symbol: 'circle',
symbolSize: 8,
itemStyle: {
color: '#87BDF5',
shadowColor: '#87BDF5',
shadowBlur: 8
},
lineStyle: {
color: '#87BDF5',
width: 1
},
smooth: true
}
]
})
window.addEventListener('resize', debounce(() => {
chart.resize()
}, 100))
}
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,154 @@
<template>
<div class="taskArea">
<el-row class="taskDiv">
<el-col v-for="(item,index) in taskDetail" :key="'task'+index" :span="8">
<div class="num">{{ item.num }}</div>
<div class="name">{{ item.name }}</div>
</el-col>
</el-row>
<dt-srcoll v-if="fresh" class="scrollList" :new-data="dutyRateData" :menu-data="menuData" :line-height="4" :is-again="true" :table-height="37" />
</div>
</template>
<script>
import DtSrcoll from '../components/scroll'
export default {
components: {
DtSrcoll
},
props: {
data: {
type: Object,
default: () => ({})
}
},
data() {
return {
taskDetail: [
{
name: '运行任务合计',
num: 0
},
{
name: '运行卡时数',
num: 0
},
{
name: '运行时长',
num: 0
}
],
menuData: [ //
{
name: '作业名称',
prop: 'name'
},
{
name: '作业状态',
prop: 'status'
},
{
name: '策略',
prop: 'strategy'
},
{
name: '协同状态',
prop: 'synergyStatus'
},
{
name: '承接方',
prop: 'serviceName'
}
],
dutyRateData: [],
fresh: false
}
},
watch: {
data: {
handler(newValue, oldValue) {
this.fresh = false
this.taskDetail[0].num = newValue.totalCount
this.taskDetail[1].num = newValue.cardTime
this.taskDetail[2].num = newValue.totalRunTime
this.dutyRateData = newValue.tableData.map(e => { e.strategy = '时间优先'; return e })
this.$nextTick(() => {
this.fresh = true
})
},
deep: true
}
}
}
</script>
<style lang="scss" scoped>
.taskArea{
height: 29vh;
}
.scrollList{
height: 19.8vh;
overflow: hidden;
}
.taskDiv{
display: flex;
justify-content: space-between;
text-align: center;
margin-bottom: 1%;
// height: calc(100% - 190px);
>div{
// width: 25%;
.num{
font-size: 1.5rem;
font-family: Impact;
color: #FFFFFF;
letter-spacing: 0.1rem;
// height: 3vh;
// line-height: 4vh;
height: 30%;
line-height: 200%;
}
.name{
font-size: 1rem;
letter-spacing: 0.1rem;
font-weight: bold;
height: 70%;
line-height: 300%;
background: url('../../../assets/images/monitorSelect/task.png') no-repeat center;
background-size: auto 100%;
}
}
}
::v-deep{
.el-table--mini th, .el-table--mini td{
// padding: 0.375rem 0;
height: 2vh;
padding: 0;
}
.el-table--mini th{
height: 4vh;
}
.el-table thead {
font-size: 1rem;
}
.el-table__body {
font-size: 0.9rem;
}
}
// @media screen and (min-width: 1921px) {
// .taskDiv{
// margin-bottom: 1%;
// >div{
// .num{
// font-size: 26px;
// }
// .name{
// font-size: 16px;
// height: 80px;
// line-height: 55px;
// }
// }
// }
// }
</style>

View File

@ -0,0 +1,123 @@
<template>
<!-- 存储资源用量 -->
<div>
<div class="unUse use">
<div class="data">
<p class="num">{{ storageData.storageUsing }}TB</p>
<p class="percent"> {{ Math.round(storageData.usingRate*10000) /100 }}%</p>
</div>
<span class="type">未使用 </span>
</div>
<div class="used use">
<span class="type"> 已使用 </span>
<div class="data">
<p class="num">{{ storageData.storageUsed }}TB</p>
<p class="percent"> {{ Math.round(storageData.usageRate*10000) /100 }}%</p>
</div>
</div>
</div>
</template>
<script>
import { getStorageData } from '@/api/container/monitorSelect'
export default {
data() {
return {
storageData: {}
}
},
mounted() {
getStorageData().then(e => {
this.storageData = e
})
}
}
</script>
<style lang="scss" scoped>
.use{
height: 8.5vh;
font-size: 1rem;
font-weight: bold;
margin-top: 1vh;
position: relative;
.data {
width: calc(100% - 14.3vh);
background: url(../../../assets/monitor/g-2.png) no-repeat;
background-size: 100% 62%;
background-position: -1vh 1.3vh;
height: 90%;
position: absolute;
top: 0;
right: 0;
font-family: PangMenZhengDao;
font-weight: 400;
.num{
font-size: 1.875rem;
color: #FFFFFF;
line-height: 1.25rem;
padding-top: 0.6rem;
margin:0 12%;
text-align: right;
letter-spacing: 0.1rem;
}
.percent{
// float: left;
position: absolute;
left: 0;
top: 0;
line-height: 7.5vh;
letter-spacing: 0.1rem;
margin: 0;
text-indent: 1rem;
font-size: 1.2rem;
color: #3EDFFC;
}
// display: block;
}
.type {
display: block;
width: 14.3vh;
height: 100%;
position: absolute;
top: 0;
background: url(../../../assets/monitor/g-1.png) no-repeat;
background-size: auto 100%;
text-align: right;
line-height: 7.5vh;
// padding: 0 10px;
}
}
.unUsed{
.type{
left: 0;
}
}
.used{
position:relative;
.data{
left: 0;
-moz-transform: matrix(-1, 0, 0, 1, 0, 0);
-webkit-transform: matrix(-1, 0, 0, 1, 0, 0);
-o-transform: matrix(-1, 0, 0, 1, 0, 0);
z-index: -1;
.num, .percent{
-moz-transform: matrix(-1, 0, 0, 1, 0, 0);
-webkit-transform: matrix(-1, 0, 0, 1, 0, 0);
-o-transform: matrix(-1, 0, 0, 1, 0, 0);
z-index: -1;
}
.num{
text-align: left;
}
}
.type{
text-align: left;
position: absolute;
right: 0;
background-image: url(../../../assets/monitor/b-1.png);
}
}
</style>

View File

@ -0,0 +1,231 @@
<template>
<div>
<el-table id="dbM" :data="newData" border style="width: 100%" align="center" size="mini" class="customer-table">
<el-table-column :label="menuData[0].name" :prop="menuData[0].prop" min-width="70" :show-overflow-tooltip="true" />
<el-table-column :label="menuData[1].name" min-width="70" align="center">
<template slot-scope="scope">
<div v-if="scope.row.status=='Completed'" class="other">已完成</div>
<div v-if="scope.row.status=='Running'" class="running">运行中</div>
<div v-if="scope.row.status=='Submitted'" class="other">已提交</div>
<div v-if="scope.row.status=='Saved'" class="other">已保存</div>
<div v-if="scope.row.status=='Failed'" class="pending">失败</div>
</template>
</el-table-column>
<el-table-column :label="menuData[2].name" :prop="menuData[2].prop" min-width="50" align="left" :show-overflow-tooltip="true" />
<el-table-column :label="menuData[3].name" :prop="menuData[3].prop" min-width="70" align="left" :show-overflow-tooltip="true" />
<el-table-column :label="menuData[4].name" :prop="menuData[4].prop" min-width="70" align="left" :show-overflow-tooltip="true" />
<slot name="footerTable" />
</el-table>
</div>
</template>
<script>
export default {
name: 'DtSrcoll',
props: {
newData: {
type: Array, //
default: () => []
},
menuData: {
type: Array,
default: () => []
}, //
lineHeight: { //
type: Number,
default: 4
},
rowTime: { //
type: Number,
default: 2000
},
duration: { //
type: Number,
default: 500
},
tableHeight: { //
type: Number,
default: 33
},
isClear: { //
type: Boolean,
default: false
},
isAgain: { //
type: Boolean,
default: false
},
isScroll: { //
type: Boolean,
default: true
}
},
data() {
return {
active: 0,
timer: ''
}
},
watch: {
newData: {
handler(newValue, oldValue) {
this.newData = newValue
},
deep: true
}
},
mounted() {
const _this = this
this.$nextTick(() => {
const vh = window.innerHeight / 100
const elwrapper = document.getElementsByClassName('el-table__body-wrapper')[0]
elwrapper.style.height = this.lineHeight * 3.95 * 2 + 'vh'
const elBody = document.getElementsByClassName('el-table__body')[0]
const elRow = document.getElementsByClassName('el-table__row')
for (const node of elRow) {
node.style.height = '3.95vh'
}
elBody.style.top = 0
elBody.style.transactionDuration = this.duration + 'ms'
if (_this.isScroll) {
_this.timer = setInterval(() => {
if (_this.active < parseInt(_this.newData.length) - parseInt(_this.lineHeight)) {
_this.active += 1
elBody.style.top = parseInt(elBody.style.top) - parseInt(vh * 4) + 'px'
} else {
if (this.isClear) {
clearInterval(this.timer)
}
if (_this.isAgain) {
_this.active = 0
elBody.style.top = 0
} else {
clearInterval(_this.timer)
}
}
}, _this.rowTime)
}
})
},
destroyed() {
clearInterval(this.timer)
}
}
</script>
<style lang="scss" scoped>
::v-deep{
.el-table__body {
position: absolute;
transition: all 500ms linear;
background-color: transparent !important;
color: #fff;
font-size: 0.9rem;
overflow: hidden;
}
.el-table,
.el-table__expanded-cell {
color: #fff;
background-color: transparent !important;
}
.el-table th,
.el-table tr,
.el-table td {
color: #fff;
background-color: transparent !important;
}
.el-table .cell{
line-height: 3.95vh;
}
.el-table tr:nth-child(even) td{
background: rgba(35,185,255,0.06) !important;
}
.el-table--border,
.el-table--group {
border: 0px;
}
.el-table td.el-table__cell,
.el-table th.el-table__cell.is-leaf {
background-color: transparent !important;
border: 0px solid transparent !important;
}
.el-table--border,
.el-table--group {
border: 0px solid transparent !important;
}
.customer-table {
text-align: center !important;
}
.el-table__footer-wrapper,
.el-table__header-wrapper {
font-size: 0.9rem;
background: rgba(35,185,255,0.12);
}
.el-table--scrollable-x .el-table__body-wrapper {
overflow: hidden;
}
/* 去掉表格单元格边框 */
.customer-table th {
border: none;
}
.customer-table td,
.customer-table th.is-leaf {
border: none;
}
/* 表格最外边框 */
.el-table--border,
.el-table--group {
border: none;
}
/* 头部边框 */
.customer-table thead tr th.is-leaf {
border: 0px solid #EBEEF5;
border-right: none;
}
.customer-table thead tr th:nth-last-of-type(2) {
border-right: 0px solid #EBEEF5;
}
/* 表格最外层边框-底部边框 */
.el-table--border::after,
.el-table--group::after {
width: 0;
}
.customer-table::before {
width: 0;
}
.customer-table .el-table__fixed-right::before,
.el-table__fixed::before {
width: 0;
}
/* 表格有滚动时表格头边框 */
.el-table--border th.gutter:last-of-type {
border: 1px solid #EBEEF5;
border-left: none;
}
.pending, .other, .running {
width: 3.625rem;
height: 1.3rem;
line-height: 1.2rem;
background: linear-gradient(90deg, #0BBAFB 0%, #4285EC 100%);
border-radius: 1rem;
}
}
</style>

View File

@ -0,0 +1,506 @@
<template>
<div>
<div class="monitor">
<div class="top-menu">
<div class="menu">
<a href="">首页</a>
<a @click="viewMenu()">数算资源</a>
</div>
<div class="right">
<a @click="viewMenu('hpc/hpcOverview')">超算资源</a>
<a @click="viewMenu('modelarts/autoStudy')">智算资源</a>
</div>
</div>
<div class="top">
<div class="top-title">
<h1>材料AI云际计算平台</h1>
</div>
</div>
<div class="floatLeft">
<div class="left">
<div class="left_1">
<div class="title"><p>计算域信息</p></div>
<ComputeDomain />
</div>
<div class="left_2">
<div class="title"><p>算力使用趋势</p></div>
<ComputingPowerTrend id="ComputingPowerTrend" :data="tendData" :config="tendConfig" />
</div>
<div class="left_3">
<div class="title"><p>算力使用情况</p></div>
<ComputingPowerUse id="ComputingPowerUse" :data="centerData" :config="statusConfig" />
</div>
</div>
</div>
<div class="floatRight">
<div class="right">
<div class="right_1">
<div class="title"> <el-button class="createBtn" type="primary" size="mini" round @click="dialogVisible = true"><div>创建跨域调度任务</div></el-button><p></p></div>
<CumulativeTasks :data="taskData" />
</div>
<div class="right_2">
<div class="title"><p>计算资源负载</p></div>
<ComputingResourceLoad />
</div>
<div class="right_3">
<div class="title"><p>存储资源用量</p></div>
<StorageResourceUsage />
</div>
</div>
</div>
<div class="middle">
<ComputingPowerTotal />
</div>
<Earth :key="resizeKey" :center="{name: monitorSettingForm.center, longitude: Number(monitorSettingForm.centerPosition.split(',')[0]), latitude: Number(monitorSettingForm.centerPosition.split(',')[1])}" />
</div>
<el-dialog
title="创建云际跨域任务"
:visible.sync="dialogVisible"
width="30%"
>
<el-upload
action="#"
:http-request="httpRequest"
:limit="1"
:on-remove="handleRemove"
:file-list="fileList"
>
<el-button size="small" type="primary">点击选择yaml文件</el-button>
</el-upload>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" @click="submitFile()"> </el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import moment from 'moment'
import ComputeDomain from './components/ComputeDomain.vue'
import ComputingPowerTotal from './components/ComputingPowerTotal.vue'
import CumulativeTasks from './components/CumulativeTasks.vue'
import StorageResourceUsage from './components/StorageResourceUsage.vue'
import ComputingPowerTrend from './components/ComputingPowerTrend.vue'
import ComputingResourceLoad from './components/ComputingResourceLoad.vue'
import ComputingPowerUse from './components/ComputingPowerUse.vue'
import Earth from '@/views/prometheusMonitor/earth'
import { getComputePower, getCPUsage } from '@/api/container/monitorSelect.js'
import { getTaskCount, createScheduleTask } from '@/api/top-menu/TotalNum'
import { order } from '@/utils/data-process'
import { getMonitorSetting } from '@/api/container/monitorSelect'
import { debounce } from '@/utils'
export default {
components: { ComputeDomain, ComputingPowerTotal, ComputingPowerTrend, ComputingResourceLoad, ComputingPowerUse, CumulativeTasks, StorageResourceUsage, Earth },
data() {
return {
monitorSettingForm: {
'title': '广域协同智能计算系统面板',
'titleColor': '#409EFF',
'mainColor': '',
'mainColor2': '',
'textColor': '',
'backgroundColor': '',
'center': '',
'centerPosition': '',
'provinceBgColor': ''
},
resizeKey: 0,
dialogVisible: false,
rs: new FormData(),
fileList: [],
pageSize: 100,
taskData: {},
currentDate: '',
tendData: { used: [], xData: [] },
centerData: { used: [], unused: [], xData: [] },
tendConfig: { unit: '单位: 卡时', status: ['使用量'] },
statusConfig: { unit: '单位: 卡时', status: ['使用量', '使用量2'] }
}
},
created() {
getMonitorSetting().then(e => {
this.monitorSettingForm = e.data
})
this.getTrainJob()
this.resize()
this.$nextTick(() => {
this.getTend()
this.getAccrueCenter()
})
window.addEventListener('resize', debounce(() => {
this.resizeKey++
}, 100))
},
mounted() {
// this.scaleListener()
},
methods: {
handleRemove() {
this.rs.delete('file')
},
httpRequest(data) {
const isJar = data.file.name.indexOf('.yaml') === (data.file.name.length - 5)
if (!isJar) {
this.$message.warning('上传文件只能是 yaml 格式!')
} else {
this.rs.set('file', data.file)
}
},
submitFile() {
if (!this.rs.has('file')) {
this.$message.warning('请上传yaml文件')
return false
} else {
createScheduleTask(this.rs).then(res => {
if (res.code === 200) {
this.$message.success('操作成功')
this.dialogVisible = false
this.getTrainJob()
}
})
}
},
viewMenu(path) {
path ? this.$store.dispatch('user/setRouteType', path.split('/')[0]) : {}
this.$router.push({ path: path || `/monitorSelectBk` })
},
resize() {
// 1080
const scale = window.innerHeight / 900
if (scale >= 1) {
document.documentElement.style.fontSize = `${16 * scale}px`
} else {
document.documentElement.style.fontSize = `${14 * scale}px`
}
},
getTend() {
getComputePower().then((res) => {
this.tendData = { used: [], xData: [] }
if (res.dailyComputerPowers !== null) {
const timeArr = []// 12
for (let i = 0; i < 180; i++) {
timeArr.push(
`${moment(new Date()).subtract(i, 'days').format('YYYY-MM-DD')}`
)
}
timeArr.reverse()//
const arr = [] //
for (let i = 0; i < timeArr.length; i++) {
arr.push({ date: timeArr[i], computerPower: 0 })
// arr
for (let j = 0; j < res.dailyComputerPowers.length; j++) {
if (res.dailyComputerPowers[j].date === timeArr[i]) {
arr[i] = { date: res.dailyComputerPowers[j].date, computerPower: res.dailyComputerPowers[j].computerPower }
}
}
}
arr.forEach((item) => {
this.tendData.used.push(item.computerPower.toFixed(1))
this.tendData.xData.push(item.date)
})
}
})
// this.tendData.used = [59688.1, 59252.5, 59189.0, 55766.5, 55537.2, 54804.4, 52764.9]
// this.tendData.xData = ['2022-06-30', '2022-07-31', '2022-07-31', '2022-08-31', '2022-09-30', '2022-10-31', '2022-11-30']
},
getAccrueCenter() {
getCPUsage().then((res) => {
this.centerData = { used: [], xData: [] }
if (res.perCenterComputerPowers) {
const data = res.accOtJobInfo
this.accrueData = {
config1: data.accCardRunSec,
config2: data.accOtJobNum,
config3: data.accRunSec
}
const data1 = res.perCenterComputerPowers.filter(item => {
if (item.computerPower !== 0) {
return item
}
})
// this.timer = setInterval(() => {
// this.getTaskTotal()
// }, 1000)
data1.sort(order)
data1.forEach((item) => {
if (item.computerPower !== 0) {
this.centerData.used.push(item.computerPower.toFixed(1))
this.centerData.xData.push(item.centerName)
}
})
}
})
// this.centerData.used = [12, 22, 3, 55, 66, 77, 44, 32]
// this.centerData.unused = [12, 22, 3, 55, 66, 77, 44, 32]
// this.centerData.xData = ['2/1', '2/2', '2/3', '2/4', '2/5', '2/6', '2/7', '2/8']
},
getTrainJob() {
getTaskCount().then(e => {
this.taskData = {
tableData: [],
totalCount: e.data?.allJobCount || 0,
cardTime: e.data?.allCardRunTime || 0,
totalRunTime: e.data?.allJobRunTime || 0
}
e.data?.trainJobs?.forEach((item) => {
this.taskData.tableData.push({
name: item.name,
status: item.status,
strategy: item.strategy,
serviceName: item.serviceName,
synergyStatus: item.synergyStatus
// undertaker: this.showUnderTaker(item)
})
})
})
},
showUnderTaker(item) {
if (item.tasks == null) {
return ''
} else if (item.tasks.length > 2) {
return item.tasks[0].centerName[0] + '等'
} else {
if (item.tasks[0].centerName == null) {
return ''
} else {
return item.tasks[0].centerName[0]
}
}
}
}
}
</script>
<style lang="scss" scoped>
@import "~@/styles/variables.scss";
::v-deep {
.el-dialog {
background: #2c3a4e !important;
color: white;
}
.el-upload-list__item-name {
color: #ffffff;
}
.el-upload-list__item:hover {
background-color: rgb(86, 90, 95)
}
.el-button--default {
color: white;
background: rgba(255,255,255,0.1);
border-color: rgba(255,255,255,0.01);
}
.el-dialog__title {
color: white;
}
}
.monitor {
background: url('../../assets/monitor/monitor_bg.png') no-repeat;
background-size: 100% 100%;
width: 100%;
min-width: 1200px;
height: 100vh;
min-height: 900px;
overflow: hidden;
color: white;
font-size: 0.8rem;
font-family: Source Han Sans CN;
font-weight: 400;
display: block;
overflow: hidden;
.top {
width: 100%;
height: 18vh;
// vertical-align: baseline;
position: absolute;
z-index: 99;
background: url(../../assets/monitor/top-bg.png) center top no-repeat;
background-size: 100% 65%;
.top-title{
margin:0 auto;
height: 100%;
// background: url(../../assets/monitor/c-top.png) center no-repeat;
// background-size: 55% 10vh;
h1{
margin: 0;
font-size: 2rem;
line-height: 6vh;
letter-spacing: 0.3rem;
text-align: center;
text-shadow: 3px 5px 0px rgba(17,20,22,0.22);
background: linear-gradient(0deg, rgba(36,83,152,0.35) 0%, rgba(255,255,255,0.35) 100%);
background-clip: text;
-webkit-text-fill-color: #ffffff;
}
}
}
.top-menu{
width: 100%;
position: absolute;
z-index: 100;
.menu a, .right a {
float: left;
font-size: 1.13rem;
display: block;
padding: 0.9rem 60px;
height: 3.5rem;
letter-spacing: 0.2rem;
}
.menu a, .right a{
&:hover{
background: url(../../assets/monitor/t-p.png) center no-repeat;
background-size: auto 70%;
}
}
.menu a:first-child{
background: url(../../assets/monitor/t-p.png) center no-repeat;
background-size: auto 70%;
}
.right {
a { float: right;}
}
}
.title{
background: url('../../assets/monitor/title-bg.png') no-repeat left;
background-size: 105% 100%;
background-position: -3.5vh;
height: 4.5vh;
p{
font-size: 1.4rem;
height: 2.8rem;
line-height: 2.3rem;
text-indent: 2.8vw;
margin: 0;
font-family: Source Han Sans CN;
font-weight: bold;
color: #FFFFFF;
letter-spacing: 0.2rem;
text-shadow: 0px 2px 8px rgba(5,28,55,0.42);
background: linear-gradient(0deg, rgba(14,197,236,1) 0%, rgba(49,190,255,1) 0%, rgba(239,252,254,1) 58.7646484375%);
background-clip: text;
-webkit-text-fill-color: transparent;
}
}
.middle{
width: 38vw;
position: absolute;
left: 31vw;
z-index: 99;
margin-top: 10vh;
}
.floatLeft, .floatRight{
margin-top: 5vh;
padding: 0 1vh 0 2vh;
padding-top: 5vh;
padding-bottom: 4vh;
}
.floatLeft .left:before, .floatRight .right:after{
content: '';
width: 2vw;
height: 85vh;
display: block;
position: absolute;
top: 3px;
right: -2vh;
background: url(../../assets/monitor/leftr.png) no-repeat;
background-size: 100% 98%;
}
.floatLeft{
width: 27vw;
display: block;
position: absolute;
left: 0;
z-index: 10;
height: 95vh;
min-height: 800px;
.left {
width: 100%;
height: 90vh;
padding-left: 10px;
display: block;
position: relative;
background: #02020a96;
box-shadow: 20px -30px 30px 0px #02020a96;
&::before{
-moz-transform: matrix(-1, 0, 0, 1, 0, 0);
-webkit-transform: matrix(-1, 0, 0, 1, 0, 0);
-o-transform:matrix(-1,0,0,1,0,0);
z-index: 1;
left: -2vh;
}
.left_1{
height: 29vh;
overflow: hidden;
}
.left_2 {
height: 33vh;
}
.left_3 {
width: 100%;
height: 15vh;
}
}
}
.floatRight {
width: 27vw;
display: block;
// overflow: hidden;
position: absolute;
right: 0;
z-index: 10;
height: 95vh;
min-height: 800px;
padding: 0 2vh 0 1vh;
padding-top: 5vh;
padding-bottom: 4vh;
.createBtn{
height: 2.5vh;
line-height: 2.3vh;
margin: 0;
padding: 0 1rem;
position: absolute;
top: 0.5vh;
right: 2vh;
div{
font-size: 0.9rem;
@media screen and (max-height: 900px) {
transform: scale(0.8);
}
}
}
.right {
background: #02020a96;
box-shadow: -20px -30px 30px 0px #02020a96;
width: 100%;
height: 100%;
padding-right: 10px;
display: block;
position: relative;
.right_1{
height: 35vh;
overflow: hidden;
}
.right_2{
height: 27vh;
}
.right_3{
height: 21vh;
}
}
}
}
</style>
<style lang="less" rel="stylesheet/less">
@import "../../common/font/font.css";
</style>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,151 @@
<template>
<div class="card">
<span class="deco_top" />
<span class="deco_right" />
<span class="deco_bottom" />
<h4> <span>{{ title }}</span> </h4>
<div class="content">
<slot />
</div>
</div>
</template>
<script>
export default {
name: 'Card',
props: {
title: {
default: '',
type: String
}
}
}
</script>
<style lang="scss" scoped>
.card{
width: 100%;
height: 100%;
border: 1px solid #25a9f6;
background-color: rgba(#80a5c8, 0.2);
padding: 10px;
margin-bottom: 10px;
position: relative;
.content{
margin-top: 2rem;
width:100%;
height: 80%;
}
h4{
margin: 0;
position: relative;
span{
background: linear-gradient(to bottom, #c4f4fe,#60d4ef);
-webkit-background-clip: text;
color: transparent;
position: absolute;
z-index: 1;
}
}
//
h4:after{
width: 100%;
height: 0.9rem;
content: '';
display: block;
position: absolute;
top: 8px;
left: 0;
z-index: 0;
background: linear-gradient(to right, #1f4b72 ,#163963);
}
h4:before {
content: '';
display: block;
width: 50px;
height: 2px;
position: absolute;
top: -13px;
right: 37px;
background-color: #409eff;
}
.deco_top{
position: absolute;
display: block;
background: #031c44;
width: 60px;
height: 6px;
top: 0px;
right: 40px;
transform: perspective(0.5em) scale(1.1,1.3) rotateX(-10deg);
border: 1px solid #24aaf6;
border-top: 2px solid #031c44;
transform-origin: 50px;
}
.deco_top:after{
position: absolute;
display: block;
content: '';
background: #031c44;
width: 20px;
height: 10px;
top: 0px;
right: -47px;
transform: perspective(0.5em) scale(1.1,1.3) rotateX(-10deg);
border: 1px solid #24aaf6;
border-top: 2px solid #031c44;
border-right: 2px solid #031c44;
transform-origin: 75px;
}
.deco_right{
position: absolute;
display: block;
background: #1e466e;
width: 14px;
height: 100px;
bottom: 25px;
right: 6px;
transform: perspective(0.5em) scale(1.1,1.3) rotateY(-5deg);
border: 1px solid #24aaf6;
border-right: 5px dashed rgba(#24aaf6,0.8);
transform-origin: 50px;
}
.deco_bottom{
display:block;
width: 10px;
height: 15px;
position:absolute;
bottom: -6px;
right: -4px;
transform: rotateX(45deg);
background-color: #031c44;
transform: rotate(45deg);
border-left: 1px solid #24aaf6;
border-bottom: 0;
}
}
//
.card:before{
width: 3px;
height: 80px;
display: block;
position: absolute;
content: '';
left: -2px;
top: 10%;
background: radial-gradient(#e8f4ff 10%, #c4f4fe 30%, rgba(0, 0, 0, 0) 60%);
}
//
.card:after{
width: 80px;
height: 3px;
display: block;
position: absolute;
content: '';
bottom: -2px;
right: 25%;
background: radial-gradient(#e8f4ff 10%, #c4f4fe 30%, rgba(0, 0, 0, 0) 60%);
}
</style>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,93 @@
{
"centerList": [{
"name": "中国电信天翼云中南数字产业园",
"address": "长沙市天心区中意二路25号",
"longitude": 112.99449,
"latitude": 28.009243
}, {
"name": "长沙云谷数据中心",
"address": "长沙市望城区金星北路证通云计算大数据产业园内",
"longitude": 112.889616,
"latitude": 28.321779
}, {
"name": "中国联通湖南长沙云数据中心",
"address": "长沙市岳麓区嘉运路",
"longitude": 112.860612,
"latitude": 28.228898
}, {
"name": "中国电信云大数据中心(湖南)",
"address": "长沙市岳麓区桐梓坡西路189号",
"longitude": 112.902607,
"latitude": 28.223713
}, {
"name": "中国移动长沙数据中心",
"address": "长沙市岳麓区麓景路与桐梓坡西路交叉路口西侧",
"longitude": 112.899441,
"latitude": 28.221986
}, {
"name": "长沙磐云数据中心",
"address": "长沙市岳麓区茯苓路31号",
"longitude": 112.895346,
"latitude": 28.120142
}, {
"name": "易信科技数据中心",
"address": "郴州市资兴市东江街道沿江北路",
"longitude": 113.25323,
"latitude": 25.955507
}, {
"name": "东江湖大数据中心",
"address": "郴州市资兴市东江街道沿江北路",
"longitude": 113.25323,
"latitude": 25.955507
}, {
"name": "中国电信郴州资兴东江湖数据中心",
"address": "郴州市资兴市东江街道沿江北路",
"longitude": 113.25323,
"latitude": 25.955507
}, {
"name": "中国移动湖南株洲数据中心",
"address": "株洲市石峰区盘龙路",
"longitude": 113.183145,
"latitude": 27.972326
}, {
"name": "湖南数据湖产业园数据中心",
"address": "菖塘路",
"longitude": 113.189571,
"latitude": 27.971911
}, {
"name": "大数据产业园(湘潭高新)",
"address": "湖南湘潭市岳塘区晓塘路9号",
"longitude": 112.946758,
"latitude": 27.828805
}, {
"name": "常德大数据中心",
"address": "常德市澧县桃花滩路豪盛国际现代城",
"longitude": 111.776166,
"latitude": 29.655702
}, {
"name": "芙蓉云大数据中心",
"address": "益阳市赫山区高新大道10号",
"longitude": 112.489535,
"latitude": 28.453288
}, {
"name": "华为永州云计算数据中心",
"address": "永州市冷水滩区袁家路",
"longitude": 111.591789,
"latitude": 26.399643
}]
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,99 @@
import * as THREE from 'three'
var uniforms = {
u_time: { value: 0.0 }
}
var clock = new THREE.Clock()
export const timerFlyCurve = setInterval(() => {
const elapsed = clock.getElapsedTime()
uniforms.u_time.value = elapsed
}, 20)
// 着色器设置
const vertexShader = `
varying vec2 vUv;
attribute float percent;
uniform float u_time;
uniform float number;
uniform float speed;
uniform float length;
varying float opacity;
uniform float size;
void main()
{
vUv = uv;
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
float l = clamp(1.0-length,0.0,1.0);
gl_PointSize = clamp(fract(percent*number + l - u_time*number*speed)-l ,0.0,1.) * size * (1./length);
opacity = gl_PointSize/size;
gl_Position = projectionMatrix * mvPosition;
}
`
const fragmentShader = `
#ifdef GL_ES
precision mediump float;
#endif
varying float opacity;
uniform vec3 color;
void main(){
if(opacity <=0.2){
discard;
}
gl_FragColor = vec4(color,1.0);
}
`
export function createFlyCurve(points, closed) {
var curve = new THREE.CatmullRomCurve3(points, closed)
// 流光的颜色三个数字分别代表rgb的值不过注意需要除以255
// 比如浅绿色的rgb是(0,255,127)那么这里的Vector3就等于(0,1,127/255)也就是(0,1,0.49803921)
// var color = new THREE.Vector3(0.5999758518718452, 0.7798940272761521, 0.6181903838257632)
console.log()
var color = new THREE.Color(0x3EDFFC)
var flyLine = initFlyLine(curve, {
speed: 0.6,
color: color,
number: 1, // 同时跑动的流光数量
length: 4, // 流光线条长度
size: 2 // 粗细
}, 5000)
return flyLine
}
function initFlyLine(curve, matSetting, pointsNumber) {
var points = curve.getPoints(pointsNumber)
var geometry = new THREE.BufferGeometry().setFromPoints(points)
const length = points.length
var percents = new Float32Array(length)
for (let i = 0; i < points.length; i += 1) {
percents[i] = (i / length)
}
geometry.setAttribute('percent', new THREE.BufferAttribute(percents, 1))
const lineMaterial = initLineMaterial(matSetting)
var flyLine = new THREE.Points(geometry, lineMaterial)
return flyLine
}
function initLineMaterial(setting) {
const number = setting ? (Number(setting.number) || 1.0) : 1.0
const speed = setting ? (Number(setting.speed) || 1.0) : 1.0
const length = setting ? (Number(setting.length) || 0.5) : 0.5
const size = setting ? (Number(setting.size) || 3.0) : 3.0
const color = setting ? setting.color || new THREE.Vector3(0, 1, 1) : new THREE.Vector3(0, 1, 1)
const singleUniforms = {
u_time: uniforms.u_time,
number: { type: 'f', value: number },
speed: { type: 'f', value: speed },
length: { type: 'f', value: length },
size: { type: 'f', value: size },
color: { type: 'v3', value: color }
}
const lineMaterial = new THREE.ShaderMaterial({
uniforms: singleUniforms,
vertexShader: vertexShader,
fragmentShader: fragmentShader,
transparent: true
})
return lineMaterial
}
export default
{
createFlyCurve,
timerFlyCurve
}

View File

@ -0,0 +1,98 @@
import * as THREE from 'three'
var uniforms = {
u_time: { value: 0.0 }
}
var clock = new THREE.Clock()
export const timerFlyCurve = setInterval(() => {
const elapsed = clock.getElapsedTime()
uniforms.u_time.value = elapsed
}, 20)
// 着色器设置
const vertexShader = `
attribute float percent;
uniform float time;
uniform float number;
uniform float speed;
uniform float length;
uniform float size;
varying float opacity;
void main() {
float l = clamp(1.0 - length, 0.0, 1.0);
gl_PointSize = clamp(fract(percent * number + l - time * number * speed) - l, 0.0, 1.0) * size * (1.0 / length);
opacity = gl_PointSize / size;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`
const fragmentShader = `
varying float opacity;
uniform vec3 color;
void main() {
if (opacity <= 0.2) {
discard;
}
gl_FragColor = vec4(color, 1.0);
}
`
export function createFlyCurve(points, closed) {
var curve = new THREE.CatmullRomCurve3(points, closed)
// 流光的颜色三个数字分别代表rgb的值不过注意需要除以255
// 比如浅绿色的rgb是(0,255,127)那么这里的Vector3就等于(0,1,127/255)也就是(0,1,0.49803921)
// var color = new THREE.Vector3(0.5999758518718452, 0.7798940272761521, 0.6181903838257632)
console.log()
var color = new THREE.Color(0x3EDFFC)
var flyLine = initFlyLine(curve, {
speed: 0.6,
color: color,
number: 1, // 同时跑动的流光数量
length: 4, // 流光线条长度
size: 2 // 粗细
}, 5000)
return flyLine
}
function initFlyLine(curve, matSetting, pointsNumber) {
var points = curve.getPoints(pointsNumber)
var geometry = new THREE.BufferGeometry().setFromPoints(points)
const length = points.length
var percents = new Float32Array(length)
for (let i = 0; i < points.length; i += 1) {
percents[i] = (i / length)
}
geometry.setAttribute('percent', new THREE.BufferAttribute(percents, 1))
const lineMaterial = initLineMaterial(matSetting)
var flyLine = new THREE.Points(geometry, lineMaterial)
return flyLine
}
function initLineMaterial(setting) {
const number = setting ? (Number(setting.number) || 1.0) : 1.0
const speed = setting ? (Number(setting.speed) || 1.0) : 1.0
const length = setting ? (Number(setting.length) || 0.5) : 0.5
const size = setting ? (Number(setting.size) || 3.0) : 3.0
const color = setting ? setting.color || new THREE.Vector3(0, 1, 1) : new THREE.Vector3(0, 1, 1)
const singleUniforms = {
u_time: uniforms.u_time,
number: { type: 'f', value: number },
speed: { type: 'f', value: speed },
length: { type: 'f', value: length },
size: { type: 'f', value: size },
color: { type: 'v3', value: color }
}
const lineMaterial = new THREE.ShaderMaterial({
uniforms: singleUniforms,
vertexShader: vertexShader,
fragmentShader: fragmentShader,
transparent: true
})
return lineMaterial
}
export default
{
createFlyCurve,
timerFlyCurve
}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,119 @@
// lineConnect(posStart, posEnd){
// // 根据目标坐标设置3D坐标 z轴位置在地图表面
// const p1 = this.getPosition(posStart[0] + 90, posStart[1], 100.01)
// const p2 = this.getPosition(posEnd[0] + 90, posEnd[1], 100.01)
// const pmiddle = this.getPosition((posStart[0] + posEnd[0]) / 2 + 90, (posStart[1] + posEnd[1]) / 2, 110)
// // 使用QuadraticBezierCurve3() 创建 三维二次贝塞尔曲线
// const curve = new Three.QuadraticBezierCurve3(
// new Three.Vector3(p1.x, p1.y, p1.z),
// // new Three.Vector3((p1.x + p2.x) / 2, (p1.y + p2.y) / 2 + 2, (p1.z + p2.z) / 2),
// new Three.Vector3(pmiddle.x, pmiddle.y, pmiddle.z),
// new Three.Vector3(p2.x, p2.y, p2.z)
// )
// // 绘制 目标位置
// // spotCircle([x0, y0, z0])
// // spotCircle([x1, y1, z1])
// const lineGeometry = new Three.BufferGeometry()
// // 获取曲线 上的50个点
// var points = curve.getPoints(50)
// var positions = []
// // var colors = []
// // var color = new Three.Color()
// // 给每个顶点设置演示 实现渐变
// for (var j = 0; j < points.length; j++) {
// // color.setHSL( .31666+j*0.005,0.7, 0.7); //绿色
// // color.setHSL(0.81666 + j, 0.88, 0.715 + j * 0.0025) // 粉色
// // colors.push(color.r, color.g, color.b)
// positions.push(points[j].x, points[j].y, points[j].z)
// }
// // // 放入顶点 和 设置顶点颜色
// lineGeometry.setAttribute('position', new Three.BufferAttribute(new Float32Array(positions), 3, true))
// // lineGeometry.setAttribute('color', new Three.BufferAttribute(new Float32Array(colors), 3, true))
// // const material = new Three.LineBasicMaterial({ vertexColors: Three.VertexColors, side: Three.DoubleSide })
// // const line = new MeshLine(lineGeometry)
// const defaultOptions = {
// speed: 0.3,
// lineWidth: 2,
// length: 0.3,
// isHalf: false,
// lineColor: 'rgba(171,157,245,0.2)',
// lightColor: 'rgba(239,238,255,1)',
// duration: 1000,
// delay: 0,
// repeat: Infinity
// }
// // const geometry = new Three.Geometry()
// // geometry.vertices = [
// // // ... THREE.Vector3,
// // ]
// // const geometry = new Three.BufferGeometry()
// // geometry.vertices = [
// // new Three.Vector3(p1.x, p1.y, p1.z),
// // // new Three.Vector3((p1.x + p2.x) / 2, (p1.y + p2.y) / 2 + 2, (p1.z + p2.z) / 2),
// // new Three.Vector3(pmiddle.x, pmiddle.y, pmiddle.z),
// // new Three.Vector3(p2.x, p2.y, p2.z)
// // ]
// // 代码生成材质
// const getTexture = (length, lineColor, lightColor, isHalf) => {
// const canvas = document.createElement('canvas')
// canvas.width = 256
// canvas.height = 1
// const ctx = canvas.getContext('2d')
// const gradient = ctx.createLinearGradient(0, 0, 256, 1)
// gradient.addColorStop(0, lineColor)
// gradient.addColorStop(isHalf ? length : length / 2, lightColor)
// gradient.addColorStop(length, lineColor)
// gradient.addColorStop(length, lineColor)
// gradient.addColorStop(1, lineColor)
// ctx.fillStyle = gradient
// ctx.fillRect(0, 0, 256, 1)
// const texture = new Three.Texture(canvas)
// texture.needsUpdate = true
// texture.wrapS = Three.RepeatWrapping
// texture.wrapT = Three.RepeatWrapping
// return texture
// }
// const meshLine = new MeshLine()
// // meshLine.setGeometry(lineGeometry)
// meshLine.setGeometry(lineGeometry)
// const texture = getTexture(defaultOptions.length, defaultOptions.lineColor, defaultOptions.lightColor, defaultOptions.isHalf)
// texture.anisotropy = 16
// texture.wrapS = Three.RepeatWrapping
// texture.wrapT = Three.RepeatWrapping
// this.dynamicMaterial = new MeshLineMaterial({
// map: texture, // 材质
// useMap: 0, // 使用材质
// // color: color,
// lineWidth: 0.5, // 线宽
// sizeAttenuation: 1, // 是否随距离衰减
// transparent: true, // 开启透明度
// dashOffset: 0,
// dashArray: 0.5,
// dashRatio: 0.1,
// repeat: new Three.Vector2(2, 1)
// })
// this.flyLineAnimate()
// // const { width, height } = getCanvasSize()
// // material.uniforms.resolution.value.set(width, height)
// const mesh = new Three.Mesh(meshLine.geometry, this.dynamicMaterial)
// // const tween = new TWEEN.Tween(material.uniforms.offset.value) // 飞线移动动画
// // .to({ x: material.uniforms.offset.value.x - 1 }, duration)
// // .delay(delay)
// // .repeat(repeat)
// // .start()
// return mesh
// }

View File

@ -0,0 +1,559 @@
<template>
<div>
<div class="back">
<el-button @click="clickback()">返回</el-button>
</div>
<div class="top">
<div class="canvasBox">
<canvas id="container" />
</div>
</div>
<div class="spin">
<div class="circle circle1">
<div class="turnAround" />
</div>
<div class="circle circle2">
<div class="turnAround" />
</div>
<div class="circle circle3">
<div class="turnAround" />
</div>
</div>
</div>
</template>
<script>
import guangdongJson from './geoJson/guangdong.json'
import guangdongOutline from './geoJson/guangdongOutline.json'
import chuanyuJson from './geoJson/chuanyu.json'
import gansuJson from './geoJson/gansu.json'
import guizhouJson from './geoJson/guizhou.json'
import jingjinjiJson from './geoJson/jingjinji.json'
import neimengguJson from './geoJson/neimenggu.json'
import ningxiaJson from './geoJson/ningxia.json'
import changsanjiaoJson from './geoJson/changsanjiao.json'
import hunanJson from './geoJson/hunan.json'
import hunanOutline from './geoJson/hunanOutline.json'
export default {
props: {
value: {
type: Boolean,
default: false
},
mapType: {
type: Number,
default: 1
},
// count: {
// type: Object,
// default: () => { return { ys: 0, zs: 0, cs: 0 } }
// },
cluster: {
type: Array,
default: () => []
}
},
data() {
return {
selectedCity: '',
allJSON: {
guangdongJson,
chuanyuJson,
gansuJson,
guizhouJson, jingjinjiJson, neimengguJson, ningxiaJson, changsanjiaoJson,
guangdongOutline, hunanJson, hunanOutline
},
currentIndex: 0,
interval: undefined,
img: undefined,
activeTab: '',
scale: 1,
geoCenter: {},
offsetX: 0,
offsetY: 0,
eventType: '',
cursorFlag: false,
mapMap: {
1: 'ningxia',
2: 'neimenggu',
3: 'gansu',
4: 'guizhou',
5: 'guangdong',
6: 'chuanyu',
7: 'changsanjiao',
8: 'jingjinji',
9: 'hunan'
},
mapName: {
1: '宁夏回族自治区',
2: '内蒙古自治区',
3: '甘肃省',
4: '贵州省',
5: '粤港澳大湾区',
6: '川渝地区',
7: '长三角地区',
8: '京津冀地区',
9: '湖南省'
}
// geoCenterY: 0
}
},
computed: {
dialogVisible: {
get() {
return this.value
},
set(value) {
this.$emit('input', value)
}
}
},
watch: {
mapType(val) {
if (val) {
this.getBoxArea()
this.drawMap()
}
}
},
mounted() {
this.getBoxArea()
this.$nextTick(() => {
this.img = new Image()
this.img.src = process.env.VUE_APP_PUBLIC_SOURCE_API + '/click-point.svg'
this.img.addEventListener('load', () => {
this.setDataRoll()
})
const canvas = document.querySelector('#container')
//
canvas.addEventListener('mousemove', (event) => {
this.offsetX = event.offsetX / 0.55
this.offsetY = event.offsetY / 0.65
this.eventType = 'mousemove'
this.drawMap()
})
//
canvas.addEventListener('click', (event) => {
this.offsetX = event.offsetX / 0.55
this.offsetY = event.offsetY / 0.65
this.eventType = 'click'
clearInterval(this.interval)
this.drawMap()
})
})
},
methods: {
setDataRoll() {
clearInterval(this.interval)
this.interval = setInterval(() => {
this.currentIndex = (this.currentIndex + 1) % this.cluster.length//
this.drawMap()
}, 4000)
},
clickback() {
this.dialogVisible = false
},
filterData(data) {
this.selectedCity = data
if (data === '') {
this.setDataRoll()
}
this.$emit('selectedCity', data)
},
drawMap() {
try {
const canvas = document.querySelector('#container')
const ctx = canvas.getContext('2d')
ctx.clearRect(0, 0, window.innerWidth, window.innerHeight)
this.initOutline()
this.initMap()
this.setPoint()
} catch (error) {
console.log(error)
}
},
setPoint() {
const canvas = document.querySelector('#container')
const ctx = canvas.getContext('2d')
ctx.beginPath()
this.cluster.forEach((e, i) => {
const position = this.toScreenPosition(e.longitude, e.latitude)
if (this.currentIndex === i) {
ctx.drawImage(this.img, position.x - 40, position.y - 55, 80, 80)
ctx.fillStyle = 'rgba(255, 197, 39, 1)'
ctx.font = '30px PangMenZhengDao'
ctx.fillText(e.name, position.x - e.name.length / 2 * 35, position.y - 55)
ctx.fillStyle = 'rgba(0, 0, 0, 0.5)'
const txtlength = e.name.length > e.address.length ? e.name.length : e.address.length
ctx.fillRect(position.x + 20, position.y + 5, txtlength * 27, 90)
ctx.strokeStyle = '#3EDFFC'
ctx.strokeRect(position.x + 20, position.y + 5, txtlength * 27, 90)
ctx.fillStyle = '#FFFFFF'
ctx.font = '20px Arial'
ctx.fillText('名称:' + e.name, position.x + 20 + 20, position.y + 5 + 40)
ctx.fillText('地址:' + e.address || '-', position.x + 20 + 20, position.y + 5 + 70)
} else {
ctx.beginPath()
ctx.arc(position.x, position.y, 5, 0, Math.PI * 2) // 5
ctx.fillStyle = '#ffffff' //
ctx.fill()
ctx.closePath()
}
})
ctx.stroke()
ctx.restore()
},
getBoxArea() {
const canvasW = window.innerWidth
const canvasH = window.innerHeight
let N = -90; let S = 90; let W = 180; let E = -180
this.allJSON[this.mapMap[this.mapType] + 'Json'].features.forEach(item => {
if (item.geometry.type === 'Polygon') {
item.geometry.coordinates = [item.geometry.coordinates]
}
item.geometry.coordinates.forEach(area => {
area[0].forEach(elem => {
if (elem[0] < W) {
W = elem[0]
}
if (elem[0] > E) {
E = elem[0]
}
if (elem[1] > N) {
N = elem[1]
}
if (elem[1] < S) {
S = elem[1]
}
})
})
})
var wScale = canvasW / Math.abs(E - W)
var hScale = canvasH / Math.abs(N - S)
this.scale = (wScale > hScale ? hScale : wScale) * 0.9
this.geoCenter = {
W: W,
N: N,
xoffset: canvasW / 2 - Math.abs(E - W) / 2 * this.scale,
yoffset: canvasH / 2 - Math.abs(N - S) / 2 * this.scale
}
},
toScreenPosition(longitude, latitude) {
return {
x: (longitude - this.geoCenter.W) * this.scale + this.geoCenter.xoffset,
y: (this.geoCenter.N - latitude) * this.scale + this.geoCenter.yoffset
}
},
initMap() {
const canvas = document.querySelector('#container')
const ctx = canvas.getContext('2d')
this.cursorFlag = false
ctx.beginPath()
ctx.strokeStyle = '#3EDFFC'
ctx.lineWidth = 1
this.allJSON[this.mapMap[this.mapType] + 'Json'].features.forEach(elem => {
const coordinates = elem.geometry.coordinates
coordinates.forEach(multiPolygon => {
multiPolygon.forEach(polygon => {
ctx.save()
ctx.beginPath()
// ctx.translate(0, 0)
for (let i = 0; i < polygon.length; i++) {
const position = this.toScreenPosition(polygon[i][0], polygon[i][1])
if (i === 0) {
ctx.moveTo(position.x, position.y - 5)
} else {
ctx.lineTo(position.x, position.y - 5)
}
}
ctx.closePath()
ctx.strokeStyle = '#34CEE9'
ctx.lineWidth = 1
if (ctx.isPointInPath(this.offsetX, this.offsetY)) {
this.cursorFlag = true
ctx.fillStyle = '#a2f7ff'
if (this.eventType === 'click') {
this.filterData(elem.properties.name)
//
}
} else {
if (this.eventType === 'mousemove' && this.selectedCity === '') ctx.fillStyle = 'transparent'
}
if (this.selectedCity === elem.properties.name) ctx.fillStyle = '#00eaff'
ctx.fill()
ctx.stroke()
ctx.restore()
})
})
})
if (this.cursorFlag) {
canvas.style.cursor = 'pointer'
} else {
canvas.style.cursor = 'default'
}
},
initOutline() {
const canvas = document.querySelector('#container')
const ctx = canvas.getContext('2d')
const canvasW = canvas.width = window.innerWidth
const canvasH = canvas.height = window.innerHeight
ctx.clearRect(0, 0, canvasW, canvasH)
ctx.fillStyle = 'transparent'
ctx.fillRect(0, 0, canvasW, canvasH)
ctx.beginPath()
ctx.strokeStyle = '#3EDFFC'
ctx.lineWidth = 1
this.allJSON[this.mapMap[this.mapType] + 'Outline'].features.forEach(elem => {
const coordinates = elem.geometry.coordinates
ctx.save()
coordinates.forEach(multiPolygon => {
multiPolygon.forEach(polygon => {
for (let i = 0; i < polygon.length; i++) {
const position = this.toScreenPosition(polygon[i][0], polygon[i][1])
if (i === 0) {
ctx.moveTo(position.x, position.y + 5)
} else {
ctx.lineTo(position.x, position.y + 5)
}
}
})
})
})
ctx.closePath()
if (!ctx.isPointInPath(this.offsetX, this.offsetY)) {
if (this.eventType === 'click') {
this.filterData('')
//
}
}
ctx.fillStyle = '#3edffc'
var grd = ctx.createLinearGradient(0, 0, 1500, 0)
for (let i = 0; i < 1000; i++) {
grd.addColorStop(i / 1000, 'white')
grd.addColorStop(i / 1000 + 0.001, '#059BFC')
}
ctx.fillStyle = grd
// ctx.shadowColor = '#3EDFFC'
// ctx.shadowBlur = 0
// // ctx.shadowOffsetX = 50
// ctx.shadowOffsetY = 20
ctx.fill()
ctx.stroke()
ctx.restore()
ctx.beginPath()
this.allJSON[this.mapMap[this.mapType] + 'Outline'].features.forEach(elem => {
const coordinates = elem.geometry.coordinates
ctx.save()
coordinates.forEach(multiPolygon => {
multiPolygon.forEach(polygon => {
for (let i = 0; i < polygon.length; i++) {
const position = this.toScreenPosition(polygon[i][0], polygon[i][1])
if (i === 0) {
ctx.moveTo(position.x, position.y - 5)
} else {
ctx.lineTo(position.x, position.y - 5)
}
}
})
})
})
ctx.closePath()
var g = ctx.createRadialGradient(700, 600, 50, 1000, 600, 600)
g.addColorStop(0, '#29a0ee')
g.addColorStop(1, '#0b4eaf')
ctx.fillStyle = g
ctx.fill()
ctx.stroke()
ctx.restore()
}
}
}
</script>
<style lang="scss" scoped>
.back{
position:absolute;
top: 20vh;
left: 31vw;
z-index: 99;
}
.data-view {
position: absolute;
right: 0px;
border: 1px solid #3EDFFC;
padding: 0 10px;
margin: 10px;
background-color: #1a2d47ad;
bottom: 0;
font-size: 0.8rem;
p{
color: #DDDDDD;
text-indent: 1rem;
position: relative;
}
p:before{
content: '';
display: block;
width: 8px;
height: 8px;
border-radius: 8px;
background-color: #0fe765;
position: absolute;
left: 3px;
top: 3px;
}
p:nth-child(3):before{
background-color: #3EDFFC;
}
p:nth-child(4):before{
background-color: #f3ca45;
}
h5{font-weight: bold; font-size: 1rem; margin: 1rem 0}
}
.top{
width: 100%;
position: absolute;
display: block;
height: 60vh;
z-index: 8;
}
.center{
position:absolute;
bottom: 11vh;
right: 30vw;
z-index: 100;
width: 20vh;
.el-button,.el-button + .el-button{
margin: 0;
// margin-bottom: 10px;
// padding: 10px 15px;
padding: 0.5vh 2rem;
height: 5vh;
width: 100%;
background: url(../../assets/monitor/b.png) left no-repeat;
background-size: 100% 100%;
font-weight: 500;
font-style: italic;
color: #FFFFFF;
text-shadow: 0px 2px 6px rgba(19,23,27,0.31);
border-radius: 0;
text-align: left;
border: 0;
// line-height: 4vh;
div{
font-size: 1.2rem;
@media screen and (max-height: 900px) {
// transform: scale(0.8);
font-size: 0.8rem;
}
}
}
.active{
background: url(../../assets/monitor/b-p.png) left no-repeat;
background-size: 100% 100%;
}
}
.canvasBox{
width: 100%;
height: 100%;
position: relative;
}
#container {
width: 55vw;
height: 65vh;
margin: auto;
margin-top: 18vh;
display: block;
}
.spin{
width: 100%;
height: 30vh;
display: block;
position: absolute;
bottom: 0;
perspective: 200vh;
z-index: 0;
// animation: rotate 13s linear infinite;
.circle {
width: 50vw;
height: 30vh;
position: absolute;
left: 0;
top: -49vh;
display: block;
// border: 1px solid #ffffff;
}
.circle1{
width: 28vw;
height: 80vh;
top: -25.5vh;
left: 36vw;
transform: rotateX(80deg);
.turnAround{
width: 100%;
height: 100%;
animation: rotate 8s linear infinite;
background: url('../../assets/monitor/circle1.png') center no-repeat;
background-size: 80% auto;
}
}
.circle2{
width: 54vw;
height: 99vh;
left: 23vw;
top: -34vh;
transform: rotateX(80deg);
.turnAround{
width: 100%;
height: 100%;
animation: backRotate 15s linear infinite;
background: url('../../assets/monitor/circle2.png') center no-repeat;
background-size: 80% auto;
}
}
.circle3{
width: 46vw;
height: 80vh;
left: 27vw;
top: -25vh;
transform: rotateX(80deg);
.turnAround{
width: 100%;
height: 100%;
animation: rotate 10s linear infinite;
background: url('../../assets/monitor/circle3.png') center no-repeat;
background-size: 80% auto;
opacity: 0.5;
}
}
@keyframes rotate {
0% {
transform: rotate(0);
}
100% {
transform: rotate(360deg);
}
}
@keyframes backRotate {
0% {
transform: rotate(360deg);
}
100% {
transform: rotate(0deg);
}
}
}
</style>

View File

@ -0,0 +1,835 @@
<template>
<div>
<div id="earth" />
<a class="switchBtn toChina" :class="!globe?'activeBtn':''" @click="toChina"><svg-icon icon-class="china" /></a>
<a class="switchBtn" :class="globe?'activeBtn':''" @click="toWorld"><svg-icon icon-class="globe" /></a>
</div>
</template>
<script>
import * as Three from 'three'
import proj4 from 'proj4'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { getEarthRegion, getEarthDetails } from '@/api/top-menu/TotalNum'
import chinaJson from './chinaProvince.json'
import continentsJson from './worldContinents.json'
import TWEEN from '@tweenjs/tween.js'
// import { MeshLine, MeshLineMaterial } from 'three.meshline'
import {
createFlyCurve, timerFlyCurve
} from './flyCurve.js'
export default {
data() {
return {
mshs: 1.0,
satellitesArr: [],
mapMarks: [],
area: [],
monitorColor: '#23B9FF',
raycaster: undefined,
mouse: undefined,
aniId: '',
saaniId: '',
groupDots: [],
width: window.innerWidth,
height: window.innerHeight,
k: window.innerWidth / window.innerHeight,
dynamicMaterial: undefined,
originPosition: undefined,
globe: true,
flyArr: [],
flyId: 0
}
},
mounted() {
this.getEarth()
setTimeout(() => {
this.$nextTick(() => {
this.init()
})
}, 1000)
},
beforeDestroy() {
this.scene = null
this.renderer = null
this.camera = null
clearInterval(timerFlyCurve)
},
methods: {
getEarth() {
getEarthRegion().then(res => {
const demo = res.data
const that = this
for (let i = 0; i < 6; i++) {
const modelItem = []
const value = []
modelItem['name'] = demo[i].area
modelItem['count'] = demo[i].areaCount
value[0] = demo[i].value[0]
value[1] = demo[i].value[1]
modelItem['value'] = value
that.mapMarks[i] = modelItem
}
})
getEarthDetails('杭州').then(res => {
const demo = res.data
const that = this
that.area['resourceArea'] = demo.resourceArea
that.area['userNum'] = demo.userNum
that.area['areaCount'] = demo.areaCount
that.area['clusterNum'] = demo.clusterNum
that.area['usagedRate'] = demo.usagedRate
})
},
toWorld() {
this.globe = true
var s = 140
this.zoomAnimate()
const tweenL1 = new TWEEN.Tween(this.camera).to({ left: -s * this.k, right: s * this.k, top: s, bottom: -s }, 1000)
.easing(TWEEN.Easing.Sinusoidal.InOut).onUpdate(() => {
this.scene.children[4].material.color.copy(new Three.Color())
this.resetVisible()
})
tweenL1.start()
// const tweenL2 = new TWEEN.Tween(this.camera.position).to({ x: this.originPosition.x, y: this.originPosition.y, z: this.originPosition.z }, 1800).easing(TWEEN.Easing.Sinusoidal.InOut)
// .onUpdate(() => {
// this.camera.zoom = 2.3
// this.scene.children[4].material.color.copy(new Three.Color(0x0a263e))
this.orbitControls.reset()
this.orbitControls.autoRotate = true
// })
this.render()
},
resetVisible() {
this.scene.children[6].visible = this.globe
this.scene.children[7].visible = this.globe
this.scene.children[8].visible = this.globe
},
toChina() {
this.globe = false
this.orbitControls.autoRotate = false
// this.camera.zoom = 2.3
this.resetVisible()
var s = 50
this.render()
this.orbitControls.update()
this.zoomAnimate()
this.originPosition = this.camera.position
console.log(this.originPosition)
const tweenL1 = new TWEEN.Tween(
this.camera.position).to({ x: -400, y: 900, z: 1700 }, 1800)
.easing(TWEEN.Easing.Sinusoidal.InOut)
// const tweenL2 = new TWEEN.Tween(
// this.camera).to({ zoom: 2.3 }, 1800)
// .easing(TWEEN.Easing.Sinusoidal.InOut)
// var zoom = { val: this.camera.zoom }
// var zoomEnd = { value: 2.3 }
const tweenL2 = new TWEEN.Tween(this.camera).to({ left: -s * this.k, right: s * this.k, top: s, bottom: -s }, 1000).easing(TWEEN.Easing.Sinusoidal.InOut)
.onUpdate(() => {
// this.camera.zoom = 2.3
this.scene.children[4].material.color.copy(new Three.Color(0x0a263e))
})
tweenL1.chain(tweenL2).start()
this.renderChinaDetailData()
},
renderChinaDetailData() {
// chinamap
// this.scene.children[4].visible = false
// this.setRandomDot(this.mapMarks)
const groupLines = new Three.Group()
this.mapMarks.forEach(r => {
if (this.mapMarks[0].value[0] !== r.value[0]) {
var i = this.lineConnect(this.mapMarks[0].value, r.value)
groupLines.add(i)
}
})
// console.log(groupLines)
// this.flyAnimation()
this.scene.add(groupLines)
// this.setChinaMark(this.mapMarks)
},
setChinaMark(_markData) {
for (var i = 0; i < _markData.length; i++) {
var markPos = this.getPosition(_markData[i].value[0] + 90, _markData[i].value[1], 100)
// mark.position.set(markPos.x, markPos.y, markPos.z)
var textureLoader = new Three.TextureLoader()
var material = new Three.MeshBasicMaterial({
map: textureLoader.load(process.env.VUE_APP_PUBLIC_SOURCE_API + '/point.png'),
transparent: true, // 使png
blending: Three.AdditiveBlending,
// side: THREE.DoubleSide, //
depthWrite: false //
})
var mesh = new Three.Mesh(new Three.PlaneGeometry(8, 8, 3, 3), material)
// var size = 10 * 0.04// Mesh
// mesh.scale.set(size, size, size)// mesh
// mesh
mesh.position.set(markPos.x, markPos.y, markPos.z)
// mesh线()
var coordVec3 = new Three.Vector3(markPos.x, markPos.y, markPos.z).normalize()
// meshXOY线沿znew THREE.Vector3(0, 0, 1)
var meshNormal = new Three.Vector3(0, 0, 1)
// .quaternionmesh
// .setFromUnitVectors();
mesh.quaternion.setFromUnitVectors(meshNormal, coordVec3)
this.marking.add(mesh)
// eg: 18
var texture = new Three.CanvasTexture(this.getCanvasFont(_markData[i].name + '' + _markData[i].count + '个'))
//
const fontNumber = _markData[i].count.toString().length * 5.8642578125 + _markData[i].name.length * 10 + 10 + 2.4072265625 + 5
texture.needsUpdate = true
var fontMesh = new Three.Sprite(
new Three.SpriteMaterial({
map: texture
})
)
fontMesh.scale.x = fontNumber
fontMesh.scale.y = 10
fontMesh.position.set(markPos.x + 10, markPos.y + 10, markPos.z - 20)
this.textMarking.add(fontMesh)
}
this.scene.add(this.marking)
this.scene.add(this.textMarking)
},
lineConnect(posStart, posEnd) {
const p1 = this.getPosition(posStart[0] + 90, posStart[1], 100.01)
const p2 = this.getPosition(posEnd[0] + 90, posEnd[1], 100.01)
const pmiddle = this.getPosition((posStart[0] + posEnd[0]) / 2 + 90, (posStart[1] + posEnd[1]) / 2, 110)
var points = [
new Three.Vector3(p1.x, p1.y, p1.z),
new Three.Vector3(pmiddle.x, pmiddle.y, pmiddle.z),
new Three.Vector3(p2.x, p2.y, p2.z)
]
return createFlyCurve(points, false)
// this.scene.add(flyLine)
},
// lineConnect(posStart, posEnd) {
// // 3D z
// const p1 = this.getPosition(posStart[0] + 90, posStart[1], 100.01)
// const p2 = this.getPosition(posEnd[0] + 90, posEnd[1], 100.01)
// const pmiddle = this.getPosition((posStart[0] + posEnd[0]) / 2 + 90, (posStart[1] + posEnd[1]) / 2, 110)
// // 使QuadraticBezierCurve3() 线
// const curve = new Three.QuadraticBezierCurve3(
// new Three.Vector3(p1.x, p1.y, p1.z),
// // new Three.Vector3((p1.x + p2.x) / 2, (p1.y + p2.y) / 2 + 2, (p1.z + p2.z) / 2),
// new Three.Vector3(pmiddle.x, pmiddle.y, pmiddle.z),
// new Three.Vector3(p2.x, p2.y, p2.z)
// )
// // console.log(curve)
// //
// // spotCircle([x0, y0, z0])
// // spotCircle([x1, y1, z1])
// const lineGeometry = new Three.BufferGeometry()
// var curve2 = new Three.CatmullRomCurve3(curve.getPoints(50), false)
// console.log(curve2)
// // 线 50
// var points = curve2.points
// var positions = []
// var index = []
// // var colors = []
// // var color = new Three.Color()
// points.forEach((elem, idx) => {
// positions.push(elem.x, elem.y, elem.z)
// index.push(idx)
// })
// // //
// // lineGeometry.setAttribute('position', new Three.BufferAttribute(new Float32Array(positions), 3, true))
// // lineGeometry.setAttribute('color', new Three.BufferAttribute(new Float32Array(colors), 3, true))
// lineGeometry.setAttribute('position', new Three.Float32BufferAttribute(positions, 3))
// lineGeometry.setAttribute('u_index', new Three.Float32BufferAttribute(index, 1))
// console.log(lineGeometry)
// const mesh = new Three.Mesh(lineGeometry, this.flylineMaterial())
// console.log(mesh)
// mesh.name = 'fly'
// // mesh._flyId = 0
// mesh._speed = 1
// mesh._repeat = 1
// mesh._been = 0
// mesh._total = curve2.length
// // mesh._callback = callback
// this.flyId++
// this.flyArr.push(mesh)
// return mesh
// },
flylineMaterial() {
const colorArr = this.getColorArr('rgba(255,255,255,1)')
this.flyShader = {
vertexshader: `
uniform float size;
uniform float time;
uniform float u_len;
attribute float u_index;
varying float u_opacitys;
void main() {
if( u_index < time + u_len && u_index > time){
float u_scale = 1.0 - (time + u_len - u_index) /u_len;
u_opacitys = u_scale;
vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
gl_Position = projectionMatrix * mvPosition;
gl_PointSize = size * u_scale * 300.0 / (-mvPosition.z);
}
}
`,
fragmentshader: `
uniform sampler2D u_map;
uniform float u_opacity;
uniform vec3 color;
uniform float isTexture;
varying float u_opacitys;
void main() {
vec4 u_color = vec4(color,u_opacity * u_opacitys);
if( isTexture != 0.0 ){
gl_FragColor = u_color * texture2D(u_map, vec2(gl_PointCoord.x, 1.0 - gl_PointCoord.y));
}else{
gl_FragColor = u_color;
}
}`
}
const texture = new Three.TextureLoader().load(process.env.VUE_APP_PUBLIC_SOURCE_API + '/point.png')
const material = new Three.ShaderMaterial({
uniforms: {
color: {
value: colorArr[0],
type: 'v3'
},
size: {
value: 1, // width,
type: 'f'
},
u_map: {
value: texture,
type: 't2'
},
u_len: {
value: length,
type: 'f'
},
u_opacity: {
value: colorArr[1],
type: 'f'
},
time: {
value: -10, // length,
type: 'f'
},
isTexture: {
value: 1.0,
type: 'f'
}
},
transparent: false,
depthTest: true,
vertexShader: this.flyShader.vertexshader,
fragmentShader: this.flyShader.fragmentshader
})
return material
},
flyAnimation(delta = 0.015) {
console.log(this.flyArr)
TWEEN.update()
if (delta > 0.2) return
this.flyArr.forEach(elem => {
if (!elem.parent) return
if (elem._been > elem._repeat) {
elem.visible = false
// if (typeof elem._callback === 'function') {
// elem._callback(elem)
// }
// this.remove(elem)
} else {
const uniforms = elem.material.uniforms
//
if (uniforms.time.value < elem._total) {
uniforms.time.value += delta * (this.baicSpeed / delta) * elem._speed
} else {
elem._been += 1
uniforms.time.value = -uniforms.u_len.value
}
}
})
},
getColorArr(str) {
if (Array.isArray(str)) return str // error
var _arr = []
str = str + ''
str = str.toLowerCase().replace(/\s/g, '')
if (/^((?:rgba)?)\(\s*([^\)]*)/.test(str)) {
var arr = str.replace(/rgba\(|\)/gi, '').split(',')
var hex = [
pad2(Math.round(arr[0] * 1 || 0).toString(16)),
pad2(Math.round(arr[1] * 1 || 0).toString(16)),
pad2(Math.round(arr[2] * 1 || 0).toString(16))
]
_arr[0] = new Three.Color('#' + hex.join(''))
_arr[1] = Math.max(0, Math.min(1, (arr[3] * 1 || 0)))
} else if (str === 'transparent') {
_arr[0] = new Three.Color()
_arr[1] = 0
} else {
_arr[0] = new Three.Color(str)
_arr[1] = 1
}
function pad2(c) {
return c.length === 1 ? '0' + c : '' + c
}
return _arr
},
flyLineAnimate() {
requestAnimationFrame(this.flyLineAnimate)
if (this.dynamicMaterial) {
this.dynamicMaterial.uniforms.dashOffset.value -= 0.005
}
},
zoomAnimate() {
this.render()
// this.controls.update()
this.camera.updateProjectionMatrix()
requestAnimationFrame(this.zoomAnimate)
TWEEN.update()
},
initRender() {
this.renderer = new Three.WebGLRenderer({ alpha: true, antialias: true })
this.renderer.setPixelRatio(window.devicePixelRatio)
this.renderer.setSize(window.width, window.height)//
},
initScene() {
this.scene = new Three.Scene()
},
initCamera() {
var s = 140 //
this.camera = new Three.OrthographicCamera(-s * this.k, s * this.k, s, -s, 1, 2000)
this.camera.position.set(200, 200, 1900)
this.camera.lookAt(this.scene.position)
},
initLight() {
const ambientLight = new Three.AmbientLight(0xcccccc, 1.1)
this.scene.add(ambientLight) // 0
var directionalLight = new Three.DirectionalLight(0xffffff)
directionalLight.position.set(1, 500, -20)
directionalLight.castShadow = true
directionalLight.shadow.camera.top = 18
directionalLight.shadow.camera.bottom = -10
directionalLight.shadow.camera.left = -52
directionalLight.shadow.camera.right = 12
this.scene.add(directionalLight) // 1
},
initControl() {
this.orbitControls = new OrbitControls(this.camera, this.renderer.domElement)
this.orbitControls.enablePan = false
this.orbitControls.target = new Three.Vector3(0, 0, 0)
this.orbitControls.autoRotate = true//
this.orbitControls.autoRotateSpeed = 4
this.orbitControls.minPolarAngle = Math.PI / 4
this.orbitControls.maxPolarAngle = Math.PI / 2
// this.orbitControls.minAzimuthAngle = 0
// this.orbitControls.maxAzimuthAngle = 0
this.orbitControls.minZoom = 1
this.orbitControls.maxZoom = 2
},
initModel() {
var geometry = new Three.SphereGeometry(100, 40, 40) //
//
var textureLoader = new Three.TextureLoader()
textureLoader.load(process.env.VUE_APP_PUBLIC_SOURCE_API + '/earth.jpg', (texture) => {
var material = new Three.MeshLambertMaterial({
// color: 0x0a263e,
transparent: true,
opacity: 0.96,
map: texture
})
// var geometry2 = new Three.SphereGeometry(101, 40, 40)
var material2 = new Three.MeshLambertMaterial({
transparent: true,
opacity: 0.1,
// blending: Three.AdditiveBlending,
map: textureLoader.load(process.env.VUE_APP_PUBLIC_SOURCE_API + '/earth_cloud.png')
})
this.mesh = new Three.Mesh(geometry, material)
this.mesh2 = new Three.Mesh(geometry, material2)
this.scene.add(this.mesh) // 4
this.scene.add(this.mesh2) // 5
this.setMark(this.mapMarks) //
this.setAreaMark(this.area)
// this.scene.rotation.z = Math.PI / 10
this.scene.rotation.x = Math.PI / 20
this.scene.rotation.y = -500
// this.scene.rotation.set(0.5, 2.9, 0.1)
//
textureLoader.load(process.env.VUE_APP_PUBLIC_SOURCE_API + '/light.png', (texture2) => {
const spriteMaterial = new Three.SpriteMaterial({
map: texture2,
transparent: true,
opacity: 0.7
})
const sprite = new Three.Sprite(spriteMaterial)
sprite.scale.set(Math.PI * 95, Math.PI * 95, 1)
this.scene.add(sprite) // 10
})
// satellites
this.satellitesArr.push(this.setSatellites({ x: -Math.PI / 2, y: 0, z: 0 }, 0.021))
this.renderer.setSize(this.width, this.height)
// this.renderer.setClearColor(0x03060f, 1) //
const earth = document.getElementById('earth')
earth.appendChild(this.renderer.domElement)
this.animate()
})
},
render() {
this.renderer.render(this.scene, this.camera)
},
initMap() {
//
const map = new Three.Object3D()
chinaJson.features.forEach(elem => {
// 线
const province = new Three.Object3D()
const coordinates = elem.geometry.coordinates
coordinates.forEach(multiPolygon => {
multiPolygon.forEach(polygon => {
const lineMaterial = new Three.LineBasicMaterial({ color: 0x3EDFFC })
const positions = []
const lineGeometry = new Three.BufferGeometry()
for (let i = 0; i < polygon.length; i++) {
var pos = this.getPosition(polygon[i][0] + 90, polygon[i][1], 100)
if (pos.x) {
positions.push(pos.x, pos.y, pos.z)
} else {
console.log(polygon[i])
}
}
const ps = new Three.Float32BufferAttribute(positions, 3)
lineGeometry.setAttribute('position', ps)
const line = new Three.LineLoop(lineGeometry, lineMaterial)
province.add(line)
})
})
map.add(province)
})
this.scene.add(map) // 2
const map1 = new Three.Object3D()
continentsJson.features.forEach(elem => {
const continents = new Three.Object3D()
const coordinates = elem.geometry.coordinates
coordinates.forEach(multiPolygon => {
if (elem.geometry.type === 'MultiPolygon') {
multiPolygon.forEach(polygon => {
const lineMaterial = new Three.LineBasicMaterial({ color: 0x0a315a80 }) // 0x3BFA9E
const positions = []
const linGeometry = new Three.BufferGeometry()
for (let i = 0; i < polygon.length; i++) {
const LL = this.transformToLatLon(polygon[i], continentsJson['hc-transform'].default)
var pos = this.getPosition(LL.x + 90, LL.y, 100)
if (pos.x) {
positions.push(pos.x, pos.y, pos.z)
} else {
console.log(multiPolygon[i])
}
}
linGeometry.setAttribute('position', new Three.Float32BufferAttribute(positions, 3))
const line = new Three.Line(linGeometry, lineMaterial)
continents.add(line)
})
} else {
const lineMaterial = new Three.LineBasicMaterial({ color: 0x0a315a80 })
const positions = []
const linGeometry = new Three.BufferGeometry()
for (let i = 0; i < multiPolygon.length; i++) {
const LL = this.transformToLatLon(multiPolygon[i], continentsJson['hc-transform'].default)
var pos = this.getPosition(LL.x + 90, LL.y, 100)
if (pos.x) {
positions.push(pos.x, pos.y, pos.z)
} else {
console.log(multiPolygon[i])
}
}
linGeometry.setAttribute('position', new Three.Float32BufferAttribute(positions, 3))
const line = new Three.Line(linGeometry, lineMaterial)
continents.add(line)
}
})
map1.add(continents)
})
this.scene.add(map1) // 3
},
// geojson
transformToLatLon(a, b) {
var d = b.jsonmarginX
var f = b.jsonmarginY
var e = b.jsonres
e = void 0 === e ? 1 : e
var n = b.scale
n = void 0 === n ? 1 : n
var t = b.xoffset
var r = b.xpan
var m = b.yoffset
var h = b.ypan
a = {
x: ((a[0] - (void 0 === d ? 0 : d)) / e - (void 0 === r ? 0 : r)) / n + (void 0 === t ? 0 : t),
y: ((a[1] - (void 0 === f ? 0 : f)) / e + (void 0 === h ? 0 : h)) / n + (void 0 === m ? 0 : m)
}
d = b.cosAngle || b.rotation && Math.cos(b.rotation)
f = b.sinAngle || b.rotation && Math.sin(b.rotation)
b = proj4(b.crs, 'WGS84', b.rotation ? {
x: a.x * d + a.y * -f,
y: a.x * f + a.y * d
} : a)
return {
y: b.y,
x: b.x
}
},
init() {
this.initRender()
this.initScene()
this.initCamera()
this.initLight()
this.initModel()
this.initControl()
this.initMap()
document.addEventListener('mousedown', this.onDocumentMouseDown, false)
},
onDocumentMouseDown(e) {
e.preventDefault()
var raycaster = new Three.Raycaster()
var mouse = new Three.Vector2() // threejs,
mouse.x = (e.clientX / this.width) * 2 - 1
mouse.y = -(e.clientY / this.height) * 2 + 1
// z0.5
//
// var vector = new Three.Vector3(mouse.x, mouse.y, 0.5).unproject(this.camera)
raycaster.setFromCamera(mouse, this.camera)
// 线,线 线
// var raycaster = new Three.Raycaster(this.camera.position, vector.sub(this.camera.position).normalize())
// 线线
// console.log(this.scene)
// var intersects = raycaster.intersectObjects(this.scene.children)
// console.log(intersects)
// if (intersects.length > 0) {
// // 线
// console.log(intersects[0].object)
// }
},
//
setSatellites(rotation, speed) {
const distance = 130
const satellite = new Three.Sprite(new Three.SpriteMaterial({ map: new Three.CanvasTexture(this.generateSprite()) }))
satellite.scale.x = satellite.scale.y = satellite.scale.z = 3
satellite.position.set(distance + 0.1, -2, -1)
const track = new Three.Mesh(new Three.RingGeometry(distance - 0.1, distance + 0.1, 64, 1), new Three.MeshBasicMaterial({ color: this.monitorColor, side: Three.DoubleSide }))
const centerMesh = new Three.Mesh(new Three.SphereGeometry(1, 1, 1), new Three.MeshLambertMaterial())
var pivotPoint = new Three.Object3D()
pivotPoint.add(satellite)
pivotPoint.add(track)
centerMesh.add(pivotPoint)
centerMesh.rotation.set(rotation.x, rotation.y, rotation.z)
this.scene.add(centerMesh) // 9
return { satellite: centerMesh, speed: speed }
},
//
generateSprite() {
var canvas = document.createElement('canvas')
canvas.width = 100
canvas.height = 100
var context = canvas.getContext('2d')
context.beginPath()
context.arc(20, 20, 20, 0, 2 * Math.PI, true)
context.fillStyle = this.monitorColor
context.fill()
context.lineWidth = 1
context.strokeStyle = this.monitorColor
context.stroke()
return canvas
},
//
setAreaMark(_area) {
const borderSize = 2
const ctx = document.createElement('canvas').getContext('2d')
// measure how long the name will be
const doubleBorderSize = borderSize * 2
const width = (700 + doubleBorderSize)
ctx.canvas.width = width
ctx.canvas.height = 580
// need to set font again after resizing canvas
ctx.textBaseline = 'top'
ctx.font = '70px Arial'
ctx.lineWidth = 15
ctx.fillStyle = 'rgba(3, 38, 81, 0.3)'
ctx.fillRect(0, 0, width, 580)
ctx.strokeStyle = '#008aff'
ctx.strokeRect(0, 0, width, 580)
ctx.fillStyle = 'white'
ctx.fillText('资源区域: ' + _area.resourceArea, borderSize * 30, borderSize * 20)
ctx.fillText('活跃用户: ' + _area.userNum, borderSize * 30, borderSize * 20 + 100)
ctx.fillText('服务器数量: ' + _area.areaCount, borderSize * 30, borderSize * 20 + 200)
ctx.fillText('集群数量: ' + _area.clusterNum, borderSize * 30, borderSize * 20 + 300)
ctx.fillText('资源使用率: ' + _area.usagedRate, borderSize * 30, borderSize * 20 + 400)
const markPos = this.getPosition(130.21029 + 90, 23.527138, 100)
var texture = new Three.CanvasTexture(ctx.canvas)
texture.needsUpdate = true
var fontMesh = new Three.Sprite(
new Three.SpriteMaterial({
map: texture
})
)
fontMesh.scale.x = 40
fontMesh.scale.y = 34
fontMesh.position.set(markPos.x - 30, markPos.y - 10, markPos.z - 20)
this.scene.add(fontMesh) // 8
},
//
//
setMark(_markData) {
this.marking = new Three.Group() // 6
this.textMarking = new Three.Group() // 7
for (var i = 0; i < _markData.length; i++) {
//
// var mark = new Three.Mesh(new Three.SphereGeometry(2, 2, 2), new Three.MeshBasicMaterial({
// color: '#1bb4b0'
// }))
// //
var markPos = this.getPosition(_markData[i].value[0] + 90, _markData[i].value[1], 100)
// mark.position.set(markPos.x, markPos.y, markPos.z)
var textureLoader = new Three.TextureLoader()
var material = new Three.MeshBasicMaterial({
map: textureLoader.load(process.env.VUE_APP_PUBLIC_SOURCE_API + '/point.png'),
transparent: true, // 使png
blending: Three.AdditiveBlending,
// side: THREE.DoubleSide, //
depthWrite: false //
})
var mesh = new Three.Mesh(new Three.PlaneGeometry(8, 8, 3, 3), material)
// var size = 10 * 0.04// Mesh
// mesh.scale.set(size, size, size)// mesh
// mesh
mesh.position.set(markPos.x, markPos.y, markPos.z)
// mesh线()
var coordVec3 = new Three.Vector3(markPos.x, markPos.y, markPos.z).normalize()
// meshXOY线沿znew THREE.Vector3(0, 0, 1)
var meshNormal = new Three.Vector3(0, 0, 1)
// .quaternionmesh
// .setFromUnitVectors();
mesh.quaternion.setFromUnitVectors(meshNormal, coordVec3)
this.marking.add(mesh)
// eg: 18
var texture = new Three.CanvasTexture(this.getCanvasFont(_markData[i].name + '' + _markData[i].count + '个'))
//
const fontNumber = _markData[i].count.toString().length * 5.8642578125 + _markData[i].name.length * 10 + 10 + 2.4072265625 + 5
texture.needsUpdate = true
var fontMesh = new Three.Sprite(
new Three.SpriteMaterial({
map: texture
})
)
fontMesh.scale.x = fontNumber
fontMesh.scale.y = 10
fontMesh.position.set(markPos.x + 10, markPos.y + 10, markPos.z - 20)
this.textMarking.add(fontMesh)
}
this.scene.add(this.marking)
this.scene.add(this.textMarking)
},
//
getCanvasFont(name) {
const borderSize = 2
const ctx = document.createElement('canvas').getContext('2d')
// measure how long the name will be
const doubleBorderSize = borderSize * 2
const width = (ctx.measureText(name).width + doubleBorderSize * 2) * 11
ctx.canvas.width = width
// need to set font again after resizing canvas
ctx.textBaseline = 'top'
ctx.font = '85px Arial'
ctx.lineWidth = 15
ctx.fillStyle = 'rgba(0, 0, 0, 0.5)'
ctx.fillRect(0, 0, width, 150)
ctx.strokeStyle = '#3EDFFC'
ctx.strokeRect(0, 0, width, 150)
ctx.fillStyle = 'white'
if (ctx.measureText(name).width > 540) {
ctx.fillText(name, borderSize * 80, borderSize * 20)
} else {
ctx.fillText(name, borderSize * 60, borderSize * 20)
}
return ctx.canvas
},
//
getPosition(_longitude, _latitude, _radius) {
var lg = Three.Math.degToRad(_longitude)
var lt = Three.Math.degToRad(_latitude)
var temp = _radius * Math.cos(lt)
var x = temp * Math.sin(lg)
var y = _radius * Math.sin(lt)
var z = temp * Math.cos(lg)
return {
x: x,
y: y,
z: z
}
},
animate() {
// this.scene.rotation.x = 0.5
// this.scene.rotation.y += 0.005
this.clock = new Three.Clock()//
// const delta = this.clock.getDelta()
//
if (this.scene.children[6].children.length) {
this.scene.children[6].children.forEach((mesh) => {
this.mshs += 0.005
mesh.scale.set(this.mshs, this.mshs, 3 * this.mshs)
if (this.mshs <= 1.5) {
// mesh._s=1=0 mesh._s=1.5=1
mesh.material.opacity = (this.mshs - 1) * 2
} else if (this.mshs > 1.5 && this.mshs <= 2) {
// mesh._s=1.5=1 mesh._s=2=0
mesh.material.opacity = 1 - (this.mshs - 1.5) * 2
} else {
this.mshs = 1.0
}
})
}
//
for (let i = 0; i < this.satellitesArr.length; i++) {
this.satellitesArr[i].satellite.rotation.z -= this.satellitesArr[i].speed
}
this.render()
this.orbitControls.update()
this.aniId = requestAnimationFrame(this.animate)
}
}
}
</script>
<style lang="scss" scoped>
.switchBtn {
font-size: 1.5rem;
position: absolute;
bottom: 50px;
right: 29.5vw;
z-index: 100;
color: #fff;
}
.toChina{
right: 32vw;
}
.activeBtn{
color: #3EDFFC
}
</style>

View File

@ -0,0 +1,758 @@
(function() {
'use strict'
var root = this
var has_require = typeof require !== 'undefined'
var THREE = root.THREE || has_require && require('three')
if (!THREE) { throw new Error('MeshLine requires three.js') }
function MeshLine() {
this.positions = []
this.previous = []
this.next = []
this.side = []
this.width = []
this.indices_array = []
this.uvs = []
this.counters = []
this.geometry = new THREE.BufferGeometry()
this.widthCallback = null
// Used to raycast
this.matrixWorld = new THREE.Matrix4()
}
MeshLine.prototype.setMatrixWorld = function(matrixWorld) {
this.matrixWorld = matrixWorld
}
MeshLine.prototype.setGeometry = function(g, c) {
this.widthCallback = c
this.positions = []
this.counters = []
// g.computeBoundingBox();
// g.computeBoundingSphere();
// set the normals
// g.computeVertexNormals();
// if (g instanceof THREE.Geometry) {
// for (var j = 0; j < g.vertices.length; j++) {
// var v = g.vertices[ j ]
// var c = j / g.vertices.length
// this.positions.push(v.x, v.y, v.z)
// this.positions.push(v.x, v.y, v.z)
// this.counters.push(c)
// this.counters.push(c)
// }
// }
if (g instanceof THREE.BufferGeometry) {
// read attribute positions ?
for (var j = 0; j < g.attributes.position.length; j++) {
const v = g.attributes.position[ j ]
const c = j / g.attributes.position.length
this.positions.push(v.x, v.y, v.z)
this.positions.push(v.x, v.y, v.z)
this.counters.push(c)
this.counters.push(c)
}
}
if (g instanceof Float32Array || g instanceof Array) {
for (let j = 0; j < g.length; j += 3) {
const c = j / g.length
this.positions.push(g[ j ], g[ j + 1 ], g[ j + 2 ])
this.positions.push(g[ j ], g[ j + 1 ], g[ j + 2 ])
this.counters.push(c)
this.counters.push(c)
}
}
this.process()
}
MeshLine.prototype.raycast = (function() {
var inverseMatrix = new THREE.Matrix4()
var ray = new THREE.Ray()
var sphere = new THREE.Sphere()
return function raycast(raycaster, intersects) {
var precision = raycaster.linePrecision
var precisionSq = precision * precision
var interRay = new THREE.Vector3()
var geometry = this.geometry
if (geometry.boundingSphere === null) geometry.computeBoundingSphere()
// Checking boundingSphere distance to ray
sphere.copy(geometry.boundingSphere)
sphere.applyMatrix4(this.matrixWorld)
if (raycaster.ray.intersectSphere(sphere, interRay) === false) {
return
}
inverseMatrix.getInverse(this.matrixWorld)
ray.copy(raycaster.ray).applyMatrix4(inverseMatrix)
var vStart = new THREE.Vector3()
var vEnd = new THREE.Vector3()
var interSegment = new THREE.Vector3()
var step = this instanceof THREE.LineSegments ? 2 : 1
if (geometry instanceof THREE.BufferGeometry) {
var index = geometry.index
var attributes = geometry.attributes
if (index !== null) {
var indices = index.array
var positions = attributes.position.array
for (var i = 0, l = indices.length - 1; i < l; i += step) {
var a = indices[ i ]
var b = indices[ i + 1 ]
vStart.fromArray(positions, a * 3)
vEnd.fromArray(positions, b * 3)
var distSq = ray.distanceSqToSegment(vStart, vEnd, interRay, interSegment)
if (distSq > precisionSq) continue
interRay.applyMatrix4(this.matrixWorld) // Move back to world space for distance calculation
var distance = raycaster.ray.origin.distanceTo(interRay)
if (distance < raycaster.near || distance > raycaster.far) continue
intersects.push({
distance: distance,
// What do we want? intersection point on the ray or on the segment??
// point: raycaster.ray.at( distance ),
point: interSegment.clone().applyMatrix4(this.matrixWorld),
index: i,
face: null,
faceIndex: null,
object: this
})
}
} else {
const positions = attributes.position.array
for (let i = 0, l = positions.length / 3 - 1; i < l; i += step) {
vStart.fromArray(positions, 3 * i)
vEnd.fromArray(positions, 3 * i + 3)
const distSq = ray.distanceSqToSegment(vStart, vEnd, interRay, interSegment)
if (distSq > precisionSq) continue
interRay.applyMatrix4(this.matrixWorld) // Move back to world space for distance calculation
const distance = raycaster.ray.origin.distanceTo(interRay)
if (distance < raycaster.near || distance > raycaster.far) continue
intersects.push({
distance: distance,
// What do we want? intersection point on the ray or on the segment??
// point: raycaster.ray.at( distance ),
point: interSegment.clone().applyMatrix4(this.matrixWorld),
index: i,
face: null,
faceIndex: null,
object: this
})
}
}
} else if (geometry instanceof THREE.Geometry) {
var vertices = geometry.vertices
var nbVertices = vertices.length
for (let i = 0; i < nbVertices - 1; i += step) {
const distSq = ray.distanceSqToSegment(vertices[ i ], vertices[ i + 1 ], interRay, interSegment)
if (distSq > precisionSq) continue
interRay.applyMatrix4(this.matrixWorld) // Move back to world space for distance calculation
const distance = raycaster.ray.origin.distanceTo(interRay)
if (distance < raycaster.near || distance > raycaster.far) continue
intersects.push({
distance: distance,
// What do we want? intersection point on the ray or on the segment??
// point: raycaster.ray.at( distance ),
point: interSegment.clone().applyMatrix4(this.matrixWorld),
index: i,
face: null,
faceIndex: null,
object: this
})
}
}
}
}())
MeshLine.prototype.compareV3 = function(a, b) {
var aa = a * 6
var ab = b * 6
return (this.positions[ aa ] === this.positions[ ab ]) && (this.positions[ aa + 1 ] === this.positions[ ab + 1 ]) && (this.positions[ aa + 2 ] === this.positions[ ab + 2 ])
}
MeshLine.prototype.copyV3 = function(a) {
var aa = a * 6
return [this.positions[ aa ], this.positions[ aa + 1 ], this.positions[ aa + 2 ]]
}
MeshLine.prototype.process = function() {
var l = this.positions.length / 6
this.previous = []
this.next = []
this.side = []
this.width = []
this.indices_array = []
this.uvs = []
for (var j = 0; j < l; j++) {
this.side.push(1)
this.side.push(-1)
}
var w
for (let j = 0; j < l; j++) {
if (this.widthCallback) w = this.widthCallback(j / (l - 1))
else w = 1
this.width.push(w)
this.width.push(w)
}
for (let j = 0; j < l; j++) {
this.uvs.push(j / (l - 1), 0)
this.uvs.push(j / (l - 1), 1)
}
var v
if (this.compareV3(0, l - 1)) {
v = this.copyV3(l - 2)
} else {
v = this.copyV3(0)
}
this.previous.push(v[ 0 ], v[ 1 ], v[ 2 ])
this.previous.push(v[ 0 ], v[ 1 ], v[ 2 ])
for (let j = 0; j < l - 1; j++) {
v = this.copyV3(j)
this.previous.push(v[ 0 ], v[ 1 ], v[ 2 ])
this.previous.push(v[ 0 ], v[ 1 ], v[ 2 ])
}
for (let j = 1; j < l; j++) {
v = this.copyV3(j)
this.next.push(v[ 0 ], v[ 1 ], v[ 2 ])
this.next.push(v[ 0 ], v[ 1 ], v[ 2 ])
}
if (this.compareV3(l - 1, 0)) {
v = this.copyV3(1)
} else {
v = this.copyV3(l - 1)
}
this.next.push(v[ 0 ], v[ 1 ], v[ 2 ])
this.next.push(v[ 0 ], v[ 1 ], v[ 2 ])
for (let j = 0; j < l - 1; j++) {
var n = j * 2
this.indices_array.push(n, n + 1, n + 2)
this.indices_array.push(n + 2, n + 1, n + 3)
}
if (!this.attributes) {
this.attributes = {
position: new THREE.BufferAttribute(new Float32Array(this.positions), 3),
previous: new THREE.BufferAttribute(new Float32Array(this.previous), 3),
next: new THREE.BufferAttribute(new Float32Array(this.next), 3),
side: new THREE.BufferAttribute(new Float32Array(this.side), 1),
width: new THREE.BufferAttribute(new Float32Array(this.width), 1),
uv: new THREE.BufferAttribute(new Float32Array(this.uvs), 2),
index: new THREE.BufferAttribute(new Uint16Array(this.indices_array), 1),
counters: new THREE.BufferAttribute(new Float32Array(this.counters), 1)
}
} else {
this.attributes.position.copyArray(new Float32Array(this.positions))
this.attributes.position.needsUpdate = true
this.attributes.previous.copyArray(new Float32Array(this.previous))
this.attributes.previous.needsUpdate = true
this.attributes.next.copyArray(new Float32Array(this.next))
this.attributes.next.needsUpdate = true
this.attributes.side.copyArray(new Float32Array(this.side))
this.attributes.side.needsUpdate = true
this.attributes.width.copyArray(new Float32Array(this.width))
this.attributes.width.needsUpdate = true
this.attributes.uv.copyArray(new Float32Array(this.uvs))
this.attributes.uv.needsUpdate = true
this.attributes.index.copyArray(new Uint16Array(this.indices_array))
this.attributes.index.needsUpdate = true
}
this.geometry.setAttribute('position', this.attributes.position)
this.geometry.setAttribute('previous', this.attributes.previous)
this.geometry.setAttribute('next', this.attributes.next)
this.geometry.setAttribute('side', this.attributes.side)
this.geometry.setAttribute('width', this.attributes.width)
this.geometry.setAttribute('uv', this.attributes.uv)
this.geometry.setAttribute('counters', this.attributes.counters)
// this.geometry.addAttribute('position', this.attributes.position)
// this.geometry.addAttribute('previous', this.attributes.previous)
// this.geometry.addAttribute('next', this.attributes.next)
// this.geometry.addAttribute('side', this.attributes.side)
// this.geometry.addAttribute('width', this.attributes.width)
// this.geometry.addAttribute('uv', this.attributes.uv)
// this.geometry.addAttribute('counters', this.attributes.counters)
this.geometry.setIndex(this.attributes.index)
}
function memcpy(src, srcOffset, dst, dstOffset, length) {
var i
src = src.subarray || src.slice ? src : src.buffer
dst = dst.subarray || dst.slice ? dst : dst.buffer
src = srcOffset ? src.subarray
? src.subarray(srcOffset, length && srcOffset + length)
: src.slice(srcOffset, length && srcOffset + length) : src
if (dst.set) {
dst.set(src, dstOffset)
} else {
for (i = 0; i < src.length; i++) {
dst[i + dstOffset] = src[i]
}
}
return dst
}
/**
* Fast method to advance the line by one position. The oldest position is removed.
* @param position
*/
MeshLine.prototype.advance = function(position) {
var positions = this.attributes.position.array
var previous = this.attributes.previous.array
var next = this.attributes.next.array
var l = positions.length
// PREVIOUS
memcpy(positions, 0, previous, 0, l)
// POSITIONS
memcpy(positions, 6, positions, 0, l - 6)
positions[l - 6] = position.x
positions[l - 5] = position.y
positions[l - 4] = position.z
positions[l - 3] = position.x
positions[l - 2] = position.y
positions[l - 1] = position.z
// NEXT
memcpy(positions, 6, next, 0, l - 6)
next[l - 6] = position.x
next[l - 5] = position.y
next[l - 4] = position.z
next[l - 3] = position.x
next[l - 2] = position.y
next[l - 1] = position.z
this.attributes.position.needsUpdate = true
this.attributes.previous.needsUpdate = true
this.attributes.next.needsUpdate = true
}
THREE.ShaderChunk[ 'meshline_vert' ] = [
'',
THREE.ShaderChunk.logdepthbuf_pars_vertex,
THREE.ShaderChunk.fog_pars_vertex,
'',
'attribute vec3 previous;',
'attribute vec3 next;',
'attribute float side;',
'attribute float width;',
'attribute float counters;',
'',
'uniform vec2 resolution;',
'uniform float lineWidth;',
'uniform vec3 color;',
'uniform float opacity;',
'uniform float near;',
'uniform float far;',
'uniform float sizeAttenuation;',
'uniform vec2 offset;',
'',
'varying vec2 vUV;',
'varying vec4 vColor;',
'varying float vCounters;',
'',
'vec2 fix( vec4 i, float aspect ) {',
'',
' vec2 res = i.xy / i.w;',
' res.x *= aspect;',
' vCounters = counters;',
' return res;',
'',
'}',
'',
'void main() {',
'',
' float aspect = resolution.x / resolution.y;',
' float pixelWidthRatio = 1. / (resolution.x * projectionMatrix[0][0]);',
'',
' vColor = vec4( color, opacity );',
' vUV = uv + offset;',
'',
' mat4 m = projectionMatrix * modelViewMatrix;',
' vec4 finalPosition = m * vec4( position, 1.0 );',
' vec4 prevPos = m * vec4( previous, 1.0 );',
' vec4 nextPos = m * vec4( next, 1.0 );',
'',
' vec2 currentP = fix( finalPosition, aspect );',
' vec2 prevP = fix( prevPos, aspect );',
' vec2 nextP = fix( nextPos, aspect );',
'',
' float pixelWidth = finalPosition.w * pixelWidthRatio;',
' float w = 1.8 * pixelWidth * lineWidth * width;',
'',
' if( sizeAttenuation == 1. ) {',
' w = 1.8 * lineWidth * width;',
' }',
'',
' vec2 dir;',
' if( nextP == currentP ) dir = normalize( currentP - prevP );',
' else if( prevP == currentP ) dir = normalize( nextP - currentP );',
' else {',
' vec2 dir1 = normalize( currentP - prevP );',
' vec2 dir2 = normalize( nextP - currentP );',
' dir = normalize( dir1 + dir2 );',
'',
' vec2 perp = vec2( -dir1.y, dir1.x );',
' vec2 miter = vec2( -dir.y, dir.x );',
' //w = clamp( w / dot( miter, perp ), 0., 4. * lineWidth * width );',
'',
' }',
'',
' //vec2 normal = ( cross( vec3( dir, 0. ), vec3( 0., 0., 1. ) ) ).xy;',
' vec2 normal = vec2( -dir.y, dir.x );',
' normal.x /= aspect;',
' normal *= .5 * w;',
'',
' vec4 offset = vec4( normal * side, 0.0, 1.0 );',
' finalPosition.xy += offset.xy;',
'',
' gl_Position = finalPosition;',
'',
THREE.ShaderChunk.logdepthbuf_vertex,
THREE.ShaderChunk.fog_vertex && ' vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );',
THREE.ShaderChunk.fog_vertex,
'}'
].join('\r\n')
THREE.ShaderChunk[ 'meshline_frag' ] = [
'',
THREE.ShaderChunk.fog_pars_fragment,
THREE.ShaderChunk.logdepthbuf_pars_fragment,
'',
'uniform sampler2D map;',
'uniform sampler2D alphaMap;',
'uniform float useMap;',
'uniform float useAlphaMap;',
'uniform float useDash;',
'uniform float dashArray;',
'uniform float dashOffset;',
'uniform float dashRatio;',
'uniform float visibility;',
'uniform float alphaTest;',
'uniform vec2 repeat;',
'',
'varying vec2 vUV;',
'varying vec4 vColor;',
'varying float vCounters;',
'',
'void main() {',
'',
THREE.ShaderChunk.logdepthbuf_fragment,
'',
' vec4 c = vColor;',
' if( useMap == 1. ) c *= texture2D( map, vUV * repeat );',
' if( useAlphaMap == 1. ) c.a *= texture2D( alphaMap, vUV * repeat ).a;',
' if( c.a < alphaTest ) discard;',
' if( useDash == 1. ){',
' c.a *= ceil(mod(vCounters + dashOffset, dashArray) - (dashArray * dashRatio));',
' }',
' gl_FragColor = c;',
' gl_FragColor.a *= step(vCounters, visibility);',
'',
THREE.ShaderChunk.fog_fragment,
'}'
].join('\r\n')
function MeshLineMaterial(parameters) {
THREE.ShaderMaterial.call(this, {
uniforms: Object.assign({},
THREE.UniformsLib.fog,
{
lineWidth: { value: 1 },
map: { value: null },
useMap: { value: 0 },
alphaMap: { value: null },
useAlphaMap: { value: 0 },
color: { value: new THREE.Color(0xffffff) },
opacity: { value: 1 },
resolution: { value: new THREE.Vector2(1, 1) },
sizeAttenuation: { value: 1 },
near: { value: 1 },
far: { value: 1 },
dashArray: { value: 0 },
dashOffset: { value: 0 },
dashRatio: { value: 0.5 },
useDash: { value: 0 },
visibility: { value: 1 },
alphaTest: { value: 0 },
repeat: { value: new THREE.Vector2(1, 1) },
offset: { value: new THREE.Vector2(1, 1) }
}
),
vertexShader: THREE.ShaderChunk.meshline_vert,
fragmentShader: THREE.ShaderChunk.meshline_frag
})
this.type = 'MeshLineMaterial'
Object.defineProperties(this, {
lineWidth: {
enumerable: true,
get: function() {
return this.uniforms.lineWidth.value
},
set: function(value) {
this.uniforms.lineWidth.value = value
}
},
map: {
enumerable: true,
get: function() {
return this.uniforms.map.value
},
set: function(value) {
this.uniforms.map.value = value
}
},
useMap: {
enumerable: true,
get: function() {
return this.uniforms.useMap.value
},
set: function(value) {
this.uniforms.useMap.value = value
}
},
alphaMap: {
enumerable: true,
get: function() {
return this.uniforms.alphaMap.value
},
set: function(value) {
this.uniforms.alphaMap.value = value
}
},
useAlphaMap: {
enumerable: true,
get: function() {
return this.uniforms.useAlphaMap.value
},
set: function(value) {
this.uniforms.useAlphaMap.value = value
}
},
color: {
enumerable: true,
get: function() {
return this.uniforms.color.value
},
set: function(value) {
this.uniforms.color.value = value
}
},
opacity: {
enumerable: true,
get: function() {
return this.uniforms.opacity.value
},
set: function(value) {
this.uniforms.opacity.value = value
}
},
resolution: {
enumerable: true,
get: function() {
return this.uniforms.resolution.value
},
set: function(value) {
this.uniforms.resolution.value.copy(value)
}
},
sizeAttenuation: {
enumerable: true,
get: function() {
return this.uniforms.sizeAttenuation.value
},
set: function(value) {
this.uniforms.sizeAttenuation.value = value
}
},
near: {
enumerable: true,
get: function() {
return this.uniforms.near.value
},
set: function(value) {
this.uniforms.near.value = value
}
},
far: {
enumerable: true,
get: function() {
return this.uniforms.far.value
},
set: function(value) {
this.uniforms.far.value = value
}
},
dashArray: {
enumerable: true,
get: function() {
return this.uniforms.dashArray.value
},
set: function(value) {
this.uniforms.dashArray.value = value
this.useDash = (value !== 0) ? 1 : 0
}
},
dashOffset: {
enumerable: true,
get: function() {
return this.uniforms.dashOffset.value
},
set: function(value) {
this.uniforms.dashOffset.value = value
}
},
dashRatio: {
enumerable: true,
get: function() {
return this.uniforms.dashRatio.value
},
set: function(value) {
this.uniforms.dashRatio.value = value
}
},
useDash: {
enumerable: true,
get: function() {
return this.uniforms.useDash.value
},
set: function(value) {
this.uniforms.useDash.value = value
}
},
visibility: {
enumerable: true,
get: function() {
return this.uniforms.visibility.value
},
set: function(value) {
this.uniforms.visibility.value = value
}
},
alphaTest: {
enumerable: true,
get: function() {
return this.uniforms.alphaTest.value
},
set: function(value) {
this.uniforms.alphaTest.value = value
}
},
repeat: {
enumerable: true,
get: function() {
return this.uniforms.repeat.value
},
set: function(value) {
this.uniforms.repeat.value.copy(value)
}
}
})
this.setValues(parameters)
}
MeshLineMaterial.prototype = Object.create(THREE.ShaderMaterial.prototype)
MeshLineMaterial.prototype.constructor = MeshLineMaterial
MeshLineMaterial.prototype.isMeshLineMaterial = true
MeshLineMaterial.prototype.copy = function(source) {
THREE.ShaderMaterial.prototype.copy.call(this, source)
this.lineWidth = source.lineWidth
this.map = source.map
this.useMap = source.useMap
this.alphaMap = source.alphaMap
this.useAlphaMap = source.useAlphaMap
this.color.copy(source.color)
this.opacity = source.opacity
this.resolution.copy(source.resolution)
this.sizeAttenuation = source.sizeAttenuation
this.near = source.near
this.far = source.far
this.dashArray.copy(source.dashArray)
this.dashOffset.copy(source.dashOffset)
this.dashRatio.copy(source.dashRatio)
this.useDash = source.useDash
this.visibility = source.visibility
this.alphaTest = source.alphaTest
this.repeat.copy(source.repeat)
return this
}
if (typeof exports !== 'undefined') {
if (typeof module !== 'undefined' && module.exports) {
exports = module.exports = { MeshLine: MeshLine, MeshLineMaterial: MeshLineMaterial }
}
exports.MeshLine = MeshLine
exports.MeshLineMaterial = MeshLineMaterial
} else {
root.MeshLine = MeshLine
root.MeshLineMaterial = MeshLineMaterial
}
}).call(this)

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,236 @@
<template>
<div id="zone">
<div class="data-view">
<h5>{{ mapName[mapType] }}</h5>
<p>数算中心 {{ count.ys || 0 }}</p>
<p>超算中心 {{ count.cs || 0 }}</p>
<p>智算中心 {{ count.zs || 0 }}</p>
</div>
<canvas id="contain" />
</div>
</template>
<script>
import guangdongJson from './geoJson/guangdong.json'
import chuanyuJson from './geoJson/chuanyu.json'
import gansuJson from './geoJson/gansu.json'
import guizhouJson from './geoJson/guizhou.json'
import jingjinjiJson from './geoJson/jingjinji.json'
import neimengguJson from './geoJson/neimenggu.json'
import ningxiaJson from './geoJson/ningxia.json'
import changsanjiaoJson from './geoJson/changsanjiao.json'
export default {
props: {
mapType: {
type: Number,
default: 1
},
count: {
type: Object,
default: () => { return { ys: 0, zs: 0, cs: 0 } }
}
},
data() {
return {
allJSON: {
guangdongJson,
chuanyuJson,
gansuJson,
guizhouJson, jingjinjiJson, neimengguJson, ningxiaJson, changsanjiaoJson
},
scale: 1,
geoCenter: {},
mapMap: {
1: 'ningxia',
2: 'neimenggu',
3: 'gansu',
4: 'guizhou',
5: 'guangdong',
6: 'chuanyu',
7: 'changsanjiao',
8: 'jingjinji'
},
mapName: {
1: '宁夏回族自治区',
2: '内蒙古自治区',
3: '甘肃省',
4: '贵州省',
5: '粤港澳大湾区',
6: '川渝地区',
7: '长三角地区',
8: '京津冀地区'
}
// geoCenterY: 0
}
},
watch: {
mapType(val) {
if (val) {
this.getBoxArea()
this.initMap()
}
}
},
mounted() {
this.getBoxArea()
this.initMap()
},
methods: {
getBoxArea() {
const canvasW = window.innerWidth
const canvasH = window.innerHeight
let N = -90; let S = 90; let W = 180; let E = -180
this.allJSON[this.mapMap[this.mapType] + 'Json'].features.forEach(item => {
if (item.geometry.type === 'Polygon') {
item.geometry.coordinates = [item.geometry.coordinates]
}
//
item.geometry.coordinates.forEach(area => {
area[0].forEach(elem => {
if (elem[0] < W) {
W = elem[0]
}
if (elem[0] > E) {
E = elem[0]
}
if (elem[1] > N) {
N = elem[1]
}
if (elem[1] < S) {
S = elem[1]
}
})
})
})
//
var wScale = canvasW / Math.abs(E - W) - 10
var hScale = canvasH / Math.abs(N - S) - 10
// const width = Math.abs(E - W)
// const height = Math.abs(N - S)
// const wScale = canvasW / width / 3
// const hScale = canvasH / height / 3
//
this.scale = wScale > hScale ? hScale : wScale
//
// this.geoCenterX = (E + W) / 2
// this.geoCenterY = (N + S) / 2
this.geoCenter = {
W: W,
N: N,
xoffset: canvasW / 2 - Math.abs(E - W) / 2 * this.scale,
yoffset: canvasH / 2 - Math.abs(N - S) / 2 * this.scale
}
// this.geoCenterY = S
// console.log({
// xoffset: width / 2.0 - width / 2 * this.scale,
// yoffset: height / 2.0 - height / 2 * this.scale
// })
},
toScreenPosition(longitude, latitude) {
// var xoffset=width/2.0-width/2*scale
// var yoffset=height/2.0-height/2*scale
return {
x: (longitude - this.geoCenter.W) * this.scale + this.geoCenter.xoffset,
y: (this.geoCenter.N - latitude) * this.scale + this.geoCenter.yoffset
}
},
initMap() {
const canvas = document.querySelector('#contain')
const ctx = canvas.getContext('2d')
const canvasW = canvas.width = window.innerWidth
const canvasH = canvas.height = window.innerHeight
ctx.clearRect(0, 0, canvasW, canvasH)
//
ctx.fillStyle = 'rgba(5,155,252,0.2)'
ctx.fillRect(0, 0, canvasW, canvasH)
ctx.beginPath()
ctx.strokeStyle = '#ffffff'
ctx.lineWidth = 4
this.allJSON[this.mapMap[this.mapType] + 'Json'].features.forEach(elem => {
// 线
const coordinates = elem.geometry.coordinates
// const centerX = canvasW / 2
// const centerY = canvasH / 2
ctx.save()
// ctx.beginPath()
// ctx.translate(centerX, centerY)
coordinates.forEach(multiPolygon => {
multiPolygon.forEach(polygon => {
for (let i = 0; i < polygon.length; i++) {
// console.log(polygon[i])
const position = this.toScreenPosition(polygon[i][0], polygon[i][1])
// console.log(position)
if (i === 0) {
ctx.moveTo(position.x, position.y)
} else {
ctx.lineTo(position.x, position.y)
}
}
})
})
})
ctx.closePath()
// ctx.strokeStyle = '#00cccc'
// ctx.lineWidth = 1
var gr = ctx.createLinearGradient(0, 0, 100, 100)
gr.addColorStop(0, 'RGBA(55,58,70,0.5)')
// gr.addColorStop(0.5, 'rgb(0,255,0)')
gr.addColorStop(1, 'RGBA(17,95,135,0.5)')
ctx.fillStyle = gr
ctx.fill()
ctx.stroke()
ctx.restore()
}
}
}
</script>
<style lang="scss" scoped>
.zone{
width: 100%;
height: 100%;
display: block;
}
.data-view {
position: absolute;
right: 0px;
border: 1px solid #3EDFFC;
padding: 0 10px;
margin: 10px;
background-color: #1a2d47ad;
bottom: 0;
font-size: 0.8rem;
p{
color: #DDDDDD;
text-indent: 1rem;
position: relative;
}
p:before{
content: '';
display: block;
width: 8px;
height: 8px;
border-radius: 8px;
background-color: #0fe765;
position: absolute;
left: 3px;
top: 3px;
}
p:nth-child(3):before{
background-color: #3EDFFC;
}
p:nth-child(4):before{
background-color: #f3ca45;
}
h5{font-weight: bold; font-size: 1rem; margin: 1rem 0}
}
#contain {
width: 100%;
height: 100%;
display: block;
}
</style>