chart.html 11 KB

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