| 第1行: |
第1行: |
| − | <!DOCTYPE html>
| |
| − | <!-- saved from url=(0044)https://wiki.swarma.org/graph.v20250715.html -->
| |
| − | <html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
| |
| − |
| |
| − | <meta name="viewport" content="width=device-width, initial-scale=1.0">
| |
| − | <title>集智百科概览</title>
| |
| − | <link rel="icon" href="./集智百科概览_files/logo.jpg">
| |
| − | <style>
| |
| − | html,
| |
| − | body {
| |
| − | margin: 0;
| |
| − | padding: 0;
| |
| − | width: 100%;
| |
| − | height: 100%;
| |
| − | }
| |
| | | | |
| − | body {
| |
| − | display: flex;
| |
| − | justify-content: center;
| |
| − | align-items: center;
| |
| − | }
| |
| − |
| |
| − | .m-graph {
| |
| − | position: relative;
| |
| − | width: 100%;
| |
| − | height: 100%;
| |
| − | box-sizing: border-box;
| |
| − | }
| |
| − |
| |
| − | .m-loading {
| |
| − | position: fixed;
| |
| − | top: 0;
| |
| − | left: 0;
| |
| − | width: 100%;
| |
| − | height: 100%;
| |
| − | background: #fff;
| |
| − | z-index: 999;
| |
| − | transition: opacity 1s ease-in-out;
| |
| − | }
| |
| − | .m-loading .m-animation {
| |
| − | position: absolute;
| |
| − | top: 50%;
| |
| − | left: 50%;
| |
| − | transform: translate(-50%, -50%);
| |
| − | text-align: center;
| |
| − | opacity: 0;
| |
| − | transition: opacity 1s ease-in-out;
| |
| − | }
| |
| − | .m-loading .m-logo {
| |
| − | display: flex;
| |
| − | align-items: center;
| |
| − | }
| |
| − | .m-loading .m-logo .u-image {
| |
| − | margin-right: 16px;
| |
| − | width: 80px;
| |
| − | height: 80px;
| |
| − | }
| |
| − | .m-loading .m-logo .u-text {
| |
| − | font-size: 28px;
| |
| − | }
| |
| − | .m-loading .u-slogan {
| |
| − | margin-top: 24px;
| |
| − | font-size: 20px;
| |
| − | }
| |
| − | </style>
| |
| − | </head>
| |
| − |
| |
| − | <body>
| |
| − | <div id="loadingEl" class="m-loading" style="opacity: 0; display: none;">
| |
| − | <div id="animationEl" class="m-animation" style="opacity: 1;">
| |
| − | <div class="m-logo">
| |
| − | <img class="u-image" src="./集智百科概览_files/logo.jpg" alt="logo">
| |
| − | <div class="u-text">欢迎来到 <b>集智百科</b></div>
| |
| − | </div>
| |
| − | <div class="u-slogan"><i>知识从我而来,问题到我为止</i></div>
| |
| − | </div>
| |
| − | </div>
| |
| − | <div id="container" class="m-graph" style="user-select: none; -webkit-tap-highlight-color: rgba(0, 0, 0, 0); position: relative;" _echarts_instance_="ec_1761038362008"><div style="position: relative; width: 2388px; height: 1188px; padding: 0px; margin: 0px; border-width: 0px; cursor: default;"><canvas data-zr-dom-id="zr_0" width="3820" height="1900" style="position: absolute; left: 0px; top: 0px; width: 2388px; height: 1188px; user-select: none; -webkit-tap-highlight-color: rgba(0, 0, 0, 0); padding: 0px; margin: 0px; border-width: 0px;"></canvas></div><div class=""></div></div>
| |
| − | <script defer="" src="./集智百科概览_files/vcd15cbe7772f49c399c6a5babf22c1241717689176015" integrity="sha512-ZpsOmlRQV6y907TI0dKBHq9Md29nnaEIPlkf84rnaERnq6zvWvPUqr2ft8M1aS28oN72PdrCzSjY4U6VaAw1EQ==" data-cf-beacon="{"version":"2024.11.0","token":"39cdf464f765499c8a52a31cda5e385e","r":1,"server_timing":{"name":{"cfCacheStatus":true,"cfEdge":true,"cfExtPri":true,"cfL4":true,"cfOrigin":true,"cfSpeedBrain":true},"location_startswith":null}}" crossorigin="anonymous"></script>
| |
| − |
| |
| − |
| |
| − | <script type="text/javascript" src="./集智百科概览_files/echarts.min.js.下载"></script>
| |
| − | <script src="./集智百科概览_files/nodes.js.下载"></script>
| |
| − | <script src="./集智百科概览_files/edges.js.下载"></script>
| |
| − |
| |
| − | <script type="text/javascript">
| |
| − | var nodes = window.nodes;
| |
| − | var edges = window.edges;
| |
| − |
| |
| − | console.log(nodes);
| |
| − | console.log(edges);
| |
| − |
| |
| − | const loadingEl = document.getElementById('loadingEl')
| |
| − | const animationEl = document.getElementById('animationEl')
| |
| − | animationEl.style.opacity = 1
| |
| − | setTimeout(() => {
| |
| − | loadingEl.style.opacity = 0
| |
| − | setTimeout(() => {
| |
| − | loadingEl.style.display = 'none'
| |
| − | }, 1000)
| |
| − | }, 3000)
| |
| − |
| |
| − | var dom = document.getElementById("container");
| |
| − | var myChart = echarts.init(dom);
| |
| − |
| |
| − | // 获取节点、连边数据
| |
| − | // Promise.all([
| |
| − | // 'https://api.swarma.org/api/science_nodes/list',
| |
| − | // 'https://api.swarma.org/api/science_edges/list'
| |
| − | // ].map(url => fetch(url, {
| |
| − | // headers: {
| |
| − | // 'X-Requested-With': 'XMLHttpRequest',
| |
| − | // 'Content-Type': 'application/json'
| |
| − | // }
| |
| − | // })
| |
| − |
| |
| − | Promise.resolve([nodes, edges]).then(res => {
| |
| − | const linkCount = new Map()
| |
| − | const links = res[1].map(item => {
| |
| − | linkCount.set(item.source_id, (linkCount.get(item.source_id) || 0) + 1)
| |
| − | linkCount.set(item.target_id, (linkCount.get(item.target_id) || 0) + 1)
| |
| − |
| |
| − | return {
| |
| − | source: 'node_' + item.source_id,
| |
| − | target: 'node_' + item.target_id
| |
| − | }
| |
| − | })
| |
| − |
| |
| − | const now = Date.now()
| |
| − | const RECENT_DAYS = 7
| |
| − | const recentUpdatedThreshold = RECENT_DAYS * 24 * 60 * 60 * 1000
| |
| − |
| |
| − | const nodes = res[0].map(item => {
| |
| − | const count = linkCount.get(item.id) || 1
| |
| − | const isRecentlyUpdated = item.updated_at && (now - new Date(item.updated_at)) < recentUpdatedThreshold
| |
| − |
| |
| − | const node = {
| |
| − | id: 'node_' + item.id,
| |
| − | name: item.name,
| |
| − | value: item.id,
| |
| − | symbolSize: count >= 15 ? count / 1.5 : 5,
| |
| − | category: 'type-' + item.type,
| |
| − | tooltip: { formatter: '{b}' },
| |
| − | emphasis: { label: { show: true } },
| |
| − | url: item.url,
| |
| − | updated_at: item.updated_at,
| |
| − | }
| |
| − |
| |
| − | if (count < 10 && !isRecentlyUpdated) {
| |
| − | node.label = { show: false }
| |
| − | }
| |
| − |
| |
| − | if (isRecentlyUpdated) {
| |
| − | node.itemStyle = {
| |
| − | // color: '#ff6666',
| |
| − | borderColor: '#FFCC00',
| |
| − | borderWidth: 3
| |
| − | }
| |
| − | node.label = {
| |
| − | show: true,
| |
| − | fontWeight: 'bold',
| |
| − | fontSize: 14
| |
| − | }
| |
| − | }
| |
| − |
| |
| − | return node
| |
| − | })
| |
| − |
| |
| − | const categories = Array.from(new Set(res[0].map(node => node.type)))
| |
| − | .map(type => ({ name: 'type-' + type }))
| |
| − |
| |
| − | const data = { nodes, links, categories }
| |
| − |
| |
| − | const option = {
| |
| − | title: {
| |
| − | text: '集智百科概览',
| |
| − | subtext: '点击节点前往wiki页面',
| |
| − | },
| |
| − | tooltip: { show: true },
| |
| − | series: [
| |
| − | {
| |
| − | type: 'graph',
| |
| − | layout: 'force',
| |
| − | draggable: true,
| |
| − | data: data.nodes,
| |
| − | links: data.links,
| |
| − | categories: data.categories,
| |
| − | roam: true,
| |
| − | label: {
| |
| − | show: true,
| |
| − | position: 'bottom'
| |
| − | },
| |
| − | force: {
| |
| − | initLayout: 'circular',
| |
| − | repulsion: 200,
| |
| − | edgeLength: 100,
| |
| − | gravity: 0.05
| |
| − | },
| |
| − | lineStyle: { opacity: 0.3 },
| |
| − | emphasis: { focus: 'adjacency' }
| |
| − | }
| |
| − | ]
| |
| − | }
| |
| − |
| |
| − | myChart.setOption(option)
| |
| − |
| |
| − | myChart.dispatchAction({
| |
| − | type: 'graphRoam',
| |
| − | zoom: 0.15 // 缩小为50%,可以根据需要调整,如0.3、0.7等
| |
| − | })
| |
| − |
| |
| − | // 添加点击跳转功能
| |
| − | myChart.on('click', function (event) {
| |
| − | if (event.dataType === 'node' && event.data.url) {
| |
| − | window.open(event.data.url, undefined, 'noopener')
| |
| − | }
| |
| − | })
| |
| − |
| |
| − | // 添加 effectScatter 闪烁层(在图渲染后添加)
| |
| − | myChart.on('finished', function () {
| |
| − | const graphSeries = myChart.getOption().series.find(s => s.type === 'graph')
| |
| − | const recentEffectPoints = []
| |
| − |
| |
| − | for (let i = 0; i < graphSeries.data.length; i++) {
| |
| − | const node = graphSeries.data[i]
| |
| − | if (node.itemStyle && node.itemStyle.borderColor === '#ff0000' && node.x != null && node.y != null) {
| |
| − | recentEffectPoints.push({
| |
| − | name: node.name,
| |
| − | value: [node.x, node.y],
| |
| − | symbolSize: node.symbolSize + 10
| |
| − | })
| |
| − | }
| |
| − | }
| |
| − |
| |
| − | if (recentEffectPoints.length > 0) {
| |
| − | myChart.setOption({
| |
| − | series: [
| |
| − | ...myChart.getOption().series,
| |
| − | {
| |
| − | type: 'effectScatter',
| |
| − | coordinateSystem: null,
| |
| − | data: recentEffectPoints,
| |
| − | rippleEffect: {
| |
| − | scale: 2.5,
| |
| − | brushType: 'stroke'
| |
| − | },
| |
| − | itemStyle: {
| |
| − | color: '#ff0000'
| |
| − | },
| |
| − | z: 100
| |
| − | }
| |
| − | ]
| |
| − | })
| |
| − | }
| |
| − | })
| |
| − |
| |
| − | window.addEventListener('resize', function () {
| |
| − | myChart.resize()
| |
| − | })
| |
| − | })
| |
| − |
| |
| − |
| |
| − | window.addEventListener('resize', function () {
| |
| − | myChart.resize()
| |
| − | })
| |
| − | </script>
| |
| − |
| |
| − |
| |
| − | </body></html>
| |