parent
e01e5bddc4
commit
132ea41f5b
8 changed files with 506 additions and 139 deletions
After Width: | Height: | Size: 52 KiB |
@ -0,0 +1,155 @@ |
|||||||
|
<template> |
||||||
|
<div :id="'3d-graph' + props.index"></div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script lang="ts" setup> |
||||||
|
// import { useRouter } from 'vue-router' |
||||||
|
import { onMounted, ref,reactive } from 'vue' |
||||||
|
import ForceGraph3D from '3d-force-graph' |
||||||
|
//@ts-ignore |
||||||
|
import { CSS2DRenderer, CSS2DObject,} from 'three/examples/jsm/renderers/CSS2DRenderer.js' |
||||||
|
//@ts-ignore |
||||||
|
import SpriteText from '../../professionalProfile/spritetext' |
||||||
|
// const $router = useRouter() |
||||||
|
// const jsonData = ref(null) |
||||||
|
let Graph = reactive({}) |
||||||
|
const props = defineProps({ |
||||||
|
width:{ |
||||||
|
type:Number, |
||||||
|
default:window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth, |
||||||
|
}, |
||||||
|
height:{ |
||||||
|
type:Number, |
||||||
|
default:window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight, |
||||||
|
}, |
||||||
|
index:{ |
||||||
|
type:Number, |
||||||
|
required:true |
||||||
|
} |
||||||
|
}) |
||||||
|
const dom = ref(null) |
||||||
|
onMounted(() => { |
||||||
|
|
||||||
|
|
||||||
|
Graph = ForceGraph3D({ |
||||||
|
extraRenderers: [new CSS2DRenderer()], |
||||||
|
})(document.getElementById('3d-graph' + props.index) as HTMLElement) |
||||||
|
.jsonUrl('../../../public/data.json') |
||||||
|
// .nodeAutoColorBy('group') |
||||||
|
.nodeThreeObject((node: any) => { |
||||||
|
const nodeEl = document.createElement('div') |
||||||
|
nodeEl.textContent = node.label |
||||||
|
nodeEl.style.color = '#333333' |
||||||
|
nodeEl.style.borderRadius = '50%' |
||||||
|
// console.log(node, 111, Graph.graphData().nodes) |
||||||
|
return new CSS2DObject(nodeEl) |
||||||
|
}) |
||||||
|
.linkLabel((link:any) => link.label) // 指定链接上显示的文字属性 |
||||||
|
.linkWidth(0.8) |
||||||
|
.linkHoverPrecision(0.5) // 设置链接文字的显示精度,这里设置为一个足够小的值 |
||||||
|
.linkColor(() => '#dd92fd') // 设置连接线颜色为红色 |
||||||
|
.backgroundColor('#f5f6fd') |
||||||
|
.width(props.width) |
||||||
|
.height(props.height) |
||||||
|
.linkThreeObjectExtend(true) |
||||||
|
.nodeColor((node: any) => { |
||||||
|
return node.color |
||||||
|
}) |
||||||
|
.nodeRelSize(7) // 设置节点的相对大小为4 |
||||||
|
.nodeResolution(20) |
||||||
|
.linkDirectionalArrowLength(3) // 设置连接线箭头长度为3 |
||||||
|
.linkDirectionalArrowRelPos(1) // 设置连接线箭头位置为连接线末端 |
||||||
|
.nodeThreeObjectExtend(true) |
||||||
|
.onNodeClick((node: any) => { |
||||||
|
// Aim at node from outside it |
||||||
|
// 目标距离 |
||||||
|
const targetDistance = 200 // 设定一个一般的距离 |
||||||
|
|
||||||
|
// 计算相机新位置 |
||||||
|
const distRatio = 1 + targetDistance / Math.hypot(node.x, node.y, node.z) |
||||||
|
const newPos = { |
||||||
|
x: node.x * distRatio, |
||||||
|
y: node.y * distRatio, |
||||||
|
z: node.z * distRatio, |
||||||
|
} |
||||||
|
|
||||||
|
// 如果节点位于原点,则特殊处理 |
||||||
|
if (node.x === 0 && node.y === 0 && node.z === 0) { |
||||||
|
newPos.z = targetDistance // 将 z 轴设定为目标距离 |
||||||
|
} |
||||||
|
|
||||||
|
// 移动相机至新位置 |
||||||
|
//@ts-ignore |
||||||
|
Graph.cameraPosition( |
||||||
|
newPos, // 新位置 |
||||||
|
node, // 视角焦点 |
||||||
|
3000, // 过渡时长 |
||||||
|
) |
||||||
|
|
||||||
|
// 获取图表数据 |
||||||
|
//@ts-ignore |
||||||
|
const graphData = Graph.graphData() |
||||||
|
|
||||||
|
// 遍历连接线,检查每条连接线的起点和终点是否与当前点击的节点相关联 |
||||||
|
graphData.links.forEach((link: any) => { |
||||||
|
// console.log(link); |
||||||
|
|
||||||
|
if (link.source.id === node.id || link.target.id === node.id) { |
||||||
|
setLabel() |
||||||
|
// 将与当前点击节点相关联的连接线颜色设置为红色 |
||||||
|
// link.color = '#FF0000' // 设置连接线颜色为红色 |
||||||
|
//@ts-ignore |
||||||
|
Graph.linkColor((item: any): any => { |
||||||
|
if (item.source.id === node.id || item.target.id === node.id) { |
||||||
|
return 'red' |
||||||
|
} else { |
||||||
|
return '#dd92fd' |
||||||
|
} |
||||||
|
|
||||||
|
}) |
||||||
|
} else { |
||||||
|
// Graph.linkColor(() => '#a4c7fe') // 设置连接线颜色为红色 |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
// 更新图形数据,以应用颜色变化 |
||||||
|
//@ts-ignore |
||||||
|
Graph.graphData(graphData) |
||||||
|
}) |
||||||
|
dom.value = document.querySelector('canvas') as any |
||||||
|
}) |
||||||
|
|
||||||
|
const setLabel = () => { |
||||||
|
//@ts-ignore |
||||||
|
Graph.linkThreeObject((link:any) => { |
||||||
|
// extend link with text sprite |
||||||
|
const sprite = new SpriteText(`${link.label}`); |
||||||
|
sprite.color = '#ccc'; |
||||||
|
sprite.textHeight = 1.5; |
||||||
|
return sprite; |
||||||
|
}) |
||||||
|
//@ts-ignore |
||||||
|
Graph.linkPositionUpdate((sprite, { start, end }) => { |
||||||
|
//@ts-ignore |
||||||
|
const middlePos = Object.assign(...['x', 'y', 'z'].map(c => ({ |
||||||
|
//@ts-ignore |
||||||
|
[c]: start[c] + (end[c] - start[c]) / 2 // calc middle point |
||||||
|
}))); |
||||||
|
|
||||||
|
// Position sprite |
||||||
|
Object.assign(sprite.position, middlePos); |
||||||
|
}); |
||||||
|
//@ts-ignore |
||||||
|
Graph.d3Force('charge').strength(-120); |
||||||
|
} |
||||||
|
// const goToEditAtlas = () => { |
||||||
|
// console.log(jsonData.value) |
||||||
|
|
||||||
|
// $router.push({ name: 'EditAtlas', params: { id: 123 } }) |
||||||
|
// } |
||||||
|
|
||||||
|
</script> |
||||||
|
|
||||||
|
<style lang='scss' scoped> |
||||||
|
|
||||||
|
</style> |
@ -0,0 +1,82 @@ |
|||||||
|
<template> |
||||||
|
<div class="view-container"> |
||||||
|
<div class="banner"></div> |
||||||
|
<div class="container"> |
||||||
|
<div class="top-video-box"> |
||||||
|
<div class="video"> |
||||||
|
<video id="video" width="100%" height="100%" controls> |
||||||
|
<source src="../../assets//videos/920b6703c5f95b9ff774f27abf5d4f29.mp4" type="video/mp4" /> |
||||||
|
您的浏览器不支持视频播放 |
||||||
|
</video> |
||||||
|
</div> |
||||||
|
<div class="info-list"></div> |
||||||
|
</div> |
||||||
|
<div class="title-container"> |
||||||
|
<div class="title">课程体系</div> |
||||||
|
<div class="description"> |
||||||
|
全面落实立德树人根本任务,CDIO工程教育理念 |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script lang="ts" setup> |
||||||
|
import {} from 'vue' |
||||||
|
</script> |
||||||
|
|
||||||
|
<style lang="scss" scoped> |
||||||
|
.view-container { |
||||||
|
height: 5000px; |
||||||
|
// background-color: #2080f7; |
||||||
|
.container { |
||||||
|
width: $base-container-width; |
||||||
|
margin: 0 auto; |
||||||
|
padding-top: 300px; |
||||||
|
.top-video-box { |
||||||
|
position: absolute; |
||||||
|
top: 120px; |
||||||
|
display: flex; |
||||||
|
height: 545px; |
||||||
|
justify-content: space-between; |
||||||
|
.video { |
||||||
|
width: 1073px; |
||||||
|
height: 100%; |
||||||
|
background-color: #d9d9d9; |
||||||
|
#video{ |
||||||
|
object-fit: cover; |
||||||
|
} |
||||||
|
} |
||||||
|
.info-list { |
||||||
|
margin-left: 20px; |
||||||
|
width: 519px; |
||||||
|
background-color: #fff; |
||||||
|
} |
||||||
|
} |
||||||
|
.title-container { |
||||||
|
width: 100%; |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
align-items: center; |
||||||
|
justify-content: center; |
||||||
|
height: 300px; |
||||||
|
.title { |
||||||
|
color: #333333; |
||||||
|
font-size: 42px; |
||||||
|
font-weight: 700; |
||||||
|
} |
||||||
|
.description { |
||||||
|
margin-top: 30px; |
||||||
|
color: #777777; |
||||||
|
font-size: 20px; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
.banner { |
||||||
|
width: 100%; |
||||||
|
height: 410px; |
||||||
|
background: url('../../assets/images/banner2.png') no-repeat; |
||||||
|
background-size: cover; |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
Loading…
Reference in new issue