chart4app.html 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. <!DOCTYPE html>
  2. <html lang="zh-CN" style="height: 100%">
  3. <head>
  4. <meta charset="utf-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>chart</title>
  7. </head>
  8. <style>
  9. *{
  10. margin: 0;
  11. padding: 0;
  12. box-sizing: border-box;
  13. }
  14. body {
  15. height: 100%;
  16. margin: 0;
  17. background-image: url(./chart4app-bg.jpg);
  18. background-size: cover;
  19. background-repeat: no-repeat;
  20. background-position: center center;
  21. }
  22. </style>
  23. <body>
  24. <div id="container" style="height: 100%"></div>
  25. <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
  26. <script type="text/javascript" src="https://cdn.staticfile.org/echarts/5.4.2/echarts.min.js"></script>
  27. <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
  28. <script type="text/javascript">
  29. function getRandomColorPair() {
  30. const colorR = Math.floor(Math.random() * (220 - 50) + 50)
  31. const colorG = Math.floor(Math.random() * (220 - 50) + 50)
  32. const colorB = Math.floor(Math.random() * (220 - 50) + 50)
  33. const colorDiff = Math.floor(Math.random() * ((255 - 220) - 20) + 20)
  34. return [
  35. `rgb(${colorR}, ${colorG}, ${colorB})`,
  36. `rgb(${colorR + colorDiff}, ${colorG + colorDiff}, ${colorB + colorDiff})`
  37. ]
  38. }
  39. const rawInfo = [
  40. {
  41. name: '开埠通商',
  42. corpList: [
  43. // {
  44. // companyName: "正泰橡皮物品制造厂",
  45. // createTime: "2023-08-03 14:21:45",
  46. // creatorId: null,
  47. // creatorName: "",
  48. // description: "创办正泰橡皮物品制造厂,首创“回力”商标。",
  49. // dirCode: "",
  50. // display: null,
  51. // fileIds: "",
  52. // id: 10,
  53. // name: "刘永康",
  54. // sort: null,
  55. // stage: "开埠通商",
  56. // story: "",
  57. // updateTime: "2023-08-03 14:21:45",
  58. // }
  59. ],
  60. id: 'time-0'
  61. },
  62. {
  63. name: '曲折发展',
  64. corpList: [],
  65. id: 'time-1'
  66. },
  67. {
  68. name: '步履维艰',
  69. corpList: [],
  70. id: 'time-2'
  71. },
  72. {
  73. name: '筚路蓝缕',
  74. corpList: [],
  75. id: 'time-3'
  76. },
  77. {
  78. name: '改革开放',
  79. corpList: [],
  80. id: 'time-4'
  81. },
  82. {
  83. name: '战略负重',
  84. corpList: [],
  85. id: 'time-5'
  86. },
  87. {
  88. name: '创新驱动',
  89. corpList: [],
  90. id: 'time-6'
  91. },
  92. {
  93. name: '追梦未来',
  94. corpList: [],
  95. id: 'time-7'
  96. },
  97. ]
  98. for (const iterator of rawInfo) {
  99. iterator.color = {
  100. type: "radial",
  101. x: 0.5,
  102. y: 0.5,
  103. r: 0.5,
  104. colorStops: [
  105. {
  106. offset: 0,
  107. color: 'rgba(51, 175, 202, 0.20)'
  108. },
  109. {
  110. offset: 1,
  111. color: 'rgba(0, 157, 191, 0.7)'
  112. },
  113. ],
  114. global: false
  115. }
  116. }
  117. const nodesForRender = [
  118. {
  119. name: "历史回顾",
  120. level: 0,
  121. category: null,
  122. symbolSize: 76,
  123. itemStyle: {
  124. color: {
  125. type: "radial",
  126. x: 0.5,
  127. y: 0.5,
  128. r: 0.5,
  129. colorStops: [
  130. {
  131. offset: 0,
  132. color: "rgba(223, 201, 145, 0.2)"
  133. },
  134. {
  135. offset: 0.5,
  136. color: "rgba(223, 201, 145, 0.5)"
  137. },
  138. {
  139. offset: 1,
  140. color: "rgba(223, 201, 145, 1)"
  141. },
  142. ],
  143. global: false
  144. },
  145. borderColor: "rgba(255,236,186,1)",
  146. borderWidth: 2,
  147. shadowColor: "rgba(223, 201, 145, 1)",
  148. shadowBlur: 10
  149. },
  150. label: {
  151. position: 'inside',
  152. show: true,
  153. color: '#fff',
  154. fontSize: '16px',
  155. fontWeight: 'bold',
  156. }
  157. },
  158. ]
  159. const edgesForRender = []
  160. Promise.allSettled(rawInfo.map((timeInfoItem) => {
  161. return axios({
  162. method: 'post',
  163. url: `https://sit-shgybwg.4dage.com/api/show/history/pageList`,
  164. headers: {
  165. "Content-Type": "application/json",
  166. },
  167. data: {
  168. stage: timeInfoItem.name
  169. },
  170. }).then((res) => {
  171. return res.data.data.records
  172. }).then((res) => {
  173. timeInfoItem.corpList = res
  174. })
  175. })).then((res) => {
  176. for (const timeInfoItem of rawInfo) {
  177. nodesForRender.push({
  178. name: timeInfoItem.name,
  179. level: 1,
  180. category: timeInfoItem.name,
  181. symbolSize: 57,
  182. itemStyle: {
  183. color: timeInfoItem.color,
  184. borderColor: "rgba(0, 157, 191, 0.6)",
  185. shadowColor: "rgba(97,170,238,0.5)",
  186. shadowBlur: 15,
  187. borderColor: 'rgba(42,174,203,1)',
  188. borderWidth: 1,
  189. },
  190. label: {
  191. position: 'inside',
  192. show: true,
  193. color: '#fff',
  194. fontSize: '13px',
  195. }
  196. })
  197. edgesForRender.push({
  198. category: null,
  199. lineStyle: {
  200. normal: {
  201. color: 'rgba(42, 174, 203, 1)',
  202. },
  203. },
  204. source: '历史回顾',
  205. target: timeInfoItem.name,
  206. })
  207. for (const corpItem of timeInfoItem.corpList) {
  208. nodesForRender.push({
  209. name: corpItem.name,
  210. level: 2,
  211. idForSend: corpItem.id,
  212. category: timeInfoItem.name,
  213. symbolSize: 12,
  214. itemStyle: {
  215. borderColor: 'rgba(42, 174, 203, 1)',
  216. color: 'transparent',
  217. },
  218. select: {
  219. itemStyle: {
  220. borderColor: timeInfoItem.color.colorStops[1].color,
  221. color: timeInfoItem.color.colorStops[1].color,
  222. },
  223. },
  224. label: {
  225. position: 'right',
  226. show: true,
  227. color: '#fff',
  228. fontSize: '13px',
  229. }
  230. })
  231. edgesForRender.push({
  232. category: timeInfoItem.name,
  233. lineStyle: {
  234. normal: {
  235. color: 'rgba(42, 174, 203, 1)',
  236. },
  237. },
  238. source: timeInfoItem.name,
  239. target: corpItem.name,
  240. })
  241. }
  242. }
  243. showAll()
  244. window.vuplex.postMessage('fetch data done', '*')
  245. })
  246. let myChart = null
  247. var dom = document.getElementById('container');
  248. myChart = echarts.init(dom, null, {
  249. renderer: 'canvas',
  250. useDirtyRect: false
  251. });
  252. function showAll() {
  253. return showChart()
  254. }
  255. function changeTime(timeIdx) {
  256. if (Number.isInteger(timeIdx) && timeIdx >= 0) {
  257. return showChart(timeIdx)
  258. } else {
  259. console.error('[page using echart] changeTime: invalid param!', timeIdx);
  260. }
  261. }
  262. let nodesForRenderTemp = null
  263. let edgesForRenderTemp = null
  264. function showChart(timeIdx) {
  265. if (timeIdx !== undefined) {
  266. nodesForRenderTemp = nodesForRender.filter((item) => {
  267. return item.category === rawInfo[timeIdx].name
  268. })
  269. edgesForRenderTemp = edgesForRender.filter((item) => {
  270. return item.category === rawInfo[timeIdx].name
  271. })
  272. } else {
  273. nodesForRenderTemp = null
  274. edgesForRenderTemp = null
  275. }
  276. myChart.clear()
  277. myChart.setOption({
  278. animationDurationUpdate: 1500,
  279. animationEasingUpdate: 'quinticInOut',
  280. series: [
  281. {
  282. type: 'graph',
  283. layout: 'force',
  284. // 力引导布局是模拟弹簧电荷模型在每两个节点之间添加一个斥力,每条边的两个节点之间添加一个引力
  285. force: {
  286. initLayout: 'circular', // 进行力引导布局前的初始化布局,初始化布局会影响到力引导的效果。默认不进行任何布局,使用节点中提供的 x, y 作为节点的位置。如果不存在的话会随机生成一个位置。也可以选择使用环形布局 'circular'。
  287. // repulsion: 100, // 节点之间的斥力因子。傻逼文档把edgeLength当数组用的用法写到这上边了。
  288. repulsion: 300, // 节点之间的斥力因子。傻逼文档把edgeLength当数组用的用法写到这上边了。
  289. // gravity: 0.1, // 节点受到的向中心的引力因子。该值越大节点越往中心点靠拢。
  290. // edgeLength: [50, 400], // 把各个边的两个节点之间的距离归一化到这个范围内。与repulsion共同作用。
  291. edgeLength: 100, // 把各个边的两个节点之间的距离归一化到这个范围内。与repulsion共同作用。
  292. layoutAnimation: true,
  293. friction: 0.5, // 这个参数能减缓节点的移动速度。取值范围 0 到 1。但是仍然是个试验性的参数,参见 #11024。
  294. },
  295. data: timeIdx === undefined ? nodesForRender : nodesForRenderTemp,
  296. // 或者叫edges
  297. links: timeIdx === undefined ? edgesForRender : edgesForRenderTemp,
  298. // 单选or多选or不可选
  299. selectedMode: 'single',
  300. // 选中时的图形样式
  301. select: {
  302. itemStyle: {
  303. shadowBlur: 30,
  304. shadowColor: 'rgba(255, 255, 125, 0.7)',
  305. },
  306. label: {
  307. fontWeight: 'bold',
  308. },
  309. },
  310. // hover时的图形样式
  311. emphasis: {
  312. scale: false,
  313. },
  314. // hover时只照常显示有联系的那些节点和边,其余的暗色显示。
  315. focusNodeAdjacency: true,
  316. // 图表是否可以移动、缩放
  317. roam: true,
  318. scaleLimit: {
  319. min: 0.5, //最小的缩放值
  320. max: 3, //最大的缩放值
  321. },
  322. draggable: true,
  323. lineStyle: {
  324. normal: {
  325. width: 1.5,
  326. curveness: 0,
  327. type: "solid"
  328. }
  329. },
  330. edgeSymbol: ["circle", "arrow"],
  331. edgeSymbolSize: [1, 8],
  332. }
  333. ]
  334. }, true)
  335. }
  336. // 用户选中节点后,向父窗口post message
  337. function onSelect(params) {
  338. if (params.dataType !== 'node') {
  339. return
  340. }
  341. window.vuplex.postMessage({
  342. msg: `node-selected`,
  343. nodeLevel: nodesForRenderTemp ? nodesForRenderTemp[params.dataIndexInside].level : nodesForRender[params.dataIndexInside].level,
  344. nodeStageName: nodesForRenderTemp ? nodesForRenderTemp[params.dataIndexInside].category : nodesForRender[params.dataIndexInside].category,
  345. nodeStageIdx: rawInfo.findIndex((item) => {
  346. return item.name === (nodesForRenderTemp ? nodesForRenderTemp[params.dataIndexInside].category : nodesForRender[params.dataIndexInside].category)
  347. }),
  348. nodeId: nodesForRenderTemp ? nodesForRenderTemp[params.dataIndexInside].idForSend : nodesForRender[params.dataIndexInside].idForSend,
  349. })
  350. }
  351. myChart.on('select', onSelect)
  352. window.addEventListener('resize', myChart.resize);
  353. </script>
  354. </body>
  355. </html>