Merge branch 'master' of https://gitlink.org.cn/JointCloud/JCC-RIP into cetc
|
@ -3,3 +3,4 @@ ENV = 'development'
|
|||
|
||||
# base api
|
||||
VUE_APP_BASE_API = '/jcc-ks'
|
||||
VUE_APP_PUBLIC_SOURCE_API = ''
|
||||
|
|
|
@ -3,4 +3,5 @@ ENV = 'production'
|
|||
|
||||
# base api
|
||||
VUE_APP_BASE_API = '/jcc-ks'
|
||||
VUE_APP_PUBLIC_SOURCE_API = '/monitor'
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
After Width: | Height: | Size: 976 KiB |
After Width: | Height: | Size: 596 KiB |
After Width: | Height: | Size: 1004 KiB |
After Width: | Height: | Size: 1.3 MiB |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 50 KiB |
|
@ -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",
|
||||
|
|
|
@ -97,7 +97,8 @@
|
|||
"dataSafe": "数据安全",
|
||||
"storageMana": "存储管理",
|
||||
"appObserve": "应用观测",
|
||||
"logMana": "日志管理"
|
||||
"logMana": "日志管理",
|
||||
"monitorSelectPcm": "材料AI云际计算平台"
|
||||
},
|
||||
"check": {
|
||||
"input": "请输入",
|
||||
|
|
After Width: | Height: | Size: 2.6 KiB |
|
@ -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 |
|
@ -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 |
|
@ -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 |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 6.5 KiB |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 45 KiB |
After Width: | Height: | Size: 107 KiB |
After Width: | Height: | Size: 98 KiB |
After Width: | Height: | Size: 287 KiB |
After Width: | Height: | Size: 273 KiB |
After Width: | Height: | Size: 9.3 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 1.2 MiB |
After Width: | Height: | Size: 1.3 MiB |
After Width: | Height: | Size: 6.0 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 161 KiB |
|
@ -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' })
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -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
|
||||
// 基于准备好的dom,初始化echarts实例
|
||||
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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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
|
||||
}]
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
// }
|
|
@ -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>
|
|
@ -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()
|
||||
// mesh默认在XOY平面上,法线方向沿着z轴new THREE.Vector3(0, 0, 1)
|
||||
var meshNormal = new Three.Vector3(0, 0, 1)
|
||||
// 四元数属性.quaternion表示mesh的角度状态
|
||||
// .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
|
||||
// 新建一个三维单位向量 假设z方向就是0.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()
|
||||
// mesh默认在XOY平面上,法线方向沿着z轴new THREE.Vector3(0, 0, 1)
|
||||
var meshNormal = new Three.Vector3(0, 0, 1)
|
||||
// 四元数属性.quaternion表示mesh的角度状态
|
||||
// .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>
|
||||
|
|
@ -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)
|
|
@ -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>
|