Merge branch 'bigevent' into master

This commit is contained in:
changyunju 2025-06-25 16:37:33 +08:00
commit 111bedc3f0
14 changed files with 1207 additions and 548 deletions

View File

@ -2,15 +2,15 @@
<div class="app-container">
<header class="el-header">
<div>
<img src="./assets/images/head.png" alt="" style="width: 100%;height: 100%;">
<img src="./assets/images/head.png" alt="" style="width: 100%; height: 100%" />
<div>
<!-- 转换为按钮添加点击事件 -->
<button
<!-- <button
style="
width: 110px;
height: 34px;
border: 2px solid;
border-image:linear-gradient(to bottom, #C9E4FF, #0783FA00) 0;
border-image: linear-gradient(to bottom, #c9e4ff, #0783fa00) 0;
margin-left: 800px;
margin-top: -140px;
position: absolute;
@ -20,14 +20,18 @@
"
@click="showToggleJianjie = true"
>
<img src="./assets/images/shijianjianjie.png" alt="" style=" width: 100%; height: 100%; object-fit: cover;">
</button>
<button
<img
src="./assets/images/shijianjianjie.png"
alt=""
style="width: 100%; height: 100%; object-fit: cover"
/>
</button> -->
<!-- <button
style="
width: 111px;
height: 34px;
border: 2px solid;
border-image:linear-gradient(to bottom, #C9E4FF, #0783FA00) 0;
border-image: linear-gradient(to bottom, #c9e4ff, #0783fa00) 0;
margin-left: 950px;
margin-top: -140px;
position: absolute;
@ -37,53 +41,79 @@
"
@click="showToggleJianjie = false"
>
<img src="./assets/images/zhanshidaping.png" alt="" style=" width: 100%; height: 100%; object-fit: cover;">
</button>
<img
src="./assets/images/zhanshidaping.png"
alt=""
style="width: 100%; height: 100%; object-fit: cover"
/>
</button> -->
<!-- 根据状态控制显示 -->
<div
class="toogle-jianjie"
v-if="showToggleJianjie"
>
<img src="./assets/images/toogle-pei.png" alt="" style="width: 640px;margin-left: 640px;margin-top: 176px;">
<img src="./assets/images/cancel.png" alt="" style="margin-left: -40px;margin-bottom: 159px;cursor: pointer;"
@click="showToggleJianjie = false">
<div class="toogle-jianjie" v-if="showToggleJianjie">
<img
src="./assets/images/toogle-pei.png"
alt=""
style="width: 640px; margin-left: 640px; margin-top: 176px"
/>
<img
src="./assets/images/cancel.png"
alt=""
style="margin-left: -40px; margin-bottom: 159px; cursor: pointer"
@click="showToggleJianjie = false"
/>
</div>
</div>
</div>
</header>
<aside class="el-aside">
<nav class="el-menu">
<aside class="aside">
<nav class="menu">
<!-- 手动生成第一个菜单项 -->
<div key="1" class="el-sub-menu">
<div class="menu-title">
<div class="tltlemenu-left">
<img src="./assets/images/titlelogo.png" alt="" style="width: 20px;height: 20px;margin-right: 12px; ">
<img
src="./assets/images/titlelogo.png"
alt=""
style="width: 20px; height: 20px; margin-right: 12px"
/>
{{ menuItems[0].title }}
</div>
<img src="./assets/images/titleright.png" alt="" style="width: 66px;height: 16px;">
<img src="./assets/images/titleright.png" alt="" style="width: 66px; height: 16px" />
</div>
<ul class="sub-menu-items">
<router-link :to="menuItems[0].subItems[0].index" style="text-decoration:none;">
<li key="/key-node-1" class="el-menu-item"
:class="{ 'active': isActive(menuItems[0].subItems[0].index) }">
<ul class="menu-items">
<router-link :to="menuItems[0].subItems[0].index" style="text-decoration: none">
<li
key="/key-node-1"
class="el-menu-item"
:class="{ active: isActive(menuItems[0].subItems[0].index) }"
>
<!-- 修改为 router-link -->
<router-link :to="menuItems[0].subItems[0].index">
{{ menuItems[0].subItems[0].title }}
</router-link>
</li>
</router-link>
<router-link :to="menuItems[0].subItems[1].index" style="text-decoration:none;">
<li key="/key-node-2" class="el-menu-item"
:class="{ 'active': isActive(menuItems[0].subItems[1].index) }">
<router-link :to="menuItems[0].subItems[1].index" style="text-decoration: none">
<li
key="/key-node-2"
class="el-menu-item"
:class="{ active: isActive(menuItems[0].subItems[1].index) }"
>
<!-- 修改为 router-link -->
<router-link :to="menuItems[0].subItems[1].index">{{ menuItems[0].subItems[1].title }}</router-link>
<router-link :to="menuItems[0].subItems[1].index">{{
menuItems[0].subItems[1].title
}}</router-link>
</li>
</router-link>
<router-link :to="menuItems[0].subItems[1].index" style="text-decoration:none;">
<li key="/key-node-3" class="el-menu-item"
:class="{ 'active': isActive(menuItems[0].subItems[2].index) }">
<router-link :to="menuItems[0].subItems[1].index" style="text-decoration: none">
<li
key="/key-node-3"
class="el-menu-item"
:class="{ active: isActive(menuItems[0].subItems[2].index) }"
>
<!-- 修改为 router-link -->
<router-link :to="menuItems[0].subItems[2].index">{{ menuItems[0].subItems[2].title }}</router-link>
<router-link :to="menuItems[0].subItems[2].index">{{
menuItems[0].subItems[2].title
}}</router-link>
</li>
</router-link>
</ul>
@ -92,31 +122,50 @@
<div key="2" class="el-sub-menu">
<div class="menu-title">
<div class="tltlemenu-left">
<img src="./assets/images/search.png" alt="" style="width: 20px;height: 20px;margin-right: 12px; ">
<img
src="./assets/images/search.png"
alt=""
style="width: 20px; height: 20px; margin-right: 12px"
/>
{{ menuItems[1].title }}
</div>
<img src="./assets/images/titleright.png" alt="" style="width: 66px;height: 16px;">
<img src="./assets/images/titleright.png" alt="" style="width: 66px; height: 16px" />
</div>
<ul class="sub-menu-items">
<router-link :to="menuItems[1].subItems[0].index" style="text-decoration:none;">
<li key="/link-prediction-1" class="el-menu-item"
:class="{ 'active': isActive(menuItems[1].subItems[0].index) }">
<router-link :to="menuItems[1].subItems[0].index" style="text-decoration: none">
<li
key="/link-prediction-1"
class="el-menu-item"
:class="{ active: isActive(menuItems[1].subItems[0].index) }"
>
<!-- 修改为 router-link -->
<router-link :to="menuItems[1].subItems[0].index">{{ menuItems[1].subItems[0].title }}</router-link>
<router-link :to="menuItems[1].subItems[0].index">{{
menuItems[1].subItems[0].title
}}</router-link>
</li>
</router-link>
<router-link :to="menuItems[1].subItems[1].index" style="text-decoration:none;">
<li key="/link-prediction-2" class="el-menu-item"
:class="{ 'active': isActive(menuItems[1].subItems[1].index) }">
<router-link :to="menuItems[1].subItems[1].index" style="text-decoration: none">
<li
key="/link-prediction-2"
class="el-menu-item"
:class="{ active: isActive(menuItems[1].subItems[1].index) }"
>
<!-- 修改为 router-link -->
<router-link :to="menuItems[1].subItems[1].index">{{ menuItems[1].subItems[1].title }}</router-link>
<router-link :to="menuItems[1].subItems[1].index">{{
menuItems[1].subItems[1].title
}}</router-link>
</li>
</router-link>
<router-link :to="menuItems[1].subItems[2].index" style="text-decoration:none;">
<li key="/link-prediction-3" class="el-menu-item"
:class="{ 'active': isActive(menuItems[1].subItems[2].index) }">
<router-link :to="menuItems[1].subItems[2].index" style="text-decoration: none">
<li
key="/link-prediction-3"
class="el-menu-item"
:class="{ active: isActive(menuItems[1].subItems[2].index) }"
>
<!-- 修改为 router-link -->
<router-link :to="menuItems[1].subItems[2].index">{{ menuItems[1].subItems[2].title }}</router-link>
<router-link :to="menuItems[1].subItems[2].index">{{
menuItems[1].subItems[2].title
}}</router-link>
</li>
</router-link>
</ul>
@ -125,38 +174,62 @@
<div key="3" class="el-sub-menu">
<div class="menu-title">
<div class="tltlemenu-left">
<img src="./assets/images/quntiyanhua.png" alt="" style="width: 20px;height: 20px;margin-right: 12px; ">
<img
src="./assets/images/quntiyanhua.png"
alt=""
style="width: 20px; height: 20px; margin-right: 12px"
/>
{{ menuItems[2].title }}
</div>
<img src="./assets/images/titleright.png" alt="" style="width: 66px;height: 16px;">
<img src="./assets/images/titleright.png" alt="" style="width: 66px; height: 16px" />
</div>
<ul class="sub-menu-items">
<router-link :to="menuItems[2].subItems[0].index" style="text-decoration:none;">
<li key="/group-evolution-1" class="el-menu-item"
:class="{ 'active': isActive(menuItems[2].subItems[0].index) }">
<router-link :to="menuItems[2].subItems[0].index" style="text-decoration: none">
<li
key="/group-evolution-1"
class="el-menu-item"
:class="{ active: isActive(menuItems[2].subItems[0].index) }"
>
<!-- 修改为 router-link -->
<router-link :to="menuItems[2].subItems[0].index">{{ menuItems[2].subItems[0].title }}</router-link>
<router-link :to="menuItems[2].subItems[0].index">{{
menuItems[2].subItems[0].title
}}</router-link>
</li>
</router-link>
<router-link :to="menuItems[2].subItems[1].index" style="text-decoration:none;">
<li key="/group-evolution-2" class="el-menu-item"
:class="{ 'active': isActive(menuItems[2].subItems[1].index) }">
<router-link :to="menuItems[2].subItems[1].index" style="text-decoration: none">
<li
key="/group-evolution-2"
class="el-menu-item"
:class="{ active: isActive(menuItems[2].subItems[1].index) }"
>
<!-- 修改为 router-link -->
<router-link :to="menuItems[2].subItems[1].index">{{ menuItems[2].subItems[1].title }}</router-link>
<router-link :to="menuItems[2].subItems[1].index">{{
menuItems[2].subItems[1].title
}}</router-link>
</li>
</router-link>
<router-link :to="menuItems[2].subItems[2].index" style="text-decoration:none;">
<li key="/group-evolution-3" class="el-menu-item"
:class="{ 'active': isActive(menuItems[2].subItems[2].index) }">
<router-link :to="menuItems[2].subItems[2].index" style="text-decoration: none">
<li
key="/group-evolution-3"
class="el-menu-item"
:class="{ active: isActive(menuItems[2].subItems[2].index) }"
>
<!-- 修改为 router-link -->
<router-link :to="menuItems[2].subItems[2].index">{{ menuItems[2].subItems[2].title }}</router-link>
<router-link :to="menuItems[2].subItems[2].index">{{
menuItems[2].subItems[2].title
}}</router-link>
</li>
</router-link>
<router-link :to="menuItems[2].subItems[3].index" style="text-decoration:none;">
<li key="/group-evolution-4" class="el-menu-item"
:class="{ 'active': isActive(menuItems[2].subItems[3].index) }">
<router-link :to="menuItems[2].subItems[3].index" style="text-decoration: none">
<li
key="/group-evolution-4"
class="el-menu-item"
:class="{ active: isActive(menuItems[2].subItems[3].index) }"
>
<!-- 修改为 router-link -->
<router-link :to="menuItems[2].subItems[3].index">{{ menuItems[2].subItems[3].title }}</router-link>
<router-link :to="menuItems[2].subItems[3].index">{{
menuItems[2].subItems[3].title
}}</router-link>
</li>
</router-link>
</ul>
@ -171,39 +244,39 @@
</template>
<script setup>
import { ref } from 'vue';
import { useRoute } from 'vue-router';
import { ref } from "vue";
import { useRoute } from "vue-router";
const route = useRoute();
const menuItems = [
{
index: '1',
title: '关键节点识别',
index: "1",
title: "关键节点识别",
subItems: [
{ index: '/key-node-1', title: '传播意见领袖识别' },
{ index: '/key-node-2', title: '传播桥梁节点识别' },
{ index: '/key-node-3', title: '重大舆情事件锚点推荐' },
],
{ index: "/key-node-1", title: "传播意见领袖识别" },
{ index: "/key-node-2", title: "传播桥梁节点识别" },
{ index: "/key-node-3", title: "重大舆情事件锚点推荐" }
]
},
{
index: '2',
title: '链路预测',
index: "2",
title: "链路预测",
subItems: [
{ index: '/link-prediction-1', title: '人物互动隐关系预测' },
{ index: '/link-prediction-2', title: '社交紧密团体识别' },
{ index: '/link-prediction-3', title: '人物社交隐关系预测' },
],
{ index: "/link-prediction-1", title: "人物互动隐关系预测" },
{ index: "/link-prediction-2", title: "社交紧密团体识别" },
{ index: "/link-prediction-3", title: "人物社交隐关系预测" }
]
},
{
index: '3',
title: '群体演化分析',
index: "3",
title: "群体演化分析",
subItems: [
{ index: '/group-evolution-1', title: '群体识别发现' },
{ index: '/group-evolution-2', title: '群体结构演化分析' },
{ index: '/group-evolution-3', title: '群体成员演化分析' },
{ index: '/group-evolution-4', title: '异常群体捕捉' },
],
},
{ index: "/group-evolution-1", title: "群体识别发现" },
{ index: "/group-evolution-2", title: "群体结构演化分析" },
{ index: "/group-evolution-3", title: "群体成员演化分析" },
{ index: "/group-evolution-4", title: "异常群体捕捉" }
]
}
];
//
@ -217,30 +290,30 @@ const showToggleJianjie = ref(false);
<style scoped>
.app-container {
width: 1920px;
width: 100vw;
height: 1080px;
background-image: url('./assets/images/bci.png');
background-image: url("./assets/images/bci.png");
background-size: cover;
background-repeat: no-repeat;
background-position: center;
background-color: #02131F;
background-color: #02131f;
}
.el-header {
width: 100%;
height: 100px;
}
.toogle-jianjie{
.toogle-jianjie {
top: 0;
left: 0;
right: 0;
bottom: 0;
position: fixed;
z-index: 9999;
position: fixed;
z-index: 9999;
backdrop-filter: blur(4px);
background-color: rgba(0, 0, 0, 0.7);
background-color: rgba(0, 0, 0, 0.7);
}
.el-aside {
.aside {
width: 320px;
height: 944px;
border: 2px;
@ -251,16 +324,16 @@ const showToggleJianjie = ref(false);
position: absolute;
}
.el-menu {
.menu {
width: 320px;
height: 100%;
border-width: 2px;
border-style: solid;
border-image: linear-gradient(to bottom, #3AA1F8, #3AA1F833) 1;
background-image: linear-gradient(to right, #063D7133, #081E38CC);
border-image: linear-gradient(to bottom, #3aa1f8, #3aa1f833) 1;
background-image: linear-gradient(to right, #063d7133, #081e38cc);
}
.el-sub-menu {
.sub-menu {
width: 288px;
height: 176px;
}
@ -272,15 +345,15 @@ const showToggleJianjie = ref(false);
border-radius: 2px;
margin-top: 16px;
margin-left: 16px;
background-image: linear-gradient(to right, #18395C, #3378C200);
border-image: linear-gradient(to right, #225F9200, #3AA1F8) 1;
background-image: linear-gradient(to right, #18395c, #3378c200);
border-image: linear-gradient(to right, #225f9200, #3aa1f8) 1;
display: flex;
align-items: center;
justify-content: space-between;
}
.menu-title:hover {
background-image: linear-gradient(to right, #0876BE, #0EA7D500);
background-image: linear-gradient(to right, #0876be, #0ea7d500);
}
.el-menu-item {
@ -292,14 +365,13 @@ const showToggleJianjie = ref(false);
}
.el-menu-item.active {
background-image: linear-gradient(to right, #0876BE, #0EA7D500);
background-image: linear-gradient(to right, #0876be, #0ea7d500);
/* 可以添加其他样式,如文字颜色等 */
}
.tltlemenu-left {
display: flex;
align-items: center;
}
.sub-menu-items {
@ -324,7 +396,7 @@ const showToggleJianjie = ref(false);
}
.el-menu-item:hover {
background-image: linear-gradient(to right, #0876BE, #0EA7D500);
background-image: linear-gradient(to right, #0876be, #0ea7d500);
}
.main {

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
src/assets/images/point.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

View File

@ -0,0 +1,67 @@
/* src/assets/styles/reset.css */
/* 常用的现代 CSS Reset */
:where(:root) {
line-height: 1.5;
-webkit-text-size-adjust: 100%;
}
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
:where(html) {
-moz-tab-size: 4;
tab-size: 4;
}
:where(body) {
font-family:
system-ui,
-apple-system,
sans-serif;
}
:where(a) {
background-color: transparent;
color: inherit;
text-decoration: none;
}
:where(img, picture, svg, video, canvas) {
display: block;
max-width: 100%;
}
/* 移除列表默认样式 */
:where(ul, ol) {
list-style: none;
}
/* 表单元素重置 */
:where(input, button, textarea, select) {
font: inherit;
color: inherit;
border: none;
background: none;
}
/* 表格重置 */
:where(table) {
border-collapse: collapse;
border-spacing: 0;
}
/* 隐藏不可见但可访问的元素 */
:where([hidden]) {
display: none !important;
}
/* 现代 focus 样式 */
:focus-visible {
outline: 2px solid currentColor;
outline-offset: 2px;
}

View File

@ -1,10 +1,12 @@
import { createApp } from 'vue'
import App from './App.vue'
import ElementPlus from 'element-plus'
import { createApp } from "vue";
import App from "./App.vue";
import ElementPlus from "element-plus";
import "./assets/style/reset.css";
import "element-plus/dist/index.css"; // 导入所有样式
import router from './router'
import router from "./router";
const app = createApp(App)
app.use(ElementPlus)
app.use(router)
app.mount('#app')
const app = createApp(App);
app.use(ElementPlus);
app.use(router);
app.mount("#app");

View File

30
src/utils/generateNode.js Normal file
View File

@ -0,0 +1,30 @@
export function generateNonOverlappingNodes(count, width, height, minDist) {
const nodes = [];
let tryCount = 0;
for (let i = 0; i < count; i++) {
let valid = false;
let x, y;
while (!valid && tryCount < 1000) {
x = Math.random() * (width - minDist) + minDist / 2;
y = Math.random() * (height - minDist) + minDist / 2;
valid = true;
for (const node of nodes) {
const dx = node.x - x;
const dy = node.y - y;
if (Math.sqrt(dx * dx + dy * dy) < minDist) {
valid = false;
break;
}
}
tryCount++;
}
nodes.push({
id: `user_${i}`,
name: `User ${i}`,
x,
y,
category: 1
});
}
return nodes;
}

View File

@ -9,7 +9,7 @@
<div class="leader-containner1">
<!-- 区域1: 意见领袖列表 -->
<div class="left-panel">
<h2 class="panel-title">意见领袖抽展示</h2>
<img src="../assets/images/leaderTitle.png" alt="" />
<div class="tabs">
<button
v-for="tab in tabs"
@ -81,7 +81,7 @@
</svg>
</div>
<div class="content-wrapper">
<h1 class="graph-title">佩洛西系列事件</h1>
<img src="../assets/images/graphTitle.png" alt="" />
<div ref="chartContainer" class="chart-container"></div>
<div class="timeline-container">
<span class="time-label">2022.07.31 00:00:00</span>
@ -121,6 +121,10 @@
<div ref="detailsChart" class="details-chart-container"></div>
</div>
</div>
<el-dialog v-model="leaderDetailDialog" width="500" align-center>
<span>Open the dialog from the center from the screen</span>
</el-dialog>
</div>
</template>
@ -132,6 +136,7 @@ import { TitleComponent, TooltipComponent } from "echarts/components";
import { CanvasRenderer } from "echarts/renderers";
import { SVGRenderer } from "echarts/renderers";
import { cropImageToCircle } from "@/utils/transform"; //
import { generateNonOverlappingNodes } from "../utils/generateNode";
echarts.use([TitleComponent, TooltipComponent, GraphChart, SVGRenderer]);
const allGraphNodes = ref([]);
//
@ -145,6 +150,7 @@ import WordCloud from "./KeyNodeRecognition1/WordCloud.vue";
// ===================================================================
const activeTimePoint = ref(1);
const timePoints = ref(Array.from({ length: 10 }, (_, i) => ({ id: i + 1 })));
const leaderDetailDialog = ref(false);
// [] 10
const allLeaderData = ref([
@ -155,7 +161,29 @@ const allLeaderData = ref([
followers: "53.8万",
posts: "54",
avatar: new URL("@/assets/images/huxijin.png", import.meta.url).toString(),
category: "自媒体"
category: "自媒体",
labelling: [
{
id: 1,
like: "3935",
comment: "1727",
transmit: "842",
time: "2022-8-1 23:11:01",
type: "原发",
content:
"1.Where is Pelosi now, does anybody know? Some said that she will be going to Taiwan by a submarine instead, and others said that she has sneaked into Taiwan disguised as someone else, is that the case?"
},
{
id: 2,
like: "2827",
comment: "1350",
transmit: "1115",
time: "2022-8-2 00:12:01",
type: "原发",
content:
"If Pelosi really visits Taiwan as planned, the Tsai Ing-wen authorities are accomplice. The mainland will definitely carry out severe punishment actions on Taiwan at the same time. The unbearable consequences will fall on Tsai authorities."
}
]
},
{
id: "bidishalolo",
@ -164,7 +192,19 @@ const allLeaderData = ref([
followers: "2387",
posts: "8380",
avatar: new URL("@/assets/images/bidishalolo.png", import.meta.url).toString(),
category: "自媒体"
category: "自媒体",
labelling: [
{
id: 1,
like: "5013",
comment: "247",
transmit: "1376",
time: "2022-8-1 17:26:46",
type: "原发",
content:
"BREAKING: #Pelosi seen flying over #Taiwan. Stunning footage... https://t.co/8AOJ6yMPvl"
}
]
},
{
id: "indopacific",
@ -173,7 +213,29 @@ const allLeaderData = ref([
followers: "11.5万",
posts: "11.3万",
avatar: new URL("@/assets/images/indo.png", import.meta.url).toString(),
category: "新闻媒体"
category: "新闻媒体",
labelling: [
{
id: 1,
like: "2466",
comment: "89",
transmit: "938",
time: "2022-08-02 04:02:24",
type: "原发",
content:
"The US is moving planes and aircraft carriers closer to #Taiwan due to the upcoming visit of House Speaker Nancy Pelosi to Taiwan - Nikkei Asia\n\nThe #USNavy has 2 aircraft carrier groups &amp; 2 amphibious assault groups in the region, plus other assets based in #Japan, Hawaii &amp; Guam https://t.co/L0eEr3px5N"
},
{
id: 2,
like: "2506",
comment: "128",
transmit: "658",
time: "2022-8-2 02:39:49",
type: "原发",
content:
"Nancy Pelosis #Taiwan Itinerary Confirmed by Local Media\n\nPelosi will touch down in Taipei Tuesday night and is going to spend the evening at the Grand Hyatt Hotel, local media said.\n\nPelosi will then visit Taiwans parliament Wednesday morning where she will meet Tsai Ing-Wen. https://t.co/Bu7VPkd9yK"
}
]
},
{
id: "spectator",
@ -182,7 +244,28 @@ const allLeaderData = ref([
followers: "233.5万",
posts: "56",
avatar: new URL("@/assets/images/spectator.png", import.meta.url).toString(),
category: "新闻媒体"
category: "新闻媒体",
labelling: [
{
id: 1,
like: "12118",
comment: "623",
transmit: "3731",
time: "2022-8-2 03:21:04",
type: "原发",
content: "BREAKING: CNN reports US House Speaker Nancy Pelosi will visit Taiwan"
},
{
id: 2,
like: "6238",
comment: "409",
transmit: "1698",
time: "2022-8-1 22:56:59",
type: "原发",
content:
"BREAKING: Press release by US House Speaker Pelosi lists she will visit Singapore, Malaysia, South Korea and Japan on upcoming trip, without mention of Taiwan."
}
]
},
{
id: "mickwallace",
@ -191,7 +274,28 @@ const allLeaderData = ref([
followers: "24.8万",
posts: "10259",
avatar: new URL("@/assets/images/mick.png", import.meta.url).toString(),
category: "自媒体"
category: "自媒体",
labelling: [
{
id: 1,
like: "5354",
comment: "155",
transmit: "1410",
time: "2022-8-1 17:56:56",
type: "引用",
content: "BREAKING : Pelosi seen flying over Taiwan https://t.co/VQdm88KVeU"
},
{
id: 2,
like: "2254",
comment: "168",
transmit: "428",
time: "2022-8-1 10:55:50",
type: "二级转发",
content:
"If #Pelosi visits Taiwan to selfishly promote herself while knowingly undermining Peace and Security in the Region,she will be remembered as a disappointing piece of work..."
}
]
},
{
id: "reuters",
@ -200,7 +304,29 @@ const allLeaderData = ref([
followers: "2575.7万",
posts: "98",
avatar: new URL("@/assets/images/reuters.png", import.meta.url).toString(),
category: "新闻媒体"
category: "新闻媒体",
labelling: [
{
id: 1,
like: "1786",
comment: "362",
transmit: "741",
time: "2022-8-2 03:41:57",
type: "原发",
content:
"1.U.S. House Speaker Pelosi to visit Taiwan on Tuesday -Taiwan media https://t.co/UWXopyKO5I https://t.co/KIoLpCFfXf"
},
{
id: 2,
like: "277",
comment: "266",
transmit: "132",
time: "2022-8-2 14:04:22",
type: "原发",
content:
"U.S. looking to China not to escalate tensions in event of Pelosi visit to Taiwan -Blinken https://t.co/CPdyuIbA88 https://t.co/sKhaWTyS4p"
}
]
},
{
id: "jiushiniya",
@ -209,7 +335,29 @@ const allLeaderData = ref([
followers: "557",
posts: "16020",
avatar: new URL("@/assets/images/jiushiniya.png", import.meta.url).toString(),
category: "自媒体"
category: "自媒体",
labelling: [
{
id: 1,
like: "3336",
comment: "135",
transmit: "1197",
time: "2022-8-2 15:33:45",
type: "引用",
content:
"House Speaker Nancy Pelosi is going to Taiwan as a show of US support for Taiwans independence. Trump holds a secret Chinese bank account &amp; Ivanka owns patents on Chinese Coffins &amp; Body Bags. Democrats are tough on China. Republicans invest in China. MAGA hats are made in China"
},
{
id: 2,
like: "2405",
comment: "140",
transmit: "669",
time: "2022-8-2 02:48:07",
type: "引用",
content:
"BREAKING:\n\nCNN confirms Speaker of the House, Nancy Pelosi, will travel to Taiwan.\n\nTaiwanese sources say she will arrive tomorrow.\n\nPelosi will be the highest-ranking American to visit Taiwan in 25 years.\n\nThe island is the nod in the First Island Chain that is closest to China. https://t.co/wTjBnm0zpv"
}
]
},
{
id: "levi_godman",
@ -218,7 +366,28 @@ const allLeaderData = ref([
followers: "4.6万",
posts: "12847",
avatar: new URL("@/assets/images/levi.png", import.meta.url).toString(),
category: "自媒体"
category: "自媒体",
labelling: [
{
id: 1,
like: "5354",
comment: "155",
transmit: "1410",
time: "2022-8-1 17:56:56",
type: "原发",
content: "BREAKING : Pelosi seen flying over Taiwan https://t.co/VQdm88KVeU"
},
{
id: 2,
like: "469",
comment: "41",
transmit: "163",
time: "2022-8-2 04:39:53",
type: "原发",
content:
"The Taiwanese press writes that tomorrow Pelosi will arrive in Taipei at around 17.30 Moscow time (22.30 local time), spend the night at the Grand Hyatt Hotel, and the next morning will visit the Taiwan Legislative Council, where she will meet with the leadership of the island"
}
]
},
{
id: "liuxiaoming",
@ -227,7 +396,29 @@ const allLeaderData = ref([
followers: "33.8万",
posts: "8757",
avatar: new URL("@/assets/images/liuxiaoming.png", import.meta.url).toString(),
category: "自媒体"
category: "自媒体",
labelling: [
{
id: 1,
like: "6545",
comment: "1561",
transmit: "1062",
time: "2022-8-2 19:48:22",
type: "原发",
content:
"我们正告美方,中方正严阵以待,中国人民解放军绝不会坐视不管,必将采取坚决应对和有力反制措施,捍卫中国主权和领土完整。美方应该做的是恪守一个中国原则和中美三个联合公报规定,兑现拜登总统不支持“台独”的承诺,不安排佩洛西访问台湾。"
},
{
id: 2,
like: "5261",
comment: "1602",
transmit: "1741",
time: "2022-8-2 13:44:38",
type: "原发",
content:
"We are closely following the itinerary of #Pelosi. A visit to #Taiwan by her would constitute a gross interference in #Chinas internal affairs, seriously undermine Chinas sovereignty and territorial integrity, wantonly trample on the #one-China principle."
}
]
},
{
id: "indobosss",
@ -236,7 +427,29 @@ const allLeaderData = ref([
followers: "32",
posts: "1403",
avatar: new URL("@/assets/images/indobosss.png", import.meta.url).toString(),
category: "自媒体"
category: "自媒体",
labelling: [
{
id: 1,
like: "1310",
comment: "60",
transmit: "300",
time: "2022-8-1 21:55:31",
type: "引用",
content:
"Taiwan is China. \n\nThe UN says so. \n\nThe U.S. and China have said so in three different joint communiques.\n\nIt's called the One-China policy and Nancy Pelosi has gone full neocon to violate it."
},
{
id: 2,
like: "555",
comment: "123",
transmit: "204",
time: "2022-8-1 21:55:31",
type: "引用",
content:
"US House Speaker Nancy #Pelosi office officially announced her itinerary to Asia on Sunday. It said Pelosi will lead a Congressional delegation to the Indo-Pacific region, including visits to Singapore, Malaysia, South Korea and Japan, Chinas #Taiwan was not mentioned. https://t.co/AK6X0lm8OU"
}
]
}
]);
@ -285,7 +498,7 @@ const chartOptions = {
categories: [
{
name: "Leader",
symbolSize: 70,
symbolSize: 50,
itemStyle: {
borderColor: "rgba(0, 191, 255, 0.8)",
borderWidth: 3,
@ -318,13 +531,16 @@ const formatAllGraphNodes = async () => {
y: Math.random() * 600
};
const base64_res = await cropImageToCircle(leader.avatar, 50);
const node = {
id: leader.id,
name: leader.name,
symbol: `image://${base64_res}`,
category: 0,
leaderOriginInfo: leader,
...coords
};
if (leader.id === "mickwallace") {
node.itemStyle = {
borderColor: "rgba(255, 220, 0, 0.9)",
@ -335,27 +551,29 @@ const formatAllGraphNodes = async () => {
return node;
})
);
const userNodes = Array.from({ length: 40 }, (_, i) => ({
id: `user_${i}`,
name: `User ${i}`,
x: Math.random() * 1000,
y: Math.random() * 600,
category: 1
}));
const userNodes = generateNonOverlappingNodes(40, 1000, 600, 60); // 60
allGraphNodes.value = [...tempResLeaderData, ...userNodes];
};
// []
const allGraphLinks = computed(() => [
{ source: "reuters", target: "spectator" },
{ source: "reuters", target: "indopacific" },
{ source: "liuxiaoming", target: "huxijin" },
{ source: "huxijin", target: "mickwallace" },
{ source: "spectator", target: "liuxiaoming" },
{ source: "jiushiniya", target: "levi_godman" },
{ source: "bidishalolo", target: "indobosss" }
//...
]);
const allGraphLinks = computed(() => {
const leaders = allGraphNodes.value.filter((node) => node.category === 0);
const users = allGraphNodes.value.filter((node) => node.category === 1);
const randomLinks = [];
leaders.forEach((leader) => {
//
const shuffled = users.slice().sort(() => Math.random() - 0.5);
//
shuffled.slice(0, 3).forEach((user) => {
randomLinks.push({
source: leader.id,
target: user.id
});
});
});
return randomLinks;
});
// ===================================================================
//
@ -445,7 +663,31 @@ const closeDetailsModal = () => {
myDetailsChart = null;
}
};
//
let timer = null;
const automaticPlay = () => {
let index = 1;
if (timer) clearInterval(timer);
timer = setInterval(() => {
onTimePointClick(index);
if (index == allLeaderData.value.length) {
clearInterval(timer);
timer = null;
return;
}
index++;
}, 1500);
};
//leader
const monitoringNode = (myChart) => {
myChart.on("click", (params) => {
//
if (params.data && params.data.category === 0) {
leaderDetailDialog.value = true;
console.log(params);
}
});
};
// ===================================================================
//
// ===================================================================
@ -469,6 +711,8 @@ onMounted(async () => {
});
window.addEventListener("resize", myChart.resize);
}
monitoringNode(myChart);
automaticPlay();
});
onUnmounted(() => {
@ -552,7 +796,7 @@ onUnmounted(() => {
}
.leader-list {
width: 100%;
height: 410px;
height: 310px;
flex-grow: 1;
overflow: auto;
scrollbar-width: none;
@ -695,13 +939,13 @@ onUnmounted(() => {
transform: scale(1.3);
}
.active-pin {
width: 20px;
height: 24px;
background-image: url('data:image/svg+xml;utf8,<svg width="20" height="24" viewBox="0 0 20 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M10 24L15 14H5L10 24Z" fill="%23FFC94D"/><path d="M1.5 8C1.5 4.41015 4.41015 1.5 8 1.5H12C15.5899 1.5 18.5 4.41015 18.5 8V11C18.5 12.6569 17.1569 14 15.5 14H4.5C2.84315 14 1.5 12.6569 1.5 11V8Z" fill="%23FFC94D" stroke="white"/></svg>');
position: absolute;
width: 30px;
height: 34px;
background-image: url("../assets/images/point.png");
background-size: cover;
bottom: 5px;
left: 50%;
transform: translateX(-50%);
left: -11px;
position: absolute;
}
.modal-overlay {
position: fixed;

View File

@ -1,55 +1,86 @@
<template>
<div class="panel-container event-hot">
<!-- 1. 标题行 -->
<div class="header-title">
<img src="../../assets/images/evenhot.png" alt="" style="margin-top: -6px;">
</div>
<!-- 2. 控件行 -->
<div class="header-controls">
<div class="chart-tabs">
<button :class="{ active: activeChartTab === 'trend' }" @click="activeChartTab = 'trend'">时序热度图</button>
<button :class="{ active: activeChartTab === 'cumulative' }" @click="activeChartTab = 'cumulative'">累计热度图</button>
</div>
<button class="details-btn" @click="showDetails">查看详情</button>
</div>
<!-- 3. ECharts 容器 -->
<div ref="hotspotChart" class="chart-container"></div>
<div class="panel-container event-hot">
<!-- 1. 标题行 -->
<div class="header-title">
<img src="../../assets/images/evenhot.png" alt="" style="margin-top: -6px" />
</div>
<!-- 2. 控件行 -->
<div class="header-controls">
<div class="chart-tabs">
<button :class="{ active: activeChartTab === 'trend' }" @click="activeChartTab = 'trend'">
时序热度图
</button>
<button
:class="{ active: activeChartTab === 'cumulative' }"
@click="activeChartTab = 'cumulative'"
>
累计热度图
</button>
</div>
<button class="details-btn" @click="showDetails">查看详情</button>
</div>
<!-- 3. ECharts 容器 -->
<div ref="hotspotChart" class="chart-container"></div>
</div>
</template>
<script setup>
import { ref, watch, onMounted, onUnmounted } from 'vue';
import * as echarts from 'echarts';
import { ref, watch, onMounted, onUnmounted } from "vue";
import * as echarts from "echarts";
const emit = defineEmits(['showDetails']);
const emit = defineEmits(["showDetails"]);
// ===================================================================
//
// ===================================================================
const activeChartTab = ref('trend');
const activeChartTab = ref("trend");
// --- / (Granular/Details Data) ---
const granularTrendData = [8959, 7460, 8334, 7902, 5753, 3070, 3481, 16878, 17819, 15296, 18883, 3734, 938, 101, 12];
const granularXAxisLabels = ['7.31 00h', '7.31 06h', '7.31 12h', '7.31 18h', '8.1 00h', '8.1 06h', '8.1 12h', '8.1 18h', '8.2 00h', '8.2 06h', '8.2 12h', '8.2 18h', '8.3 00h', '8.3 06h', '8.3 12h'];
const granularCumulativeData = granularTrendData.reduce((acc, val) => { acc.push((acc.length > 0 ? acc[acc.length - 1] : 0) + val); return acc; }, []);
const granularTrendData = [
8959, 7460, 8334, 7902, 5753, 3070, 3481, 16878, 17819, 15296, 18883, 3734, 938, 101, 12
];
const granularXAxisLabels = [
"7.31 00h",
"7.31 06h",
"7.31 12h",
"7.31 18h",
"8.1 00h",
"8.1 06h",
"8.1 12h",
"8.1 18h",
"8.2 00h",
"8.2 06h",
"8.2 12h",
"8.2 18h",
"8.3 00h",
"8.3 06h",
"8.3 12h"
];
const granularCumulativeData = granularTrendData.reduce((acc, val) => {
acc.push((acc.length > 0 ? acc[acc.length - 1] : 0) + val);
return acc;
}, []);
// --- (Panel Data - Daily Summary) ---
const panelTrendData = [32655, 29182, 55732, 1051]; // Figma
const panelXAxisLabels = ['2022.7.31', '2022.8.1', '2022.8.2', '2022.8.3'];
const panelCumulativeData = panelTrendData.reduce((acc, val) => { acc.push((acc.length > 0 ? acc[acc.length - 1] : 0) + val); return acc; }, []);
const panelXAxisLabels = ["2022.7.31", "2022.8.1", "2022.8.2", "2022.8.3"];
const panelCumulativeData = panelTrendData.reduce((acc, val) => {
acc.push((acc.length > 0 ? acc[acc.length - 1] : 0) + val);
return acc;
}, []);
// --- ---
const chartDataSets = {
panel: {
trend: { data: panelTrendData, xAxis: panelXAxisLabels, yAxisMax: 60000 },
cumulative: { data: panelCumulativeData, xAxis: panelXAxisLabels, yAxisMax: 120000 }
},
details: {
trend: { data: granularTrendData, xAxis: granularXAxisLabels, yAxisMax: 20000 },
cumulative: { data: granularCumulativeData, xAxis: granularXAxisLabels, yAxisMax: 120000 }
}
panel: {
trend: { data: panelTrendData, xAxis: panelXAxisLabels, yAxisMax: 60000 },
cumulative: { data: panelCumulativeData, xAxis: panelXAxisLabels, yAxisMax: 120000 }
},
details: {
trend: { data: granularTrendData, xAxis: granularXAxisLabels, yAxisMax: 20000 },
cumulative: { data: granularCumulativeData, xAxis: granularXAxisLabels, yAxisMax: 120000 }
}
};
// ===================================================================
@ -59,144 +90,153 @@ const hotspotChart = ref(null);
let myChart = null;
const getChartOptions = (xAxisData, seriesData, yMax, rotate = 0) => ({
tooltip: { trigger: 'axis', backgroundColor: 'rgba(0,21,41,0.8)', borderColor: '#3a95ff', textStyle: { color: '#cbeaff' } },
grid: { left: '3%', right: '8%', bottom: '5%', top: '20%', containLabel: true },
xAxis: {
type: 'category',
boundaryGap: false,
data: xAxisData,
axisLine: { lineStyle: { color: 'rgba(62, 115, 171, 0.5)' } },
axisLabel: { color: '#a7c5d4', fontSize: 12, rotate: rotate },
axisTick: { show: false }
},
yAxis: {
type: 'value',
max: yMax,
axisLabel: { color: '#a7c5d4', fontSize: 12 },
splitLine: { show: true, lineStyle: { color: 'rgba(62, 115, 171, 0.2)', type: 'dashed' } }
},
series: [{
name: '热度',
type: 'line',
smooth: true,
symbol: 'circle',
symbolSize: 8,
data: seriesData,
label: { show: true, position: 'top', color: '#cdeeff', fontSize: 12 },
itemStyle: { color: '#00baff', borderColor: '#041421', borderWidth: 2 },
lineStyle: { color: '#00baff', width: 2 },
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'rgba(0, 186, 255, 0.4)' },
{ offset: 1, color: 'rgba(0, 186, 255, 0)' }
])
}
}]
tooltip: {
trigger: "axis",
backgroundColor: "rgba(0,21,41,0.8)",
borderColor: "#3a95ff",
textStyle: { color: "#cbeaff" }
},
grid: { left: "3%", right: "8%", bottom: "5%", top: "20%", containLabel: true },
xAxis: {
type: "category",
boundaryGap: false,
data: xAxisData,
axisLine: { lineStyle: { color: "rgba(62, 115, 171, 0.5)" } },
axisLabel: { color: "#a7c5d4", fontSize: 12, rotate: rotate },
axisTick: { show: false }
},
yAxis: {
type: "value",
max: yMax,
axisLabel: { color: "#a7c5d4", fontSize: 12 },
splitLine: { show: true, lineStyle: { color: "rgba(62, 115, 171, 0.2)", type: "dashed" } }
},
series: [
{
name: "热度",
type: "line",
smooth: true,
symbol: "circle",
symbolSize: 8,
data: seriesData,
label: { show: true, position: "top", color: "#cdeeff", fontSize: 12 },
itemStyle: { color: "#00baff", borderColor: "#041421", borderWidth: 2 },
lineStyle: { color: "#00baff", width: 2 },
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: "rgba(0, 186, 255, 0.4)" },
{ offset: 1, color: "rgba(0, 186, 255, 0)" }
])
}
}
]
});
//
watch(activeChartTab, (newTab) => {
if (myChart) {
const dataSet = chartDataSets.panel[newTab];
myChart.setOption({
xAxis: [{ data: dataSet.xAxis }],
yAxis: { max: dataSet.yAxisMax },
series: [{ data: dataSet.data }]
});
}
if (myChart) {
const dataSet = chartDataSets.panel[newTab];
myChart.setOption({
xAxis: [{ data: dataSet.xAxis }],
yAxis: { max: dataSet.yAxisMax },
series: [{ data: dataSet.data }]
});
}
});
//
const showDetails = () => {
const dataSet = chartDataSets.details[activeChartTab.value];
const rotate = dataSet.xAxis.length > 5 ? 15 : 0;
const option = getChartOptions(dataSet.xAxis, dataSet.data, dataSet.yAxisMax, rotate);
emit('showDetails', { option });
const dataSet = chartDataSets.details[activeChartTab.value];
const rotate = dataSet.xAxis.length > 5 ? 15 : 0;
const option = getChartOptions(dataSet.xAxis, dataSet.data, dataSet.yAxisMax, rotate);
emit("showDetails", { option });
};
onMounted(() => {
if (hotspotChart.value) {
myChart = echarts.init(hotspotChart.value);
// 使
const initialDataSet = chartDataSets.panel[activeChartTab.value];
myChart.setOption(getChartOptions(initialDataSet.xAxis, initialDataSet.data, initialDataSet.yAxisMax));
}
if (hotspotChart.value) {
myChart = echarts.init(hotspotChart.value);
// 使
const initialDataSet = chartDataSets.panel[activeChartTab.value];
myChart.setOption(
getChartOptions(initialDataSet.xAxis, initialDataSet.data, initialDataSet.yAxisMax)
);
}
});
onUnmounted(() => {
if (myChart) myChart.dispose();
if (myChart) myChart.dispose();
});
</script>
<style scoped>
/* 容器样式,无边框 */
.panel-container {
width: 352px;
height: 276px;
background: rgba(4, 20, 33, 0.4);
border-radius: 2px;
box-shadow: 0 0 18px 0 #0A2E55 inset;
backdrop-filter: blur(4px);
-webkit-backdrop-filter: blur(4px);
padding: 15px 20px;
box-sizing: border-box;
display: flex;
flex-direction: column;
width: 352px;
height: 276px;
background: rgba(4, 20, 33, 0.4);
border-radius: 2px;
box-shadow: 0 0 18px 0 #0a2e55 inset;
backdrop-filter: blur(4px);
-webkit-backdrop-filter: blur(4px);
padding: 15px 20px;
box-sizing: border-box;
display: flex;
flex-direction: column;
border: 1px solid #1a8bff;
}
/* 标题行 */
.header-title {
width: 100%;
margin-bottom: 20px;
width: 100%;
margin-bottom: 5px;
}
.header-title img {
height: 24px;
}
/* 控件行 */
.header-controls {
display: flex;
align-items: center;
margin-bottom: 10px;
display: flex;
align-items: center;
margin-bottom: 10px;
}
.chart-tabs {
display: flex;
border: 1px solid #1C588F;
border-radius: 3px;
background-color: #031826;
display: flex;
border: 1px solid #1c588f;
border-radius: 3px;
background-color: #031826;
}
.chart-tabs button {
background: none;
border: none;
color: #a7c5d4;
padding: 4px 12px;
font-size: 14px;
cursor: pointer;
transition: all 0.2s;
background: none;
border: none;
color: #a7c5d4;
padding: 4px 12px;
font-size: 14px;
cursor: pointer;
transition: all 0.2s;
}
.chart-tabs button.active {
background-color: #236291;
color: white;
border-radius: 2px;
background-color: #236291;
color: white;
border-radius: 2px;
}
.details-btn {
margin-left: auto;
background: none;
border: 1px solid #1c588f;
color: #a7c5d4;
padding: 4px 12px;
font-size: 14px;
border-radius: 3px;
cursor: pointer;
margin-left: auto;
background: none;
border: 1px solid #1c588f;
color: #a7c5d4;
padding: 4px 12px;
font-size: 14px;
border-radius: 3px;
cursor: pointer;
}
.chart-container {
flex-grow: 1;
width: 100%;
margin-left: -10px;
flex-grow: 1;
width: 100%;
margin-left: -10px;
}
</style>
</style>

View File

@ -3,16 +3,42 @@
<div class="leader-ansys">
<!-- Background SVG provided by the user -->
<div class="bg-svg">
<svg width="100%" height="100%" viewBox="0 0 352 542" fill="none" preserveAspectRatio="none" xmlns="http://www.w3.org/2000/svg">
<path d="M350 0.5H2C1.17157 0.5 0.500008 1.17157 0.5 2V540C0.5 540.828 1.17156 541.5 2 541.5H350C350.828 541.5 351.5 540.828 351.5 540V2C351.5 1.17157 350.828 0.5 350 0.5Z" fill="url(#paint0_linear_845_47161)" fill-opacity="0.48" stroke="url(#paint1_linear_845_47161)"/>
<svg
width="100%"
height="100%"
viewBox="0 0 352 542"
fill="none"
preserveAspectRatio="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M350 0.5H2C1.17157 0.5 0.500008 1.17157 0.5 2V540C0.5 540.828 1.17156 541.5 2 541.5H350C350.828 541.5 351.5 540.828 351.5 540V2C351.5 1.17157 350.828 0.5 350 0.5Z"
fill="url(#paint0_linear_845_47161)"
fill-opacity="0.48"
stroke="url(#paint1_linear_845_47161)"
/>
<defs>
<linearGradient id="paint0_linear_845_47161" x1="-1.82995e-07" y1="167.719" x2="352" y2="167.719" gradientUnits="userSpaceOnUse">
<stop stop-color="#063D71" stop-opacity="0.2"/>
<stop offset="1" stop-color="#081E38" stop-opacity="0.8"/>
<linearGradient
id="paint0_linear_845_47161"
x1="-1.82995e-07"
y1="167.719"
x2="352"
y2="167.719"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#063D71" stop-opacity="0.2" />
<stop offset="1" stop-color="#081E38" stop-opacity="0.8" />
</linearGradient>
<linearGradient id="paint1_linear_845_47161" x1="176" y1="0" x2="176" y2="542" gradientUnits="userSpaceOnUse">
<stop stop-color="#3AA1F8"/>
<stop offset="1" stop-color="#3AA1F8" stop-opacity="0.2"/>
<linearGradient
id="paint1_linear_845_47161"
x1="176"
y1="0"
x2="176"
y2="542"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#3AA1F8" />
<stop offset="1" stop-color="#3AA1F8" stop-opacity="0.2" />
</linearGradient>
</defs>
</svg>
@ -21,7 +47,11 @@
<!-- Content Area -->
<div class="content">
<!-- Title Image: using a placeholder as the local asset is not available -->
<img src="../../assets/images/chuanbofenxititle.png" alt="传播意见领袖分析" class="title-img">
<img
src="../../assets/images/chuanbofenxititle.png"
alt="传播意见领袖分析"
class="title-img"
/>
<!-- Charts Wrapper -->
<div class="charts-wrapper">
@ -48,13 +78,17 @@
<!-- Bars -->
<div class="bars">
<div v-for="(row, index) in chart.rows" :key="index" class="bar-container">
<div class="bar" :class="row.type" :style="{ width: (row.value / chart.max) * 100 + '%' }"></div>
<div
class="bar"
:class="row.type"
:style="{ width: (row.value / chart.max) * 100 + '%' }"
></div>
<span class="value" :class="{ highlight: row.highlight }">{{ row.value }}</span>
</div>
</div>
<!-- X-Axis Labels -->
<div class="x-axis-labels">
<span v-for="n in 6" :key="n">{{ (n-1) * 2 }}</span>
<span v-for="n in 6" :key="n">{{ (n - 1) * 2 }}</span>
<span class="unit">{{ chart.unit }}</span>
</div>
</div>
@ -66,39 +100,39 @@
</template>
<script setup>
import { ref } from 'vue';
import { ref } from "vue";
const chartData = ref([
{
id: 1,
title: '平均发帖数',
unit: '数量',
title: "平均发帖数",
unit: "数量",
max: 10,
rows: [
{ label: '领袖', value: 6.4, type: 'leader' },
{ label: '所有用户', value: 0.46, type: 'user' },
],
{ label: "领袖", value: 6.4, type: "leader" },
{ label: "所有用户", value: 0.46, type: "user" }
]
},
{
id: 2,
title: '帖子平均生存周期',
unit: '天数',
title: "帖子平均生存周期",
unit: "天数",
max: 10,
rows: [
{ label: '领袖', value: 2.19, type: 'leader' },
{ label: '所有用户', value: 0.46, type: 'user' },
],
{ label: "领袖", value: 2.19, type: "leader" },
{ label: "所有用户", value: 2.32, type: "user" }
]
},
{
id: 3,
title: '平均粉丝数',
unit: '天数',
title: "平均粉丝数",
unit: "天数",
max: 10,
rows: [
{ label: '领袖', value: 2.19, type: 'leader', highlight: true },
{ label: '所有用户', value: 0.46, type: 'user' },
],
},
{ label: "领袖", value: 290.4, type: "leader", highlight: false },
{ label: "所有用户", value: 1.31, type: "user" }
]
}
]);
</script>
@ -109,10 +143,11 @@ const chartData = ref([
height: 542px;
background-color: #04142166;
border-radius: 2px;
box-shadow: 0px 0px 18px 0px #0A2E55 inset;
box-shadow: 0px 0px 18px 0px #0a2e55 inset;
backdrop-filter: blur(4px);
color: #fff;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
font-family:
-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
overflow: hidden;
box-sizing: border-box;
}
@ -139,7 +174,6 @@ const chartData = ref([
.title-img {
display: block;
margin: 0 auto;
width: 250px;
}
.charts-wrapper {
@ -154,13 +188,13 @@ const chartData = ref([
align-items: center;
margin-bottom: 16px;
font-size: 16px;
color: #E0E0E0;
color: #e0e0e0;
}
.section-title .icon {
width: 8px;
height: 8px;
background-color: #3AA1F8;
background-color: #3aa1f8;
margin-right: 8px;
flex-shrink: 0;
}
@ -175,7 +209,7 @@ const chartData = ref([
justify-content: space-around;
padding-right: 15px;
font-size: 14px;
color: #A9C2E1;
color: #a9c2e1;
text-align: right;
height: 70px;
flex-shrink: 0;
@ -202,7 +236,7 @@ const chartData = ref([
}
.grid-lines .line:first-child,
.grid-lines .line:last-child {
display: none;
display: none;
}
.bars {
@ -226,22 +260,22 @@ const chartData = ref([
}
.bar.leader {
background: linear-gradient(90deg, #2E7CFB 0%, #3ADBF3 100%);
background: linear-gradient(90deg, #2e7cfb 0%, #3adbf3 100%);
}
.bar.user {
background: linear-gradient(90deg, #07BDB8 0%, #3ADBF3 100%);
background: linear-gradient(90deg, #07bdb8 0%, #3adbf3 100%);
}
.value {
margin-left: 8px;
font-size: 14px;
color: #FFFFFF;
color: #ffffff;
white-space: nowrap;
}
.value.highlight {
background-color: #D65050;
background-color: #d65050;
padding: 2px 5px;
border-radius: 3px;
font-size: 12px;
@ -256,8 +290,8 @@ const chartData = ref([
position: relative;
}
.x-axis-labels .unit {
position: absolute;
right: -25px;
top: 0;
position: absolute;
right: -25px;
top: 0;
}
</style>
</style>

View File

@ -1,8 +1,6 @@
<template>
<div class="post-dynamics-container">
<div class="header">
帖子动态
</div>
<div class="header">帖子动态</div>
<div class="post-list-wrapper">
<div class="scrolling-content" :style="{ animationDuration }">
<div
@ -12,12 +10,19 @@
:class="{ highlighted: post.highlighted }"
>
<div class="post-type">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" class="icon">
<rect opacity="0.1" width="20" height="20" rx="2" fill="#2B88DD"/>
<path d="M5 4V7C5 7.55228 5.44772 8 6 8H7" stroke="#8EFBFF"/>
<path d="M15 4V7C15 7.55228 14.5523 8 14 8H13" stroke="#8EFBFF"/>
<path d="M5 16V13C5 12.4477 5.44772 12 6 12H7" stroke="#8EFBFF"/>
<path d="M15 16V13C15 12.4477 14.5523 12 14 12H13" stroke="#8EFBFF"/>
<svg
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
class="icon"
>
<rect opacity="0.1" width="20" height="20" rx="2" fill="#2B88DD" />
<path d="M5 4V7C5 7.55228 5.44772 8 6 8H7" stroke="#8EFBFF" />
<path d="M15 4V7C15 7.55228 14.5523 8 14 8H13" stroke="#8EFBFF" />
<path d="M5 16V13C5 12.4477 5.44772 12 6 12H7" stroke="#8EFBFF" />
<path d="M15 16V13C15 12.4477 14.5523 12 14 12H13" stroke="#8EFBFF" />
</svg>
<span class="post-type-text">帖文</span>
</div>
@ -40,17 +45,59 @@
</template>
<script setup>
import { ref, computed } from 'vue';
import { ref, computed } from "vue";
const posts = ref([
{ id: 1, timestamp: '2022.07.31 00:52:43', author: 'Hu Xijin 胡锡进', influence: 5292, highlighted: false },
{ id: 2, timestamp: '2022.07.31 10:53:51', author: 'Indo-pacific ...', influence: 545, highlighted: false },
{ id: 3, timestamp: '2022.07.31 13:57:12', author: 'The Spectat...', influence: 8345, highlighted: true },
{ id: 4, timestamp: '2022.07.31 15:10:08', author: 'Reuters', influence: 557, highlighted: false },
{ id: 5, timestamp: '2022.07.31 17:19:13', author: '刘晓明 Liu Xi...', influence: 325, highlighted: false },
{ id: 6, timestamp: '2022.07.31 18:20:45', author: 'Global Times', influence: 4500, highlighted: false },
{ id: 7, timestamp: '2022.07.31 19:05:30', author: 'CGTN', influence: 7800, highlighted: false },
{ id: 8, timestamp: '2022.07.31 20:11:02', author: 'Anonymous', influence: 120, highlighted: false },
{
id: 1,
timestamp: "2022.07.31 00:52:43",
author: "Hu Xijin 胡锡进",
influence: 5292,
highlighted: false
},
{
id: 2,
timestamp: "2022.07.31 10:53:51",
author: "Indo-pacific ...",
influence: 545,
highlighted: false
},
{
id: 3,
timestamp: "2022.07.31 13:57:12",
author: "The Spectat...",
influence: 8345,
highlighted: true
},
{
id: 4,
timestamp: "2022.07.31 15:10:08",
author: "Reuters",
influence: 557,
highlighted: false
},
{
id: 5,
timestamp: "2022.07.31 17:19:13",
author: "刘晓明 Liu Xi...",
influence: 325,
highlighted: false
},
{
id: 6,
timestamp: "2022.07.31 18:20:45",
author: "Global Times",
influence: 4500,
highlighted: false
},
{ id: 7, timestamp: "2022.07.31 19:05:30", author: "CGTN", influence: 7800, highlighted: false },
{
id: 8,
timestamp: "2022.07.31 20:11:02",
author: "Anonymous",
influence: 120,
highlighted: false
}
]);
const doubledPosts = computed(() => [...posts.value, ...posts.value]);
@ -76,13 +123,19 @@ const getInfluenceWidth = (influence) => {
}
.post-dynamics-container {
width: 768px;
height: 244px; /* Set a fixed height to enable scrolling for the list */
width: 800px;
height: 275px; /* Set a fixed height to enable scrolling for the list */
padding: 16px;
background-color: #03102a; /* A dark blue background to mimic the screenshot context */
font-family: 'PingFang SC', sans-serif;
font-family: "PingFang SC", sans-serif;
display: flex;
flex-direction: column;
background-color: rgba(4, 20, 33, 0.4);
background-image: linear-gradient(to right, rgba(6, 61, 113, 0.2), rgba(8, 30, 56, 0.8));
border: none;
border-radius: 2px;
box-shadow: inset 0 0 18px rgba(6, 45, 84, 1);
border: 1px solid #1a8bff;
}
.header {
@ -118,7 +171,7 @@ const getInfluenceWidth = (influence) => {
height: 36px;
padding: 0 16px;
background: linear-gradient(90deg, rgba(63, 169, 245, 0.16) 0%, rgba(0, 84, 187, 0) 100%);
border-left: 2px solid #3FA9F5;
border-left: 2px solid #3fa9f5;
color: white;
font-size: 14px;
gap: 12px;
@ -126,7 +179,7 @@ const getInfluenceWidth = (influence) => {
}
.post-item.highlighted {
background: linear-gradient(90deg, rgba(63, 169, 245, 0.40) 0%, rgba(0, 84, 187, 0) 100%);
background: linear-gradient(90deg, rgba(63, 169, 245, 0.4) 0%, rgba(0, 84, 187, 0) 100%);
}
.post-type {
@ -137,7 +190,7 @@ const getInfluenceWidth = (influence) => {
}
.post-type-text {
color: #8EFBFF;
color: #8efbff;
font-size: 14px;
font-weight: 400;
text-shadow: 0px 1px 1px rgba(0, 0, 0, 0.25);
@ -180,7 +233,7 @@ const getInfluenceWidth = (influence) => {
.bar-fill {
position: absolute;
height: 2px;
background: linear-gradient(270deg, #00F3FF 0%, #00527D 100%);
background: linear-gradient(270deg, #00f3ff 0%, #00527d 100%);
}
.bar-handle-wrapper {
@ -198,13 +251,13 @@ const getInfluenceWidth = (influence) => {
width: 10px;
height: 10px;
border-radius: 50%;
background-color: #E0F1FF;
background-color: #e0f1ff;
position: relative;
box-shadow: 0 0 6px 0 rgba(13, 97, 255, 0.8);
}
.bar-handle::before {
content: '';
content: "";
position: absolute;
top: 50%;
left: 50%;
@ -214,4 +267,4 @@ const getInfluenceWidth = (influence) => {
border-radius: 50%;
border: 1px solid rgba(21, 154, 255, 0.3);
}
</style>
</style>

View File

@ -2,139 +2,196 @@
<div class="word-cloud-container">
<!-- Header -->
<div class="header">
<svg class="header-bg" width="302" height="42" viewBox="1 6 301 36" fill="none" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="header-bg-fill" x1="200" y1="32.5585" x2="-98.5844" y2="32.5585" gradientUnits="userSpaceOnUse">
<stop stop-color="#04192F"/>
<stop offset="1" stop-color="#04192F" stop-opacity="0.1"/>
</linearGradient>
<linearGradient id="header-border-fill-1" x1="81" y1="7" x2="81" y2="39" gradientUnits="userSpaceOnUse">
<stop stop-color="#0E76C3" stop-opacity="0"/>
<stop offset="1" stop-color="#0E76C3" stop-opacity="0.32"/>
</linearGradient>
<linearGradient id="header-border-stroke-1" x1="81" y1="7" x2="81" y2="39" gradientUnits="userSpaceOnUse">
<stop stop-color="#2AB9FE"/>
<stop offset="1" stop-color="#196F98" stop-opacity="0"/>
</linearGradient>
<linearGradient id="header-line-stroke-1" x1="197.27" y1="70.9998" x2="1.13774" y2="70.9998" gradientUnits="userSpaceOnUse">
<stop stop-color="#37F2FF" stop-opacity="0"/>
<stop offset="0.300536" stop-color="#37F2FF"/>
<stop offset="0.82807" stop-color="#37F2FF" stop-opacity="0"/>
</linearGradient>
<linearGradient id="header-line-stroke-2" x1="162.723" y1="7" x2="162.723" y2="41" gradientUnits="userSpaceOnUse">
<stop stop-color="#28A8E2" stop-opacity="0.35"/>
<stop offset="1" stop-color="#28A8E2" stop-opacity="0"/>
</linearGradient>
<linearGradient id="header-line-stroke-3" x1="246.353" y1="9.2159" x2="189.422" y2="37.9664" gradientUnits="userSpaceOnUse">
<stop stop-color="#28A6E0" stop-opacity="0"/>
<stop offset="0.491986" stop-color="#28A6E0"/>
<stop offset="1" stop-color="#28A8E2" stop-opacity="0"/>
</linearGradient>
<filter id="slash-filter" x="0" y="0" width="100%" height="100%" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="1"/>
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.129412 0 0 0 0 0.494118 0 0 0 0 0.780392 0 0 0 1 0"/>
<feBlend mode="normal" in2="shape" result="effect1_innerShadow"/>
</filter>
</defs>
<path d="M193.5 7H1.5V39H177.774L200 14.4805L193.5 7Z" fill="black" fill-opacity="0.7"/>
<path d="M193.5 7H1.5V39H177.774L200 14.4805L193.5 7Z" fill="url(#header-bg-fill)"/>
<path d="M192.698 7.5L199.304 14.4727L175.556 38.5H1.5V7.5H192.698Z" fill="url(#header-border-fill-1)" stroke="url(#header-border-stroke-1)"/>
<path d="M1 6.99976L193 6.99974" stroke="url(#header-line-stroke-1)" stroke-width="1.26227"/>
<path d="M187 41L212.498 13.5L206.688 7H269.578L267 9.5H259.925L255 13.5H218.442L192.942 41" stroke="url(#header-line-stroke-2)" stroke-width="1.32953"/>
<path d="M187 41L212.498 13.5L206.688 7H269.578L267 9.5H259.925L255 13.5" stroke="url(#header-line-stroke-3)" stroke-width="1.32953"/>
<g filter="url(#slash-filter)">
<path d="M225 23H236L220 39.5H209L225 23Z" fill="#0E365A" fill-opacity="0.38"/>
<path d="M247 23H258L242 39.5H231L247 23Z" fill="#0E365A" fill-opacity="0.38"/>
<path d="M269 23H280L264 39.5H253L269 23Z" fill="#0E365A" fill-opacity="0.38"/>
<path d="M291 23H302L286 39.5H275L291 23Z" fill="#0E365A" fill-opacity="0.38"/>
</g>
</svg>
<div class="title-text"><img src="../../assets/images/words.png" alt="" style="margin-top: -6px;"></div>
<img src="../../assets/images/words.png" alt="" />
</div>
<!-- Central Globe and Rings -->
<div class="globe-center">
<div class="ring-dashed"></div>
<div class="ring-solid"></div>
<div class="globe-icon">
<div class="globe-land"></div>
</div>
<div class="ring-dashed"></div>
<div class="ring-solid"></div>
<div class="globe-icon">
<div class="globe-land"></div>
</div>
</div>
<!-- Word Items -->
<div
v-for="word in words"
:key="word.text"
class="word-item"
:style="getWordStyle(word)"
>
<div v-for="word in words" :key="word.text" class="word-item" :style="getWordStyle(word)">
<span class="dot"></span>
<span class="text">{{ word.text }}</span>
</div>
<!-- Bottom decoration -->
<div class="bottom-decor">
<svg width="29" height="9" viewBox="164 278 29 9" fill="none" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="diamond-fill" x1="-0.0829921" y1="0.082992" x2="3.0011" y2="3.16708" gradientUnits="userSpaceOnUse">
<stop stop-color="#47CAF7" stop-opacity="0"/>
<stop offset="1" stop-color="#47CAF7"/>
</linearGradient>
<filter id="diamond-shadow" x="0" y="0" width="13" height="12" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.396078 0 0 0 0 0.921569 0 0 0 0 0.992157 0 0 0 1 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow" result="shape"/>
</filter>
</defs>
<g filter="url(#diamond-shadow)" transform="translate(2, -2)">
<rect width="2.90771" height="2.90771" transform="matrix(0.725875 0.687827 -0.725875 0.687827 166.109 278)" fill="#74FBFE"/>
<rect width="2.90771" height="2.90771" transform="matrix(0.725875 0.687827 -0.725875 0.687827 166.109 278)" fill="url(#diamond-fill)"/>
</g>
<g filter="url(#diamond-shadow)" transform="translate(11.83, -2)">
<rect width="2.90771" height="2.90771" transform="matrix(0.725875 0.687827 -0.725875 0.687827 166.109 278)" fill="#74FBFE"/>
<rect width="2.90771" height="2.90771" transform="matrix(0.725875 0.687827 -0.725875 0.687827 166.109 278)" fill="url(#diamond-fill)"/>
</g>
<g filter="url(#diamond-shadow)" transform="translate(21.78, -2)">
<rect width="2.90771" height="2.90771" transform="matrix(0.725875 0.687827 -0.725875 0.687827 166.109 278)" fill="#74FBFE"/>
<rect width="2.90771" height="2.90771" transform="matrix(0.725875 0.687827 -0.725875 0.687827 166.109 278)" fill="url(#diamond-fill)"/>
</g>
</svg>
<svg
width="29"
height="9"
viewBox="164 278 29 9"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<defs>
<linearGradient
id="diamond-fill"
x1="-0.0829921"
y1="0.082992"
x2="3.0011"
y2="3.16708"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#47CAF7" stop-opacity="0" />
<stop offset="1" stop-color="#47CAF7" />
</linearGradient>
<filter
id="diamond-shadow"
x="0"
y="0"
width="13"
height="12"
filterUnits="userSpaceOnUse"
color-interpolation-filters="sRGB"
>
<feFlood flood-opacity="0" result="BackgroundImageFix" />
<feColorMatrix
in="SourceAlpha"
type="matrix"
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
result="hardAlpha"
/>
<feOffset />
<feGaussianBlur stdDeviation="2" />
<feComposite in2="hardAlpha" operator="out" />
<feColorMatrix
type="matrix"
values="0 0 0 0 0.396078 0 0 0 0 0.921569 0 0 0 0 0.992157 0 0 0 1 0"
/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow" />
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow" result="shape" />
</filter>
</defs>
<g filter="url(#diamond-shadow)" transform="translate(2, -2)">
<rect
width="2.90771"
height="2.90771"
transform="matrix(0.725875 0.687827 -0.725875 0.687827 166.109 278)"
fill="#74FBFE"
/>
<rect
width="2.90771"
height="2.90771"
transform="matrix(0.725875 0.687827 -0.725875 0.687827 166.109 278)"
fill="url(#diamond-fill)"
/>
</g>
<g filter="url(#diamond-shadow)" transform="translate(11.83, -2)">
<rect
width="2.90771"
height="2.90771"
transform="matrix(0.725875 0.687827 -0.725875 0.687827 166.109 278)"
fill="#74FBFE"
/>
<rect
width="2.90771"
height="2.90771"
transform="matrix(0.725875 0.687827 -0.725875 0.687827 166.109 278)"
fill="url(#diamond-fill)"
/>
</g>
<g filter="url(#diamond-shadow)" transform="translate(21.78, -2)">
<rect
width="2.90771"
height="2.90771"
transform="matrix(0.725875 0.687827 -0.725875 0.687827 166.109 278)"
fill="#74FBFE"
/>
<rect
width="2.90771"
height="2.90771"
transform="matrix(0.725875 0.687827 -0.725875 0.687827 166.109 278)"
fill="url(#diamond-fill)"
/>
</g>
</svg>
</div>
</div>
</template>
<script>
export default {
name: 'WorldCloud',
name: "WorldCloud",
data() {
return {
words: [
{ text: '佩洛西', top: 115.5, left: 215.5, width: 109, height: 40, fontSize: 28, opacity: 1 },
{ text: '中国', top: 183.5, left: 69.5, width: 73, height: 35, fontSize: 22, opacity: 1 },
{ text: '中国人民解放军', top: 72.5, left: 132.5, width: 123, height: 22, fontSize: 12, opacity: 1 },
{ text: '中美关系', top: 171.5, left: 212.5, width: 81, height: 22, fontSize: 14, opacity: 0.8 },
{ text: '台独', top: 135.5, left: 42.5, width: 57, height: 24, fontSize: 16, opacity: 1 },
{ text: '台海和平', top: 228.5, left: 230.5, width: 81, height: 22, fontSize: 14, opacity: 0.8 },
{ text: '坚决反对', top: 233.5, left: 38.5, width: 73, height: 19, fontSize: 12, opacity: 0.7 },
{ text: '联合公报', top: 241.5, left: 130.5, width: 73, height: 19, fontSize: 12, opacity: 0.7 },
{ text: '有力反制', top: 211.5, left: 143.5, width: 73, height: 19, fontSize: 12, opacity: 1 },
{ text: '白宫', top: 176.5, left: 15.5, width: 49, height: 19, fontSize: 12, opacity: 0.8 },
{ text: '内政', top: 87.5, left: 36.5, width: 53, height: 22, fontSize: 14, opacity: 1 },
{ text: '访台', top: 103.5, left: 95.5, width: 49, height: 19, fontSize: 12, opacity: 0.8 },
{ text: '领土', top: 57.5, left: 72.5, width: 49, height: 19, fontSize: 12, opacity: 0.6 },
{ text: '原则', top: 77.5, left: 264.5, width: 49, height: 19, fontSize: 12, opacity: 0.7 },
{ text: '台湾', top: 195.5, left: 287.5, width: 49, height: 19, fontSize: 12, opacity: 0.8 },
{
text: "佩洛西",
top: 115.5,
left: 215.5,
width: 109,
height: 40,
fontSize: 28,
opacity: 1
},
{ text: "中国", top: 183.5, left: 69.5, width: 73, height: 35, fontSize: 22, opacity: 1 },
{
text: "中国人民解放军",
top: 72.5,
left: 132.5,
width: 123,
height: 22,
fontSize: 12,
opacity: 1
},
{
text: "中美关系",
top: 171.5,
left: 212.5,
width: 81,
height: 22,
fontSize: 14,
opacity: 0.8
},
{ text: "台独", top: 135.5, left: 42.5, width: 57, height: 24, fontSize: 16, opacity: 1 },
{
text: "台海和平",
top: 228.5,
left: 230.5,
width: 81,
height: 22,
fontSize: 14,
opacity: 0.8
},
{
text: "坚决反对",
top: 233.5,
left: 38.5,
width: 73,
height: 19,
fontSize: 12,
opacity: 0.7
},
{
text: "联合公报",
top: 241.5,
left: 130.5,
width: 73,
height: 19,
fontSize: 12,
opacity: 0.7
},
{
text: "有力反制",
top: 211.5,
left: 143.5,
width: 73,
height: 19,
fontSize: 12,
opacity: 1
},
{ text: "白宫", top: 176.5, left: 15.5, width: 49, height: 19, fontSize: 12, opacity: 0.8 },
{ text: "内政", top: 87.5, left: 36.5, width: 53, height: 22, fontSize: 14, opacity: 1 },
{ text: "访台", top: 103.5, left: 95.5, width: 49, height: 19, fontSize: 12, opacity: 0.8 },
{ text: "领土", top: 57.5, left: 72.5, width: 49, height: 19, fontSize: 12, opacity: 0.6 },
{ text: "原则", top: 77.5, left: 264.5, width: 49, height: 19, fontSize: 12, opacity: 0.7 },
{ text: "台湾", top: 195.5, left: 287.5, width: 49, height: 19, fontSize: 12, opacity: 0.8 }
]
};
},
@ -149,7 +206,7 @@ export default {
opacity: word.opacity,
fontSize: `${word.fontSize}px`,
paddingLeft: `${word.fontSize * 0.8}px`,
paddingRight: '10px'
paddingRight: "10px"
};
}
}
@ -159,109 +216,137 @@ export default {
<style scoped>
.word-cloud-container {
position: relative;
width: 352px;
height: 286px;
width: 370px;
height: 276px;
background-color: rgba(4, 20, 33, 0.4);
background-image: linear-gradient(to right, rgba(6, 61, 113, 0.2), rgba(8, 30, 56, 0.8));
border: none;
border-radius: 2px;
box-shadow: inset 0 0 18px rgba(6, 45, 84, 1);
overflow: hidden;
font-family: 'Microsoft YaHei', sans-serif;
font-family: "Microsoft YaHei", sans-serif;
right: 0;
border: 1px solid #1a8bff;
}
.header {
position: absolute;
top: 0;
left: 0;
position: absolute;
top: 0;
left: 0;
}
.header-bg {
position: absolute;
top: 0;
left: 0;
position: absolute;
top: 0;
left: 0;
}
.title-text {
position: absolute;
top: 6px;
left: 15px;
position: absolute;
top: 6px;
left: 15px;
}
.globe-center {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 200px;
height: 200px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 200px;
height: 200px;
}
.globe-center > div {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
border-radius: 50%;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
border-radius: 50%;
}
.ring-dashed {
width: 125px;
height: 125px;
background: conic-gradient(from 0deg,
#3FA9F5 0.5deg, transparent 0.5deg 3.6deg,
#3FA9F5 3.6deg 4.1deg, transparent 4.1deg 7.2deg,
#3FA9F5 7.2deg 7.7deg, transparent 7.7deg 10.8deg,
#3FA9F5 10.8deg 11.3deg, transparent 11.3deg 14.4deg,
#3FA9F5 14.4deg 14.9deg, transparent 14.9deg 18deg,
#3FA9F5 18deg 18.5deg, transparent 18.5deg 21.6deg,
#3FA9F5 21.6deg 22.1deg, transparent 22.1deg 25.2deg,
#3FA9F5 25.2deg 25.7deg, transparent 25.7deg 28.8deg,
#3FA9F5 28.8deg 29.3deg, transparent 29.3deg 32.4deg,
#3FA9F5 32.4deg 32.9deg, transparent 32.9deg 36deg,
#3FA9F5 36deg 36.5deg, transparent 36.5deg 360deg
);
opacity: 0.5;
animation: spin 20s linear infinite;
width: 125px;
height: 125px;
background: conic-gradient(
from 0deg,
#3fa9f5 0.5deg,
transparent 0.5deg 3.6deg,
#3fa9f5 3.6deg 4.1deg,
transparent 4.1deg 7.2deg,
#3fa9f5 7.2deg 7.7deg,
transparent 7.7deg 10.8deg,
#3fa9f5 10.8deg 11.3deg,
transparent 11.3deg 14.4deg,
#3fa9f5 14.4deg 14.9deg,
transparent 14.9deg 18deg,
#3fa9f5 18deg 18.5deg,
transparent 18.5deg 21.6deg,
#3fa9f5 21.6deg 22.1deg,
transparent 22.1deg 25.2deg,
#3fa9f5 25.2deg 25.7deg,
transparent 25.7deg 28.8deg,
#3fa9f5 28.8deg 29.3deg,
transparent 29.3deg 32.4deg,
#3fa9f5 32.4deg 32.9deg,
transparent 32.9deg 36deg,
#3fa9f5 36deg 36.5deg,
transparent 36.5deg 360deg
);
opacity: 0.5;
animation: spin 20s linear infinite;
}
.ring-solid {
width: 108px;
height: 108px;
background: radial-gradient(circle, rgba(0, 151, 225, 0.1) 0%, rgba(0, 151, 225, 0.5) 100%);
opacity: 0.2;
width: 108px;
height: 108px;
background: radial-gradient(circle, rgba(0, 151, 225, 0.1) 0%, rgba(0, 151, 225, 0.5) 100%);
opacity: 0.2;
}
.globe-icon {
width: 70px;
height: 70px;
border: 1px solid #2974b3;
background: linear-gradient(135deg, #22629E09, #2975B534 38%, #3693DA72 75%, #3FA9F5 100%);
width: 70px;
height: 70px;
border: 1px solid #2974b3;
background: linear-gradient(135deg, #22629e09, #2975b534 38%, #3693da72 75%, #3fa9f5 100%);
}
.globe-land {
width: 100%;
height: 100%;
background: linear-gradient(180deg, #FFFFFF, rgba(255, 255, 255, 0.1));
-webkit-mask-image: url('data:image/svg+xml;utf8,<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12.006 18.317C11.488 17.53 11.115 16.962 9.693 17.187C7.008 17.613 6.71 18.084 6.582 18.856L6.545 19.091L6.509 19.34C6.362 20.364 6.368 20.752 6.838 21.246C8.736 23.237 9.873 24.673 10.217 25.512C10.386 25.923 10.818 27.163 10.52 28.389C12.356 27.66 13.973 26.5 15.248 25.034C15.413 24.473 15.533 23.775 15.533 22.928V22.771C15.533 21.387 15.533 20.756 14.555 20.197C14.142 19.963 13.834 19.822 13.587 19.71C13.037 19.459 12.672 19.295 12.18 18.575C12.121 18.489 12.064 18.404 12.006 18.317ZM10 4.75C6.524 4.75 3.386 6.198 1.156 8.523C1.422 8.708 1.653 8.967 1.812 9.324C2.118 10.01 2.118 10.717 2.118 11.341C2.117 11.834 2.117 12.301 2.275 12.64C2.492 13.102 3.425 13.298 4.248 13.471C4.542 13.533 4.846 13.596 5.122 13.673C5.881 13.883 6.468 14.565 6.939 15.112C7.134 15.34 7.423 15.674 7.567 15.758C7.643 15.703 7.885 15.441 8.005 15.01C8.096 14.682 8.07 14.39 7.936 14.231C7.097 13.242 7.143 11.335 7.402 10.632C7.81 9.524 9.086 9.606 10.018 9.666C10.366 9.689 10.694 9.71 10.939 9.68C11.872 9.562 12.159 8.143 12.362 7.865C12.801 7.265 14.141 6.361 14.974 5.802C13.454 5.126 11.771 4.75 10 4.75Z" fill="black"/></svg>');
mask-image: url('data:image/svg+xml;utf8,<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12.006 18.317C11.488 17.53 11.115 16.962 9.693 17.187C7.008 17.613 6.71 18.084 6.582 18.856L6.545 19.091L6.509 19.34C6.362 20.364 6.368 20.752 6.838 21.246C8.736 23.237 9.873 24.673 10.217 25.512C10.386 25.923 10.818 27.163 10.52 28.389C12.356 27.66 13.973 26.5 15.248 25.034C15.413 24.473 15.533 23.775 15.533 22.928V22.771C15.533 21.387 15.533 20.756 14.555 20.197C14.142 19.963 13.834 19.822 13.587 19.71C13.037 19.459 12.672 19.295 12.18 18.575C12.121 18.489 12.064 18.404 12.006 18.317ZM10 4.75C6.524 4.75 3.386 6.198 1.156 8.523C1.422 8.708 1.653 8.967 1.812 9.324C2.118 10.01 2.118 10.717 2.118 11.341C2.117 11.834 2.117 12.301 2.275 12.64C2.492 13.102 3.425 13.298 4.248 13.471C4.542 13.533 4.846 13.596 5.122 13.673C5.881 13.883 6.468 14.565 6.939 15.112C7.134 15.34 7.423 15.674 7.567 15.758C7.643 15.703 7.885 15.441 8.005 15.01C8.096 14.682 8.07 14.39 7.936 14.231C7.097 13.242 7.143 11.335 7.402 10.632C7.81 9.524 9.086 9.606 10.018 9.666C10.366 9.689 10.694 9.71 10.939 9.68C11.872 9.562 12.159 8.143 12.362 7.865C12.801 7.265 14.141 6.361 14.974 5.802C13.454 5.126 11.771 4.75 10 4.75Z" fill="black"/></svg>');
-webkit-mask-size: contain;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
-webkit-mask-position: center;
mask-position: center;
width: 100%;
height: 100%;
background: linear-gradient(180deg, #ffffff, rgba(255, 255, 255, 0.1));
-webkit-mask-image: url('data:image/svg+xml;utf8,<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12.006 18.317C11.488 17.53 11.115 16.962 9.693 17.187C7.008 17.613 6.71 18.084 6.582 18.856L6.545 19.091L6.509 19.34C6.362 20.364 6.368 20.752 6.838 21.246C8.736 23.237 9.873 24.673 10.217 25.512C10.386 25.923 10.818 27.163 10.52 28.389C12.356 27.66 13.973 26.5 15.248 25.034C15.413 24.473 15.533 23.775 15.533 22.928V22.771C15.533 21.387 15.533 20.756 14.555 20.197C14.142 19.963 13.834 19.822 13.587 19.71C13.037 19.459 12.672 19.295 12.18 18.575C12.121 18.489 12.064 18.404 12.006 18.317ZM10 4.75C6.524 4.75 3.386 6.198 1.156 8.523C1.422 8.708 1.653 8.967 1.812 9.324C2.118 10.01 2.118 10.717 2.118 11.341C2.117 11.834 2.117 12.301 2.275 12.64C2.492 13.102 3.425 13.298 4.248 13.471C4.542 13.533 4.846 13.596 5.122 13.673C5.881 13.883 6.468 14.565 6.939 15.112C7.134 15.34 7.423 15.674 7.567 15.758C7.643 15.703 7.885 15.441 8.005 15.01C8.096 14.682 8.07 14.39 7.936 14.231C7.097 13.242 7.143 11.335 7.402 10.632C7.81 9.524 9.086 9.606 10.018 9.666C10.366 9.689 10.694 9.71 10.939 9.68C11.872 9.562 12.159 8.143 12.362 7.865C12.801 7.265 14.141 6.361 14.974 5.802C13.454 5.126 11.771 4.75 10 4.75Z" fill="black"/></svg>');
mask-image: url('data:image/svg+xml;utf8,<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12.006 18.317C11.488 17.53 11.115 16.962 9.693 17.187C7.008 17.613 6.71 18.084 6.582 18.856L6.545 19.091L6.509 19.34C6.362 20.364 6.368 20.752 6.838 21.246C8.736 23.237 9.873 24.673 10.217 25.512C10.386 25.923 10.818 27.163 10.52 28.389C12.356 27.66 13.973 26.5 15.248 25.034C15.413 24.473 15.533 23.775 15.533 22.928V22.771C15.533 21.387 15.533 20.756 14.555 20.197C14.142 19.963 13.834 19.822 13.587 19.71C13.037 19.459 12.672 19.295 12.18 18.575C12.121 18.489 12.064 18.404 12.006 18.317ZM10 4.75C6.524 4.75 3.386 6.198 1.156 8.523C1.422 8.708 1.653 8.967 1.812 9.324C2.118 10.01 2.118 10.717 2.118 11.341C2.117 11.834 2.117 12.301 2.275 12.64C2.492 13.102 3.425 13.298 4.248 13.471C4.542 13.533 4.846 13.596 5.122 13.673C5.881 13.883 6.468 14.565 6.939 15.112C7.134 15.34 7.423 15.674 7.567 15.758C7.643 15.703 7.885 15.441 8.005 15.01C8.096 14.682 8.07 14.39 7.936 14.231C7.097 13.242 7.143 11.335 7.402 10.632C7.81 9.524 9.086 9.606 10.018 9.666C10.366 9.689 10.694 9.71 10.939 9.68C11.872 9.562 12.159 8.143 12.362 7.865C12.801 7.265 14.141 6.361 14.974 5.802C13.454 5.126 11.771 4.75 10 4.75Z" fill="black"/></svg>');
-webkit-mask-size: contain;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
-webkit-mask-position: center;
mask-position: center;
}
.word-item {
position: absolute;
display: flex;
align-items: center;
color: #DEF6FF;
background: linear-gradient(135deg, rgba(47,101,195,0) 0%, rgba(45,102,196,0.02) 15%, rgba(40,110,200,0.08) 33%, rgba(32,116,204,0.19) 48%, rgba(6,143,220,0.51) 92%, rgba(0,151,225,0.6) 100%);
color: #def6ff;
background: linear-gradient(
135deg,
rgba(47, 101, 195, 0) 0%,
rgba(45, 102, 196, 0.02) 15%,
rgba(40, 110, 200, 0.08) 33%,
rgba(32, 116, 204, 0.19) 48%,
rgba(6, 143, 220, 0.51) 92%,
rgba(0, 151, 225, 0.6) 100%
);
border: 1px solid transparent;
border-image-source: linear-gradient(135deg, rgba(63,169,245,0) 0%, rgba(63,169,245,0.04) 49%, rgba(61,169,246,0.08) 64%, rgba(49,174,247,0.15) 71%, rgba(0,192,255,0.7) 100%);
border-image-source: linear-gradient(
135deg,
rgba(63, 169, 245, 0) 0%,
rgba(63, 169, 245, 0.04) 49%,
rgba(61, 169, 246, 0.08) 64%,
rgba(49, 174, 247, 0.15) 71%,
rgba(0, 192, 255, 0.7) 100%
);
border-image-slice: 1;
font-weight: 500;
}
@ -269,20 +354,20 @@ export default {
.word-item .dot {
width: 3px;
height: 3px;
background: #D9E021;
background: #d9e021;
border-radius: 50%;
box-shadow: 0 0 3px 1.5px rgba(217, 224, 33, 0.4);
margin-right: 5px;
}
.word-item .text {
white-space: nowrap;
white-space: nowrap;
}
.bottom-decor {
position: absolute;
bottom: -3px;
left: 50%;
transform: translateX(-50%);
position: absolute;
bottom: -3px;
left: 50%;
transform: translateX(-50%);
}
@keyframes spin {
@ -293,4 +378,4 @@ export default {
transform: translate(-50%, -50%) rotate(360deg);
}
}
</style>
</style>

View File

@ -255,6 +255,7 @@ const nodeCoordinates = {
};
const visibleLeaders = computed(() => allLeaderData.value.slice(0, activeTimePoint.value));
const tabs = ref(["全部", "新闻媒体", "自媒体", "政府官号"]);
const activeTab = ref("全部");
const filteredVisibleLeaders = computed(() => {
@ -284,12 +285,12 @@ const chartOptions = {
categories: [
{
name: "Leader",
symbolSize: 70,
symbolSize: 50,
itemStyle: {
borderColor: "rgba(0, 191, 255, 0.8)",
borderWidth: 3,
shadowBlur: 15,
shadowColor: "rgba(0, 191, 255, 0.7)"
shadowColor: "rgba(0, 10, 255, 0.7)"
}
},
{
@ -345,17 +346,23 @@ const formatAllGraphNodes = async () => {
allGraphNodes.value = [...tempResLeaderData, ...userNodes];
};
// []
const allGraphLinks = computed(() => [
{ source: "reuters", target: "spectator" },
{ source: "reuters", target: "indopacific" },
{ source: "liuxiaoming", target: "huxijin" },
{ source: "huxijin", target: "mickwallace" },
{ source: "spectator", target: "liuxiaoming" },
{ source: "jiushiniya", target: "levi_godman" },
{ source: "bidishalolo", target: "indobosss" }
//...
]);
const allGraphLinks = computed(() => {
const leaders = allGraphNodes.value.filter((node) => node.category === 0);
const users = allGraphNodes.value.filter((node) => node.category === 1);
const randomLinks = [];
leaders.forEach((leader) => {
//
const shuffled = users.slice().sort(() => Math.random() - 0.5);
//
shuffled.slice(0, 3).forEach((user) => {
randomLinks.push({
source: leader.id,
target: user.id
});
});
});
return randomLinks;
});
// ===================================================================
//
@ -445,7 +452,30 @@ const closeDetailsModal = () => {
myDetailsChart = null;
}
};
//
let timer = null;
const automaticPlay = () => {
let index = 1;
if (timer) clearInterval(timer);
timer = setInterval(() => {
onTimePointClick(index);
if (index == allLeaderData.value.length) {
clearInterval(timer);
timer = null;
return;
}
index++;
}, 1500);
};
//leader
const monitoringNode = (myChart) => {
myChart.on("click", (params) => {
//
if (params.data && params.data.category === 0) {
console.log(params);
}
});
};
// ===================================================================
//
// ===================================================================
@ -470,6 +500,8 @@ onMounted(async () => {
});
window.addEventListener("resize", myChart.resize);
}
monitoringNode(myChart);
automaticPlay();
});
onUnmounted(() => {