chart4app.html 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  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. background-color: #04060a;
  16. }
  17. </style>
  18. <body style="height: 100%; margin: 0">
  19. <div id="container" style="height: 100%"></div>
  20. <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
  21. <script type="text/javascript" src="https://cdn.staticfile.org/echarts/5.4.2/echarts.min.js"></script>
  22. <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
  23. <script src="./history.js"></script>
  24. <script type="text/javascript">
  25. const timeList = [
  26. '开埠通商',
  27. '曲折发展',
  28. '步履维艰',
  29. '筚路蓝缕',
  30. '改革开放',
  31. '战略负重',
  32. '创新驱动',
  33. '追梦未来',
  34. ]
  35. function randomColor() {
  36. return '#' + Math.floor(
  37. (
  38. Math.random() * (1 - 0.3) + 0.3
  39. ) * 0xffffff
  40. ).toString(16)
  41. }
  42. const dataForRender = {}
  43. let myChart = null
  44. var dom = document.getElementById('container');
  45. myChart = echarts.init(dom, null, {
  46. renderer: 'canvas',
  47. useDirtyRect: false
  48. });
  49. async function showChart(timeIdx) {
  50. myChart.clear()
  51. // const res = await axios({
  52. // method: 'post',
  53. // url: `https://sit-shgybwg.4dage.com/api/show/history/pageList`,
  54. // headers: {
  55. // "Content-Type": "application/json",
  56. // },
  57. // data: {
  58. // stage: timeList[timeIdx]
  59. // },
  60. // })
  61. // const corpList = res.data.data.records
  62. const corpList = historyRawData['阶段任务信息'][timeIdx].children.map((item) => {
  63. return {
  64. companyName: item['品牌'],
  65. description: item['简介'],
  66. id: item['序号'],
  67. name: item['名称'],
  68. story: item['故事'],
  69. }
  70. })
  71. dataForRender.nodes = [
  72. {
  73. name: timeList[timeIdx],
  74. id: '-1',
  75. symbolSize: 100,
  76. itemStyle: {
  77. color: randomColor()
  78. },
  79. },
  80. ]
  81. dataForRender.edges = []
  82. for (const iterator of corpList) {
  83. const newNode = {
  84. name: iterator.name || iterator.companyName,
  85. id: iterator.id.toString(),
  86. symbolSize: iterator.importance || (100 * Math.random()),
  87. itemStyle: {
  88. color: randomColor()
  89. }
  90. }
  91. dataForRender.nodes.push(newNode)
  92. }
  93. // 除了代表时代的那个节点,其他节点的尺寸归一化
  94. let vMax = Number.NEGATIVE_INFINITY
  95. let vMin = Number.POSITIVE_INFINITY
  96. const vMaxNew = 50
  97. const vMinNew = 30
  98. for (let index = 1; index < dataForRender.nodes.length; index++) {
  99. const size = dataForRender.nodes[index].symbolSize
  100. if (size > vMax) {
  101. vMax = size
  102. }
  103. if (size < vMin) {
  104. vMin = size
  105. }
  106. }
  107. let scale = null
  108. if (vMax === vMin) {
  109. scale = 1
  110. for (const iterator of dataForRender.nodes.slice(1)) {
  111. iterator.symbolSize = vMinNew + (vMaxNew - vMinNew) / 2
  112. }
  113. } else {
  114. scale = (vMaxNew - vMinNew) / (vMax - vMin)
  115. for (const iterator of dataForRender.nodes.slice(1)) {
  116. iterator.symbolSize = vMinNew + (iterator.symbolSize - vMin) * scale
  117. }
  118. }
  119. // 画边
  120. for (let i = 0; i < dataForRender.nodes.length; i++) {
  121. for (let j = i + 1; j < dataForRender.nodes.length; j++) {
  122. const hasCenterNode = (i === 0 || j === 0)
  123. if (hasCenterNode) {
  124. const newEdge = {
  125. source: dataForRender.nodes[i].id,
  126. target: dataForRender.nodes[j].id,
  127. value: dataForRender.nodes[i].symbolSize * dataForRender.nodes[j].symbolSize * 10, // 值越大,连接的两个节点间斥力越小。
  128. }
  129. dataForRender.edges.push(newEdge)
  130. } else {
  131. const newEdge = {
  132. source: dataForRender.nodes[i].id,
  133. target: dataForRender.nodes[j].id,
  134. value: dataForRender.nodes[i].symbolSize * dataForRender.nodes[j].symbolSize * 1, // 值越大,连接的两个节点间斥力越小。
  135. lineStyle: {
  136. opacity: 0,
  137. }
  138. }
  139. dataForRender.edges.push(newEdge)
  140. }
  141. }
  142. }
  143. // console.log(dataForRender);
  144. myChart.setOption({
  145. animationDurationUpdate: 1500,
  146. animationEasingUpdate: 'quinticInOut',
  147. series: [
  148. {
  149. type: 'graph',
  150. layout: 'force',
  151. draggable: false,
  152. // 力引导布局是模拟弹簧电荷模型在每两个节点之间添加一个斥力,每条边的两个节点之间添加一个引力
  153. force: {
  154. initLayout: 'circular', // 进行力引导布局前的初始化布局,初始化布局会影响到力引导的效果。默认不进行任何布局,使用节点中提供的 x, y 作为节点的位置。如果不存在的话会随机生成一个位置。也可以选择使用环形布局 'circular'。
  155. repulsion: 100, // 节点之间的斥力因子。傻逼文档把edgeLength当数组用的用法写到这上边了。
  156. gravity: 0.1, // 节点受到的向中心的引力因子。该值越大节点越往中心点靠拢。
  157. edgeLength: [50, 400], // 把各个边的两个节点之间的距离归一化到这个范围内。与repulsion共同作用。
  158. layoutAnimation: true,
  159. friction: 0.1, // 这个参数能减缓节点的移动速度。取值范围 0 到 1。但是仍然是个试验性的参数,参见 #11024。
  160. },
  161. data: dataForRender.nodes,
  162. // 或者叫edges
  163. links: dataForRender.edges,
  164. selectedMode: 'single',
  165. select: {
  166. itemStyle: {
  167. shadowBlur: 50,
  168. shadowColor: 'rgba(255, 255, 125, 0.7)',
  169. },
  170. label: {
  171. position: 'right',
  172. show: true,
  173. }
  174. },
  175. // 高亮状态的图形样式
  176. emphasis: {
  177. scale: false,
  178. label: {
  179. position: 'right',
  180. show: true
  181. }
  182. },
  183. // 图表是否可以移动、缩放
  184. roam: true,
  185. lineStyle: {
  186. width: 0.5,
  187. curveness: 0.3,
  188. opacity: 0.7,
  189. }
  190. }
  191. ]
  192. }, true)
  193. setTimeout(() => {
  194. // 等myChart上注册了select回调后再执行
  195. // 一开始自动选中表示时代的那个节点
  196. myChart.dispatchAction({
  197. type: 'select',
  198. seriesIndex: 0,
  199. name: timeList[timeIdx],
  200. })
  201. }, 0);
  202. }
  203. showChart(0)
  204. // 用户选中节点后,向父窗口post message
  205. function onSelect(params) {
  206. if (params.dataType === 'node') { // 用户选中节点触发的
  207. if (window.vuplex) {
  208. window.vuplex.postMessage({ type: 'select-id', message: dataForRender.nodes[params.dataIndexInside].id });
  209. } else {
  210. console.error('不存在window.vuplex!');
  211. }
  212. } else if (params.type === 'select') { // 程序里调用dispatchAction触发的,且type为select
  213. if (window.vuplex) {
  214. window.vuplex.postMessage({ type: 'select-id', message: dataForRender.nodes[0].id });
  215. } else {
  216. console.error('不存在window.vuplex!');
  217. }
  218. }
  219. }
  220. myChart.on('select', onSelect)
  221. window.addEventListener('resize', myChart.resize);
  222. // 切换时代
  223. window.changeTime = function (idx) {
  224. if (Number.isInteger(idx) && idx >= 0) {
  225. showChart(idx)
  226. } else {
  227. console.error('[page using echart] changeTime: invalid param!', idx);
  228. }
  229. }
  230. </script>
  231. </body>
  232. </html>